[VOL-3036] Read MIB Templates from ETCD

Change-Id: I59143cd1b51fa64b70b7a1f63eebfd3463f24017
Signed-off-by: Holger Hildebrandt <holger.hildebrandt@adtran.com>
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index 44a5b6a..1aca121 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -70,6 +70,27 @@
 	cOnuActivatedEvent = "ONU_ACTIVATED"
 )
 
+type resourceEntry int
+
+const (
+	cResourceGemPort resourceEntry = 1
+	cResourceTcont   resourceEntry = 2
+)
+
+type OnuSerialNumber struct {
+	VendorId       []byte
+	VendorSpecific []byte
+}
+
+type onuPersistentData struct {
+	persOnuID      uint32
+	persIntfID     uint32
+	persSnr        OnuSerialNumber
+	persAdminState string
+	persOperState  string
+	persUniTpPath  map[uint32]string
+}
+
 //DeviceHandler will interact with the ONU ? device.
 type DeviceHandler struct {
 	deviceID         string
@@ -82,9 +103,13 @@
 	parentId         string
 	ponPortNumber    uint32
 
-	coreProxy       adapterif.CoreProxy
-	AdapterProxy    adapterif.AdapterProxy
-	EventProxy      adapterif.EventProxy
+	coreProxy    adapterif.CoreProxy
+	AdapterProxy adapterif.AdapterProxy
+	EventProxy   adapterif.EventProxy
+
+	tpProcMutex        sync.RWMutex
+	sOnuPersistentData onuPersistentData
+
 	pOpenOnuAc      *OpenONUAC
 	pDeviceStateFsm *fsm.FSM
 	pPonPort        *voltha.Port
@@ -122,6 +147,8 @@
 	dh.DeviceType = cloned.Type
 	dh.adminState = "up"
 	dh.device = cloned
+	dh.tpProcMutex = sync.RWMutex{}
+	dh.sOnuPersistentData.persUniTpPath = make(map[uint32]string)
 	dh.pOpenOnuAc = adapter
 	dh.exitChannel = make(chan int, 1)
 	dh.lockDevice = sync.RWMutex{}
@@ -217,14 +244,15 @@
 			msgBody := msg.GetBody()
 			omciMsg := &ic.InterAdapterOmciMessage{}
 			if err := ptypes.UnmarshalAny(msgBody, omciMsg); err != nil {
-				logger.Warnw("cannot-unmarshal-omci-msg-body", log.Fields{"error": err})
+				logger.Warnw("cannot-unmarshal-omci-msg-body", log.Fields{
+					"deviceID": dh.deviceID, "error": err})
 				return err
 			}
 
 			//assuming omci message content is hex coded!
 			// with restricted output of 16(?) bytes would be ...omciMsg.Message[:16]
-			logger.Debugw("inter-adapter-recv-omci",
-				log.Fields{"RxOmciMessage": hex.EncodeToString(omciMsg.Message)})
+			logger.Debugw("inter-adapter-recv-omci", log.Fields{
+				"deviceID": dh.deviceID, "RxOmciMessage": hex.EncodeToString(omciMsg.Message)})
 			//receive_message(omci_msg.message)
 			pDevEntry := dh.GetOnuDeviceEntry(true)
 			if pDevEntry != nil {
@@ -239,7 +267,8 @@
 			msgBody := msg.GetBody()
 			onu_indication := &oop.OnuIndication{}
 			if err := ptypes.UnmarshalAny(msgBody, onu_indication); err != nil {
-				logger.Warnw("cannot-unmarshal-onu-indication-msg-body", log.Fields{"error": err})
+				logger.Warnw("cannot-unmarshal-onu-indication-msg-body", log.Fields{
+					"deviceID": dh.deviceID, "error": err})
 				return err
 			}
 
@@ -258,9 +287,89 @@
 				return errors.New("InvalidOperState")
 			}
 		}
