[SEBA-434] Replacing omci-sim with omci-lib-go

Change-Id: I499afc9ec49bb483467ea93bd6ce3077dd0ccc6e
diff --git a/internal/bbr/devices/olt.go b/internal/bbr/devices/olt.go
index 2093520..b65a174 100644
--- a/internal/bbr/devices/olt.go
+++ b/internal/bbr/devices/olt.go
@@ -20,6 +20,7 @@
 	"context"
 	"encoding/hex"
 	"fmt"
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"io"
 	"reflect"
 	"time"
@@ -273,9 +274,9 @@
 		"Pkt":    omciInd.Pkt,
 	}).Trace("Received Onu omci indication")
 
-	msg := devices.Message{
-		Type: devices.OmciIndication,
-		Data: devices.OmciIndicationMessage{
+	msg := types.Message{
+		Type: types.OmciIndication,
+		Data: types.OmciIndicationMessage{
 			OnuSN:   onu.SerialNumber,
 			OnuID:   onu.ID,
 			OmciInd: omciInd,
@@ -329,9 +330,9 @@
 		service := s.(*devices.Service)
 		onu := service.Onu
 
-		msg := devices.Message{
-			Type: devices.OnuPacketIn,
-			Data: devices.OnuPacketMessage{
+		msg := types.Message{
+			Type: types.OnuPacketIn,
+			Data: types.OnuPacketMessage{
 				IntfId:    pktIndication.IntfId,
 				OnuId:     onu.ID,
 				Packet:    pkt,
@@ -362,9 +363,9 @@
 		}
 		// NOTE when we push the EAPOL flow we set the PortNo = OnuId for convenience sake
 		// BBsim responds setting the port number that was sent with the flow
-		msg := devices.Message{
-			Type: devices.OnuPacketIn,
-			Data: devices.OnuPacketMessage{
+		msg := types.Message{
+			Type: types.OnuPacketIn,
+			Data: types.OnuPacketMessage{
 				IntfId: pktIndication.IntfId,
 				OnuId:  pktIndication.PortNo,
 				Packet: pkt,
diff --git a/internal/bbsim/alarmsim/alarmsim.go b/internal/bbsim/alarmsim/alarmsim.go
index cbb51da..6c6a290 100644
--- a/internal/bbsim/alarmsim/alarmsim.go
+++ b/internal/bbsim/alarmsim/alarmsim.go
@@ -17,17 +17,14 @@
 package alarmsim
 
 import (
-	"context"
 	"fmt"
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"strconv"
 
 	"github.com/opencord/bbsim/internal/common"
 
 	"github.com/opencord/bbsim/api/bbsim"
-	"github.com/opencord/bbsim/internal/bbsim/devices"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/status"
 )
 
 func AlarmNameToEnum(name string) (bbsim.AlarmType_Types, error) {
@@ -54,9 +51,8 @@
 }
 
 // BuildOnuAlarmIndication function forms openolt alarmIndication as per ONUAlarmRequest
-func BuildOnuAlarmIndication(req *bbsim.ONUAlarmRequest, o *devices.OltDevice) (*openolt.AlarmIndication, error) {
+func BuildOnuAlarmIndication(req *bbsim.ONUAlarmRequest, onuID uint32, ponPortID uint32) (*openolt.AlarmIndication, error) {
 	var alarm *openolt.AlarmIndication
-	var onu *devices.Onu
 	var err error
 
 	alarmType, err := AlarmNameToEnum(req.AlarmType)
@@ -64,37 +60,29 @@
 		return nil, err
 	}
 
-	if alarmType != bbsim.AlarmType_LOS {
-		// No ONU Id for LOS
-		onu, err = o.FindOnuBySn(req.SerialNumber)
-		if err != nil {
-			return nil, err
-		}
-	}
-
 	switch alarmType {
 	case bbsim.AlarmType_DYING_GASP:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_DyingGaspInd{DyingGaspInd: &openolt.DyingGaspIndication{
 				Status: req.Status,
-				OnuId:  onu.ID,
-				IntfId: onu.PonPortID,
+				OnuId:  onuID,
+				IntfId: ponPortID,
 			}},
 		}
 	case bbsim.AlarmType_ONU_STARTUP_FAILURE:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuStartupFailInd{OnuStartupFailInd: &openolt.OnuStartupFailureIndication{
 				Status: req.Status,
-				OnuId:  onu.ID,
-				IntfId: onu.PonPortID,
+				OnuId:  onuID,
+				IntfId: ponPortID,
 			}},
 		}
 	case bbsim.AlarmType_ONU_SIGNAL_DEGRADE:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuSignalDegradeInd{OnuSignalDegradeInd: &openolt.OnuSignalDegradeIndication{
 				Status:              req.Status,
-				OnuId:               onu.ID,
-				IntfId:              onu.PonPortID,
+				OnuId:               onuID,
+				IntfId:              ponPortID,
 				InverseBitErrorRate: uint32(extractInt(req.Parameters, "InverseBitErrorRate", 0)),
 			}},
 		}
@@ -102,8 +90,8 @@
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuSignalsFailInd{OnuSignalsFailInd: &openolt.OnuSignalsFailureIndication{
 				Status:              req.Status,
-				OnuId:               onu.ID,
-				IntfId:              onu.PonPortID,
+				OnuId:               onuID,
+				IntfId:              ponPortID,
 				InverseBitErrorRate: uint32(extractInt(req.Parameters, "InverseBitErrorRate", 0)),
 			}},
 		}
@@ -111,8 +99,8 @@
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuDriftOfWindowInd{OnuDriftOfWindowInd: &openolt.OnuDriftOfWindowIndication{
 				Status: req.Status,
-				OnuId:  onu.ID,
-				IntfId: onu.PonPortID,
+				OnuId:  onuID,
+				IntfId: ponPortID,
 				Drift:  uint32(extractInt(req.Parameters, "Drift", 0)),
 				NewEqd: uint32(extractInt(req.Parameters, "NewEqd", 0)),
 			}},
@@ -121,47 +109,47 @@
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuLossOmciInd{OnuLossOmciInd: &openolt.OnuLossOfOmciChannelIndication{
 				Status: req.Status,
-				OnuId:  onu.ID,
-				IntfId: onu.PonPortID,
+				OnuId:  onuID,
+				IntfId: ponPortID,
 			}},
 		}
 	case bbsim.AlarmType_ONU_TRANSMISSION_INTERFERENCE_WARNING:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuTiwiInd{OnuTiwiInd: &openolt.OnuTransmissionInterferenceWarning{
 				Status: req.Status,
-				OnuId:  onu.ID,
-				IntfId: onu.PonPortID,
+				OnuId:  onuID,
+				IntfId: ponPortID,
 				Drift:  uint32(extractInt(req.Parameters, "Drift", 0)),
 			}},
 		}
 	case bbsim.AlarmType_ONU_ACTIVATION_FAILURE:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuActivationFailInd{OnuActivationFailInd: &openolt.OnuActivationFailureIndication{
-				OnuId:      onu.ID,
-				IntfId:     onu.PonPortID,
+				OnuId:      onuID,
+				IntfId:     ponPortID,
 				FailReason: uint32(extractInt(req.Parameters, "FailReason", 0)),
 			}},
 		}
 	case bbsim.AlarmType_ONU_PROCESSING_ERROR:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuProcessingErrorInd{OnuProcessingErrorInd: &openolt.OnuProcessingErrorIndication{
-				OnuId:  onu.ID,
-				IntfId: onu.PonPortID,
+				OnuId:  onuID,
+				IntfId: ponPortID,
 			}},
 		}
 	case bbsim.AlarmType_ONU_LOSS_OF_KEY_SYNC_FAILURE:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuLossOfSyncFailInd{OnuLossOfSyncFailInd: &openolt.OnuLossOfKeySyncFailureIndication{
-				OnuId:  onu.ID,
-				IntfId: onu.PonPortID,
+				OnuId:  onuID,
+				IntfId: ponPortID,
 				Status: req.Status,
 			}},
 		}
 	case bbsim.AlarmType_ONU_ITU_PON_STATS:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuItuPonStatsInd{OnuItuPonStatsInd: &openolt.OnuItuPonStatsIndication{
-				OnuId:  onu.ID,
-				IntfId: onu.PonPortID,
+				OnuId:  onuID,
+				IntfId: ponPortID,
 				Stats: &openolt.OnuItuPonStatsIndication_RdiErrorInd{
 					RdiErrorInd: &openolt.RdiErrorIndication{
 						RdiErrorCount: uint64(extractInt(req.Parameters, "RdiErrors", 0)),
@@ -174,48 +162,48 @@
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
 				LosStatus: req.Status,
-				OnuId:     onu.ID,
-				IntfId:    onu.PonPortID,
+				OnuId:     onuID,
+				IntfId:    ponPortID,
 			}},
 		}
 	case bbsim.AlarmType_ONU_ALARM_LOB:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
 				LobStatus: req.Status,
-				OnuId:     onu.ID,
-				IntfId:    onu.PonPortID,
+				OnuId:     onuID,
+				IntfId:    ponPortID,
 			}},
 		}
 	case bbsim.AlarmType_ONU_ALARM_LOPC_MISS:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
 				LopcMissStatus: req.Status,
-				OnuId:          onu.ID,
-				IntfId:         onu.PonPortID,
+				OnuId:          onuID,
+				IntfId:         ponPortID,
 			}},
 		}
 	case bbsim.AlarmType_ONU_ALARM_LOPC_MIC_ERROR:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
 				LopcMicErrorStatus: req.Status,
-				OnuId:              onu.ID,
-				IntfId:             onu.PonPortID,
+				OnuId:              onuID,
+				IntfId:             ponPortID,
 			}},
 		}
 	case bbsim.AlarmType_ONU_ALARM_LOFI:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
 				LofiStatus: req.Status,
-				OnuId:      onu.ID,
-				IntfId:     onu.PonPortID,
+				OnuId:      onuID,
+				IntfId:     ponPortID,
 			}},
 		}
 	case bbsim.AlarmType_ONU_ALARM_LOAMI:
 		alarm = &openolt.AlarmIndication{
 			Data: &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
 				LoamiStatus: req.Status,
-				OnuId:       onu.ID,
-				IntfId:      onu.PonPortID,
+				OnuId:       onuID,
+				IntfId:      ponPortID,
 			}},
 		}
 	default:
@@ -226,70 +214,18 @@
 }
 
 // SimulateOnuAlarm accept request for Onu alarms and send proper alarmIndication to openolt stream