+	// TODO: temporarily commented out - see https://gerrit.opencord.org/#/c/19330/
+	// case ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST:
+	// 	{
+	// 		msgBody := msg.GetBody()
+	// 		techProfMsg := &ic.InterAdapterTechProfileDownloadMessage{}
+	// 		if err := ptypes.UnmarshalAny(msgBody, techProfMsg); err != nil {
+	// 			logger.Warnw("cannot-unmarshal-techprof-msg-body", log.Fields{
+	// 				"deviceID": dh.deviceID, "error": err})
+	// 			return err
+	// 		}
+	// 		// we have to lock access to TechProfile processing based on different messageType calls or
+	// 		// even to fast subsequent calls of the same messageType
+	// 		dh.tpProcMutex.Lock()
+	// 		// lock hangs as long as below decoupled or other related TechProfile processing is active
+	// 		if bTpModify := dh.updateOnuUniTpPath(techProfMsg.UniId, techProfMsg.Path); bTpModify == true {
+	// 			//	if there has been some change for some uni TechProfilePath
+	// 			//in order to allow concurrent calls to other dh instances we do not wait for execution here
+	// 			//but doing so we can not indicate problems to the caller (who does what with that then?)
+	// 			//by now we just assume straightforward successful execution
+	// 			//TODO!!! Generally: In this scheme it would be good to have some means to indicate
+	// 			//  possible problems to the caller later autonomously
+
+	// 			// some code to coordinate TP 'run to completion'
+	// 			// attention: completion and wg.Add is assumed to be doen in both routines,
+	// 			// no timeout control so far (needed)
+	// 			var wg sync.WaitGroup
+	// 			wg.Add(2) // for the 2 go routines to finish
+	// 			go dh.configureUniTp(techProfMsg.UniId, techProfMsg.Path, &wg)
+	// 			go dh.updateOnuTpPathKvStore(&wg)
+	// 			//the wait.. function is responsible for tpProcMutex.Unlock()
+	// 			go dh.waitForTpCompletion(&wg) //let that also run off-line to let the IA messaging return!
+	// 		} else {
+	// 			dh.tpProcMutex.Unlock()
+	// 		}
+	// 	}
+	// case ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST:
+	// 	{
+	// 		msgBody := msg.GetBody()
+	// 		delGemPortMsg := &ic.InterAdapterDeleteGemPortMessage{}
+	// 		if err := ptypes.UnmarshalAny(msgBody, delGemPortMsg); err != nil {
+	// 			logger.Warnw("cannot-unmarshal-delete-gem-msg-body", log.Fields{
+	// 				"deviceID": dh.deviceID, "error": err})
+	// 			return err
+	// 		}
+
+	// 		//compare TECH_PROFILE_DOWNLOAD_REQUEST
+	// 		dh.tpProcMutex.Lock()
+	// 		var wg sync.WaitGroup
+	// 		wg.Add(1) // for the 1 go routine to finish
+	// 		go dh.deleteTpRessource(delGemPortMsg.UniId, delGemPortMsg.TpPath,
+	// 			cResourceGemPort, delGemPortMsg.GemPortId, &wg)
+	// 		//the wait.. function is responsible for tpProcMutex.Unlock()
+	// 		go dh.waitForTpCompletion(&wg) //let that also run off-line to let the IA messaging return!
+	// 	}
+	// case ic.InterAdapterMessageType_DELETE_TCONT_REQUEST:
+	// 	{
+	// 		msgBody := msg.GetBody()
+	// 		delTcontMsg := &ic.InterAdapterDeleteTcontMessage{}
+	// 		if err := ptypes.UnmarshalAny(msgBody, delTcontMsg); err != nil {
+	// 			logger.Warnw("cannot-unmarshal-delete-tcont-msg-body", log.Fields{
+	// 				"deviceID": dh.deviceID, "error": err})
+	// 			return err
+	// 		}
+
+	// 		//compare TECH_PROFILE_DOWNLOAD_REQUEST
+	// 		dh.tpProcMutex.Lock()
+	// 		if bTpModify := dh.updateOnuUniTpPath(delTcontMsg.UniId, ""); bTpModify == true {
+	// 			var wg sync.WaitGroup
+	// 			wg.Add(2) // for the 1 go routine to finish
+	// 			go dh.deleteTpRessource(delTcontMsg.UniId, delTcontMsg.TpPath,
+	// 				cResourceTcont, delTcontMsg.AllocId, &wg)
+	// 			// Removal of the tcont/alloc id mapping represents the removal of the tech profile
+	// 			go dh.updateOnuTpPathKvStore(&wg)
+	// 			//the wait.. function is responsible for tpProcMutex.Unlock()
+	// 			go dh.waitForTpCompletion(&wg) //let that also run off-line to let the IA messaging return!
+	// 		} else {
+	// 			dh.tpProcMutex.Unlock()
+	// 		}
+	// 	}
 	default:
 		{
-			logger.Errorw("inter-adapter-unhandled-type", log.Fields{"msgType": msg.Header.Type})
+			logger.Errorw("inter-adapter-unhandled-type", log.Fields{
+				"deviceID": dh.deviceID, "msgType": msg.Header.Type})
 			return errors.New("unimplemented")
 		}
 	}
@@ -834,9 +943,9 @@
 				//Determine ONU status and start/re-start MIB Synchronization tasks
 				//Determine if this ONU has ever synchronized
 				if true { //TODO: insert valid check
-					if err := pMibUlFsm.Event("load_mib_template"); err != nil {
-						logger.Errorw("MibSyncFsm: Can't go to state loading_mib_template", log.Fields{"err": err})
-						return errors.New("Can't go to state loading_mib_template")
+					if err := pMibUlFsm.Event("reset_mib"); err != nil {
+						logger.Errorw("MibSyncFsm: Can't go to state resetting_mib", log.Fields{"err": err})
+						return errors.New("Can't go to state resetting_mib")
 					}
 				} else {
 					pMibUlFsm.Event("examine_mds")
@@ -1239,12 +1348,88 @@
 	}
 }
 
+/* **** Traffic Profile related processing  **********/
+// updateOnuUniTpPath verifies and updates changes in the dh.onuUniTpPath
+func (dh *DeviceHandler) updateOnuUniTpPath(aUniID uint32, aPathString string) bool {
+	/* within some specific InterAdapter processing request write/read access to data is ensured to be sequentially,
+	   as also the complete sequence is ensured to 'run to  completion' before some new request is accepted
+	   no specific concurrency protection to sOnuPersistentData is required here
+	*/
+	if existingPath, present := dh.sOnuPersistentData.persUniTpPath[aUniID]; present {
+		// uni entry already exists
+		//logger.Debugw(" already exists", log.Fields{"for InstanceId": a_uniInstNo})
+		if existingPath != aPathString {
+			if aPathString == "" {
+				//existing entry to be deleted
+				logger.Debugw("UniTp path delete", log.Fields{
+					"deviceID": dh.deviceID, "uniID": aUniID, "path": aPathString})
+				delete(dh.sOnuPersistentData.persUniTpPath, aUniID)
+			} else {
+				//existing entry to be modified
+				logger.Debugw("UniTp path modify", log.Fields{
+					"deviceID": dh.deviceID, "uniID": aUniID, "path": aPathString})
+				dh.sOnuPersistentData.persUniTpPath[aUniID] = aPathString
+			}
+			return true
+		}
+		//entry already exists
+		logger.Debugw("UniTp path already exists", log.Fields{
+			"deviceID": dh.deviceID, "uniID": aUniID, "path": aPathString})
+		return false
+	} else {
+		//uni entry does not exist
+		if aPathString == "" {
+			//delete request in non-existing state , accept as no change
+			logger.Debugw("UniTp path already removed", log.Fields{
+				"deviceID": dh.deviceID, "uniID": aUniID})
+			return false
+		}
+		//new entry to be set
+		logger.Debugw("New UniTp path set", log.Fields{
+			"deviceID": dh.deviceID, "uniID": aUniID, "path": aPathString})
+		dh.sOnuPersistentData.persUniTpPath[aUniID] = aPathString
+		return true
+	}
+}
+
+func (dh *DeviceHandler) configureUniTp(aUniID uint32, aPathString string, wg *sync.WaitGroup) {
+	defer wg.Done()
+	logger.Debugw("this would configure the Uni according to TpPath", log.Fields{
+		"deviceID": dh.deviceID, "uniID": aUniID, "path": aPathString})
+	//TODO!!!
+	//this processing requires reading of the TechProfile config data from KV-Store,
+	//  to evaluate the configuration and to start the corresponding OMCI configuation of the UNI port
+}
+
+func (dh *DeviceHandler) updateOnuTpPathKvStore(wg *sync.WaitGroup) {
+	defer wg.Done()
+	logger.Debugw("this would update the ONU's TpPath in KVStore", log.Fields{
+		"deviceID": dh.deviceID})
+	//TODO!!!
+	//make use of dh.sOnuPersistentData to store the TpPath to KVStore
+}
+
+// deleteTpRessource removes ressources from the ONU's specified Uni
+func (dh *DeviceHandler) deleteTpRessource(aUniID uint32, aPathString string,
+	aRessource resourceEntry, aEntryID uint32, wg *sync.WaitGroup) {
+	defer wg.Done()
+	logger.Debugw("this would remove TP resources from ONU's UNI", log.Fields{
+		"deviceID": dh.deviceID, "uniID": aUniID, "path": aPathString, "ressource": aRessource})
+	//TODO!!!
+}
+
+func (dh *DeviceHandler) waitForTpCompletion(wg *sync.WaitGroup) {
+	wg.Wait()
+	logger.Debug("some TechProfile Processing completed")
+	dh.tpProcMutex.Unlock() //allow further TP related processing
+}
+
 /* *********************************************************** */
 
-func genMacFromOctets(a_octets [6]uint8) string {
+func genMacFromOctets(aOctets [6]uint8) string {
 	return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x",
-		a_octets[5], a_octets[4], a_octets[3],
-		a_octets[2], a_octets[1], a_octets[0])
+		aOctets[5], aOctets[4], aOctets[3],
+		aOctets[2], aOctets[1], aOctets[0])
 }
 
 //copied from OLT Adapter: unify centrally ?