-func SimulateOnuAlarm(ctx context.Context, req *bbsim.ONUAlarmRequest, o *devices.OltDevice) error {
-	alarmIndication, err := BuildOnuAlarmIndication(req, o)
+func SimulateOnuAlarm(req *bbsim.ONUAlarmRequest, onuID uint32, ponPortID uint32, channel chan types.Message) error {
+	alarmIndication, err := BuildOnuAlarmIndication(req, onuID, ponPortID)
 	if err != nil {
 		return err
 	}
 
-	err = o.SendAlarmIndication(ctx, alarmIndication)
-	if err != nil {
-		return err
+	msg := types.Message{
+		Type: types.AlarmIndication,
+		Data: alarmIndication,
 	}
 
-	return nil
-}
-
-// IsPonPortPresentInOlt verifies if given Pon port is present in olt
-func IsPonPortPresentInOlt(PonPort uint32) bool {
-	o := devices.GetOLT()
-	for _, intf := range o.Pons {
-		if intf.ID == PonPort {
-			return true
-		}
-	}
-	return false
-}
-
-// IsNniPortPresentInOlt verifies if given nni port is present in olt
-func IsNniPortPresentInOlt(nniPort uint32) bool {
-	o := devices.GetOLT()
-	for _, intf := range o.Nnis {
-		if intf.ID == nniPort {
-			return true
-		}
-	}
-	return false
-}
-
-// SimulateOltAlarm accept request for Olt alarms and send proper alarmIndication to openolt stream
-func SimulateOltAlarm(ctx context.Context, req *bbsim.OLTAlarmRequest, o *devices.OltDevice) error {
-	var alarmIndication *openolt.AlarmIndication
-	var err error
-
-	//check if its a valid port id
-	switch req.InterfaceType {
-	case "nni":
-		if !IsNniPortPresentInOlt(uint32(req.InterfaceID)) {
-			return status.Errorf(codes.NotFound, strconv.Itoa(int(req.InterfaceID))+" NNI not present in olt")
-		}
-
-	case "pon":
-		if !IsPonPortPresentInOlt(uint32(req.InterfaceID)) {
-			return status.Errorf(codes.NotFound, strconv.Itoa(int(req.InterfaceID))+" PON not present in olt")
-		}
-	}
-	alarmIndication = &openolt.AlarmIndication{
-		Data: &openolt.AlarmIndication_LosInd{LosInd: &openolt.LosIndication{
-			Status: req.Status,
-			IntfId: devices.InterfaceIDToPortNo(req.InterfaceID, req.InterfaceType),
-		}},
-	}
-
-	err = o.SendAlarmIndication(ctx, alarmIndication)
-	if err != nil {
-		return err
-	}
+	channel <- msg
 
 	return nil
 }
diff --git a/internal/bbsim/api/grpc_api_server.go b/internal/bbsim/api/grpc_api_server.go
index 84d3478..5fd6392 100644
--- a/internal/bbsim/api/grpc_api_server.go
+++ b/internal/bbsim/api/grpc_api_server.go
@@ -23,7 +23,6 @@
 	"time"
 
 	"github.com/opencord/bbsim/api/bbsim"
-	"github.com/opencord/bbsim/internal/bbsim/alarmsim"
 	"github.com/opencord/bbsim/internal/bbsim/devices"
 	"github.com/opencord/bbsim/internal/common"
 	log "github.com/sirupsen/logrus"
@@ -193,12 +192,22 @@
 
 func (s BBSimServer) SetOnuAlarmIndication(ctx context.Context, req *bbsim.ONUAlarmRequest) (*bbsim.Response, error) {
 	o := devices.GetOLT()
-	err := alarmsim.SimulateOnuAlarm(ctx, req, o)
+
+	res := &bbsim.Response{}
+
+	onu, err := o.FindOnuBySn(req.SerialNumber)
 	if err != nil {
+		res.StatusCode = int32(codes.NotFound)
+		res.Message = err.Error()
 		return nil, err
 	}
 
-	res := &bbsim.Response{}
+	if err := onu.SetAlarm(req.AlarmType, req.Status); err != nil {
+		res.StatusCode = int32(codes.Internal)
+		res.Message = err.Error()
+		return nil, err
+	}
+
 	res.StatusCode = int32(codes.OK)
 	res.Message = fmt.Sprintf("Onu Alarm Indication Sent.")
 	return res, nil
@@ -207,12 +216,14 @@
 // SetOltAlarmIndication generates OLT Alarms for LOS
 func (s BBSimServer) SetOltAlarmIndication(ctx context.Context, req *bbsim.OLTAlarmRequest) (*bbsim.Response, error) {
 	o := devices.GetOLT()
-	err := alarmsim.SimulateOltAlarm(ctx, req, o)
-	if err != nil {
+	res := &bbsim.Response{}
+
+	if err := o.SetAlarm(req.InterfaceID, req.InterfaceType, req.Status); err != nil {
+		res.StatusCode = int32(codes.Internal)
+		res.Message = err.Error()
 		return nil, err
 	}
 
-	res := &bbsim.Response{}
 	res.StatusCode = int32(codes.OK)
 	res.Message = fmt.Sprintf("Olt Alarm Indication Sent.")
 	return res, nil
diff --git a/internal/bbsim/api/onus_handler.go b/internal/bbsim/api/onus_handler.go
index 43b624f..2533fa3 100644
--- a/internal/bbsim/api/onus_handler.go
+++ b/internal/bbsim/api/onus_handler.go
@@ -19,10 +19,10 @@
 import (
 	"context"
 	"fmt"
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
 
 	"github.com/opencord/bbsim/api/bbsim"
-	"github.com/opencord/bbsim/internal/bbsim/alarmsim"
 	"github.com/opencord/bbsim/internal/bbsim/devices"
 	log "github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
@@ -270,7 +270,7 @@
 					"Service": service.Name,
 				}).Debugf("Sending %s event on Service %s", event, service.Name)
 
-				if err := service.IGMPState.Event(event, devices.IgmpMessage{GroupAddress: req.GroupAddress}); err != nil {
+				if err := service.IGMPState.Event(event, types.IgmpMessage{GroupAddress: req.GroupAddress}); err != nil {
 					logger.WithFields(log.Fields{
 						"OnuId":   onu.ID,
 						"IntfId":  onu.PonPortID,
@@ -452,64 +452,13 @@
 
 func handlePoweronONU(onu *devices.Onu) (*bbsim.Response, error) {
 	res := &bbsim.Response{}
-	olt := devices.GetOLT()
-	intitalState := onu.InternalState.Current()
-	if onu.InternalState.Current() == "created" || onu.InternalState.Current() == "disabled" {
-		if err := onu.InternalState.Event("initialize"); err != nil {
-			logger.WithFields(log.Fields{
-				"OnuId":  onu.ID,
-				"IntfId": onu.PonPortID,
-				"OnuSn":  onu.Sn(),
-			}).Errorf("Cannot poweron ONU: %s", err.Error())
-			res.StatusCode = int32(codes.FailedPrecondition)
-			res.Message = err.Error()
-			return res, err
-		}
-	}
 
-	losReq := bbsim.ONUAlarmRequest{
-		AlarmType:    "ONU_ALARM_LOS",
-		SerialNumber: onu.Sn(),
-		Status:       "off",
-	}
-
-	if err := alarmsim.SimulateOnuAlarm(context.TODO(), &losReq, olt); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot send LOS: %s", err.Error())
+	if err := onu.HandlePowerOnONU(); err != nil {
 		res.StatusCode = int32(codes.FailedPrecondition)
 		res.Message = err.Error()
 		return res, err
 	}
 
-	if err := onu.InternalState.Event("discover"); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot poweron ONU: %s", err.Error())
-		res.StatusCode = int32(codes.FailedPrecondition)
-		res.Message = err.Error()
-		return res, err
-	}
-	// move onu directly to enable state only when its a powercycle case
-	// in case of first time onu poweron onu will be moved to enable on
-	// receiving ActivateOnu request from openolt adapter
-	if intitalState == "disabled" {
-		if err := onu.InternalState.Event("enable"); err != nil {
-			logger.WithFields(log.Fields{
-				"OnuId":  onu.ID,
-				"IntfId": onu.PonPortID,
-				"OnuSn":  onu.Sn(),
-			}).Errorf("Cannot enable ONU: %s", err.Error())
-			res.StatusCode = int32(codes.FailedPrecondition)
-			res.Message = err.Error()
-			return res, err
-		}
-	}
-
 	res.StatusCode = int32(codes.OK)
 	res.Message = fmt.Sprintf("ONU %s successfully powered on.", onu.Sn())
 
@@ -518,50 +467,8 @@
 
 func handleShutdownONU(onu *devices.Onu) (*bbsim.Response, error) {
 	res := &bbsim.Response{}
-	olt := devices.GetOLT()
 
-	dyingGasp := bbsim.ONUAlarmRequest{
-		AlarmType:    "DYING_GASP",
-		SerialNumber: onu.Sn(),
-		Status:       "on",
-	}
-
-	if err := alarmsim.SimulateOnuAlarm(context.TODO(), &dyingGasp, olt); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot send Dying Gasp: %s", err.Error())
-		res.StatusCode = int32(codes.FailedPrecondition)
-		res.Message = err.Error()
-		return res, err
-	}
-
-	losReq := bbsim.ONUAlarmRequest{
-		AlarmType:    "ONU_ALARM_LOS",
-		SerialNumber: onu.Sn(),
-		Status:       "on",
-	}
-
-	if err := alarmsim.SimulateOnuAlarm(context.TODO(), &losReq, olt); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot send LOS: %s", err.Error())
-		res.StatusCode = int32(codes.FailedPrecondition)
-		res.Message = err.Error()
-		return res, err
-	}
-
-	// TODO if it's the last ONU on the PON, then send a PON LOS
-
-	if err := onu.InternalState.Event("disable"); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot shutdown ONU: %s", err.Error())
+	if err := onu.HandleShutdownONU(); err != nil {
 		res.StatusCode = int32(codes.FailedPrecondition)
 		res.Message = err.Error()
 		return res, err
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index 9e26ad2..6540a56 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -21,8 +21,10 @@
 	"encoding/hex"
 	"fmt"
 	"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/voltha-protos/v4/go/ext/config"
 	"net"
+	"strconv"
 	"sync"
 	"time"
 
@@ -31,7 +33,6 @@
 	"github.com/looplab/fsm"
 	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
 	"github.com/opencord/bbsim/internal/common"
-	omcisim "github.com/opencord/omci-sim"
 	common_protos "github.com/opencord/voltha-protos/v4/go/common"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
 	"github.com/opencord/voltha-protos/v4/go/tech_profile"
@@ -57,7 +58,7 @@
 	NumPon               int
 	NumOnuPerPon         int
 	InternalState        *fsm.FSM
-	channel              chan Message
+	channel              chan types.Message
 	dhcpServer           dhcp.DHCPServerIf
 	Flows                sync.Map
 	Delay                int
@@ -230,7 +231,7 @@
 	}
 
 	// create new channel for processOltMessages Go routine
-	o.channel = make(chan Message)
+	o.channel = make(chan types.Message)
 
 	// FIXME we are assuming we have only one NNI
 	if o.Nnis[0] != nil {
@@ -272,10 +273,10 @@
 		for _, pon := range o.Pons {
 			if pon.InternalState.Current() == "enabled" {
 				// disable PONs
-				msg := Message{
-					Type: PonIndication,
-					Data: PonIndicationMessage{
-						OperState: DOWN,
+				msg := types.Message{
+					Type: types.PonIndication,
+					Data: types.PonIndicationMessage{
+						OperState: types.DOWN,
 						PonPortID: pon.ID,
 					},
 				}
@@ -388,35 +389,33 @@
 	go o.processOltMessages(o.enableContext, stream, &wg)
 
 	// enable the OLT
-	oltMsg := Message{
-		Type: OltIndication,
-		Data: OltIndicationMessage{
-			OperState: UP,
+	oltMsg := types.Message{
+		Type: types.OltIndication,
+		Data: types.OltIndicationMessage{
+			OperState: types.UP,
 		},
 	}
 	o.channel <- oltMsg
 
 	// send NNI Port Indications
 	for _, nni := range o.Nnis {
-		msg := Message{
-			Type: NniIndication,
-			Data: NniIndicationMessage{
-				OperState: UP,
+		msg := types.Message{
+			Type: types.NniIndication,
+			Data: types.NniIndicationMessage{
+				OperState: types.UP,
 				NniPortID: nni.ID,
 			},
 		}
 		o.channel <- msg
 	}
 
-	go o.processOmciMessages(o.enableContext, stream, &wg)
-
 	if rebootFlag {
 		for _, pon := range o.Pons {
 			if pon.InternalState.Current() == "disabled" {
-				msg := Message{
-					Type: PonIndication,
-					Data: PonIndicationMessage{
-						OperState: UP,
+				msg := types.Message{
+					Type: types.PonIndication,
+					Data: types.PonIndicationMessage{
+						OperState: types.UP,
 						PonPortID: pon.ID,
 					},
 				}
@@ -431,10 +430,10 @@
 		if o.ControlledActivation == Default || o.ControlledActivation == OnlyONU {
 			// send PON Port indications
 			for _, pon := range o.Pons {
-				msg := Message{
-					Type: PonIndication,
-					Data: PonIndicationMessage{
-						OperState: UP,
+				msg := types.Message{
+					Type: types.PonIndication,
+					Data: types.PonIndicationMessage{
+						OperState: types.UP,
 						PonPortID: pon.ID,
 					},
 				}
@@ -453,43 +452,6 @@
 	wg.Wait()
 }
 
-func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
-	ch := omcisim.GetChannel()
-
-	oltLogger.Debug("Starting OMCI Indication Channel")
-
-loop:
-	for {
-		select {
-		case <-ctx.Done():
-			oltLogger.Debug("OMCI processing canceled via context")
-			break loop
-		case message, ok := <-ch:
-			if !ok || ctx.Err() != nil {
-				oltLogger.Debug("OMCI processing canceled via channel close")
-				break loop
-			}
-
-			oltLogger.WithFields(log.Fields{
-				"messageType": message.Type,
-				"OnuId":       message.Data.OnuId,
-				"IntfId":      message.Data.IntfId,
-			}).Debug("Received message on OMCI Sim channel")
-
-			onuId := message.Data.OnuId
-			intfId := message.Data.IntfId
-			onu, err := o.FindOnuById(intfId, onuId)
-			if err != nil {
-				oltLogger.Errorf("Failed to find onu: %v", err)
-				continue
-			}
-			go onu.processOmciMessage(message, stream)
-		}
-	}
-
-	wg.Done()
-}
-
 func (o *OltDevice) periodicPortStats(ctx context.Context) {
 	var portStats *openolt.PortStatistics
 	for {
@@ -525,6 +487,55 @@
 
 // Helpers method
 
+func (o *OltDevice) SetAlarm(interfaceId uint32, interfaceType string, alarmStatus string) error {
+
+	switch interfaceType {
+	case "nni":
+		if !o.HasNni(interfaceId) {
+			return status.Errorf(codes.NotFound, strconv.Itoa(int(interfaceId))+" NNI not present in olt")
+		}
+
+	case "pon":
+		if !o.HasPon(interfaceId) {
+			return status.Errorf(codes.NotFound, strconv.Itoa(int(interfaceId))+" PON not present in olt")
+		}
+	}
+
+	alarmIndication := &openolt.AlarmIndication{
+		Data: &openolt.AlarmIndication_LosInd{LosInd: &openolt.LosIndication{
+			Status: alarmStatus,
+			IntfId: InterfaceIDToPortNo(interfaceId, interfaceType),
+		}},
+	}
+
+	msg := types.Message{
+		Type: types.AlarmIndication,
+		Data: alarmIndication,
+	}
+
+	o.channel <- msg
+
+	return nil
+}
+
+func (o *OltDevice) HasNni(id uint32) bool {
+	for _, intf := range o.Nnis {
+		if intf.ID == id {
+			return true
+		}
+	}
+	return false
+}
+
+func (o *OltDevice) HasPon(id uint32) bool {
+	for _, intf := range o.Pons {
+		if intf.ID == id {
+			return true
+		}
+	}
+	return false
+}
+
 func (o *OltDevice) GetPonById(id uint32) (*PonPort, error) {
 	for _, pon := range o.Pons {
 		if pon.ID == id {
@@ -555,7 +566,7 @@
 	}).Debug("Sent Indication_AlarmInd")
 }
 
-func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *OltDevice) sendOltIndication(msg types.OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
 	data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
 	if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
 		oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
@@ -567,9 +578,9 @@
 	}).Debug("Sent Indication_OltInd")
 }
 
-func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *OltDevice) sendNniIndication(msg types.NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
 	nni, _ := o.getNniById(msg.NniPortID)
-	if msg.OperState == UP {
+	if msg.OperState == types.UP {
 		if err := nni.OperState.Event("enable"); err != nil {
 			log.WithFields(log.Fields{
 				"Type":      nni.Type,
@@ -577,7 +588,7 @@
 				"OperState": nni.OperState.Current(),
 			}).Errorf("Can't move NNI Port to enabled state: %v", err)
 		}
-	} else if msg.OperState == DOWN {
+	} else if msg.OperState == types.DOWN {
 		if err := nni.OperState.Event("disable"); err != nil {
 			log.WithFields(log.Fields{
 				"Type":      nni.Type,
@@ -685,26 +696,26 @@
 			}).Trace("Received message")
 
 			switch message.Type {
-			case OltIndication:
-				msg, _ := message.Data.(OltIndicationMessage)
-				if msg.OperState == UP {
+			case types.OltIndication:
+				msg, _ := message.Data.(types.OltIndicationMessage)
+				if msg.OperState == types.UP {
 					_ = o.InternalState.Event("enable")
 					_ = o.OperState.Event("enable")
-				} else if msg.OperState == DOWN {
+				} else if msg.OperState == types.DOWN {
 					_ = o.InternalState.Event("disable")
 					_ = o.OperState.Event("disable")
 				}
 				o.sendOltIndication(msg, stream)
-			case AlarmIndication:
+			case types.AlarmIndication:
 				alarmInd, _ := message.Data.(*openolt.AlarmIndication)
 				o.sendAlarmIndication(alarmInd, stream)
-			case NniIndication:
-				msg, _ := message.Data.(NniIndicationMessage)
+			case types.NniIndication:
+				msg, _ := message.Data.(types.NniIndicationMessage)
 				o.sendNniIndication(msg, stream)
-			case PonIndication:
-				msg, _ := message.Data.(PonIndicationMessage)
+			case types.PonIndication:
+				msg, _ := message.Data.(types.PonIndicationMessage)
 				pon, _ := o.GetPonById(msg.PonPortID)
-				if msg.OperState == UP {
+				if msg.OperState == types.UP {
 					if err := pon.OperState.Event("enable"); err != nil {
 						oltLogger.WithFields(log.Fields{
 							"IntfId": msg.PonPortID,
@@ -717,7 +728,7 @@
 							"Err":    err,
 						}).Error("Can't Enable Internal state for PON Port")
 					}
-				} else if msg.OperState == DOWN {
+				} else if msg.OperState == types.DOWN {
 					if err := pon.OperState.Event("disable"); err != nil {
 						oltLogger.WithFields(log.Fields{
 							"IntfId": msg.PonPortID,
@@ -873,10 +884,10 @@
 	for _, pon := range o.Pons {
 		if pon.InternalState.Current() == "enabled" {
 			// disable PONs
-			msg := Message{
-				Type: PonIndication,
-				Data: PonIndicationMessage{
-					OperState: DOWN,
+			msg := types.Message{
+				Type: types.PonIndication,
+				Data: types.PonIndicationMessage{
+					OperState: types.DOWN,
 					PonPortID: pon.ID,
 				},
 			}
@@ -888,10 +899,10 @@
 	// The reason for that is in-band management
 
 	// disable OLT
-	oltMsg := Message{
-		Type: OltIndication,
-		Data: OltIndicationMessage{
-			OperState: DOWN,
+	oltMsg := types.Message{
+		Type: types.OltIndication,
+		Data: types.OltIndicationMessage{
+			OperState: types.DOWN,
 		},
 	}
 	o.channel <- oltMsg
@@ -903,10 +914,10 @@
 	ponID := intf.GetIntfId()
 	pon, _ := o.GetPonById(intf.IntfId)
 
-	msg := Message{
-		Type: PonIndication,
-		Data: PonIndicationMessage{
-			OperState: DOWN,
+	msg := types.Message{
+		Type: types.PonIndication,
+		Data: types.PonIndicationMessage{
+			OperState: types.DOWN,
 			PonPortID: ponID,
 		},
 	}
@@ -914,8 +925,8 @@
 
 	for _, onu := range pon.Onus {
 
-		onuIndication := OnuIndicationMessage{
-			OperState: DOWN,
+		onuIndication := types.OnuIndicationMessage{
+			OperState: types.DOWN,
 			PonPortID: ponID,
 			OnuID:     onu.ID,
 			OnuSN:     onu.SerialNumber,
@@ -939,10 +950,10 @@
 	ponID := intf.GetIntfId()
 	pon, _ := o.GetPonById(intf.IntfId)
 
-	msg := Message{
-		Type: PonIndication,
-		Data: PonIndicationMessage{
-			OperState: UP,
+	msg := types.Message{
+		Type: types.PonIndication,
+		Data: types.PonIndicationMessage{
+			OperState: types.UP,
 			PonPortID: ponID,
 		},
 	}
@@ -950,8 +961,8 @@
 
 	for _, onu := range pon.Onus {
 
-		onuIndication := OnuIndicationMessage{
-			OperState: UP,
+		onuIndication := types.OnuIndicationMessage{
+			OperState: types.UP,
 			PonPortID: ponID,
 			OnuID:     onu.ID,
 			OnuSN:     onu.SerialNumber,
@@ -1030,9 +1041,9 @@
 			}
 		}
 
-		msg := Message{
-			Type: FlowAdd,
-			Data: OnuFlowUpdateMessage{
+		msg := types.Message{
+			Type: types.FlowAdd,
+			Data: types.OnuFlowUpdateMessage{
 				PonPortID: pon.ID,
 				OnuID:     onu.ID,
 				Flow:      flow,
@@ -1107,9 +1118,9 @@
 			return nil, err
 		}
 
-		msg := Message{
-			Type: FlowRemoved,
-			Data: OnuFlowUpdateMessage{
+		msg := types.Message{
+			Type: types.FlowRemoved,
+			Data: types.OnuFlowUpdateMessage{
 				Flow: flow,
 			},
 		}
@@ -1193,12 +1204,12 @@
 		"OnuId":  onu.ID,
 		"OnuSn":  onu.Sn(),
 	}).Tracef("Received OmciMsgOut")
-	msg := Message{
-		Type: OMCI,
-		Data: OmciMessage{
+	msg := types.Message{
+		Type: types.OMCI,
+		Data: types.OmciMessage{
 			OnuSN:   onu.SerialNumber,
 			OnuID:   onu.ID,
-			omciMsg: omci_msg,
+			OmciMsg: omci_msg,
 		},
 	}
 	onu.Channel <- msg
@@ -1254,9 +1265,9 @@
 		return new(openolt.Empty), nil
 	}
 
-	msg := Message{
-		Type: OnuPacketOut,
-		Data: OnuPacketMessage{
+	msg := types.Message{
+		Type: types.OnuPacketOut,
+		Data: types.OnuPacketMessage{
 			IntfId:     onuPkt.IntfId,
 			OnuId:      onuPkt.OnuId,
 			Packet:     rawpkt,
@@ -1291,20 +1302,20 @@
 	publishEvent("OLT-reenable-received", -1, -1, "")
 
 	// enable OLT
-	oltMsg := Message{
-		Type: OltIndication,
-		Data: OltIndicationMessage{
-			OperState: UP,
+	oltMsg := types.Message{
+		Type: types.OltIndication,
+		Data: types.OltIndicationMessage{
+			OperState: types.UP,
 		},
 	}
 	o.channel <- oltMsg
 
 	for _, pon := range o.Pons {
 		if pon.InternalState.Current() == "disabled" {
-			msg := Message{
-				Type: PonIndication,
-				Data: PonIndicationMessage{
-					OperState: UP,
+			msg := types.Message{
+				Type: types.PonIndication,
+				Data: types.PonIndicationMessage{
+					OperState: types.UP,
 					PonPortID: pon.ID,
 				},
 			}
@@ -1397,17 +1408,6 @@
 	return new(openolt.Empty), nil
 }
 
-// assumes caller has properly formulated an openolt.AlarmIndication
-func (o *OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
-	msg := Message{
-		Type: AlarmIndication,
-		Data: ind,
-	}
-
-	o.channel <- msg
-	return nil
-}
-
 func (o *OltDevice) PerformGroupOperation(ctx context.Context, group *openolt.Group) (*openolt.Empty, error) {
 	oltLogger.WithFields(log.Fields{
 		"GroupId": group.GroupId,
diff --git a/internal/bbsim/devices/olt_test.go b/internal/bbsim/devices/olt_test.go
index 0081ffa..154942b 100644
--- a/internal/bbsim/devices/olt_test.go
+++ b/internal/bbsim/devices/olt_test.go
@@ -17,6 +17,7 @@
 package devices
 
 import (
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/bbsim/internal/common"
 	"net"
 	"testing"
@@ -202,7 +203,7 @@
 		FlowId:     64,
 		Classifier: &openolt.Classifier{},
 	}
-	msg1 := OnuFlowUpdateMessage{
+	msg1 := types.OnuFlowUpdateMessage{
 		OnuID:     onu1.ID,
 		PonPortID: onu1.PonPortID,
 		Flow:      &flow1,
@@ -214,7 +215,7 @@
 		FlowId:     72,
 		Classifier: &openolt.Classifier{},
 	}
-	msg2 := OnuFlowUpdateMessage{
+	msg2 := types.OnuFlowUpdateMessage{
 		OnuID:     onu2.ID,
 		PonPortID: onu2.PonPortID,
 		Flow:      &flow2,
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index b85c804..822ec6b 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -20,20 +20,24 @@
 	"context"
 	"encoding/hex"
 	"fmt"
+	pb "github.com/opencord/bbsim/api/bbsim"
+	"github.com/opencord/bbsim/internal/bbsim/alarmsim"
+	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
+	me "github.com/opencord/omci-lib-go/generated"
+	"strconv"
+
 	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
 	"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
 	"github.com/opencord/bbsim/internal/bbsim/responders/eapol"
 	"net"
-
 	"time"
 
-	"github.com/cboling/omci"
 	"github.com/google/gopacket/layers"
 	"github.com/jpillora/backoff"
 	"github.com/looplab/fsm"
 	"github.com/opencord/bbsim/internal/common"
 	omcilib "github.com/opencord/bbsim/internal/common/omci"
-	omcisim "github.com/opencord/omci-sim"
+	"github.com/opencord/omci-lib-go"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
 	"github.com/opencord/voltha-protos/v4/go/tech_profile"
 	log "github.com/sirupsen/logrus"
@@ -72,7 +76,7 @@
 	OperState    *fsm.FSM
 	SerialNumber *openolt.SerialNumber
 
-	Channel chan Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
+	Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
 
 	// OMCI params
 	tid       uint16
@@ -143,7 +147,7 @@
 			},
 			"enter_initialized": func(e *fsm.Event) {
 				// create new channel for ProcessOnuMessages Go routine
-				o.Channel = make(chan Message, 2048)
+				o.Channel = make(chan bbsim.Message, 2048)
 
 				if err := o.OperState.Event("enable"); err != nil {
 					onuLogger.WithFields(log.Fields{
@@ -159,22 +163,21 @@
 				}
 			},
 			"enter_discovered": func(e *fsm.Event) {
-				msg := Message{
-					Type: OnuDiscIndication,
-					Data: OnuDiscIndicationMessage{
-						Onu:       &o,
-						OperState: UP,
+				msg := bbsim.Message{
+					Type: bbsim.OnuDiscIndication,
+					Data: bbsim.OnuDiscIndicationMessage{
+						OperState: bbsim.UP,
 					},
 				}
 				o.Channel <- msg
 			},
 			"enter_enabled": func(event *fsm.Event) {
-				msg := Message{
-					Type: OnuIndication,
-					Data: OnuIndicationMessage{
+				msg := bbsim.Message{
+					Type: bbsim.OnuIndication,
+					Data: bbsim.OnuIndicationMessage{
 						OnuSN:     o.SerialNumber,
 						PonPortID: o.PonPortID,
-						OperState: UP,
+						OperState: bbsim.UP,
 					},
 				}
 				o.Channel <- msg
@@ -201,12 +204,12 @@
 				}
 
 				// send the OnuIndication DOWN event
-				msg := Message{
-					Type: OnuIndication,
-					Data: OnuIndicationMessage{
+				msg := bbsim.Message{
+					Type: bbsim.OnuIndication,
+					Data: bbsim.OnuIndicationMessage{
 						OnuSN:     o.SerialNumber,
 						PonPortID: o.PonPortID,
-						OperState: DOWN,
+						OperState: bbsim.DOWN,
 					},
 				}
 				o.Channel <- msg
@@ -223,14 +226,14 @@
 			},
 			// BBR states
 			"enter_eapol_flow_sent": func(e *fsm.Event) {
-				msg := Message{
-					Type: SendEapolFlow,
+				msg := bbsim.Message{
+					Type: bbsim.SendEapolFlow,
 				}
 				o.Channel <- msg
 			},
 			"enter_dhcp_flow_sent": func(e *fsm.Event) {
-				msg := Message{
-					Type: SendDhcpFlow,
+				msg := bbsim.Message{
+					Type: bbsim.SendDhcpFlow,
 				}
 				o.Channel <- msg
 			},
@@ -280,26 +283,45 @@
 			}).Tracef("Received message on ONU Channel")
 
 			switch message.Type {
-			case OnuDiscIndication:
-				msg, _ := message.Data.(OnuDiscIndicationMessage)
+			case bbsim.OnuDiscIndication:
+				msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
 				// NOTE we need to slow down and send ONU Discovery Indication in batches to better emulate a real scenario
 				time.Sleep(o.DiscoveryDelay)
 				o.sendOnuDiscIndication(msg, stream)
-			case OnuIndication:
-				msg, _ := message.Data.(OnuIndicationMessage)
+			case bbsim.OnuIndication:
+				msg, _ := message.Data.(bbsim.OnuIndicationMessage)
 				o.sendOnuIndication(msg, stream)
-			case OMCI:
-				msg, _ := message.Data.(OmciMessage)
-				o.handleOmciMessage(msg, stream)
-			case FlowAdd:
-				msg, _ := message.Data.(OnuFlowUpdateMessage)
+			case bbsim.OMCI:
+				msg, _ := message.Data.(bbsim.OmciMessage)
+				o.handleOmciRequest(msg, stream)
+			case bbsim.UniStatusAlarm:
+				msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
+				pkt := omcilib.CreateUniStatusAlarm(msg.AdminState, msg.EntityID)
+				if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
+					onuLogger.WithFields(log.Fields{
+						"IntfId":       o.PonPortID,
+						"SerialNumber": o.Sn(),
+						"omciPacket":   pkt,
+						"adminState":   msg.AdminState,
+						"entityID":     msg.EntityID,
+					}).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
+				}
+				onuLogger.WithFields(log.Fields{
+					"IntfId":       o.PonPortID,
+					"SerialNumber": o.Sn(),
+					"omciPacket":   pkt,
+					"adminState":   msg.AdminState,
+					"entityID":     msg.EntityID,
+				}).Trace("UNI-Link-alarm-sent")
+			case bbsim.FlowAdd:
+				msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
 				o.handleFlowAdd(msg)
-			case FlowRemoved:
-				msg, _ := message.Data.(OnuFlowUpdateMessage)
+			case bbsim.FlowRemoved:
+				msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
 				o.handleFlowRemove(msg)
-			case OnuPacketOut:
+			case bbsim.OnuPacketOut:
 
-				msg, _ := message.Data.(OnuPacketMessage)
+				msg, _ := message.Data.(bbsim.OnuPacketMessage)
 
 				onuLogger.WithFields(log.Fields{
 					"IntfId":  msg.IntfId,
@@ -333,11 +355,11 @@
 					}
 				}
 
-			case OnuPacketIn:
+			case bbsim.OnuPacketIn:
 				// NOTE we only receive BBR packets here.
 				// Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
 				// in the DHCP case VOLTHA only act as a proxy, the behaviour is completely different thus we have a dhcp.HandleNextBbrPacket
-				msg, _ := message.Data.(OnuPacketMessage)
+				msg, _ := message.Data.(bbsim.OnuPacketMessage)
 
 				log.WithFields(log.Fields{
 					"IntfId":  msg.IntfId,
@@ -351,12 +373,12 @@
 					_ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
 				}
 				// BBR specific messages
-			case OmciIndication:
-				msg, _ := message.Data.(OmciIndicationMessage)
-				o.handleOmci(msg, client)
-			case SendEapolFlow:
+			case bbsim.OmciIndication:
+				msg, _ := message.Data.(bbsim.OmciIndicationMessage)
+				o.handleOmciResponse(msg, client)
+			case bbsim.SendEapolFlow:
 				o.sendEapolFlow(client)
-			case SendDhcpFlow:
+			case bbsim.SendDhcpFlow:
 				o.sendDhcpFlow(client)
 			default:
 				onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
@@ -369,42 +391,6 @@
 	}).Debug("Stopped handling ONU Indication Channel")
 }
 
-func (o *Onu) processOmciMessage(message omcisim.OmciChMessage, stream openolt.Openolt_EnableIndicationServer) {
-	switch message.Type {
-	case omcisim.UniLinkUp, omcisim.UniLinkDown:
-		onuLogger.WithFields(log.Fields{
-			"OnuId":  message.Data.OnuId,
-			"IntfId": message.Data.IntfId,
-			"Type":   message.Type,
-		}).Debug("UNI Link Alarm")
-		// TODO send to OLT
-
-		omciInd := openolt.OmciIndication{
-			IntfId: message.Data.IntfId,
-			OnuId:  message.Data.OnuId,
-			Pkt:    message.Packet,
-		}
-
-		omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
-		if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
-			onuLogger.WithFields(log.Fields{
-				"IntfId":       o.PonPortID,
-				"SerialNumber": o.Sn(),
-				"Type":         message.Type,
-				"omciPacket":   omciInd.Pkt,
-			}).Errorf("Failed to send UNI Link Alarm: %v", err)
-			return
-		}
-
-		onuLogger.WithFields(log.Fields{
-			"IntfId":       o.PonPortID,
-			"SerialNumber": o.Sn(),
-			"Type":         message.Type,
-			"omciPacket":   omciInd.Pkt,
-		}).Debug("UNI Link alarm sent")
-	}
-}
-
 func (o Onu) NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
 
 	sn := new(openolt.SerialNumber)
@@ -416,10 +402,10 @@
 	return sn
 }
 
-func (o *Onu) sendOnuDiscIndication(msg OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
 	discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
-		IntfId:       msg.Onu.PonPortID,
-		SerialNumber: msg.Onu.SerialNumber,
+		IntfId:       o.PonPortID,
+		SerialNumber: o.SerialNumber,
 	}}
 
 	if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
@@ -428,11 +414,11 @@
 	}
 
 	onuLogger.WithFields(log.Fields{
-		"IntfId": msg.Onu.PonPortID,
-		"OnuSn":  msg.Onu.Sn(),
+		"IntfId": o.PonPortID,
+		"OnuSn":  o.Sn(),
 		"OnuId":  o.ID,
 	}).Debug("Sent Indication_OnuDiscInd")
-	publishEvent("ONU-discovery-indication-sent", int32(msg.Onu.PonPortID), int32(o.ID), msg.Onu.Sn())
+	publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
 
 	// after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
 	go func(delay time.Duration) {
@@ -443,7 +429,7 @@
 	}(o.DiscoveryRetryDelay)
 }
 
-func (o *Onu) sendOnuIndication(msg OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
+func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
 	// NOTE voltha returns an ID, but if we use that ID then it complains:
 	// expected_onu_id: 1, received_onu_id: 1024, event: ONU-id-mismatch, can happen if both voltha and the olt rebooted
 	// so we're using the internal ID that is 1
@@ -471,17 +457,136 @@
 
 }
 
-func (o *Onu) publishOmciEvent(msg OmciMessage) {
+func (o *Onu) HandleShutdownONU() error {
+
+	dyingGasp := pb.ONUAlarmRequest{
+		AlarmType:    "DYING_GASP",
+		SerialNumber: o.Sn(),
+		Status:       "on",
+	}
+
+	if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Errorf("Cannot send Dying Gasp: %s", err.Error())
+		return err
+	}
+
+	losReq := pb.ONUAlarmRequest{
+		AlarmType:    "ONU_ALARM_LOS",
+		SerialNumber: o.Sn(),
+		Status:       "on",
+	}
+
+	if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Errorf("Cannot send LOS: %s", err.Error())
+
+		return err
+	}
+
+	// TODO if it's the last ONU on the PON, then send a PON LOS
+
+	if err := o.InternalState.Event("disable"); err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Errorf("Cannot shutdown ONU: %s", err.Error())
+		return err
+	}
+
+	return nil
+}
+
+func (o *Onu) HandlePowerOnONU() error {
+	intitalState := o.InternalState.Current()
+
+	// initialize the ONU
+	if intitalState == "created" || intitalState == "disabled" {
+		if err := o.InternalState.Event("initialize"); err != nil {
+			onuLogger.WithFields(log.Fields{
+				"OnuId":  o.ID,
+				"IntfId": o.PonPortID,
+				"OnuSn":  o.Sn(),
+			}).Errorf("Cannot poweron ONU: %s", err.Error())
+			return err
+		}
+	}
+
+	// turn off the LOS Alarm
+	losReq := pb.ONUAlarmRequest{
+		AlarmType:    "ONU_ALARM_LOS",
+		SerialNumber: o.Sn(),
+		Status:       "off",
+	}
+
+	if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Errorf("Cannot send LOS: %s", err.Error())
+		return err
+	}
+
+	// Send a ONU Discovery indication
+	if err := o.InternalState.Event("discover"); err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":  o.ID,
+			"IntfId": o.PonPortID,
+			"OnuSn":  o.Sn(),
+		}).Errorf("Cannot poweron ONU: %s", err.Error())
+		return err
+	}
+
+	// move o directly to enable state only when its a powercycle case
+	// in case of first time o poweron o will be moved to enable on
+	// receiving ActivateOnu request from openolt adapter
+	if intitalState == "disabled" {
+		if err := o.InternalState.Event("enable"); err != nil {
+			onuLogger.WithFields(log.Fields{
+				"OnuId":  o.ID,
+				"IntfId": o.PonPortID,
+				"OnuSn":  o.Sn(),
+			}).Errorf("Cannot enable ONU: %s", err.Error())
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (o *Onu) SetAlarm(alarmType string, status string) error {
+	alarmReq := pb.ONUAlarmRequest{
+		AlarmType:    alarmType,
+		SerialNumber: o.Sn(),
+		Status:       status,
+	}
+
+	err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
 	if olt.PublishEvents {
-		_, _, msgType, _, _, _, err := omcisim.ParsePkt(HexDecode(msg.omciMsg.Pkt))
+		_, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
 		if err != nil {
 			log.Errorf("error in getting msgType %v", err)
 			return
 		}
-		if msgType == omcisim.MibUpload {
+		if omciMsg.MessageType == omci.MibUploadRequestType {
 			o.seqNumber = 0
 			publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
-		} else if msgType == omcisim.MibUploadNext {
+		} else if omciMsg.MessageType == omci.MibUploadNextRequestType {
 			o.seqNumber++
 			if o.seqNumber > 290 {
 				publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
@@ -491,8 +596,8 @@
 }
 
 // Create a TestResponse packet and send it
-func (o *Onu) sendTestResult(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
-	resp, err := omcilib.BuildTestResult(HexDecode(msg.omciMsg.Pkt))
+func (o *Onu) sendTestResult(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
+	resp, err := omcilib.BuildTestResult(msg.OmciMsg.Pkt)
 	if err != nil {
 		return err
 	}
@@ -504,12 +609,6 @@
 
 	omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
 	if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
-		onuLogger.WithFields(log.Fields{
-			"IntfId":       o.PonPortID,
-			"SerialNumber": o.Sn(),
-			"omciPacket":   omciInd.Pkt,
-			"msg":          msg,
-		}).Errorf("send TestResult omcisim indication failed: %v", err)
 		return err
 	}
 	onuLogger.WithFields(log.Fields{
@@ -521,57 +620,151 @@
 	return nil
 }
 
-func (o *Onu) handleOmciMessage(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
+// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
+// and generate the appropriate response to it
+func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
+
+	omciPkt, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
+	if err != nil {
+		log.WithFields(log.Fields{
+			"IntfId":       o.PonPortID,
+			"SerialNumber": o.Sn(),
+			"omciPacket":   msg.OmciMsg.Pkt,
+		}).Error("cannot-parse-OMCI-packet")
+	}
 
 	onuLogger.WithFields(log.Fields{
+		"omciMsgType":  omciMsg.MessageType,
+		"transCorrId":  strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		"DeviceIdent":  omciMsg.DeviceIdentifier,
 		"IntfId":       o.PonPortID,
 		"SerialNumber": o.Sn(),
-		"omciPacket":   msg.omciMsg.Pkt,
-	}).Tracef("Received OMCI message")
+	}).Trace("omci-message-decoded")
+
+	var responsePkt []byte
+	switch omciMsg.MessageType {
+	case omci.MibResetRequestType:
+		responsePkt, _ = omcilib.CreateMibResetResponse(omciMsg.TransactionID)
+	case omci.MibUploadRequestType:
+		responsePkt, _ = omcilib.CreateMibUploadResponse(omciMsg.TransactionID)
+	case omci.MibUploadNextRequestType:
+		responsePkt, _ = omcilib.CreateMibUploadNextResponse(omciPkt, omciMsg)
+	case omci.GetRequestType:
+		responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg)
+	case omci.SetRequestType:
+		responsePkt, _ = omcilib.CreateSetResponse(omciPkt, omciMsg)
+
+		msgObj, _ := omcilib.ParseSetRequest(omciPkt)
+		switch msgObj.EntityClass {
+		case me.PhysicalPathTerminationPointEthernetUniClassID:
+			// if we're Setting a PPTP state
+			// we need to send the appropriate alarm
+
+			if msgObj.EntityInstance == 257 {
+				// for now we're only caring about the first UNI
+				// NOTE that the EntityID for the UNI port is for now hardcoded in
+				// omci/mibpackets.go where the PhysicalPathTerminationPointEthernetUni
+				// are reported during the MIB Upload sequence
+				adminState := msgObj.Attributes["AdministrativeState"].(uint8)
+				msg := bbsim.Message{
+					Type: bbsim.UniStatusAlarm,
+					Data: bbsim.UniStatusAlarmMessage{
+						OnuSN:      o.SerialNumber,
+						OnuID:      o.ID,
+						AdminState: adminState,
+						EntityID:   msgObj.EntityInstance,
+					},
+				}
+				o.Channel <- msg
+			}
+		}
+	case omci.CreateRequestType:
+		responsePkt, _ = omcilib.CreateCreateResponse(omciPkt, omciMsg)
+	case omci.DeleteRequestType:
+		responsePkt, _ = omcilib.CreateDeleteResponse(omciPkt, omciMsg)
+	case omci.RebootRequestType:
+
+		responsePkt, _ = omcilib.CreateRebootResponse(omciPkt, omciMsg)
+
+		// powercycle the ONU
+		go func() {
+			// we run this in a separate goroutine so that
+			// the RebootRequestResponse is sent to VOLTHA
+			onuLogger.WithFields(log.Fields{
+				"IntfId":       o.PonPortID,
+				"SerialNumber": o.Sn(),
+			}).Debug("shutting-down-onu-for-omci-reboot")
+			_ = o.HandleShutdownONU()
+			time.Sleep(10 * time.Second)
+			onuLogger.WithFields(log.Fields{
+				"IntfId":       o.PonPortID,
+				"SerialNumber": o.Sn(),
+			}).Debug("power-on-onu-for-omci-reboot")
+			_ = o.HandlePowerOnONU()
+		}()
+	case omci.TestRequestType:
+
+		// Test message is special, it requires sending two packets:
+		//     first packet: TestResponse, says whether test was started successully, handled by omci-sim
+		//     second packet, TestResult, reports the result of running the self-test
+		// TestResult can come some time after a TestResponse
+		//     TODO: Implement some delay between the TestResponse and the TestResult
+		isTest, err := omcilib.IsTestRequest(msg.OmciMsg.Pkt)
+		if (err == nil) && (isTest) {
+			if sendErr := o.sendTestResult(msg, stream); sendErr != nil {
+				onuLogger.WithFields(log.Fields{
+					"IntfId":       o.PonPortID,
+					"SerialNumber": o.Sn(),
+					"omciPacket":   msg.OmciMsg.Pkt,
+					"msg":          msg,
+					"err":          sendErr,
+				}).Error("send-TestResult-indication-failed")
+			}
+		}
+
+	default:
+		log.WithFields(log.Fields{
+			"omciMsgType":  omciMsg.MessageType,
+			"transCorrId":  omciMsg.TransactionID,
+			"IntfId":       o.PonPortID,
+			"SerialNumber": o.Sn(),
+		}).Warnf("OMCI-message-not-supported")
+	}
+
+	if responsePkt != nil {
+		if err := o.sendOmciIndication(responsePkt, omciMsg.TransactionID, stream); err != nil {
+			onuLogger.WithFields(log.Fields{
+				"IntfId":       o.PonPortID,
+				"SerialNumber": o.Sn(),
+				"omciPacket":   responsePkt,
+				"omciMsgType":  omciMsg.MessageType,
+				"transCorrId":  omciMsg.TransactionID,
+			}).Errorf("failed-to-send-omci-message: %v", err)
+		}
+	}
 
 	o.publishOmciEvent(msg)
+}
 
-	var omciInd openolt.OmciIndication
-	respPkt, err := omcisim.OmciSim(o.PonPort.Olt.ID, o.PonPortID, o.ID, HexDecode(msg.omciMsg.Pkt))
-	if err != nil {
-		onuLogger.WithFields(log.Fields{
-			"IntfId":       o.PonPortID,
-			"SerialNumber": o.Sn(),
-			"omciPacket":   omciInd.Pkt,
-			"msg":          msg,
-		}).Errorf("Error handling OMCI message %v", msg)
-		return
+// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
+func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
+	indication := &openolt.Indication_OmciInd{
+		OmciInd: &openolt.OmciIndication{
+			IntfId: o.PonPortID,
+			OnuId:  o.ID,
+			Pkt:    responsePkt,
+		},
 	}
-
-	omciInd.IntfId = o.PonPortID
-	omciInd.OnuId = o.ID
-	omciInd.Pkt = respPkt
-
-	omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
-	if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
-		onuLogger.WithFields(log.Fields{
-			"IntfId":       o.PonPortID,
-			"SerialNumber": o.Sn(),
-			"omciPacket":   omciInd.Pkt,
-			"msg":          msg,
-		}).Errorf("send omcisim indication failed: %v", err)
-		return
+	if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
+		return fmt.Errorf("failed-to-send-omci-message: %v", err)
 	}
 	onuLogger.WithFields(log.Fields{
 		"IntfId":       o.PonPortID,
 		"SerialNumber": o.Sn(),
-		"omciPacket":   omciInd.Pkt,
-	}).Tracef("Sent OMCI message")
-
-	// Test message is special, it requires sending two packets:
-	//     first packet: TestResponse, says whether test was started successully, handled by omci-sim
-	//     second packet, TestResult, reports the result of running the self-test
-	// TestResult can come some time after a TestResponse
-	//     TODO: Implement some delay between the TestResponse and the TestResult
-	isTest, err := omcilib.IsTestRequest(HexDecode(msg.omciMsg.Pkt))
-	if (err == nil) && (isTest) {
-		_ = o.sendTestResult(msg, stream)
-	}
+		"omciPacket":   indication.OmciInd.Pkt,
+		"transCorrId":  txId,
+	}).Trace("omci-message-sent")
+	return nil
 }
 
 func (o *Onu) storePortNumber(portNo uint32) {
@@ -602,7 +795,7 @@
 	o.ID = id
 }
 
-func (o *Onu) handleFlowAdd(msg OnuFlowUpdateMessage) {
+func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
 	onuLogger.WithFields(log.Fields{
 		"Cookie":            msg.Flow.Cookie,
 		"DstPort":           msg.Flow.Classifier.DstPort,
@@ -667,7 +860,7 @@
 	}
 }
 
-func (o *Onu) handleFlowRemove(msg OnuFlowUpdateMessage) {
+func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
 	onuLogger.WithFields(log.Fields{
 		"IntfId":       o.PonPortID,
 		"OnuId":        o.ID,
@@ -700,19 +893,6 @@
 	}
 }
 
-// HexDecode converts the hex encoding to binary
-func HexDecode(pkt []byte) []byte {
-	p := make([]byte, len(pkt)/2)
-	for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
-		// Go figure this ;)
-		u := (pkt[i] & 15) + (pkt[i]>>6)*9
-		l := (pkt[i+1] & 15) + (pkt[i+1]>>6)*9
-		p[j] = u<<4 + l
-	}
-	onuLogger.Tracef("Omci decoded: %x.", p)
-	return p
-}
-
 // BBR methods
 
 func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
@@ -762,24 +942,36 @@
 	sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
 }
 
-func (o *Onu) handleOmci(msg OmciIndicationMessage, client openolt.OpenoltClient) {
-	msgType, packet := omcilib.DecodeOmci(msg.OmciInd.Pkt)
+// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
+func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
+
+	// we need to encode the packet in HEX
+	pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
+	hex.Encode(pkt, msg.OmciInd.Pkt)
+	packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
+	if err != nil {
+		log.WithFields(log.Fields{
+			"IntfId":       o.PonPortID,
+			"SerialNumber": o.Sn(),
+			"omciPacket":   msg.OmciInd.Pkt,
+		}).Error("BBR Cannot parse OMCI packet")
+	}
 
 	log.WithFields(log.Fields{
 		"IntfId":  msg.OmciInd.IntfId,
 		"OnuId":   msg.OmciInd.OnuId,
-		"OnuSn":   common.OnuSnToString(o.SerialNumber),
+		"OnuSn":   o.Sn(),
 		"Pkt":     msg.OmciInd.Pkt,
-		"msgType": msgType,
+		"msgType": omciMsg.MessageType,
 	}).Trace("ONU Receives OMCI Msg")
-	switch msgType {
+	switch omciMsg.MessageType {
 	default:
 		log.WithFields(log.Fields{
 			"IntfId":  msg.OmciInd.IntfId,
 			"OnuId":   msg.OmciInd.OnuId,
-			"OnuSn":   common.OnuSnToString(o.SerialNumber),
+			"OnuSn":   o.Sn(),
 			"Pkt":     msg.OmciInd.Pkt,
-			"msgType": msgType,
+			"msgType": omciMsg.MessageType,
 		}).Fatalf("unexpected frame: %v", packet)
 	case omci.MibResetResponseType:
 		mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
diff --git a/internal/bbsim/devices/onu_flow_test.go b/internal/bbsim/devices/onu_flow_test.go
index 1464ae5..e0ad9fe 100644
--- a/internal/bbsim/devices/onu_flow_test.go
+++ b/internal/bbsim/devices/onu_flow_test.go
@@ -19,6 +19,7 @@
 import (
 	"github.com/google/gopacket/layers"
 	"github.com/looplab/fsm"
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
 	"gotest.tools/assert"
 	"testing"
@@ -54,7 +55,7 @@
 		FlowId:     64,
 		Classifier: &openolt.Classifier{},
 	}
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		OnuID:     onu.ID,
 		PonPortID: onu.PonPortID,
 		Flow:      &flow,
@@ -74,7 +75,7 @@
 		FlowId:     64,
 		Classifier: &openolt.Classifier{},
 	}
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		OnuID:     onu.ID,
 		PonPortID: onu.PonPortID,
 		Flow:      &flow,
@@ -107,7 +108,7 @@
 		FlowId:     64,
 		Classifier: &openolt.Classifier{},
 	}
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		OnuID:     onu.ID,
 		PonPortID: onu.PonPortID,
 		Flow:      &flow,
@@ -147,7 +148,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -194,7 +195,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -235,7 +236,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -279,7 +280,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -323,7 +324,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -367,7 +368,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -409,7 +410,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
@@ -457,7 +458,7 @@
 		PortNo:   uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
 	}
 
-	msg := OnuFlowUpdateMessage{
+	msg := types.OnuFlowUpdateMessage{
 		PonPortID: 1,
 		OnuID:     1,
 		Flow:      &flow,
diff --git a/internal/bbsim/devices/onu_test_helpers.go b/internal/bbsim/devices/onu_test_helpers.go
index 89eb195..ef6e4a2 100644
--- a/internal/bbsim/devices/onu_test_helpers.go
+++ b/internal/bbsim/devices/onu_test_helpers.go
@@ -19,6 +19,7 @@
 import (
 	"context"
 	"errors"
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/voltha-protos/v4/go/common"
 	"github.com/opencord/voltha-protos/v4/go/ext/config"
 	"time"
@@ -137,7 +138,7 @@
 		},
 	}
 	o.SerialNumber = o.NewSN(0, ponPortId, o.ID)
-	o.Channel = make(chan Message, 10)
+	o.Channel = make(chan types.Message, 10)
 	return &o
 }
 
diff --git a/internal/bbsim/devices/services.go b/internal/bbsim/devices/services.go
index bd4d13c..4391414 100644
--- a/internal/bbsim/devices/services.go
+++ b/internal/bbsim/devices/services.go
@@ -71,9 +71,9 @@
 	EapolState    *fsm.FSM
 	DHCPState     *fsm.FSM
 	IGMPState     *fsm.FSM
-	Channel       chan Message          // drive Service lifecycle
-	PacketCh      chan OnuPacketMessage // handle packets
-	Stream        bbsimTypes.Stream     // the gRPC stream to communicate with the adapter, created in the initialize transition
+	Channel       chan bbsimTypes.Message          // drive Service lifecycle
+	PacketCh      chan bbsimTypes.OnuPacketMessage // handle packets
+	Stream        bbsimTypes.Stream                // the gRPC stream to communicate with the adapter, created in the initialize transition
 }
 
 func NewService(name string, hwAddress net.HardwareAddr, onu *Onu, cTag int, sTag int,
@@ -117,8 +117,8 @@
 
 				service.Stream = stream
 
-				service.PacketCh = make(chan OnuPacketMessage)
-				service.Channel = make(chan Message)
+				service.PacketCh = make(chan bbsimTypes.OnuPacketMessage)
+				service.Channel = make(chan bbsimTypes.Message)
 
 				go service.HandlePackets()
 				go service.HandleChannel()
@@ -153,8 +153,8 @@
 				service.logStateChange("EapolState", e.Src, e.Dst)
 			},
 			"before_start_auth": func(e *fsm.Event) {
-				msg := Message{
-					Type: StartEAPOL,
+				msg := bbsimTypes.Message{
+					Type: bbsimTypes.StartEAPOL,
 				}
 				service.Channel <- msg
 			},
@@ -207,8 +207,8 @@
 				service.logStateChange("DHCPState", e.Src, e.Dst)
 			},
 			"before_start_dhcp": func(e *fsm.Event) {
-				msg := Message{
-					Type: StartDHCP,
+				msg := bbsimTypes.Message{
+					Type: bbsimTypes.StartDHCP,
 				}
 				service.Channel <- msg
 			},
@@ -255,30 +255,30 @@
 		},
 		fsm.Callbacks{
 			"igmp_join_start": func(e *fsm.Event) {
-				igmpInfo, _ := e.Args[0].(IgmpMessage)
-				msg := Message{
-					Type: IGMPMembershipReportV2,
-					Data: IgmpMessage{
+				igmpInfo, _ := e.Args[0].(bbsimTypes.IgmpMessage)
+				msg := bbsimTypes.Message{
+					Type: bbsimTypes.IGMPMembershipReportV2,
+					Data: bbsimTypes.IgmpMessage{
 						GroupAddress: igmpInfo.GroupAddress,
 					},
 				}
 				service.Channel <- msg
 			},
 			"igmp_leave": func(e *fsm.Event) {
-				igmpInfo, _ := e.Args[0].(IgmpMessage)
-				msg := Message{
-					Type: IGMPLeaveGroup,
-					Data: IgmpMessage{
+				igmpInfo, _ := e.Args[0].(bbsimTypes.IgmpMessage)
+				msg := bbsimTypes.Message{
+					Type: bbsimTypes.IGMPLeaveGroup,
+					Data: bbsimTypes.IgmpMessage{
 						GroupAddress: igmpInfo.GroupAddress,
 					},
 				}
 				service.Channel <- msg
 			},
 			"igmp_join_startv3": func(e *fsm.Event) {
-				igmpInfo, _ := e.Args[0].(IgmpMessage)
-				msg := Message{
-					Type: IGMPMembershipReportV3,
-					Data: IgmpMessage{
+				igmpInfo, _ := e.Args[0].(bbsimTypes.IgmpMessage)
+				msg := bbsimTypes.Message{
+					Type: bbsimTypes.IGMPMembershipReportV3,
+					Data: bbsimTypes.IgmpMessage{
 						GroupAddress: igmpInfo.GroupAddress,
 					},
 				}
@@ -411,7 +411,7 @@
 	}()
 	for msg := range s.Channel {
 		switch msg.Type {
-		case StartEAPOL:
+		case bbsimTypes.StartEAPOL:
 			if err := s.handleEapolStart(s.Stream); err != nil {
 				serviceLogger.WithFields(log.Fields{
 					"OnuId":  s.Onu.ID,
@@ -422,7 +422,7 @@
 				}).Error("Error while sending EapolStart packet")
 				_ = s.EapolState.Event("auth_failed")
 			}
-		case StartDHCP:
+		case bbsimTypes.StartDHCP:
 			if err := s.handleDHCPStart(s.Stream); err != nil {
 				serviceLogger.WithFields(log.Fields{
 					"OnuId":  s.Onu.ID,
@@ -434,8 +434,8 @@
 				_ = s.DHCPState.Event("dhcp_failed")
 
 			}
-		case IGMPMembershipReportV2:
-			igmpInfo, _ := msg.Data.(IgmpMessage)
+		case bbsimTypes.IGMPMembershipReportV2:
+			igmpInfo, _ := msg.Data.(bbsimTypes.IgmpMessage)
 			serviceLogger.WithFields(log.Fields{
 				"OnuId":  s.Onu.ID,
 				"IntfId": s.Onu.PonPortID,
@@ -443,8 +443,8 @@
 				"Name":   s.Name,
 			}).Debug("Received IGMPMembershipReportV2 message on ONU channel")
 			_ = igmp.SendIGMPMembershipReportV2(s.Onu.PonPortID, s.Onu.ID, s.Onu.Sn(), s.Onu.PortNo, s.GemPort, s.HwAddress, s.CTag, s.UsPonCTagPriority, s.Stream, igmpInfo.GroupAddress)
-		case IGMPLeaveGroup:
-			igmpInfo, _ := msg.Data.(IgmpMessage)
+		case bbsimTypes.IGMPLeaveGroup:
+			igmpInfo, _ := msg.Data.(bbsimTypes.IgmpMessage)
 			serviceLogger.WithFields(log.Fields{
 				"OnuId":  s.Onu.ID,
 				"IntfId": s.Onu.PonPortID,
@@ -452,8 +452,8 @@
 				"Name":   s.Name,
 			}).Debug("Received IGMPLeaveGroupV2 message on ONU channel")
 			_ = igmp.SendIGMPLeaveGroupV2(s.Onu.PonPortID, s.Onu.ID, s.Onu.Sn(), s.Onu.PortNo, s.GemPort, s.HwAddress, s.CTag, s.UsPonCTagPriority, s.Stream, igmpInfo.GroupAddress)
-		case IGMPMembershipReportV3:
-			igmpInfo, _ := msg.Data.(IgmpMessage)
+		case bbsimTypes.IGMPMembershipReportV3:
+			igmpInfo, _ := msg.Data.(bbsimTypes.IgmpMessage)
 			serviceLogger.WithFields(log.Fields{
 				"OnuId":  s.Onu.ID,
 				"IntfId": s.Onu.PonPortID,
diff --git a/internal/bbsim/responders/eapol/eapol.go b/internal/bbsim/responders/eapol/eapol.go
index 0860935..688728c 100644
--- a/internal/bbsim/responders/eapol/eapol.go
+++ b/internal/bbsim/responders/eapol/eapol.go
@@ -26,7 +26,6 @@
 	"github.com/google/gopacket/layers"
 	"github.com/looplab/fsm"
 	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
-	omci "github.com/opencord/omci-sim"
 	"github.com/opencord/voltha-protos/v4/go/openolt"
 	log "github.com/sirupsen/logrus"
 )
@@ -36,7 +35,6 @@
 })
 
 var eapolVersion uint8 = 1
-var GetGemPortId = omci.GetGemPortId
 
 func sendEapolPktIn(msg bbsim.ByteMsg, portNo uint32, gemid uint32, stream bbsim.Stream) error {
 	// FIXME unify sendDHCPPktIn and sendEapolPktIn methods
diff --git a/internal/bbsim/responders/eapol/eapol_test.go b/internal/bbsim/responders/eapol/eapol_test.go
index 248fd3d..69f941f 100644
--- a/internal/bbsim/responders/eapol/eapol_test.go
+++ b/internal/bbsim/responders/eapol/eapol_test.go
@@ -94,14 +94,6 @@
 
 	eapolStateMachine.SetState("auth_started")
 
-	// Save current function and restore at the end:
-	old := GetGemPortId
-	defer func() { GetGemPortId = old }()
-
-	GetGemPortId = func(oltId int, intfId uint32, onuId uint32) (uint16, error) {
-		return 1, nil
-	}
-
 	stream := &mockStream{
 		Calls: make(map[int]*openolt.PacketIndication),
 		fail:  true,
diff --git a/internal/bbsim/devices/messageTypes.go b/internal/bbsim/types/messageTypes.go
similarity index 89%
rename from internal/bbsim/devices/messageTypes.go
rename to internal/bbsim/types/messageTypes.go
index 144e1b9..3afe7fb 100644
--- a/internal/bbsim/devices/messageTypes.go
+++ b/internal/bbsim/types/messageTypes.go
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package devices
+package types
 
 import (
 	"github.com/google/gopacket"
@@ -50,6 +50,7 @@
 
 	AlarmIndication        MessageType = 16 // message data is an openolt.AlarmIndication
 	IGMPMembershipReportV3 MessageType = 17 // Version 3 Membership Report
+	UniStatusAlarm         MessageType = 19
 )
 
 func (m MessageType) String() string {
@@ -72,6 +73,7 @@
 		"IGMPLeaveGroup",
 		"IGMPMembershipReportV3",
 		"FlowRemoved",
+		"UniStatusAlarm",
 	}
 	return names[m]
 }
@@ -97,7 +99,6 @@
 
 type OnuDiscIndicationMessage struct {
 	OperState OperState
-	Onu       *Onu
 }
 
 type OnuIndicationMessage struct {
@@ -107,12 +108,23 @@
 	OnuSN     *openolt.SerialNumber
 }
 
+// these are OMCI messages going from VOLTHA to the OLT
+// used by BBSim
 type OmciMessage struct {
 	OnuSN   *openolt.SerialNumber
 	OnuID   uint32
-	omciMsg *openolt.OmciMsg
+	OmciMsg *openolt.OmciMsg
 }
 
+type UniStatusAlarmMessage struct {
+	OnuSN      *openolt.SerialNumber
+	OnuID      uint32
+	AdminState uint8
+	EntityID   uint16
+}
+
+// these are OMCI messages going from the OLT to VOLTHA
+// these messages are received by BBR
 type OmciIndicationMessage struct {
 	OnuSN   *openolt.SerialNumber
 	OnuID   uint32
diff --git a/internal/common/omci/alarms.go b/internal/common/omci/alarms.go
new file mode 100644
index 0000000..aaa2fdd
--- /dev/null
+++ b/internal/common/omci/alarms.go
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+// CreateUniStatusAlarm will generate an Alarm packet to report that the Link is UP or DOWN
+// as a consequence of a SetRequest on PhysicalPathTerminationPointEthernetUniClassID
+func CreateUniStatusAlarm(adminState uint8, entityId uint16) []byte {
+
+	// TODO generate using omci-lib-go
+	linkMsgDown := []byte{
+		0x00, 0x00, 0x10, 0x0a, 0x00, 0x0b, 0x01, 0x01,
+		0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+	linkMsgUp := []byte{
+		0x00, 0x00, 0x10, 0x0a, 0x00, 0x0b, 0x01, 0x01,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+	if adminState == 0 {
+		return linkMsgUp
+	} else if adminState == 1 {
+		return linkMsgDown
+	}
+
+	return nil
+}
diff --git a/internal/common/omci/create.go b/internal/common/omci/create.go
new file mode 100644
index 0000000..8e4afb3
--- /dev/null
+++ b/internal/common/omci/create.go
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"encoding/hex"
+	"errors"
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	log "github.com/sirupsen/logrus"
+	"strconv"
+)
+
+func ParseCreateRequest(omciPkt gopacket.Packet) (*omci.CreateRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeCreateRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeCreateRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.CreateRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeCreateRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+func CreateCreateResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+	msgObj, err := ParseCreateRequest(omciPkt)
+
+	if err != nil {
+		return nil, err
+	}
+
+	omciLogger.WithFields(log.Fields{
+		"EntityClass":    msgObj.EntityClass,
+		"EntityInstance": msgObj.EntityInstance,
+	}).Trace("recevied-omci-create-request")
+
+	response := &omci.CreateResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    msgObj.EntityClass,
+			EntityInstance: msgObj.EntityInstance,
+		},
+		Result: me.Success,
+	}
+
+	pkt, err := serialize(omci.CreateResponseType, response, omciMsg.TransactionID)
+	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err": err,
+		}).Error("cannot-serialize-CreateResponse")
+		return nil, err
+	}
+
+	log.WithFields(log.Fields{
+		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		"pkt":  hex.EncodeToString(pkt),
+	}).Trace("omci-create-response")
+
+	return pkt, nil
+}
+
+// methods used by BBR to drive the OMCI state machine
+
+func CreateGalEnetRequest(tid uint16) ([]byte, error) {
+	params := me.ParamData{
+		EntityID:   galEthernetEID,
+		Attributes: me.AttributeValueMap{"MaximumGemPayloadSize": maxGemPayloadSize},
+	}
+	meDef, _ := me.NewGalEthernetProfile(params)
+	pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
+	if err != nil {
+		omciLogger.WithField("err", err).Fatalf("Can't generate GalEnetRequest")
+	}
+	return hexEncode(pkt)
+}
+
+func CreateEnableUniRequest(tid uint16, uniId uint16, enabled bool, isPtp bool) ([]byte, error) {
+
+	var _enabled uint8
+	if enabled {
+		_enabled = uint8(1)
+	} else {
+		_enabled = uint8(0)
+	}
+
+	data := me.ParamData{
+		EntityID: uniId,
+		Attributes: me.AttributeValueMap{
+			"AdministrativeState": _enabled,
+		},
+	}
+	var medef *me.ManagedEntity
+	var omciErr me.OmciErrors
+
+	if isPtp {
+		medef, omciErr = me.NewPhysicalPathTerminationPointEthernetUni(data)
+	} else {
+		medef, omciErr = me.NewVirtualEthernetInterfacePoint(data)
+	}
+	if omciErr != nil {
+		return nil, omciErr.GetError()
+	}
+	pkt, err := omci.GenFrame(medef, omci.SetRequestType, omci.TransactionID(tid))
+	if err != nil {
+		omciLogger.WithField("err", err).Fatalf("Can't generate EnableUniRequest")
+	}
+	return hexEncode(pkt)
+}
+
+func CreateGemPortRequest(tid uint16) ([]byte, error) {
+	params := me.ParamData{
+		EntityID: gemEID,
+		Attributes: me.AttributeValueMap{
+			"PortId":                              1,
+			"TContPointer":                        1,
+			"Direction":                           0,
+			"TrafficManagementPointerForUpstream": 0,
+			"TrafficDescriptorProfilePointerForUpstream": 0,
+			"UniCounter":                                   0,
+			"PriorityQueuePointerForDownStream":            0,
+			"EncryptionState":                              0,
+			"TrafficDescriptorProfilePointerForDownstream": 0,
+			"EncryptionKeyRing":                            0,
+		},
+	}
+	meDef, _ := me.NewGemPortNetworkCtp(params)
+	pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
+	if err != nil {
+		omciLogger.WithField("err", err).Fatalf("Can't generate GemPortRequest")
+	}
+	return hexEncode(pkt)
+}
diff --git a/internal/common/omci/delete.go b/internal/common/omci/delete.go
new file mode 100644
index 0000000..c38d696
--- /dev/null
+++ b/internal/common/omci/delete.go
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"errors"
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	log "github.com/sirupsen/logrus"
+)
+
+func ParseDeleteRequest(omciPkt gopacket.Packet) (*omci.DeleteRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeDeleteRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeDeleteRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.DeleteRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeDeleteRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+func CreateDeleteResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+	msgObj, err := ParseDeleteRequest(omciPkt)
+
+	if err != nil {
+		return nil, err
+	}
+
+	omciLogger.WithFields(log.Fields{
+		"EntityClass":    msgObj.EntityClass,
+		"EntityInstance": msgObj.EntityInstance,
+	}).Trace("recevied-omci-delete-request")
+
+	response := &omci.DeleteResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    msgObj.EntityClass,
+			EntityInstance: msgObj.EntityInstance,
+		},
+		Result: me.Success,
+	}
+
+	pkt, err := serialize(omci.DeleteResponseType, response, omciMsg.TransactionID)
+	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err": err,
+		}).Error("cannot-serialize-DeleteResponse")
+		return nil, err
+	}
+
+	return pkt, nil
+}
diff --git a/internal/common/omci/get.go b/internal/common/omci/get.go
new file mode 100644
index 0000000..64a7968
--- /dev/null
+++ b/internal/common/omci/get.go
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	log "github.com/sirupsen/logrus"
+	"strconv"
+)
+
+func ParseGetRequest(omciPkt gopacket.Packet) (*omci.GetRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeGetRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeGetRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.GetRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeGetRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+func CreateGetResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+	msgObj, err := ParseGetRequest(omciPkt)
+
+	if err != nil {
+		return nil, err
+	}
+
+	omciLogger.WithFields(log.Fields{
+		"EntityClass":    msgObj.EntityClass,
+		"EntityInstance": msgObj.EntityInstance,
+		"AttributeMask":  fmt.Sprintf("%x", msgObj.AttributeMask),
+	}).Trace("recevied-omci-get-request")
+
+	var response *omci.GetResponse
+	switch msgObj.EntityClass {
+	case me.Onu2GClassID:
+		response = createOnu2gResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+	case me.OnuGClassID:
+		response = createOnugResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+	case me.SoftwareImageClassID:
+		response = createSoftwareImageResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+	case me.IpHostConfigDataClassID:
+		response = createIpHostResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+	case me.UniGClassID:
+		response = createUnigResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+	case me.PhysicalPathTerminationPointEthernetUniClassID:
+		response = createPptpResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+	case me.AniGClassID:
+		response = createAnigResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+	case me.OnuDataClassID:
+		response = createOnuDataResponse(msgObj.AttributeMask, msgObj.EntityInstance)
+	default:
+		omciLogger.WithFields(log.Fields{
+			"EntityClass":    msgObj.EntityClass,
+			"EntityInstance": msgObj.EntityInstance,
+			"AttributeMask":  fmt.Sprintf("%x", msgObj.AttributeMask),
+		}).Warnf("do-not-know-how-to-handle-get-request-for-me-class")
+		return nil, nil
+	}
+
+	pkt, err := serialize(omci.GetResponseType, response, omciMsg.TransactionID)
+	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err":  err,
+			"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		}).Error("cannot-serialize-Onu2gResponse")
+		return nil, err
+	}
+
+	log.WithFields(log.Fields{
+		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		"pkt":  hex.EncodeToString(pkt),
+	}).Trace("omci-get-response")
+
+	return pkt, nil
+}
+
+func createOnu2gResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+
+	managedEntity, meErr := me.NewOnu2G(me.ParamData{
+		EntityID: entityID,
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId": entityID,
+			"EquipmentId":     toOctets("BBSM", 20),
+			"OpticalNetworkUnitManagementAndControlChannelOmccVersion": 180,
+			"VendorProductCode":                           0,
+			"SecurityCapability":                          1,
+			"SecurityMode":                                1,
+			"TotalPriorityQueueNumber":                    1,
+			"TotalTrafficSchedulerNumber":                 1,
+			"Deprecated":                                  1,
+			"TotalGemPortIdNumber":                        32,
+			"Sysuptime":                                   319389947, // NOTE need to be smarter?
+			"ConnectivityCapability":                      127,
+			"CurrentConnectivityMode":                     5,
+			"QualityOfServiceQosConfigurationFlexibility": 48,
+			"PriorityQueueScaleFactor":                    1,
+		},
+	})
+
+	if meErr.GetError() != nil {
+		omciLogger.Errorf("NewOnu2G %v", meErr.Error())
+		return nil
+	}
+
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass: me.Onu2GClassID,
+		},
+		Attributes:    managedEntity.GetAttributeValueMap(),
+		AttributeMask: attributeMask,
+		Result:        me.Success,
+	}
+}
+
+func createOnugResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.OnuGClassID,
+			EntityInstance: entityID,
+		},
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId":         entityID,
+			"VendorId":                toOctets("BBSM", 4),
+			"Version":                 toOctets("v0.0.1", 14),
+			"SerialNumber":            toOctets("QkJTTQAKAAE=", 8),
+			"TrafficManagementOption": 0,
+			"Deprecated":              0,
+			"BatteryBackup":           0,
+			"AdministrativeState":     0,
+			"OperationalState":        0,
+			"OnuSurvivalTime":         10,
+			"LogicalOnuId":            toOctets("BBSM", 24),
+			"LogicalPassword":         toOctets("BBSM", 12),
+			"CredentialsStatus":       0,
+			"ExtendedTcLayerOptions":  0,
+		},
+		Result:        me.Success,
+		AttributeMask: attributeMask,
+	}
+}
+
+func createSoftwareImageResponse(attributeMask uint16, entityInstance uint16) *omci.GetResponse {
+	// NOTE that we need send the response for the correct ME Instance or the adapter won't process it
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.SoftwareImageClassID,
+			EntityInstance: entityInstance,
+		},
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId": 0,
+			"Version":         toOctets("v0.0.1", 14),
+			"IsCommitted":     1,
+			"IsActive":        1,
+			"IsValid":         1,
+			"ProductCode":     toOctets("product-code", 25),
+			"ImageHash":       toOctets("broadband-sim", 16),
+		},
+		Result:        me.Success,
+		AttributeMask: attributeMask,
+	}
+}
+
+func createIpHostResponse(attributeMask uint16, entityInstance uint16) *omci.GetResponse {
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    me.IpHostConfigDataClassID,
+			EntityInstance: entityInstance,
+		},
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId": 0,
+			"MacAddress":      toOctets("aabbcc", 6),
+		},
+		Result:        me.Success,
+		AttributeMask: attributeMask,
+	}
+}
+
+func createUnigResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+	managedEntity, meErr := me.NewUniG(me.ParamData{
+		EntityID: entityID,
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId":             entityID,
+			"Deprecated":                  0,
+			"AdministrativeState":         0,
+			"ManagementCapability":        0,
+			"NonOmciManagementIdentifier": 1,
+			"RelayAgentOptions":           1,
+		},
+	})
+
+	if meErr.GetError() != nil {
+		omciLogger.Errorf("NewUniG %v", meErr.Error())
+		return nil
+	}
+
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass: me.UniGClassID,
+		},
+		Attributes:    managedEntity.GetAttributeValueMap(),
+		AttributeMask: attributeMask,
+		Result:        me.Success,
+	}
+}
+
+func createPptpResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+	managedEntity, meErr := me.NewPhysicalPathTerminationPointEthernetUni(me.ParamData{
+		EntityID: entityID,
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId":               entityID,
+			"ExpectedType":                  0,
+			"SensedType":                    0,
+			"AutoDetectionConfiguration":    0,
+			"EthernetLoopbackConfiguration": 0,
+			"AdministrativeState":           0,
+			"OperationalState":              0,
+			"ConfigurationInd":              0,
+			"MaxFrameSize":                  0,
+			"DteOrDceInd":                   0,
+			"PauseTime":                     0,
+			"BridgedOrIpInd":                0,
+			"Arc":                           0,
+			"ArcInterval":                   0,
+			"PppoeFilter":                   0,
+			"PowerControl":                  0,
+		},
+	})
+
+	if meErr.GetError() != nil {
+		omciLogger.Errorf("NewPhysicalPathTerminationPointEthernetUni %v", meErr.Error())
+		return nil
+	}
+
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass: me.PhysicalPathTerminationPointEthernetUniClassID,
+		},
+		Attributes:    managedEntity.GetAttributeValueMap(),
+		AttributeMask: attributeMask,
+		Result:        me.Success,
+	}
+}
+
+func createAnigResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+	managedEntity, meErr := me.NewAniG(me.ParamData{
+		EntityID: entityID,
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId":             entityID,
+			"SrIndication":                0,
+			"TotalTcontNumber":            0,
+			"GemBlockLength":              0,
+			"PiggybackDbaReporting":       0,
+			"Deprecated":                  0,
+			"SignalFailThreshold":         0,
+			"SignalDegradeThreshold":      0,
+			"Arc":                         0,
+			"ArcInterval":                 0,
+			"OpticalSignalLevel":          0,
+			"LowerOpticalThreshold":       0,
+			"UpperOpticalThreshold":       0,
+			"OnuResponseTime":             0,
+			"TransmitOpticalLevel":        0,
+			"LowerTransmitPowerThreshold": 0,
+			"UpperTransmitPowerThreshold": 0,
+		},
+	})
+
+	if meErr.GetError() != nil {
+		omciLogger.Errorf("NewAniG %v", meErr.Error())
+		return nil
+	}
+
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass: me.AniGClassID,
+		},
+		Attributes:    managedEntity.GetAttributeValueMap(),
+		AttributeMask: attributeMask,
+		Result:        me.Success,
+	}
+}
+
+func createOnuDataResponse(attributeMask uint16, entityID uint16) *omci.GetResponse {
+	managedEntity, meErr := me.NewOnuData(me.ParamData{
+		EntityID: entityID,
+		Attributes: me.AttributeValueMap{
+			"ManagedEntityId": entityID,
+			"MibDataSync":     0,
+		},
+	})
+
+	if meErr.GetError() != nil {
+		omciLogger.Errorf("NewOnuData %v", meErr.Error())
+		return nil
+	}
+
+	return &omci.GetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass: me.OnuDataClassID,
+		},
+		Attributes:    managedEntity.GetAttributeValueMap(),
+		AttributeMask: attributeMask,
+		Result:        me.Success,
+	}
+}
+
+func toOctets(str string, size int) []byte {
+	asciiBytes := []byte(str)
+
+	if len(asciiBytes) < size {
+		missing := size - len(asciiBytes)
+		for i := 0; i < missing; i++ {
+			asciiBytes = append(asciiBytes, []byte{0x00}[0])
+		}
+	}
+	return asciiBytes
+}
diff --git a/internal/common/omci/get_test.go b/internal/common/omci/get_test.go
new file mode 100644
index 0000000..0ab6d04
--- /dev/null
+++ b/internal/common/omci/get_test.go
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"gotest.tools/assert"
+	"testing"
+)
+
+func omciBytesToMsg(t *testing.T, data []byte) (*omci.OMCI, *gopacket.Packet) {
+	packet := gopacket.NewPacket(data, omci.LayerTypeOMCI, gopacket.NoCopy)
+	if packet == nil {
+		t.Fatal("could not decode rxMsg as OMCI")
+	}
+	omciLayer := packet.Layer(omci.LayerTypeOMCI)
+	if omciLayer == nil {
+		t.Fatal("could not decode omci layer")
+	}
+	omciMsg, ok := omciLayer.(*omci.OMCI)
+	if !ok {
+		t.Fatal("could not assign omci layer")
+	}
+	return omciMsg, &packet
+}
+
+func omciToGetResponse(t *testing.T, omciPkt *gopacket.Packet) *omci.GetResponse {
+	msgLayer := (*omciPkt).Layer(omci.LayerTypeGetResponse)
+	if msgLayer == nil {
+		t.Fatal("omci Msg layer could not be detected for GetResponse - handling of MibSyncChan stopped")
+	}
+	msgObj, msgOk := msgLayer.(*omci.GetResponse)
+	if !msgOk {
+		t.Fatal("omci Msg layer could not be assigned for GetResponse - handling of MibSyncChan stopped")
+	}
+	return msgObj
+}
+
+func TestCreateOnu2gResponse(t *testing.T) {
+	response := createOnu2gResponse(40960, 1)
+	data, _ := serialize(omci.GetResponseType, response, 1)
+
+	// emulate the openonu-go behavior:
+	// omci_cc.receiveMessage process the message (creates a gopacket and extracts the OMCI layer) and invokes a callback
+	// in the GetResponse case omci_cc.receiveOmciResponse
+	// then the OmciMessage (gopacket + OMIC layer) is is published on a channel
+	omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+	assert.Equal(t, omciMsg.MessageType, omci.GetResponseType)
+
+	// that is read by myb_sync.processMibSyncMessages
+	// the myb_sync.handleOmciMessage is called and then
+	// myb_sync.handleOmciGetResponseMessage where we extract the GetResponse layer
+	getResponseLayer := omciToGetResponse(t, omciPkt)
+
+	assert.Equal(t, getResponseLayer.Result, me.Success)
+}
+
+func TestCreateOnugResponse(t *testing.T) {
+	response := createOnugResponse(40960, 1)
+	data, _ := serialize(omci.GetResponseType, response, 1)
+
+	omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+	assert.Equal(t, omciMsg.MessageType, omci.GetResponseType)
+
+	getResponseLayer := omciToGetResponse(t, omciPkt)
+
+	assert.Equal(t, getResponseLayer.Result, me.Success)
+}
diff --git a/internal/common/omci/mib_test.go b/internal/common/omci/mib_test.go
new file mode 100644
index 0000000..c73f616
--- /dev/null
+++ b/internal/common/omci/mib_test.go
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"fmt"
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	"gotest.tools/assert"
+	"testing"
+)
+
+func TestCreateMibResetResponse(t *testing.T) {
+	data, _ := CreateMibResetResponse(1)
+
+	omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+	assert.Equal(t, omciMsg.MessageType, omci.MibResetResponseType)
+
+	msgLayer := (*omciPkt).Layer(omci.LayerTypeMibResetResponse)
+	msgObj, msgOk := msgLayer.(*omci.MibResetResponse)
+	if !msgOk {
+		t.Fail()
+	}
+
+	assert.Equal(t, msgObj.Result, me.Success)
+}
+
+// types for TestCreateMibUploadNextResponse test
+type mibArgs struct {
+	omciPkt gopacket.Packet
+	omciMsg *omci.OMCI
+}
+
+type mibExpected struct {
+	messageType   omci.MessageType
+	transactionId uint16
+	entityClass   me.ClassID
+	attributes    map[string]interface{}
+}
+
+func createTestMibUploadNextArgs(t *testing.T, tid uint16, seqNumber uint16) mibArgs {
+	mibUploadNext, _ := CreateMibUploadNextRequest(tid, seqNumber)
+	mibUploadNext = hexDecode(mibUploadNext)
+	mibUploadNextMsg, mibUploadNextPkt := omciBytesToMsg(t, mibUploadNext)
+
+	return mibArgs{
+		omciPkt: *mibUploadNextPkt,
+		omciMsg: mibUploadNextMsg,
+	}
+}
+
+func TestCreateMibUploadNextResponse(t *testing.T) {
+
+	tests := []struct {
+		name string
+		args mibArgs
+		want mibExpected
+	}{
+		{"mibUploadNext-0", createTestMibUploadNextArgs(t, 1, 0),
+			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 1, entityClass: me.OnuDataClassID, attributes: map[string]interface{}{"MibDataSync": uint8(0)}}},
+		{"mibUploadNext-1", createTestMibUploadNextArgs(t, 2, 1),
+			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 2, entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"Type": uint8(47), "NumberOfPorts": uint8(4)}}},
+		{"mibUploadNext-4", createTestMibUploadNextArgs(t, 3, 4),
+			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 3, entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"PowerShedOverride": uint32(0)}}},
+		{"mibUploadNext-10", createTestMibUploadNextArgs(t, 4, 10),
+			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 4, entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{"SensedType": uint8(47)}}},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+
+			// create the packet starting from the mibUploadNextRequest
+			data, _ := CreateMibUploadNextResponse(tt.args.omciPkt, tt.args.omciMsg)
+			omciMsg, omciPkt := omciBytesToMsg(t, data)
+
+			assert.Equal(t, omciMsg.MessageType, tt.want.messageType)
+
+			msgLayer := (*omciPkt).Layer(omci.LayerTypeMibUploadNextResponse)
+			msgObj, msgOk := msgLayer.(*omci.MibUploadNextResponse)
+			if !msgOk {
+				t.Fail()
+			}
+
+			assert.Equal(t, omciMsg.TransactionID, tt.want.transactionId) // tid
+			// GetAttribute("ManagedEntityId") returns nil,
+			// msgObj.EntityClass is always OnuDataClassID
+			// how do we check this?
+			//meId, _ := msgObj.ReportedME.GetAttribute("ManagedEntityId")
+			//assert.Equal(t, meId, tt.want.entityClass)
+			//assert.Equal(t, msgObj.EntityClass, tt.want.entityClass)
+
+			fmt.Println(msgObj.EntityInstance, msgObj.ReportedME.GetEntityID())
+
+			for k, v := range tt.want.attributes {
+				attr, _ := msgObj.ReportedME.GetAttribute(k)
+				assert.Equal(t, attr, v)
+			}
+		})
+	}
+
+}
diff --git a/internal/common/omci/mibpackets.go b/internal/common/omci/mibpackets.go
index b21da4d..fe02e5d 100755
--- a/internal/common/omci/mibpackets.go
+++ b/internal/common/omci/mibpackets.go
@@ -18,10 +18,10 @@
 
 import (
 	"encoding/hex"
-	"github.com/cboling/omci"
-	me "github.com/cboling/omci/generated"
+	"errors"
 	"github.com/google/gopacket"
-	omcisim "github.com/opencord/omci-sim"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -41,6 +41,8 @@
 	RxHandler   rxFrameParser
 }
 
+// NOTE this is basically the same as https://github.com/opencord/voltha-openonu-adapter-go/blob/master/internal/pkg/onuadaptercore/omci_cc.go#L545-L564
+// we should probably move it in "omci-lib-go"
 func serialize(msgType omci.MessageType, request gopacket.SerializableLayer, tid uint16) ([]byte, error) {
 	omciLayer := &omci.OMCI{
 		TransactionID: tid,
@@ -63,57 +65,11 @@
 	return dst, nil
 }
 
-func DecodeOmci(payload []byte) (omci.MessageType, gopacket.Packet) {
-	// Perform base OMCI decode (common to all requests)
-	packet := gopacket.NewPacket(payload, omci.LayerTypeOMCI, gopacket.NoCopy)
-
-	if omciLayer := packet.Layer(omci.LayerTypeOMCI); omciLayer != nil {
-
-		omciObj, omciOk := omciLayer.(*omci.OMCI)
-		if !omciOk {
-			panic("Not Expected") // TODO: Do something better or delete...
-		}
-		if byte(omciObj.MessageType) & ^me.AK == 0 {
-			// Not a response, silently discard
-			return 0, nil
-		}
-		return omciObj.MessageType, packet
-	}
-
-	// FIXME
-	// if we can't properly decode the packet, try using shad helper method
-	// most likely this won't be necessary once we move omci-sim to use cboling/omci
-	// to generate packets
-	_, _, msgType, _, _, _, err := omcisim.ParsePkt(payload)
-	if err != nil {
-		return 0, nil
-	}
-	if msgType == omcisim.MibReset {
-		return omci.MibResetResponseType, nil
-	}
-	if msgType == omcisim.MibUpload {
-		return omci.MibUploadResponseType, nil
-	}
-	if msgType == omcisim.MibUploadNext {
-		return omci.MibUploadNextResponseType, nil
-	}
-	if msgType == omcisim.Create {
-		return omci.CreateResponseType, nil
-	}
-	if msgType == omcisim.Set {
-		return omci.SetResponseType, nil
-	}
-
-	omciLogger.Warnf("omci-sim returns msgType: %d", msgType)
-
-	return 0, nil
-}
-
 func CreateMibResetRequest(tid uint16) ([]byte, error) {
 
 	request := &omci.MibResetRequest{
 		MeBasePacket: omci.MeBasePacket{
-			EntityClass: me.OnuDataClassId,
+			EntityClass: me.OnuDataClassID,
 		},
 	}
 	pkt, err := serialize(omci.MibResetRequestType, request, tid)
@@ -126,10 +82,29 @@
 	return hexEncode(pkt)
 }
 
+func CreateMibResetResponse(tid uint16) ([]byte, error) {
+
+	// TODO reset MDX
+	request := &omci.MibResetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass: me.OnuDataClassID,
+		},
+		Result: me.Success,
+	}
+	pkt, err := serialize(omci.MibResetResponseType, request, tid)
+	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err": err,
+		}).Error("Cannot serialize MibResetResponse")
+		return nil, err
+	}
+	return pkt, nil
+}
+
 func CreateMibUploadRequest(tid uint16) ([]byte, error) {
 	request := &omci.MibUploadRequest{
 		MeBasePacket: omci.MeBasePacket{
-			EntityClass: me.OnuDataClassId,
+			EntityClass: me.OnuDataClassID,
 			// Default Instance ID is 0
 		},
 	}
@@ -143,11 +118,31 @@
 	return hexEncode(pkt)
 }
 
+func CreateMibUploadResponse(tid uint16) ([]byte, error) {
+
+	numberOfCommands := uint16(291) //NOTE should this be configurable? (not until we have moved all the messages away from omci-sim)
+
+	request := &omci.MibUploadResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass: me.OnuDataClassID,
+		},
+		NumberOfCommands: numberOfCommands,
+	}
+	pkt, err := serialize(omci.MibUploadResponseType, request, tid)
+	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err": err,
+		}).Error("Cannot serialize MibUploadResponse")
+		return nil, err
+	}
+	return pkt, nil
+}
+
 func CreateMibUploadNextRequest(tid uint16, seqNumber uint16) ([]byte, error) {
 
 	request := &omci.MibUploadNextRequest{
 		MeBasePacket: omci.MeBasePacket{
-			EntityClass: me.OnuDataClassId,
+			EntityClass: me.OnuDataClassID,
 			// Default Instance ID is 0
 		},
 		CommandSequenceNumber: seqNumber,
@@ -163,123 +158,299 @@
 	return hexEncode(pkt)
 }
 
-// Return true if msg is an Omci Test Request
-func IsTestRequest(payload []byte) (bool, error) {
-	_, _, msgType, _, _, _, err := omcisim.ParsePkt(payload)
-	if err != nil {
-		return false, err
+func ParseMibUploadNextRequest(omciPkt gopacket.Packet) (*omci.MibUploadNextRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeMibUploadNextRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeMibUploadNextRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
 	}
-
-	return ((msgType & 0x1F) == 18), nil
+	msgObj, msgOk := msgLayer.(*omci.MibUploadNextRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for MibUploadNextRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
 }
 
-func BuildTestResult(payload []byte) ([]byte, error) {
-	transactionId, deviceId, _, class, instance, _, err := omcisim.ParsePkt(payload)
+func CreateMibUploadNextResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
 
+	msgObj, err := ParseMibUploadNextRequest(omciPkt)
 	if err != nil {
-		return []byte{}, err
+		err := "omci Msg layer could not be assigned for LayerTypeGetRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
 	}
 
-	resp := make([]byte, 48)
-	resp[0] = byte(transactionId >> 8)
-	resp[1] = byte(transactionId & 0xFF)
-	resp[2] = 27 // Upper nibble 0x0 is fixed (0000), Lower nibbles defines msg type (TestResult=27)
-	resp[3] = deviceId
-	resp[4] = byte(class >> 8)
-	resp[5] = byte(class & 0xFF)
-	resp[6] = byte(instance >> 8)
-	resp[7] = byte(instance & 0xFF)
-	// Each of these is a 1-byte code
-	// follow by a 2-byte (high, low) value
-	resp[8] = 1 // power feed voltage
-	resp[9] = 0
-	resp[10] = 123 // 123 mV, 20 mv res --> 6mv
-	resp[11] = 3   // received optical power
-	resp[12] = 1
-	resp[13] = 200 // 456 decibel-microwatts, 0.002 dB res --> 0.912 db-mw
-	resp[14] = 5   // mean optical launch power
-	resp[15] = 3
-	resp[16] = 21 // 789 uA, 0.002 dB res --> 1.578 db-mw
-	resp[17] = 9  // laser bias current
-	resp[18] = 3
-	resp[19] = 244 // 1012 uA, 2uA res --> 505 ua
-	resp[20] = 12  // temperature
-	resp[21] = 38
-	resp[22] = 148 // 9876 deg C, 1/256 resolution --> 38.57 Deg C
+	omciLogger.WithFields(log.Fields{
+		"EntityClass":           msgObj.EntityClass,
+		"EntityInstance":        msgObj.EntityInstance,
+		"CommandSequenceNumber": msgObj.CommandSequenceNumber,
+	}).Trace("received-omci-mibUploadNext-request")
 
-	return resp, nil
-}
+	// depending on the sequenceNumber we'll report a different
+	reportedMe := &me.ManagedEntity{}
+	var meErr me.OmciErrors
+	//var entityInstance uint16
+	switch msgObj.CommandSequenceNumber {
+	case 0:
+		reportedMe, meErr = me.NewOnuData(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId": me.OnuDataClassID,
+			"MibDataSync":     0,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewOnuData %v", meErr.Error())
+		}
 
-// TODO understand and refactor
-
-func CreateGalEnetRequest(tid uint16) ([]byte, error) {
-	params := me.ParamData{
-		EntityID:   galEthernetEID,
-		Attributes: me.AttributeValueMap{"MaximumGemPayloadSize": maxGemPayloadSize},
-	}
-	meDef, _ := me.NewGalEthernetProfile(params)
-	pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
-	if err != nil {
-		omciLogger.WithField("err", err).Fatalf("Can't generate GalEnetRequest")
-	}
-	return hexEncode(pkt)
-}
-
-func CreateEnableUniRequest(tid uint16, uniId uint16, enabled bool, isPtp bool) ([]byte, error) {
-
-	var _enabled uint8
-	if enabled {
-		_enabled = uint8(1)
-	} else {
-		_enabled = uint8(0)
+	case 1:
+		reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId": me.CircuitPackClassID,
+			"Type":            47,
+			"NumberOfPorts":   4,
+			"SerialNumber":    toOctets("BBSM-Circuit-Pack", 20),
+			"Version":         toOctets("v0.0.1", 20),
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+		}
+	case 2:
+		reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":     me.CircuitPackClassID,
+			"VendorId":            "ONF",
+			"AdministrativeState": 0,
+			"OperationalState":    0,
+			"BridgedOrIpInd":      0,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+		}
+	case 3:
+		reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":             me.CircuitPackClassID,
+			"EquipmentId":                 toOctets("BBSM-Circuit-Pack", 20),
+			"CardConfiguration":           0,
+			"TotalTContBufferNumber":      0,
+			"TotalPriorityQueueNumber":    8,
+			"TotalTrafficSchedulerNumber": 0,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+		}
+	case 4:
+		reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":   me.CircuitPackClassID,
+			"PowerShedOverride": uint32(0),
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+		}
+	case 5:
+		reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId": me.CircuitPackClassID,
+			"Type":            238,
+			"NumberOfPorts":   1,
+			"SerialNumber":    toOctets("BBSM-Circuit-Pack-2", 20),
+			"Version":         toOctets("v0.0.1", 20),
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+		}
+	case 6:
+		reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":     me.CircuitPackClassID,
+			"VendorId":            "ONF",
+			"AdministrativeState": 0,
+			"OperationalState":    0,
+			"BridgedOrIpInd":      0,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+		}
+	case 7:
+		reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":             me.CircuitPackClassID,
+			"EquipmentId":                 toOctets("BBSM-Circuit-Pack", 20),
+			"CardConfiguration":           0,
+			"TotalTContBufferNumber":      8,
+			"TotalPriorityQueueNumber":    40,
+			"TotalTrafficSchedulerNumber": 10,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+		}
+	case 8:
+		reportedMe, meErr = me.NewCircuitPack(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":   me.CircuitPackClassID,
+			"PowerShedOverride": uint32(0),
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewCircuitPack %v", meErr.Error())
+		}
+	case 9, 10, 11, 12:
+		// NOTE we're reporting for different UNIs, the IDs are 257, 258, 259, 260
+		meInstance := 248 + msgObj.CommandSequenceNumber
+		reportedMe, meErr = me.NewPhysicalPathTerminationPointEthernetUni(me.ParamData{
+			EntityID: meInstance,
+			Attributes: me.AttributeValueMap{
+				"ExpectedType":                  0,
+				"SensedType":                    47,
+				"AutoDetectionConfiguration":    0,
+				"EthernetLoopbackConfiguration": 0,
+				"AdministrativeState":           0,
+				"OperationalState":              0,
+				"ConfigurationInd":              3,
+				"MaxFrameSize":                  1518,
+				"DteOrDceInd":                   0,
+				"PauseTime":                     0,
+				"BridgedOrIpInd":                2,
+				"Arc":                           0,
+				"ArcInterval":                   0,
+				"PppoeFilter":                   0,
+				"PowerControl":                  0,
+			}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewPhysicalPathTerminationPointEthernetUni %v", meErr.Error())
+		}
+	case 13, 14, 15, 16, 17, 18, 19, 20:
+		// TODO report different MeID (see omci-sim pcap filter "frame[22:2] == 01:06")
+		reportedMe, meErr = me.NewTCont(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId": me.TContClassID,
+			"AllocId":         0,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewTCont %v", meErr.Error())
+		}
+	case 21:
+		reportedMe, meErr = me.NewAniG(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":             me.AniGClassID,
+			"SrIndication":                1,
+			"TotalTcontNumber":            8,
+			"GemBlockLength":              30,
+			"PiggybackDbaReporting":       0,
+			"Deprecated":                  0,
+			"SignalFailThreshold":         5,
+			"SignalDegradeThreshold":      9,
+			"Arc":                         0,
+			"ArcInterval":                 0,
+			"OpticalSignalLevel":          57428,
+			"LowerOpticalThreshold":       255,
+			"UpperOpticalThreshold":       255,
+			"OnuResponseTime":             0,
+			"TransmitOpticalLevel":        3171,
+			"LowerTransmitPowerThreshold": 129,
+			"UpperTransmitPowerThreshold": 129,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewAniG %v", meErr.Error())
+		}
+	case 22, 23, 24, 25:
+		// TODO report different MeID (see omci-sim pcap filter "frame[22:2] == 01:08")
+		reportedMe, meErr = me.NewUniG(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":     me.UniGClassID,
+			"Deprecated":          0,
+			"AdministrativeState": 0,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewUniG %v", meErr.Error())
+		}
+	case 26, 30, 34, 38, 42, 46, 50, 54,
+		58, 62, 66, 70, 74, 78, 82, 86,
+		90, 94, 98, 102, 106, 110, 114, 118,
+		122, 126, 130, 134, 138, 142, 146, 150,
+		154, 158, 162, 166, 170, 174, 178, 182,
+		186, 190, 194, 198, 202, 206, 210, 214,
+		218, 222, 226, 230, 234, 238, 242, 246,
+		250, 254, 258, 262, 266, 270, 274, 278:
+	case 27, 31, 35, 39, 43, 47, 51, 55,
+		59, 63, 67, 71, 75, 79, 83, 87,
+		91, 95, 99, 103, 107, 111, 115, 119,
+		123, 127, 131, 135, 139, 143, 147, 151,
+		155, 159, 163, 167, 171, 175, 179, 183,
+		187, 191, 195, 199, 203, 207, 211, 215,
+		219, 223, 227, 231, 235, 239, 243, 247,
+		251, 255, 259, 263, 267, 271, 275, 279:
+	case 28, 32, 36, 40, 44, 48, 52, 56,
+		60, 64, 68, 72, 76, 80, 84, 88,
+		92, 96, 100, 104, 108, 112, 116, 120,
+		124, 128, 132, 136, 140, 144, 148, 152,
+		156, 160, 164, 168, 172, 176, 180, 184,
+		188, 192, 196, 200, 204, 208, 212, 216,
+		220, 224, 228, 232, 236, 240, 244, 248,
+		252, 256, 260, 264, 268, 272, 276, 280:
+	case 29, 33, 37, 41, 45, 49, 53, 57,
+		61, 65, 69, 73, 77, 81, 85, 89,
+		93, 97, 101, 105, 109, 113, 117, 121,
+		125, 129, 133, 137, 141, 145, 149, 153,
+		157, 161, 165, 169, 173, 177, 181, 185,
+		189, 193, 197, 201, 205, 209, 213, 217,
+		221, 225, 229, 233, 237, 241, 245, 249,
+		253, 257, 261, 265, 269, 273, 277, 281:
+		reportedMe, meErr = me.NewPriorityQueue(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":                                     me.PriorityQueueClassID,
+			"QueueConfigurationOption":                            0,
+			"MaximumQueueSize":                                    100,
+			"AllocatedQueueSize":                                  100,
+			"DiscardBlockCounterResetInterval":                    0,
+			"ThresholdValueForDiscardedBlocksDueToBufferOverflow": 0,
+			"RelatedPort":                                         80010000, // does this need to change?
+			"TrafficSchedulerPointer":                             8008,     // does this need to change?
+			"Weight":                                              1,
+			"BackPressureOperation":                               1,
+			"BackPressureTime":                                    0,
+			"BackPressureOccurQueueThreshold":                     0,
+			"BackPressureClearQueueThreshold":                     0,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewPriorityQueue %v", meErr.Error())
+		}
+	case 282, 283, 284, 285, 286, 287, 288, 289:
+		reportedMe, meErr = me.NewTrafficScheduler(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":         me.TrafficSchedulerClassID,
+			"TContPointer":            8008, // NOTE does this need to change?
+			"TrafficSchedulerPointer": 0,
+			"Policy":                  02,
+			"PriorityWeight":          0,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewTrafficScheduler %v", meErr.Error())
+		}
+	case 290:
+		reportedMe, meErr = me.NewOnu2G(me.ParamData{Attributes: me.AttributeValueMap{
+			"ManagedEntityId":             me.Onu2GClassID,
+			"TotalPriorityQueueNumber":    40,
+			"SecurityMode":                1,
+			"TotalTrafficSchedulerNumber": 8,
+			"TotalGemPortIdNumber":        0,
+			"Sysuptime":                   0,
+		}})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("NewOnu2G %v", meErr.Error())
+		}
+	default:
+		omciLogger.Warn("unsupported-CommandSequenceNumber-in-mib-upload-next", msgObj.CommandSequenceNumber)
+		return nil, nil
 	}
 
-	data := me.ParamData{
-		EntityID: uniId,
-		Attributes: me.AttributeValueMap{
-			"AdministrativeState": _enabled,
+	response := &omci.MibUploadNextResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass: me.OnuDataClassID,
 		},
+		ReportedME: *reportedMe,
 	}
-	var medef *me.ManagedEntity
-	var omciErr me.OmciErrors
 
-	if isPtp {
-		medef, omciErr = me.NewPhysicalPathTerminationPointEthernetUni(data)
-	} else {
-		medef, omciErr = me.NewVirtualEthernetInterfacePoint(data)
-	}
-	if omciErr != nil {
-		return nil, omciErr.GetError()
-	}
-	pkt, err := omci.GenFrame(medef, omci.SetRequestType, omci.TransactionID(tid))
+	omciLogger.WithFields(log.Fields{
+		"reportedMe": reportedMe,
+	}).Trace("created-omci-mibUploadNext-response")
+
+	pkt, err := serialize(omci.MibUploadNextResponseType, response, omciMsg.TransactionID)
+
 	if err != nil {
-		omciLogger.WithField("err", err).Fatalf("Can't generate EnableUniRequest")
+		omciLogger.WithFields(log.Fields{
+			"Err": err,
+		}).Fatalf("Cannot serialize MibUploadNextRequest")
+		return nil, err
 	}
-	return hexEncode(pkt)
-}
 
-func CreateGemPortRequest(tid uint16) ([]byte, error) {
-	params := me.ParamData{
-		EntityID: gemEID,
-		Attributes: me.AttributeValueMap{
-			"PortId":                              1,
-			"TContPointer":                        1,
-			"Direction":                           0,
-			"TrafficManagementPointerForUpstream": 0,
-			"TrafficDescriptorProfilePointerForUpstream": 0,
-			"UniCounter":                                   0,
-			"PriorityQueuePointerForDownStream":            0,
-			"EncryptionState":                              0,
-			"TrafficDescriptorProfilePointerForDownstream": 0,
-			"EncryptionKeyRing":                            0,
-		},
-	}
-	meDef, _ := me.NewGemPortNetworkCtp(params)
-	pkt, err := omci.GenFrame(meDef, omci.CreateRequestType, omci.TransactionID(tid))
-	if err != nil {
-		omciLogger.WithField("err", err).Fatalf("Can't generate GemPortRequest")
-	}
-	return hexEncode(pkt)
+	return pkt, nil
 }
-
-// END TODO
diff --git a/internal/common/omci/omci_base.go b/internal/common/omci/omci_base.go
new file mode 100644
index 0000000..e74ec4a
--- /dev/null
+++ b/internal/common/omci/omci_base.go
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+	log "github.com/sirupsen/logrus"
+)
+
+// ParseOpenOltOmciPacket receive an OMCI packet in the openolt format and returns
+// an OMCI Layer as per omci-lib-go
+func ParseOpenOltOmciPacket(pkt []byte) (gopacket.Packet, *omci.OMCI, error) {
+	rxMsg := hexDecode(pkt)
+
+	// NOTE this is may not be needed, VOLTHA sends the correct message
+	if len(rxMsg) >= 44 {
+		trailerLenData := rxMsg[42:44]
+		trailerLen := binary.BigEndian.Uint16(trailerLenData)
+		if trailerLen != 40 { // invalid base Format entry -> autocorrect
+			binary.BigEndian.PutUint16(rxMsg[42:44], 40)
+			omciLogger.Trace("cc-corrected-omci-message: trailer len inserted")
+		}
+	} else {
+		omciLogger.WithFields(log.Fields{"Length": len(rxMsg)}).Error("received omci-message too small for OmciBaseFormat - abort")
+		return nil, nil, errors.New("received omci-message too small for OmciBaseFormat - abort")
+	}
+
+	packet := gopacket.NewPacket(rxMsg, omci.LayerTypeOMCI, gopacket.NoCopy)
+	if packet == nil {
+		omciLogger.Error("omci-message could not be decoded")
+		return nil, nil, errors.New("omci-message could not be decoded")
+	}
+	omciLayer := packet.Layer(omci.LayerTypeOMCI)
+	if omciLayer == nil {
+		omciLogger.Error("omci-message could not decode omci layer")
+		return nil, nil, fmt.Errorf("omci-message could not decode omci layer")
+	}
+	parsed, ok := omciLayer.(*omci.OMCI)
+	if !ok {
+		omciLogger.Error("omci-message could not assign omci layer")
+		return nil, nil, errors.New("omci-message could not assign omci layer")
+	}
+
+	return packet, parsed, nil
+}
+
+// hexDecode converts the hex encoding to binary
+func hexDecode(pkt []byte) []byte {
+	p := make([]byte, len(pkt)/2)
+	for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
+		// Go figure this ;)
+		u := (pkt[i] & 15) + (pkt[i]>>6)*9
+		l := (pkt[i+1] & 15) + (pkt[i+1]>>6)*9
+		p[j] = u<<4 + l
+	}
+	return p
+}
diff --git a/internal/common/omci/reboot.go b/internal/common/omci/reboot.go
new file mode 100644
index 0000000..e315044
--- /dev/null
+++ b/internal/common/omci/reboot.go
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"errors"
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	log "github.com/sirupsen/logrus"
+)
+
+func ParseRebootRequest(omciPkt gopacket.Packet) (*omci.RebootRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeRebootRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeRebootRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.RebootRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeRebootRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+func CreateRebootResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+	msgObj, err := ParseRebootRequest(omciPkt)
+
+	if err != nil {
+		return nil, err
+	}
+
+	omciLogger.WithFields(log.Fields{
+		"EntityClass":    msgObj.EntityClass,
+		"EntityInstance": msgObj.EntityInstance,
+	}).Trace("received-omci-set-request")
+
+	response := &omci.SetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    msgObj.EntityClass,
+			EntityInstance: msgObj.EntityInstance,
+		},
+		Result: me.Success,
+	}
+
+	pkt, err := serialize(omci.RebootResponseType, response, omciMsg.TransactionID)
+	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err": err,
+		}).Error("cannot-serialize-RebootResponse")
+		return nil, err
+	}
+
+	return pkt, nil
+
+}
diff --git a/internal/common/omci/set.go b/internal/common/omci/set.go
new file mode 100644
index 0000000..eeb621e
--- /dev/null
+++ b/internal/common/omci/set.go
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"errors"
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+	me "github.com/opencord/omci-lib-go/generated"
+	log "github.com/sirupsen/logrus"
+)
+
+func ParseSetRequest(omciPkt gopacket.Packet) (*omci.SetRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeSetRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeSetRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.SetRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeSetRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+func CreateSetResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
+	msgObj, err := ParseSetRequest(omciPkt)
+
+	if err != nil {
+		return nil, err
+	}
+
+	omciLogger.WithFields(log.Fields{
+		"EntityClass":    msgObj.EntityClass,
+		"EntityInstance": msgObj.EntityInstance,
+		"AttributeMask":  msgObj.AttributeMask,
+	}).Trace("received-omci-set-request")
+
+	response := &omci.SetResponse{
+		MeBasePacket: omci.MeBasePacket{
+			EntityClass:    msgObj.EntityClass,
+			EntityInstance: msgObj.EntityInstance,
+		},
+		Result: me.Success,
+	}
+
+	pkt, err := serialize(omci.SetResponseType, response, omciMsg.TransactionID)
+	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err": err,
+		}).Error("cannot-serialize-SetResponse")
+		return nil, err
+	}
+
+	return pkt, nil
+
+}
diff --git a/internal/common/omci/test.go b/internal/common/omci/test.go
new file mode 100644
index 0000000..40398ba
--- /dev/null
+++ b/internal/common/omci/test.go
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package omci
+
+import (
+	"errors"
+	"github.com/google/gopacket"
+	"github.com/opencord/omci-lib-go"
+)
+
+func ParseTestRequest(omciPkt gopacket.Packet) (*omci.TestRequest, error) {
+	msgLayer := omciPkt.Layer(omci.LayerTypeGetRequest)
+	if msgLayer == nil {
+		err := "omci Msg layer could not be detected for LayerTypeTestRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	msgObj, msgOk := msgLayer.(*omci.TestRequest)
+	if !msgOk {
+		err := "omci Msg layer could not be assigned for LayerTypeTestRequest"
+		omciLogger.Error(err)
+		return nil, errors.New(err)
+	}
+	return msgObj, nil
+}
+
+// Return true if msg is an Omci Test Request
+func IsTestRequest(payload []byte) (bool, error) {
+	_, omciMsg, err := ParseOpenOltOmciPacket(payload)
+	if err != nil {
+		return false, err
+	}
+
+	return omciMsg.MessageType == omci.TestRequestType, nil
+}
+
+func BuildTestResult(payload []byte) ([]byte, error) {
+
+	omciPkt, omciMsg, err := ParseOpenOltOmciPacket(payload)
+
+	//transactionId, deviceId, _, class, instance, _, err := omcisim.ParsePkt(payload)
+
+	if err != nil {
+		return []byte{}, err
+	}
+
+	testRequest, err := ParseTestRequest(omciPkt)
+	if err != nil {
+		return []byte{}, err
+	}
+
+	// TODO create a TestResponse using omci-lib-go
+	resp := make([]byte, 48)
+	resp[0] = byte(omciMsg.TransactionID >> 8)
+	resp[1] = byte(omciMsg.TransactionID & 0xFF)
+	resp[2] = 27 // Upper nibble 0x0 is fixed (0000), Lower nibbles defines msg type (TestResult=27)
+	resp[3] = byte(omciMsg.DeviceIdentifier)
+	resp[4] = byte(omciMsg.MessageType)
+	resp[5] = byte(omciMsg.MessageType & 0xFF)
+	resp[6] = byte(testRequest.EntityInstance >> 8)
+	resp[7] = byte(testRequest.EntityInstance & 0xFF)
+	// Each of these is a 1-byte code
+	// follow by a 2-byte (high, low) value
+	resp[8] = 1 // power feed voltage
+	resp[9] = 0
+	resp[10] = 123 // 123 mV, 20 mv res --> 6mv
+	resp[11] = 3   // received optical power
+	resp[12] = 1
+	resp[13] = 200 // 456 decibel-microwatts, 0.002 dB res --> 0.912 db-mw
+	resp[14] = 5   // mean optical launch power
+	resp[15] = 3
+	resp[16] = 21 // 789 uA, 0.002 dB res --> 1.578 db-mw
+	resp[17] = 9  // laser bias current
+	resp[18] = 3
+	resp[19] = 244 // 1012 uA, 2uA res --> 505 ua
+	resp[20] = 12  // temperature
+	resp[21] = 38
+	resp[22] = 148 // 9876 deg C, 1/256 resolution --> 38.57 Deg C
+
+	return resp, nil
+}