diff --git a/internal/pkg/onuadaptercore/mib_sync.go b/internal/pkg/onuadaptercore/mib_sync.go
index 807412d..80470ed 100644
--- a/internal/pkg/onuadaptercore/mib_sync.go
+++ b/internal/pkg/onuadaptercore/mib_sync.go
@@ -19,6 +19,7 @@
 
 import (
 	"context"
+	"encoding/hex"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -66,33 +67,76 @@
 
 func (onuDeviceEntry *OnuDeviceEntry) enterStartingState(e *fsm.Event) {
 	logger.Debugw("MibSync FSM", log.Fields{"Start processing MibSync-msgs in State": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
-
 	onuDeviceEntry.pOnuDB = NewOnuDeviceDB(context.TODO(), onuDeviceEntry)
-
 	go onuDeviceEntry.ProcessMibSyncMessages()
 }
 
-func (onuDeviceEntry *OnuDeviceEntry) enterLoadingMibTemplateState(e *fsm.Event) {
+func (onuDeviceEntry *OnuDeviceEntry) enterResettingMibState(e *fsm.Event) {
 	logger.Debugw("MibSync FSM", log.Fields{"Start MibTemplate processing in State": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
 
-	meStoredFromTemplate := false
+	logger.Debugw("MibSync FSM", log.Fields{"send mibReset in State": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
+	onuDeviceEntry.PDevOmciCC.sendMibReset(context.TODO(), ConstDefaultOmciTimeout, true)
 
-	//TODO: perform MIB-reset
 	//TODO: needs to handle timeouts
+}
 
-	//TODO: etrieve these values via OMCI GetRequests
-	//OltGClassID
-	onuDeviceEntry.vendorID = "BBSM"
-	onuDeviceEntry.serialNumber = "BBSM00000001"
-	//Onu2GClassID
-	onuDeviceEntry.equipmentID = "12345123451234512345"
-	//SoftwareImageClassID
-	onuDeviceEntry.activeSwVersion = "00000000000001"
-	//IpHostConfigDataClassID
-	onuDeviceEntry.macAddress = "00:00:00:00:00:00"
+func (onuDeviceEntry *OnuDeviceEntry) enterGettingVendorAndSerialState(e *fsm.Event) {
+	logger.Debugw("MibSync FSM", log.Fields{"Start getting VendorId and SerialNumber in State": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
+	requestedAttributes := me.AttributeValueMap{"VendorId": "", "SerialNumber": 0}
+	meInstance := onuDeviceEntry.PDevOmciCC.sendGetMe(context.TODO(), me.OnuGClassID, OnugMeId, requestedAttributes, ConstDefaultOmciTimeout, true)
+	//accept also nil as (error) return value for writing to LastTx
+	//  - this avoids misinterpretation of new received OMCI messages
+	onuDeviceEntry.PDevOmciCC.pLastTxMeInstance = meInstance
+}
 
-	Path := fmt.Sprintf(SuffixMibTemplateKvStore, onuDeviceEntry.vendorID, onuDeviceEntry.equipmentID, onuDeviceEntry.activeSwVersion)
-	Value, err := onuDeviceEntry.mibTemplateKVStore.Get(context.TODO(), Path)
+func (onuDeviceEntry *OnuDeviceEntry) enterGettingEquipmentIdState(e *fsm.Event) {
+	logger.Debugw("MibSync FSM", log.Fields{"Start getting EquipmentId in State": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
+	requestedAttributes := me.AttributeValueMap{"EquipmentId": ""}
+	meInstance := onuDeviceEntry.PDevOmciCC.sendGetMe(context.TODO(), me.Onu2GClassID, Onu2gMeId, requestedAttributes, ConstDefaultOmciTimeout, true)
+	//accept also nil as (error) return value for writing to LastTx
+	//  - this avoids misinterpretation of new received OMCI messages
+	onuDeviceEntry.PDevOmciCC.pLastTxMeInstance = meInstance
+}
+
+func (onuDeviceEntry *OnuDeviceEntry) enterGettingFirstSwVersionState(e *fsm.Event) {
+	logger.Debugw("MibSync FSM", log.Fields{"Start getting IsActive and Version of first SW-image in State": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
+	requestedAttributes := me.AttributeValueMap{"IsActive": 0, "Version": ""}
+	meInstance := onuDeviceEntry.PDevOmciCC.sendGetMe(context.TODO(), me.SoftwareImageClassID, FirstSwImageMeId, requestedAttributes, ConstDefaultOmciTimeout, true)
+	//accept also nil as (error) return value for writing to LastTx
+	//  - this avoids misinterpretation of new received OMCI messages
+	onuDeviceEntry.PDevOmciCC.pLastTxMeInstance = meInstance
+}
+
+func (onuDeviceEntry *OnuDeviceEntry) enterGettingSecondSwVersionState(e *fsm.Event) {
+	logger.Debugw("MibSync FSM", log.Fields{"Start getting IsActive and Version of second SW-image in State": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
+	requestedAttributes := me.AttributeValueMap{"IsActive": 0, "Version": ""}
+	meInstance := onuDeviceEntry.PDevOmciCC.sendGetMe(context.TODO(), me.SoftwareImageClassID, SecondSwImageMeId, requestedAttributes, ConstDefaultOmciTimeout, true)
+	//accept also nil as (error) return value for writing to LastTx
+	//  - this avoids misinterpretation of new received OMCI messages
+	onuDeviceEntry.PDevOmciCC.pLastTxMeInstance = meInstance
+}
+
+func (onuDeviceEntry *OnuDeviceEntry) enterGettingMacAddressState(e *fsm.Event) {
+	logger.Debugw("MibSync FSM", log.Fields{"Start getting MacAddress in State": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
+	requestedAttributes := me.AttributeValueMap{"MacAddress": ""}
+	meInstance := onuDeviceEntry.PDevOmciCC.sendGetMe(context.TODO(), me.IpHostConfigDataClassID, IpHostConfigDataMeId, requestedAttributes, ConstDefaultOmciTimeout, true)
+	//accept also nil as (error) return value for writing to LastTx
+	//  - this avoids misinterpretation of new received OMCI messages
+	onuDeviceEntry.PDevOmciCC.pLastTxMeInstance = meInstance
+}
+
+func (onuDeviceEntry *OnuDeviceEntry) enterGettingMibTemplate(e *fsm.Event) {
+
+	for i := FirstSwImageMeId; i <= SecondSwImageMeId; i++ {
+		if onuDeviceEntry.swImages[i].isActive > 0 {
+			onuDeviceEntry.activeSwVersion = onuDeviceEntry.swImages[i].version
+		}
+	}
+
+	meStoredFromTemplate := false
+	path := fmt.Sprintf(SuffixMibTemplateKvStore, onuDeviceEntry.vendorID, onuDeviceEntry.equipmentID, onuDeviceEntry.activeSwVersion)
+	logger.Debugw("MibSync FSM - MibTemplate - etcd search string", log.Fields{"path": path})
+	Value, err := onuDeviceEntry.mibTemplateKVStore.Get(context.TODO(), path)
 	if err == nil {
 		if Value != nil {
 			logger.Debugf("MibSync FSM - MibTemplate read: Key: %s, Value: %s  %s", Value.Key, Value.Value)
@@ -120,7 +164,7 @@
 								logger.Debugw("MibSync FSM - secondLevelKey", log.Fields{"secondLevelKey": secondLevelKey})
 								if uint16ValidNumber, err := strconv.ParseUint(secondLevelKey, 10, 16); err == nil {
 									meEntityId := uint16(uint16ValidNumber)
-									logger.Debugw("MibSync FSM - secondLevelKey is a numberand a valid EntityId", log.Fields{"meEntityId": meEntityId})
+									logger.Debugw("MibSync FSM - secondLevelKey is a number and a valid EntityId", log.Fields{"meEntityId": meEntityId})
 									thirdLevelMap := secondLevelValue.(map[string]interface{})
 									for thirdLevelKey, thirdLevelValue := range thirdLevelMap {
 										if thirdLevelKey == "attributes" {
@@ -138,10 +182,10 @@
 				}
 			}
 		} else {
-			logger.Debugw("No MIB template found", log.Fields{"device-id": onuDeviceEntry.deviceID})
+			logger.Debugw("No MIB template found", log.Fields{"path": path, "device-id": onuDeviceEntry.deviceID})
 		}
 	} else {
-		logger.Errorf("Get from kvstore operation failed for path %s", Path)
+		logger.Errorf("Get from kvstore operation failed for path %s", path)
 	}
 	if meStoredFromTemplate {
 		logger.Debug("MibSync FSM - valid MEs stored from template")
@@ -162,8 +206,8 @@
 }
 
 func (onuDeviceEntry *OnuDeviceEntry) enterUploadingState(e *fsm.Event) {
-	logger.Debugw("MibSync FSM", log.Fields{"send mibReset in State": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
-	onuDeviceEntry.PDevOmciCC.sendMibReset(context.TODO(), ConstDefaultOmciTimeout, true)
+	logger.Debugw("MibSync FSM", log.Fields{"send MibUpload in State": e.FSM.Current(), "device-id": onuDeviceEntry.deviceID})
+	onuDeviceEntry.PDevOmciCC.sendMibUpload(context.TODO(), ConstDefaultOmciTimeout, true)
 }
 
 func (onuDeviceEntry *OnuDeviceEntry) enterInSyncState(e *fsm.Event) {
@@ -247,22 +291,30 @@
 	//further analysis could be done here based on msg.OmciMsg.Payload, e.g. verification of error code ...
 	switch msg.OmciMsg.MessageType {
 	case omci.MibResetResponseType:
-		msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeMibResetResponse)
-		if msgLayer == nil {
-			logger.Error("Omci Msg layer could not be detected")
-			return
+		if onuDeviceEntry.pMibUploadFsm.pFsm.Is("resetting_mib") {
+			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeMibResetResponse)
+			if msgLayer != nil {
+				msgObj, msgOk := msgLayer.(*omci.MibResetResponse)
+				if msgOk {
+					logger.Debugw("MibResetResponse Data", log.Fields{"data-fields": msgObj})
+					if msgObj.Result == me.Success {
+						// trigger retrieval of VendorId and SerialNumber
+						onuDeviceEntry.pMibUploadFsm.pFsm.Event("get_vendor_and_serial")
+						return
+					} else {
+						logger.Errorw("Omci MibResetResponse Error", log.Fields{"Error": msgObj.Result})
+					}
+				} else {
+					logger.Error("Omci Msg layer could not be assigned")
+				}
+			} else {
+				logger.Error("Omci Msg layer could not be detected")
+			}
+		} else {
+			logger.Errorw("Omci MibResetResponse received", log.Fields{"in state ": onuDeviceEntry.pMibUploadFsm.pFsm.Current})
 		}
-		msgObj, msgOk := msgLayer.(*omci.MibResetResponse)
-		if !msgOk {
-			logger.Error("Omci Msg layer could not be assigned")
-			return
-		}
-		logger.Debugw("MibResetResponse Data", log.Fields{"data-fields": msgObj})
-		if msgObj.Result != me.Success {
-			logger.Errorw("Omci MibResetResponse Error - strange - what to do?", log.Fields{"Error": msgObj.Result})
-			return
-		}
-		onuDeviceEntry.PDevOmciCC.sendMibUpload(context.TODO(), ConstDefaultOmciTimeout, true)
+		onuDeviceEntry.pMibUploadFsm.pFsm.Event("stop")
+
 	case omci.MibUploadResponseType:
 		msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeMibUploadResponse)
 		if msgLayer == nil {
@@ -310,6 +362,85 @@
 			onuDeviceEntry.pOnuDB.LogMeDb()
 			onuDeviceEntry.pMibUploadFsm.pFsm.Event("success")
 		}
+	case omci.GetResponseType:
+		msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
+		if msgLayer != nil {
+			msgObj, msgOk := msgLayer.(*omci.GetResponse)
+			if msgOk {
+				logger.Debugw("MibSync FSM - GetResponse Data", log.Fields{"deviceId": onuDeviceEntry.deviceID, "data-fields": msgObj})
+				if msgObj.Result == me.Success {
+					entityId := onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetEntityID()
+					if msgObj.EntityClass == onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetClassID() && msgObj.EntityInstance == entityId {
+						meAttributes := msgObj.Attributes
+						switch onuDeviceEntry.PDevOmciCC.pLastTxMeInstance.GetName() {
+						case "OnuG":
+							logger.Debugw("MibSync FSM - GetResponse Data for Onu-G", log.Fields{"deviceId": onuDeviceEntry.deviceID, "data-fields": msgObj})
+							onuDeviceEntry.vendorID = fmt.Sprintf("%s", meAttributes["VendorId"])
+							snBytes, _ := me.InterfaceToOctets(meAttributes["SerialNumber"])
+							if OnugSerialNumberLen == len(snBytes) {
+								snVendorPart := fmt.Sprintf("%s", snBytes[:4])
+								snNumberPart := hex.EncodeToString(snBytes[4:])
+								onuDeviceEntry.serialNumber = snVendorPart + snNumberPart
+								logger.Debugw("MibSync FSM - GetResponse Data for Onu-G - VendorId/SerialNumber", log.Fields{"deviceId": onuDeviceEntry.deviceID,
+									"onuDeviceEntry.vendorID": onuDeviceEntry.vendorID, "onuDeviceEntry.serialNumber": onuDeviceEntry.serialNumber})
+							} else {
+								logger.Errorw("MibSync FSM - SerialNumber has wrong length", log.Fields{"deviceId": onuDeviceEntry.deviceID, "length": len(snBytes)})
+							}
+							// trigger retrieval of EquipmentId
+							onuDeviceEntry.pMibUploadFsm.pFsm.Event("get_equipment_id")
+							return
+						case "Onu2G":
+							logger.Debugw("MibSync FSM - GetResponse Data for Onu2-G", log.Fields{"deviceId": onuDeviceEntry.deviceID, "data-fields": msgObj})
+							onuDeviceEntry.equipmentID = fmt.Sprintf("%s", meAttributes["EquipmentId"])
+							logger.Debugw("MibSync FSM - GetResponse Data for Onu2-G - EquipmentId", log.Fields{"deviceId": onuDeviceEntry.deviceID,
+								"onuDeviceEntry.equipmentID": onuDeviceEntry.equipmentID})
+							// trigger retrieval of 1st SW-image info
+							onuDeviceEntry.pMibUploadFsm.pFsm.Event("get_first_sw_version")
+							return
+						case "SoftwareImage":
+							logger.Debugw("MibSync FSM - GetResponse Data for SoftwareImage", log.Fields{"deviceId": onuDeviceEntry.deviceID, "data-fields": msgObj})
+							if entityId <= SecondSwImageMeId {
+								onuDeviceEntry.swImages[entityId].version = fmt.Sprintf("%s", meAttributes["Version"])
+								onuDeviceEntry.swImages[entityId].isActive = meAttributes["IsActive"].(uint8)
+								logger.Debugw("MibSync FSM - GetResponse Data for SoftwareImage - Version/IsActive",
+									log.Fields{"deviceId": onuDeviceEntry.deviceID, "entityId": entityId,
+										"version": onuDeviceEntry.swImages[entityId].version, "isActive": onuDeviceEntry.swImages[entityId].isActive})
+							} else {
+								//TODO: error handling
+							}
+							if FirstSwImageMeId == entityId {
+								onuDeviceEntry.pMibUploadFsm.pFsm.Event("get_second_sw_version")
+								return
+							} else if SecondSwImageMeId == entityId {
+								onuDeviceEntry.pMibUploadFsm.pFsm.Event("get_mac_address")
+								return
+							}
+						case "IpHostConfigData":
+							///
+							logger.Debugw("MibSync FSM - GetResponse Data for IpHostConfigData", log.Fields{"deviceId": onuDeviceEntry.deviceID, "data-fields": msgObj})
+							macBytes, _ := me.InterfaceToOctets(meAttributes["MacAddress"])
+							if OmciMacAddressLen == len(macBytes) {
+								onuDeviceEntry.macAddress = hex.EncodeToString(macBytes[:])
+								logger.Debugw("MibSync FSM - GetResponse Data for IpHostConfigData - MacAddress", log.Fields{"deviceId": onuDeviceEntry.deviceID,
+									"onuDeviceEntry.macAddress": onuDeviceEntry.macAddress})
+							} else {
+								logger.Errorw("MibSync FSM - MacAddress wrong length", log.Fields{"deviceId": onuDeviceEntry.deviceID, "length": len(macBytes)})
+							}
+							// trigger retrieval of mib template
+							onuDeviceEntry.pMibUploadFsm.pFsm.Event("get_mib_template")
+						}
+					}
+				} else {
+					logger.Errorw("Omci GetResponse Error", log.Fields{"Error": msgObj.Result})
+				}
+			} else {
+				logger.Error("Omci Msg layer could not be assigned for GetResponse")
+			}
+		} else {
+			logger.Error("Omci Msg layer could not be detected for GetResponse")
+		}
+		//
+		onuDeviceEntry.pMibUploadFsm.pFsm.Event("stop")
 	}
 }
 
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index 9074fc8..7edd20e 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -1031,3 +1031,44 @@
 		return nil
 	}
 }
+
+func (oo *OmciCC) sendGetMe(ctx context.Context, classID me.ClassID, entityID uint16, requestedAttributes me.AttributeValueMap,
+	timeout int, highPrio bool) *me.ManagedEntity {
+
+	tid := oo.GetNextTid(highPrio)
+	logger.Debugw("send get-request-msg", log.Fields{"classID": classID, "deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16)})
+
+	meParams := me.ParamData{
+		EntityID:   entityID,
+		Attributes: requestedAttributes,
+	}
+	meInstance, omciErr := me.LoadManagedEntityDefinition(classID, meParams)
+	if omciErr.GetError() == nil {
+		meClassIdName := meInstance.GetName()
+		omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.GetRequestType, omci.TransactionID(tid))
+		if err != nil {
+			logger.Errorf("Cannot encode instance for get-request", log.Fields{"meClassIdName": meClassIdName, "Err": err, "deviceId": oo.deviceID})
+			return nil
+		}
+		pkt, err := serializeOmciLayer(omciLayer, msgLayer)
+		if err != nil {
+			logger.Errorw("Cannot serialize get-request", log.Fields{"meClassIdName": meClassIdName, "Err": err, "deviceId": oo.deviceID})
+			return nil
+		}
+		omciRxCallbackPair := CallbackPair{
+			cbKey:   tid,
+			cbEntry: CallbackPairEntry{(*oo.pOnuDeviceEntry).pMibUploadFsm.commChan, oo.receiveOmciResponse},
+		}
+		err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
+		if err != nil {
+			logger.Errorw("Cannot send get-request-msg", log.Fields{"meClassIdName": meClassIdName, "Err": err, "deviceId": oo.deviceID})
+			return nil
+		} else {
+			logger.Debugw("send get-request-msg done", log.Fields{"meClassIdName": meClassIdName, "deviceId": oo.deviceID})
+			return meInstance
+		}
+	} else {
+		logger.Errorw("Cannot generate meDefinition", log.Fields{"classID": classID, "Err": omciErr.GetError(), "deviceId": oo.deviceID})
+		return nil
+	}
+}
diff --git a/internal/pkg/onuadaptercore/onu_device_entry.go b/internal/pkg/onuadaptercore/onu_device_entry.go
index dff9545..4d31f77 100644
--- a/internal/pkg/onuadaptercore/onu_device_entry.go
+++ b/internal/pkg/onuadaptercore/onu_device_entry.go
@@ -88,6 +88,22 @@
 }
 
 //OntDeviceEntry structure holds information about the attached FSM'as and their communication
+
+const (
+	FirstSwImageMeId  = 0
+	SecondSwImageMeId = 1
+)
+const OnugMeId = 0
+const Onu2gMeId = 0
+const IpHostConfigDataMeId = 1
+const OnugSerialNumberLen = 8
+const OmciMacAddressLen = 6
+
+type SwImages struct {
+	version  string
+	isActive uint8
+}
+
 type OnuDeviceEntry struct {
 	deviceID           string
 	baseDeviceHandler  *DeviceHandler
@@ -100,6 +116,7 @@
 	vendorID           string
 	serialNumber       string
 	equipmentID        string
+	swImages           [SecondSwImageMeId + 1]SwImages
 	activeSwVersion    string
 	macAddress         string
 	//lockDeviceEntries           sync.RWMutex
@@ -173,11 +190,18 @@
 
 			{Name: "start", Src: []string{"disabled"}, Dst: "starting"},
 
-			{Name: "load_mib_template", Src: []string{"starting"}, Dst: "loading_mib_template"},
-			{Name: "upload_mib", Src: []string{"loading_mib_template"}, Dst: "uploading"},
+			{Name: "reset_mib", Src: []string{"starting"}, Dst: "resetting_mib"},
+			{Name: "get_vendor_and_serial", Src: []string{"resetting_mib"}, Dst: "getting_vendor_and_serial"},
+			{Name: "get_equipment_id", Src: []string{"getting_vendor_and_serial"}, Dst: "getting_equipment_id"},
+			{Name: "get_first_sw_version", Src: []string{"getting_equipment_id"}, Dst: "getting_first_sw_version"},
+			{Name: "get_second_sw_version", Src: []string{"getting_first_sw_version"}, Dst: "getting_second_sw_version"},
+			{Name: "get_mac_address", Src: []string{"getting_second_sw_version"}, Dst: "getting_mac_address"},
+			{Name: "get_mib_template", Src: []string{"getting_mac_address"}, Dst: "getting_mib_template"},
+
+			{Name: "upload_mib", Src: []string{"getting_mib_template"}, Dst: "uploading"},
 			{Name: "examine_mds", Src: []string{"starting"}, Dst: "examining_mds"},
 
-			{Name: "success", Src: []string{"loading_mib_template"}, Dst: "in_sync"},
+			{Name: "success", Src: []string{"getting_mib_template"}, Dst: "in_sync"},
 			{Name: "success", Src: []string{"uploading"}, Dst: "in_sync"},
 
 			{Name: "success", Src: []string{"examining_mds"}, Dst: "in_sync"},
@@ -195,21 +219,29 @@
 			{Name: "success", Src: []string{"resynchronizing"}, Dst: "in_sync"},
 			{Name: "diffs_found", Src: []string{"resynchronizing"}, Dst: "out_of_sync"},
 
-			{Name: "timeout", Src: []string{"loading_mib_template", "uploading", "resynchronizing", "examining_mds", "in_sync", "out_of_sync", "auditing"}, Dst: "starting"},
+			{Name: "timeout", Src: []string{"reset_mib", "get_vendor_and_serial", "get_equipment_id", "get_first_sw_version", "get_mac_address",
+				"get_mib_template", "uploading", "resynchronizing", "examining_mds", "in_sync", "out_of_sync", "auditing"}, Dst: "starting"},
 
-			{Name: "stop", Src: []string{"starting", "loading_mib_template", "uploading", "resynchronizing", "examining_mds", "in_sync", "out_of_sync", "auditing"}, Dst: "disabled"},
+			{Name: "stop", Src: []string{"starting", "reset_mib", "get_vendor_and_serial", "get_equipment_id", "get_first_sw_version", "get_mac_address",
+				"get_mib_template", "uploading", "resynchronizing", "examining_mds", "in_sync", "out_of_sync", "auditing"}, Dst: "disabled"},
 		},
 
 		fsm.Callbacks{
-			"enter_state":                func(e *fsm.Event) { onuDeviceEntry.pMibUploadFsm.logFsmStateChange(e) },
-			"enter_starting":             func(e *fsm.Event) { onuDeviceEntry.enterStartingState(e) },
-			"enter_loading_mib_template": func(e *fsm.Event) { onuDeviceEntry.enterLoadingMibTemplateState(e) },
-			"enter_uploading":            func(e *fsm.Event) { onuDeviceEntry.enterUploadingState(e) },
-			"enter_examining_mds":        func(e *fsm.Event) { onuDeviceEntry.enterExaminingMdsState(e) },
-			"enter_resynchronizing":      func(e *fsm.Event) { onuDeviceEntry.enterResynchronizingState(e) },
-			"enter_auditing":             func(e *fsm.Event) { onuDeviceEntry.enterAuditingState(e) },
-			"enter_out_of_sync":          func(e *fsm.Event) { onuDeviceEntry.enterOutOfSyncState(e) },
-			"enter_in_sync":              func(e *fsm.Event) { onuDeviceEntry.enterInSyncState(e) },
+			"enter_state":                     func(e *fsm.Event) { onuDeviceEntry.pMibUploadFsm.logFsmStateChange(e) },
+			"enter_starting":                  func(e *fsm.Event) { onuDeviceEntry.enterStartingState(e) },
+			"enter_resetting_mib":             func(e *fsm.Event) { onuDeviceEntry.enterResettingMibState(e) },
+			"enter_getting_vendor_and_serial": func(e *fsm.Event) { onuDeviceEntry.enterGettingVendorAndSerialState(e) },
+			"enter_getting_equipment_id":      func(e *fsm.Event) { onuDeviceEntry.enterGettingEquipmentIdState(e) },
+			"enter_getting_first_sw_version":  func(e *fsm.Event) { onuDeviceEntry.enterGettingFirstSwVersionState(e) },
+			"enter_getting_second_sw_version": func(e *fsm.Event) { onuDeviceEntry.enterGettingSecondSwVersionState(e) },
+			"enter_getting_mac_address":       func(e *fsm.Event) { onuDeviceEntry.enterGettingMacAddressState(e) },
+			"enter_getting_mib_template":      func(e *fsm.Event) { onuDeviceEntry.enterGettingMibTemplate(e) },
+			"enter_uploading":                 func(e *fsm.Event) { onuDeviceEntry.enterUploadingState(e) },
+			"enter_examining_mds":             func(e *fsm.Event) { onuDeviceEntry.enterExaminingMdsState(e) },
+			"enter_resynchronizing":           func(e *fsm.Event) { onuDeviceEntry.enterResynchronizingState(e) },
+			"enter_auditing":                  func(e *fsm.Event) { onuDeviceEntry.enterAuditingState(e) },
+			"enter_out_of_sync":               func(e *fsm.Event) { onuDeviceEntry.enterOutOfSyncState(e) },
+			"enter_in_sync":                   func(e *fsm.Event) { onuDeviceEntry.enterInSyncState(e) },
 		},
 	)
 	// Omci related Mib download state machine