VOL-3052 Onu Software preliminary upgrade extensions with internal test, version 1.2.5-dev171

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I23ee1a14af635def33b565444f1a1f81370a86a7
diff --git a/VERSION b/VERSION
index cc63d17..7585f69 100755
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.2.5-dev170
+1.2.5-dev171
diff --git a/go.mod b/go.mod
index b6adf67..81f8227 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@
 	github.com/golang/protobuf v1.4.2
 	github.com/google/gopacket v1.1.17
 	github.com/looplab/fsm v0.1.0
-	github.com/opencord/omci-lib-go v0.15.2
+	github.com/opencord/omci-lib-go v0.15.4
 	github.com/opencord/voltha-lib-go/v4 v4.0.10
 	github.com/opencord/voltha-protos/v4 v4.0.13
 	github.com/stretchr/testify v1.6.1
diff --git a/go.sum b/go.sum
index b7529f3..a0fd282 100644
--- a/go.sum
+++ b/go.sum
@@ -160,8 +160,8 @@
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
 github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/opencord/omci-lib-go v0.15.2 h1:RVqjVI0RvWlJb+n8NMWrIDt2J+o5L7JNkHZdHjpMLws=
-github.com/opencord/omci-lib-go v0.15.2/go.mod h1:6OIHB14Ch5qGgHzwSWlMACtk5KFoLzQ4LAhdcy4jwvo=
+github.com/opencord/omci-lib-go v0.15.4 h1:g+IkuCZeS7Okvm7TxjobaLwX6UHo26hCvdyyqX9Bfi8=
+github.com/opencord/omci-lib-go v0.15.4/go.mod h1:6OIHB14Ch5qGgHzwSWlMACtk5KFoLzQ4LAhdcy4jwvo=
 github.com/opencord/voltha-lib-go/v4 v4.0.10 h1:mSi9e3TD+liit5NbV+AKEJ2dza3n+DpzdExJog2LtTo=
 github.com/opencord/voltha-lib-go/v4 v4.0.10/go.mod h1:K7lDkSkJ97EyfvX8fQtBmBvpj7n6MmwnAtD8Jz79HcQ=
 github.com/opencord/voltha-protos/v4 v4.0.12 h1:x8drb8inaUByjVLFbXSiQwRTU//dfde0MKIHyKb1JMw=
@@ -209,6 +209,7 @@
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -312,6 +313,7 @@
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd h1:hHkvGJK23seRCflePJnVa9IMv8fsuavSCWKd11kDQFs=
 golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
diff --git a/internal/pkg/onuadaptercore/adapter_download_manager.go b/internal/pkg/onuadaptercore/adapter_download_manager.go
index aaaacd6..3db9cc7 100644
--- a/internal/pkg/onuadaptercore/adapter_download_manager.go
+++ b/internal/pkg/onuadaptercore/adapter_download_manager.go
@@ -20,6 +20,7 @@
 import (
 	"bufio"
 	"context"
+	"errors"
 	"os"
 	"sync"
 
@@ -95,23 +96,27 @@
 
 //startDownload returns true if the download of the requested image could be started
 func (dm *adapterDownloadManager) startDownload(ctx context.Context, apImageDsc *voltha.ImageDownload) error {
-	logger.Warnw(ctx, "image download requested - but not yet processed", log.Fields{"image-name": apImageDsc.Name})
-	newImageDscPos := len(dm.downloadImageDscSlice)
-	dm.downloadImageDscSlice = append(dm.downloadImageDscSlice, apImageDsc)
-	dm.downloadImageDscSlice[newImageDscPos].DownloadState = voltha.ImageDownload_DOWNLOAD_STARTED
-	//just some basic test file simulation
-	go dm.writeFileToLFS(ctx, apImageDsc.Name, apImageDsc.LocalDir)
-	//return success to comfort the core processing during integration
-	return nil
-	// TODO!!: also verify error response behavior
-	//return fmt.Errorf("onuSwUpgrade not yet implemented")
+	if apImageDsc.LocalDir != "" {
+		logger.Infow(ctx, "image download-to-adapter requested", log.Fields{"image-name": apImageDsc.Name})
+		newImageDscPos := len(dm.downloadImageDscSlice)
+		dm.downloadImageDscSlice = append(dm.downloadImageDscSlice, apImageDsc)
+		dm.downloadImageDscSlice[newImageDscPos].DownloadState = voltha.ImageDownload_DOWNLOAD_STARTED
+		//just some basic test file simulation
+		go dm.writeFileToLFS(ctx, apImageDsc.Name, apImageDsc.LocalDir)
+		//return success to comfort the core processing during integration
+		return nil
+	}
+	// we can use the missing local path temporary also to test some failure behavior (system reation on failure)
+	// with updated control API's or at some adequate time we could also set some defined fixed localPath internally
+	logger.Errorw(ctx, "could not start download: no valid local directory to write to", log.Fields{"image-name": (*apImageDsc).Name})
+	return errors.New("could not start download: no valid local directory to write to")
 }
 
 //writeFileToLFS writes the downloaded file to the local file system
 func (dm *adapterDownloadManager) writeFileToLFS(ctx context.Context, aFileName string, aLocalPath string) {
 	// by now just a simulation to write a file with predefined 'variable' content
 	totalFileLength := 0
-	logger.Debugw(ctx, "Writing fixed size simulation file locally", log.Fields{
+	logger.Debugw(ctx, "writing fixed size simulation file locally", log.Fields{
 		"image-name": aFileName, "image-path": aLocalPath})
 	file, err := os.Create(aLocalPath + "/" + aFileName)
 	if err == nil {
@@ -120,19 +125,19 @@
 			if written, wrErr := file.Write(dm.getIncrementalSliceContent(ctx)); wrErr == nil {
 				totalFileLength += written
 			} else {
-				logger.Errorw(ctx, "Could not write to file", log.Fields{"create-error": wrErr})
+				logger.Errorw(ctx, "could not write to file", log.Fields{"create-error": wrErr})
 				break //stop writing
 			}
 		}
 	} else {
-		logger.Errorw(ctx, "Could not create file", log.Fields{"create-error": err})
+		logger.Errorw(ctx, "could not create file", log.Fields{"create-error": err})
 	}
 
 	fileStats, statsErr := file.Stat()
 	if err != nil {
 		logger.Errorw(ctx, "created file can't be accessed", log.Fields{"stat-error": statsErr})
 	}
-	logger.Debugw(ctx, "Written file size is", log.Fields{"length": fileStats.Size()})
+	logger.Infow(ctx, "written file size is", log.Fields{"file": aLocalPath + "/" + aFileName, "length": fileStats.Size()})
 	//nolint:gosec,errcheck
 	file.Close()
 
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index 556fe62..6c4d5ce 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -936,16 +936,20 @@
 	return pDevEntry.getKvProcessingErrorIndication()
 }
 
-func (dh *deviceHandler) rebootDevice(ctx context.Context, device *voltha.Device) error {
-	logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": device.Id, "SerialNumber": device.SerialNumber})
-	if device.ConnectStatus != voltha.ConnectStatus_REACHABLE {
+//func (dh *deviceHandler) rebootDevice(ctx context.Context, device *voltha.Device) error {
+// before this change here return like this was used:
+// 		return fmt.Errorf("device-unreachable: %s, %s", dh.deviceID, device.SerialNumber)
+//was and is called in background - error return does not make sense
+func (dh *deviceHandler) rebootDevice(ctx context.Context, aCheckDeviceState bool, device *voltha.Device) {
+	logger.Infow(ctx, "reboot-device", log.Fields{"device-id": dh.deviceID, "SerialNumber": dh.device.SerialNumber})
+	if aCheckDeviceState && device.ConnectStatus != voltha.ConnectStatus_REACHABLE {
 		logger.Errorw(ctx, "device-unreachable", log.Fields{"device-id": device.Id, "SerialNumber": device.SerialNumber})
-		return fmt.Errorf("device-unreachable: %s, %s", dh.deviceID, device.SerialNumber)
+		return
 	}
 	if err := dh.pOnuOmciDevice.reboot(log.WithSpanFromContext(context.TODO(), ctx)); err != nil {
 		//TODO with VOL-3045/VOL-3046: return the error and stop further processing
 		logger.Errorw(ctx, "error-rebooting-device", log.Fields{"device-id": dh.deviceID, "error": err})
-		return err
+		return
 	}
 
 	//transfer the possibly modified logical uni port state
@@ -957,17 +961,16 @@
 		voltha.OperStatus_DISCOVERED); err != nil {
 		//TODO with VOL-3045/VOL-3046: return the error and stop further processing
 		logger.Errorw(ctx, "error-updating-device-state", log.Fields{"device-id": dh.deviceID, "error": err})
-		return err
+		return
 	}
 	if err := dh.deviceReasonUpdate(ctx, drRebooting, true); err != nil {
-		return err
+		return
 	}
 	dh.ReadyForSpecificOmciConfig = false
 	//no specific activity to synchronize any internal FSM to the 'rebooted' state is explicitly done here
 	//  the expectation ids for a real device, that it will be synced with the expected following 'down' indication
 	//  as BBSIM does not support this testing requires explicite disable/enable device calls in which sequence also
 	//  all other FSM's should be synchronized again
-	return nil
 }
 
 //doOnuSwUpgrade initiates the SW download transfer to the ONU and on success activates the (inactive) image
@@ -977,39 +980,52 @@
 		"device-id": dh.deviceID, "image-name": (*apImageDsc).Name})
 
 	var err error
+	pDevEntry := dh.getOnuDeviceEntry(ctx, true)
+	if pDevEntry == nil {
+		logger.Errorw(ctx, "start Onu SW upgrade rejected: no valid OnuDevice", log.Fields{"device-id": dh.deviceID})
+		return fmt.Errorf("start Onu SW upgrade rejected: no valid OnuDevice for device-id: %s", dh.deviceID)
+	}
+
 	if dh.ReadyForSpecificOmciConfig {
-		dh.lockUpgradeFsm.Lock()
-		defer dh.lockUpgradeFsm.Unlock()
-		if dh.pOnuUpradeFsm == nil {
-			err = dh.createOnuUpgradeFsm(ctx, OmciOnuSwUpgradeDone)
-			if err == nil {
-				if err = dh.pOnuUpradeFsm.SetDownloadParams(ctx, apImageDsc, apDownloadManager); err != nil {
-					logger.Errorw(ctx, "onu upgrade fsm could not set parameters", log.Fields{
+		var inactiveImageID uint16
+		if inactiveImageID, err = pDevEntry.GetInactiveImageMeID(ctx); err == nil {
+			dh.lockUpgradeFsm.Lock()
+			defer dh.lockUpgradeFsm.Unlock()
+			if dh.pOnuUpradeFsm == nil {
+				err = dh.createOnuUpgradeFsm(ctx, pDevEntry, OmciOnuSwUpgradeDone)
+				if err == nil {
+					if err = dh.pOnuUpradeFsm.SetDownloadParams(ctx, inactiveImageID, apImageDsc, apDownloadManager); err != nil {
+						logger.Errorw(ctx, "onu upgrade fsm could not set parameters", log.Fields{
+							"device-id": dh.deviceID, "error": err})
+					}
+				} else {
+					logger.Errorw(ctx, "onu upgrade fsm could not be created", log.Fields{
 						"device-id": dh.deviceID, "error": err})
 				}
-			} else {
-				logger.Errorw(ctx, "onu upgrade fsm could not be created", log.Fields{
-					"device-id": dh.deviceID, "error": err})
-			}
-		} else { //OnuSw upgrade already running - restart (with possible abort of running)
-			logger.Debugw(ctx, "Onu SW upgrade already running - abort", log.Fields{"device-id": dh.deviceID})
-			pUpgradeStatemachine := dh.pOnuUpradeFsm.pAdaptFsm.pFsm
-			if pUpgradeStatemachine != nil {
-				if err = pUpgradeStatemachine.Event(upgradeEvAbort); err != nil {
-					logger.Errorw(ctx, "onu upgrade fsm could not abort a running processing", log.Fields{
-						"device-id": dh.deviceID, "error": err})
+			} else { //OnuSw upgrade already running - restart (with possible abort of running)
+				logger.Debugw(ctx, "Onu SW upgrade already running - abort", log.Fields{"device-id": dh.deviceID})
+				pUpgradeStatemachine := dh.pOnuUpradeFsm.pAdaptFsm.pFsm
+				if pUpgradeStatemachine != nil {
+					if err = pUpgradeStatemachine.Event(upgradeEvAbort); err != nil {
+						logger.Errorw(ctx, "onu upgrade fsm could not abort a running processing", log.Fields{
+							"device-id": dh.deviceID, "error": err})
+					}
+					err = fmt.Errorf("aborted Onu SW upgrade but not automatically started, try again, device-id: %s", dh.deviceID)
+					//TODO!!!: wait for 'ready' to start and configure - see above SetDownloadParams()
+					// for now a second start of download should work again
+				} else { //should never occur
+					logger.Errorw(ctx, "onu upgrade fsm inconsistent setup", log.Fields{
+						"device-id": dh.deviceID})
+					err = fmt.Errorf("onu upgrade fsm inconsistent setup, baseFsm invalid for device-id: %s", dh.deviceID)
 				}
-				err = fmt.Errorf("aborted Onu SW upgrade but not automatically started, try again, device-id: %s", dh.deviceID)
-				//TODO!!!: wait for 'ready' to start and configure - see above SetDownloadParams()
-				// for now a second start of download should work again
-			} else { //should never occur
-				logger.Errorw(ctx, "onu upgrade fsm inconsistent setup", log.Fields{
-					"device-id": dh.deviceID})
-				err = fmt.Errorf("onu upgrade fsm inconsistent setup, baseFsm invalid for device-id: %s", dh.deviceID)
 			}
+		} else {
+			logger.Errorw(ctx, "start Onu SW upgrade rejected: no inactive image", log.Fields{
+				"device-id": dh.deviceID, "error": err})
 		}
 	} else {
-		logger.Errorw(ctx, "Start Onu SW upgrade rejected: no active OMCI connection", log.Fields{"device-id": dh.deviceID})
+		logger.Errorw(ctx, "start Onu SW upgrade rejected: no active OMCI connection", log.Fields{"device-id": dh.deviceID})
+		err = fmt.Errorf("start Onu SW upgrade rejected: no active OMCI connection for device-id: %s", dh.deviceID)
 	}
 	return err
 }
@@ -1753,6 +1769,10 @@
 	if !dh.isReconciling() {
 		logger.Debugw(ctx, "call DeviceStateUpdate upon mib-download done", log.Fields{"ConnectStatus": voltha.ConnectStatus_REACHABLE,
 			"OperStatus": voltha.OperStatus_ACTIVE, "device-id": dh.deviceID})
+		//we allow a possible OnuSw image commit only in the normal startup, not at reconciling
+		// in case of adapter restart connected to an ONU upgrade I would not rely on the image quality
+		// maybe some 'forced' commitment can be done in this situation from system management (or upgrade restarted)
+		dh.checkOnOnuImageCommit(ctx)
 		if err := dh.coreProxy.DeviceStateUpdate(log.WithSpanFromContext(context.TODO(), ctx), dh.deviceID,
 			voltha.ConnectStatus_REACHABLE, voltha.OperStatus_ACTIVE); err != nil {
 			//TODO with VOL-3045/VOL-3046: return the error and stop further processing
@@ -2160,17 +2180,16 @@
 }
 
 // createOnuUpgradeFsm initializes and runs the Onu Software upgrade FSM
-func (dh *deviceHandler) createOnuUpgradeFsm(ctx context.Context, devEvent OnuDeviceEvent) error {
+func (dh *deviceHandler) createOnuUpgradeFsm(ctx context.Context, apDevEntry *OnuDeviceEntry, aDevEvent OnuDeviceEvent) error {
 	//in here lockUpgradeFsm is already locked
 	chUpgradeFsm := make(chan Message, 2048)
 	var sFsmName = "OnuSwUpgradeFSM"
 	logger.Debugw(ctx, "create OnuSwUpgradeFSM", log.Fields{"device-id": dh.deviceID})
-	pDevEntry := dh.getOnuDeviceEntry(ctx, true)
-	if pDevEntry == nil {
-		logger.Errorw(ctx, "no valid OnuDevice -abort", log.Fields{"device-id": dh.deviceID})
-		return fmt.Errorf(fmt.Sprintf("no valid OnuDevice - abort for device-id: %s", dh.device.Id))
+	if apDevEntry.PDevOmciCC == nil {
+		logger.Errorw(ctx, "no valid OnuDevice or omciCC - abort", log.Fields{"device-id": dh.deviceID})
+		return fmt.Errorf(fmt.Sprintf("no valid omciCC - abort for device-id: %s", dh.device.Id))
 	}
-	dh.pOnuUpradeFsm = NewOnuUpgradeFsm(ctx, dh, pDevEntry.PDevOmciCC, pDevEntry.pOnuDB, devEvent,
+	dh.pOnuUpradeFsm = NewOnuUpgradeFsm(ctx, dh, apDevEntry, apDevEntry.pOnuDB, aDevEvent,
 		sFsmName, chUpgradeFsm)
 	if dh.pOnuUpradeFsm != nil {
 		pUpgradeStatemachine := dh.pOnuUpradeFsm.pAdaptFsm.pFsm
@@ -2211,6 +2230,43 @@
 	dh.pOnuUpradeFsm = nil //resource clearing is left to garbage collector
 }
 
+// checkOnOnuImageCommit verifies if the ONU is in some upgrade state that allows for image commit and if tries to commit
+func (dh *deviceHandler) checkOnOnuImageCommit(ctx context.Context) {
+	pDevEntry := dh.getOnuDeviceEntry(ctx, false)
+	if pDevEntry == nil {
+		logger.Errorw(ctx, "No valid OnuDevice -aborting checkOnOnuImageCommit", log.Fields{"device-id": dh.deviceID})
+		return
+	}
+
+	dh.lockUpgradeFsm.RLock()
+	defer dh.lockUpgradeFsm.RUnlock()
+	if dh.pOnuUpradeFsm != nil {
+		pUpgradeStatemachine := dh.pOnuUpradeFsm.pAdaptFsm.pFsm
+		if pUpgradeStatemachine != nil {
+			// commit is only processed in case out upgrade FSM indicates the according state (for automatic commit)
+			//  (some manual forced commit could do without)
+			if pUpgradeStatemachine.Is(upgradeStWaitForCommit) {
+				forcedTest := true //TODO!!: needed as long as BBSIM does not fully support SW upgrade simulation
+				if forcedTest || pDevEntry.IsImageToBeCommitted(ctx, dh.pOnuUpradeFsm.inactiveImageMeID) {
+					if err := pUpgradeStatemachine.Event(upgradeEvCommitSw); err != nil {
+						logger.Errorw(ctx, "OnuSwUpgradeFSM: can't call commit event", log.Fields{"err": err})
+						return
+					}
+					logger.Debugw(ctx, "OnuSwUpgradeFSM commit image requested", log.Fields{
+						"state": pUpgradeStatemachine.Current(), "device-id": dh.deviceID})
+				} else {
+					logger.Errorw(ctx, "OnuSwUpgradeFSM waiting to commit, but nothing to commit on ONU - abort upgrade",
+						log.Fields{"device-id": dh.deviceID})
+					_ = pUpgradeStatemachine.Event(upgradeEvAbort)
+					return
+				}
+			}
+		}
+	} else {
+		logger.Debugw(ctx, "no ONU image to be committed", log.Fields{"device-id": dh.deviceID})
+	}
+}
+
 //setBackend provides a DB backend for the specified path on the existing KV client
 func (dh *deviceHandler) setBackend(ctx context.Context, aBasePathKvStore string) *db.Backend {
 
@@ -2760,6 +2816,7 @@
 		}
 	}
 	logger.Infow(ctx, "handling-global-pm-config-params - done", log.Fields{"device-id": dh.device.Id})
+
 	return errorsList
 }
 
diff --git a/internal/pkg/onuadaptercore/mib_sync.go b/internal/pkg/onuadaptercore/mib_sync.go
index 0fcf7f9..0c71848 100644
--- a/internal/pkg/onuadaptercore/mib_sync.go
+++ b/internal/pkg/onuadaptercore/mib_sync.go
@@ -103,7 +103,7 @@
 
 func (oo *OnuDeviceEntry) enterGettingFirstSwVersionState(ctx context.Context, e *fsm.Event) {
 	logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start getting IsActive and Version of first SW-image in State": e.FSM.Current(), "device-id": oo.deviceID})
-	requestedAttributes := me.AttributeValueMap{"IsActive": 0, "Version": ""}
+	requestedAttributes := me.AttributeValueMap{"IsCommitted": 0, "IsActive": 0, "Version": ""}
 	meInstance := oo.PDevOmciCC.sendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.SoftwareImageClassID, firstSwImageMeID, requestedAttributes, ConstDefaultOmciTimeout, true, oo.pMibUploadFsm.commChan)
 	//accept also nil as (error) return value for writing to LastTx
 	//  - this avoids misinterpretation of new received OMCI messages
@@ -112,7 +112,7 @@
 
 func (oo *OnuDeviceEntry) enterGettingSecondSwVersionState(ctx context.Context, e *fsm.Event) {
 	logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start getting IsActive and Version of second SW-image in State": e.FSM.Current(), "device-id": oo.deviceID})
-	requestedAttributes := me.AttributeValueMap{"IsActive": 0, "Version": ""}
+	requestedAttributes := me.AttributeValueMap{"IsCommitted": 0, "IsActive": 0, "Version": ""}
 	meInstance := oo.PDevOmciCC.sendGetMe(log.WithSpanFromContext(context.TODO(), ctx), me.SoftwareImageClassID, secondSwImageMeID, requestedAttributes, ConstDefaultOmciTimeout, true, oo.pMibUploadFsm.commChan)
 	//accept also nil as (error) return value for writing to LastTx
 	//  - this avoids misinterpretation of new received OMCI messages
@@ -130,10 +130,11 @@
 
 func (oo *OnuDeviceEntry) enterGettingMibTemplate(ctx context.Context, e *fsm.Event) {
 
-	for i := firstSwImageMeID; i <= secondSwImageMeID; i++ {
-		if oo.swImages[i].isActive > 0 {
-			oo.activeSwVersion = oo.swImages[i].version
-		}
+	if oo.onuSwImageIndications.activeEntityEntry.valid {
+		oo.activeSwVersion = oo.onuSwImageIndications.activeEntityEntry.version
+	} else {
+		logger.Errorw(ctx, "get-mib-template: no active SW version found, working with empty SW version, which might be untrustworthy",
+			log.Fields{"device-id": oo.deviceID})
 	}
 
 	meStoredFromTemplate := false
@@ -477,22 +478,15 @@
 				_ = oo.pMibUploadFsm.pFsm.Event(ulEvGetFirstSwVersion)
 				return nil
 			case "SoftwareImage":
-				if entityID <= secondSwImageMeID {
-					oo.swImages[entityID].version = trimStringFromInterface(meAttributes["Version"])
-					oo.swImages[entityID].isActive = meAttributes["IsActive"].(uint8)
-					logger.Debugw(ctx, "MibSync FSM - GetResponse Data for SoftwareImage - Version/IsActive",
-						log.Fields{"device-id": oo.deviceID, "entityID": entityID,
-							"version": oo.swImages[entityID].version, "isActive": oo.swImages[entityID].isActive})
-				} else {
-					err = fmt.Errorf("mibSync FSM - Failed to GetResponse Data for SoftwareImage: %s", oo.deviceID)
+				if entityID > secondSwImageMeID {
+					logger.Errorw(ctx, "mibSync FSM - Failed to GetResponse Data for SoftwareImage with expected EntityId",
+						log.Fields{"device-id": oo.deviceID, "entity-ID": entityID})
+					return fmt.Errorf("mibSync FSM - SwResponse Data with unexpected EntityId: %s %x",
+						oo.deviceID, entityID)
 				}
-				if firstSwImageMeID == entityID {
-					_ = oo.pMibUploadFsm.pFsm.Event(ulEvGetSecondSwVersion)
-					return nil
-				} else if secondSwImageMeID == entityID {
-					_ = oo.pMibUploadFsm.pFsm.Event(ulEvGetMacAddress)
-					return nil
-				}
+				// need to use function for go lint complexity
+				oo.handleSwImageIndications(ctx, entityID, meAttributes)
+				return nil
 			case "IpHostConfigData":
 				macBytes, _ := me.InterfaceToOctets(meAttributes["MacAddress"])
 				if omciMacAddressLen == len(macBytes) {
@@ -523,6 +517,67 @@
 	return err
 }
 
+func (oo *OnuDeviceEntry) handleSwImageIndications(ctx context.Context, entityID uint16, meAttributes me.AttributeValueMap) {
+	imageIsCommitted := meAttributes["IsCommitted"].(uint8)
+	imageIsActive := meAttributes["IsActive"].(uint8)
+	imageVersion := trimStringFromInterface(meAttributes["Version"])
+	logger.Infow(ctx, "MibSync FSM - GetResponse Data for SoftwareImage",
+		log.Fields{"device-id": oo.deviceID, "entityID": entityID,
+			"version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted, "SNR": oo.serialNumber})
+	if firstSwImageMeID == entityID {
+		//always accept the state of the first image (2nd image info should not yet be available)
+		if imageIsActive == swIsActive {
+			oo.onuSwImageIndications.activeEntityEntry.entityID = entityID
+			oo.onuSwImageIndications.activeEntityEntry.valid = true
+			oo.onuSwImageIndications.activeEntityEntry.version = imageVersion
+			oo.onuSwImageIndications.activeEntityEntry.isCommitted = imageIsCommitted
+		} else {
+			oo.onuSwImageIndications.inactiveEntityEntry.entityID = entityID
+			oo.onuSwImageIndications.inactiveEntityEntry.valid = true
+			oo.onuSwImageIndications.inactiveEntityEntry.version = imageVersion
+			oo.onuSwImageIndications.inactiveEntityEntry.isCommitted = imageIsCommitted
+		}
+		_ = oo.pMibUploadFsm.pFsm.Event(ulEvGetSecondSwVersion)
+		return
+	} else if secondSwImageMeID == entityID {
+		//2nd image info might conflict with first image info, in which case we priorize first image info!
+		if imageIsActive == swIsActive { //2nd image reported to be active
+			if oo.onuSwImageIndications.activeEntityEntry.valid {
+				//conflict exists - state of first image is left active
+				logger.Warnw(ctx, "mibSync FSM - both ONU images are reported as active - assuming 2nd to be inactive",
+					log.Fields{"device-id": oo.deviceID})
+				oo.onuSwImageIndications.inactiveEntityEntry.entityID = entityID
+				oo.onuSwImageIndications.inactiveEntityEntry.valid = true ////to indicate that at least something has been reported
+				oo.onuSwImageIndications.inactiveEntityEntry.version = imageVersion
+				oo.onuSwImageIndications.inactiveEntityEntry.isCommitted = imageIsCommitted
+			} else { //first image inactive, this one active
+				oo.onuSwImageIndications.activeEntityEntry.entityID = entityID
+				oo.onuSwImageIndications.activeEntityEntry.valid = true
+				oo.onuSwImageIndications.activeEntityEntry.version = imageVersion
+				oo.onuSwImageIndications.activeEntityEntry.isCommitted = imageIsCommitted
+			}
+		} else { //2nd image reported to be inactive
+			if oo.onuSwImageIndications.inactiveEntityEntry.valid {
+				//conflict exists - both images inactive - regard it as ONU failure and assume first image to be active
+				logger.Warnw(ctx, "mibSync FSM - both ONU images are reported as inactive, defining first to be active",
+					log.Fields{"device-id": oo.deviceID})
+				oo.onuSwImageIndications.activeEntityEntry.entityID = firstSwImageMeID
+				oo.onuSwImageIndications.activeEntityEntry.valid = true //to indicate that at least something has been reported
+				//copy active commit/version from the previously stored inactive position
+				oo.onuSwImageIndications.activeEntityEntry.version = oo.onuSwImageIndications.inactiveEntityEntry.version
+				oo.onuSwImageIndications.activeEntityEntry.isCommitted = oo.onuSwImageIndications.inactiveEntityEntry.isCommitted
+			}
+			//in any case we indicate (and possibly overwrite) the second image indications as inactive
+			oo.onuSwImageIndications.inactiveEntityEntry.entityID = entityID
+			oo.onuSwImageIndications.inactiveEntityEntry.valid = true
+			oo.onuSwImageIndications.inactiveEntityEntry.version = imageVersion
+			oo.onuSwImageIndications.inactiveEntityEntry.isCommitted = imageIsCommitted
+		}
+		_ = oo.pMibUploadFsm.pFsm.Event(ulEvGetMacAddress)
+		return
+	}
+}
+
 func (oo *OnuDeviceEntry) handleOmciMessage(ctx context.Context, msg OmciMessage) {
 	logger.Debugw(ctx, "MibSync Msg", log.Fields{"OmciMessage received for device-id": oo.deviceID,
 		"msgType": msg.OmciMsg.MessageType, "msg": msg})
@@ -718,3 +773,31 @@
 		logger.Warnw(ctx, "wrong state for MDS evaluation!", log.Fields{"state": oo.pMibUploadFsm.pFsm.Current(), "device-id": oo.deviceID})
 	}
 }
+
+//GetActiveImageMeID returns the Omci MeId of the active ONU image together with error code for validity
+func (oo *OnuDeviceEntry) GetActiveImageMeID(ctx context.Context) (uint16, error) {
+	if oo.onuSwImageIndications.activeEntityEntry.valid {
+		return oo.onuSwImageIndications.activeEntityEntry.entityID, nil
+	}
+	return 0xFFFF, fmt.Errorf("no valid active image found: %s", oo.deviceID)
+}
+
+//GetInactiveImageMeID returns the Omci MeId of the inactive ONU image together with error code for validity
+func (oo *OnuDeviceEntry) GetInactiveImageMeID(ctx context.Context) (uint16, error) {
+	if oo.onuSwImageIndications.inactiveEntityEntry.valid {
+		return oo.onuSwImageIndications.inactiveEntityEntry.entityID, nil
+	}
+	return 0xFFFF, fmt.Errorf("no valid inactive image found: %s", oo.deviceID)
+}
+
+//IsImageToBeCommitted returns true if the active image is still uncommitted
+func (oo *OnuDeviceEntry) IsImageToBeCommitted(ctx context.Context, aImageID uint16) bool {
+	if oo.onuSwImageIndications.activeEntityEntry.valid {
+		if oo.onuSwImageIndications.activeEntityEntry.entityID == aImageID {
+			if oo.onuSwImageIndications.activeEntityEntry.isCommitted == swIsUncommitted {
+				return true
+			}
+		}
+	}
+	return false //all other case are treated as 'nothing to commit
+}
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index dcdbe1b..a1050bc 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -45,7 +45,7 @@
 // ### OMCI related definitions - retrieved from Python adapter code/trace ####
 
 //ConstDefaultOmciTimeout - Default OMCI Timeout
-const ConstDefaultOmciTimeout = 3
+const ConstDefaultOmciTimeout = 3 //seconds
 
 const galEthernetEID = uint16(1)
 const maxGemPayloadSize = uint16(48)
@@ -2515,42 +2515,44 @@
 	}
 	logger.Debug(ctx, "send StartSwDlRequest done")
 
-	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
-	time.Sleep(time.Millisecond * 200) //give some response time
-	respOmciLayer := &omci.OMCI{
-		TransactionID: tid,
-		MessageType:   omci.StartSoftwareDownloadResponseType,
-		// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
-		// Length:           0x28,						// Optional, defaults to 40 octets
-	}
-	response := &omci.StartSoftwareDownloadResponse{
-		MeBasePacket: omci.MeBasePacket{
-			EntityClass:    me.SoftwareImageClassID,
-			EntityInstance: aImageMeID, //inactive image
-		},
-		Result:            0,
-		WindowSize:        aDownloadWindowSize,
-		NumberOfInstances: 0, //seems at the moment I can only generate 0 instances, using 1 here panics as MeResult can not be set below
-		//MeResults: cannot set here: downloadResults type not exported from omci-lib!
-	}
-	var respOptions gopacket.SerializeOptions
-	respOptions.FixLengths = true
-	respBuffer := gopacket.NewSerializeBuffer()
-	respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
-	if respErr != nil {
-		logger.Errorw(ctx, "Cannot serialize StartSwDlResponse", log.Fields{"Err": respErr,
-			"device-id": oo.deviceID})
-		return respErr
-	}
-	respPacket := respBuffer.Bytes()
-	logger.Debugw(ctx, "simulate StartSwDlResponse", log.Fields{"device-id": oo.deviceID,
-		"SequNo":     strconv.FormatInt(int64(tid), 16),
-		"InstId":     strconv.FormatInt(int64(aImageMeID), 16),
-		"windowSize": aDownloadWindowSize})
-	go func(oo *omciCC) {
-		_ = oo.receiveMessage(ctx, respPacket)
-	}(oo)
-	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	go func() {
+		//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
+		time.Sleep(time.Millisecond * 50) //give some response time
+		respOmciLayer := &omci.OMCI{
+			TransactionID: tid,
+			MessageType:   omci.StartSoftwareDownloadResponseType,
+			// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+			// Length:           0x28,						// Optional, defaults to 40 octets
+		}
+		response := &omci.StartSoftwareDownloadResponse{
+			MeBasePacket: omci.MeBasePacket{
+				EntityClass:    me.SoftwareImageClassID,
+				EntityInstance: aImageMeID, //inactive image
+			},
+			Result:            0,
+			WindowSize:        aDownloadWindowSize,
+			NumberOfInstances: 0, //seems at the moment I can only generate 0 instances, using 1 here panics as MeResult can not be set below
+			//MeResults: cannot set here: downloadResults type not exported from omci-lib!
+		}
+		var respOptions gopacket.SerializeOptions
+		respOptions.FixLengths = true
+		respBuffer := gopacket.NewSerializeBuffer()
+		respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
+		if respErr != nil {
+			logger.Errorw(ctx, "Cannot serialize StartSwDlResponse", log.Fields{"Err": respErr,
+				"device-id": oo.deviceID})
+			return
+		}
+		respPacket := respBuffer.Bytes()
+		logger.Debugw(ctx, "simulate StartSwDlResponse", log.Fields{"device-id": oo.deviceID,
+			"SequNo":     strconv.FormatInt(int64(tid), 16),
+			"InstId":     strconv.FormatInt(int64(aImageMeID), 16),
+			"windowSize": aDownloadWindowSize})
+		go func(oo *omciCC) {
+			_ = oo.receiveMessage(ctx, respPacket)
+		}(oo)
+		//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	}()
 	return nil
 }
 
@@ -2559,18 +2561,22 @@
 	tid := oo.getNextTid(highPrio)
 	logger.Debugw(ctx, "send DlSectionRequest:", log.Fields{"device-id": oo.deviceID,
 		"SequNo": strconv.FormatInt(int64(tid), 16),
-		"InstId": strconv.FormatInt(int64(aImageMeID), 16)})
+		"InstId": strconv.FormatInt(int64(aImageMeID), 16), "omci-ack": aAckRequest})
 
 	//TODO!!!: don't know by now on how to generate the possibly needed AR (or enforce it to 0) with current omci-lib
 	//    by now just try to send it as defined by omci-lib
+	msgType := omci.DownloadSectionRequestType
+	if aAckRequest > 0 {
+		msgType = omci.DownloadSectionRequestWithResponseType
+	}
 	omciLayer := &omci.OMCI{
 		TransactionID: tid,
-		MessageType:   omci.DownloadSectionRequestType,
+		MessageType:   msgType,
 		// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
 		// Length:           0x28,						// Optional, defaults to 40 octets
 	}
 	var localSectionData [31]byte
-	copy(localSectionData[:], aSection)
+	copy(localSectionData[:], aSection) // as long as DownloadSectionRequest defines array for SectionData we need to copy into the array
 	request := &omci.DownloadSectionRequest{
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass:    me.SoftwareImageClassID,
@@ -2591,8 +2597,14 @@
 	}
 	outgoingPacket := buffer.Bytes()
 
+	//for initial debug purpose overrule the requested print state for some frames
+	printFrame := aPrint
+	if aAckRequest > 0 || aDownloadSectionNo == 0 {
+		printFrame = true
+	}
+
 	omciRxCallbackPair := callbackPair{cbKey: tid,
-		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, aPrint},
+		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, printFrame /*aPrint*/},
 	}
 	err = oo.send(ctx, outgoingPacket, timeout, 0, highPrio, omciRxCallbackPair)
 	if err != nil {
@@ -2602,48 +2614,50 @@
 	}
 	logger.Debug(ctx, "send DlSectionRequest done")
 
-	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
-	if aAckRequest > 0 {
-		time.Sleep(time.Millisecond * 200) //give some response time
-		respOmciLayer := &omci.OMCI{
-			TransactionID: tid,
-			MessageType:   omci.DownloadSectionResponseType,
-			// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
-			// Length:           0x28,						// Optional, defaults to 40 octets
+	go func() {
+		//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
+		if aAckRequest > 0 {
+			time.Sleep(time.Millisecond * 50) //give some response time
+			respOmciLayer := &omci.OMCI{
+				TransactionID: tid,
+				MessageType:   omci.DownloadSectionResponseType,
+				// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+				// Length:           0x28,						// Optional, defaults to 40 octets
+			}
+			response := &omci.DownloadSectionResponse{
+				MeBasePacket: omci.MeBasePacket{
+					EntityClass:    me.SoftwareImageClassID,
+					EntityInstance: aImageMeID, //inactive image
+				},
+				Result:        0,
+				SectionNumber: aDownloadSectionNo,
+			}
+			var respOptions gopacket.SerializeOptions
+			respOptions.FixLengths = true
+			respBuffer := gopacket.NewSerializeBuffer()
+			respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
+			if respErr != nil {
+				logger.Errorw(ctx, "Cannot serialize DlSectionResponse", log.Fields{"Err": respErr,
+					"device-id": oo.deviceID})
+				return
+			}
+			respPacket := respBuffer.Bytes()
+			if aPrint {
+				logger.Debugw(ctx, "simulate DlSectionResponse", log.Fields{"device-id": oo.deviceID,
+					"SequNo": strconv.FormatInt(int64(tid), 16),
+					"InstId": strconv.FormatInt(int64(aImageMeID), 16),
+					"packet": hex.EncodeToString(respPacket)})
+			} else {
+				logger.Debugw(ctx, "simulate DlSectionResponse", log.Fields{"device-id": oo.deviceID,
+					"SequNo": strconv.FormatInt(int64(tid), 16),
+					"InstId": strconv.FormatInt(int64(aImageMeID), 16)})
+			}
+			go func(oo *omciCC) {
+				_ = oo.receiveMessage(ctx, respPacket)
+			}(oo)
 		}
-		response := &omci.DownloadSectionResponse{
-			MeBasePacket: omci.MeBasePacket{
-				EntityClass:    me.SoftwareImageClassID,
-				EntityInstance: aImageMeID, //inactive image
-			},
-			Result:        0,
-			SectionNumber: aDownloadSectionNo,
-		}
-		var respOptions gopacket.SerializeOptions
-		respOptions.FixLengths = true
-		respBuffer := gopacket.NewSerializeBuffer()
-		respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
-		if respErr != nil {
-			logger.Errorw(ctx, "Cannot serialize DlSectionResponse", log.Fields{"Err": respErr,
-				"device-id": oo.deviceID})
-			return err
-		}
-		respPacket := respBuffer.Bytes()
-		if aPrint {
-			logger.Debugw(ctx, "simulate DlSectionResponse", log.Fields{"device-id": oo.deviceID,
-				"SequNo": strconv.FormatInt(int64(tid), 16),
-				"InstId": strconv.FormatInt(int64(aImageMeID), 16),
-				"packet": hex.EncodeToString(respPacket)})
-		} else {
-			logger.Debugw(ctx, "simulate DlSectionResponse", log.Fields{"device-id": oo.deviceID,
-				"SequNo": strconv.FormatInt(int64(tid), 16),
-				"InstId": strconv.FormatInt(int64(aImageMeID), 16)})
-		}
-		go func(oo *omciCC) {
-			_ = oo.receiveMessage(ctx, respPacket)
-		}(oo)
-	}
-	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+		//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	}()
 	return nil
 }
 
@@ -2654,93 +2668,81 @@
 		"SequNo": strconv.FormatInt(int64(tid), 16),
 		"InstId": strconv.FormatInt(int64(aImageMeID), 16)})
 
-	//**** test simulation - as long as omci-lib serialize for this type is not corrected - just bypass sending *** start *****
-	/*
-		omciLayer := &omci.OMCI{
-			TransactionID: tid,
-			MessageType:   omci.EndSoftwareDownloadRequestType,
-			// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
-			// Length:           0x28,						// Optional, defaults to 40 octets
-		}
-		request := &omci.EndSoftwareDownloadRequest{
-			MeBasePacket: omci.MeBasePacket{
-				EntityClass:    me.SoftwareImageClassID,
-				EntityInstance: aImageMeID, //inactive image
-			},
-			CRC32:             aImageCrc,
-			ImageSize:         aFileLen,
-			NumberOfInstances: 1,           //parallel download to multiple circuit packs not supported
-			ImageInstances:    []uint16{0}, //don't care for NumberOfInstances=1, but probably needed by omci-lib as in startSwDlRequest
-		}
-
-		var options gopacket.SerializeOptions
-		options.FixLengths = true
-		buffer := gopacket.NewSerializeBuffer()
-		err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
-		if err != nil {
-			logger.Errorw(ctx, "Cannot serialize EndSwDlRequest", log.Fields{"Err": err,
-				"device-id": oo.deviceID})
-			return err
-		}
-		outgoingPacket := buffer.Bytes()
-
-		omciRxCallbackPair := callbackPair{cbKey: tid,
-			cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
-		}
-		err = oo.send(ctx, outgoingPacket, timeout, 0, highPrio, omciRxCallbackPair)
-		if err != nil {
-			logger.Errorw(ctx, "Cannot send EndSwDlRequest", log.Fields{"Err": err,
-				"device-id": oo.deviceID})
-			return err
-		}
-	*/
-	//**** test simulation - as long as omci-lib serialize for this type is not corrected - just bypass sending *** end *****
-	logger.Debug(ctx, "send EndSwDlRequest done")
-
-	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
-	//callback code necessary here only as long as sending the request is not possible
-	omciRxCallbackPair := callbackPair{cbKey: tid,
-		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
-	}
-	oo.mutexRxSchedMap.Lock()
-	oo.rxSchedulerMap[omciRxCallbackPair.cbKey] = omciRxCallbackPair.cbEntry
-	oo.mutexRxSchedMap.Unlock()
-	//callback code necessary here only as long as sending the request is not possible
-
-	time.Sleep(time.Millisecond * 200) //give some response time
-	respOmciLayer := &omci.OMCI{
+	omciLayer := &omci.OMCI{
 		TransactionID: tid,
-		MessageType:   omci.EndSoftwareDownloadResponseType,
+		MessageType:   omci.EndSoftwareDownloadRequestType,
 		// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
 		// Length:           0x28,						// Optional, defaults to 40 octets
 	}
-	response := &omci.EndSoftwareDownloadResponse{
+	request := &omci.EndSoftwareDownloadRequest{
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass:    me.SoftwareImageClassID,
 			EntityInstance: aImageMeID, //inactive image
 		},
-		Result:            0, //simulate done, option would be busy
-		NumberOfInstances: 0, //seems at the moment I can only generate 0 instances, using 1 here panics as MeResult can not be set below
-		//MeResults: cannot set here: downloadResults type not exported from omci-lib!
+		CRC32:             aImageCrc,
+		ImageSize:         aFileLen,
+		NumberOfInstances: 1,           //parallel download to multiple circuit packs not supported
+		ImageInstances:    []uint16{0}, //don't care for NumberOfInstances=1, but probably needed by omci-lib as in startSwDlRequest
 	}
-	var respOptions gopacket.SerializeOptions
-	respOptions.FixLengths = true
-	respBuffer := gopacket.NewSerializeBuffer()
-	respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
-	if respErr != nil {
-		logger.Errorw(ctx, "Cannot serialize EndSwDlResponse", log.Fields{"Err": respErr,
+
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
+	buffer := gopacket.NewSerializeBuffer()
+	err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot serialize EndSwDlRequest", log.Fields{"Err": err,
 			"device-id": oo.deviceID})
-		return respErr
+		return err
 	}
-	respPacket := respBuffer.Bytes()
-	logger.Debugw(ctx, "simulate EndSwDlResponse", log.Fields{"device-id": oo.deviceID,
-		"SequNo": strconv.FormatInt(int64(tid), 16),
-		"InstId": strconv.FormatInt(int64(aImageMeID), 16),
-		"result": 0})
-	go func(oo *omciCC) {
-		_ = oo.receiveMessage(ctx, respPacket)
-	}(oo)
-	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	outgoingPacket := buffer.Bytes()
+
+	omciRxCallbackPair := callbackPair{cbKey: tid,
+		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
+	}
+	err = oo.send(ctx, outgoingPacket, timeout, 0, highPrio, omciRxCallbackPair)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot send EndSwDlRequest", log.Fields{"Err": err,
+			"device-id": oo.deviceID})
+		return err
+	}
+	logger.Debug(ctx, "send EndSwDlRequest done")
+
+	go func() {
+		//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
+		time.Sleep(time.Millisecond * 50) //give some response time
+		respOmciLayer := &omci.OMCI{
+			TransactionID: tid,
+			MessageType:   omci.EndSoftwareDownloadResponseType,
+			// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+			// Length:           0x28,						// Optional, defaults to 40 octets
+		}
+		response := &omci.EndSoftwareDownloadResponse{
+			MeBasePacket: omci.MeBasePacket{
+				EntityClass:    me.SoftwareImageClassID,
+				EntityInstance: aImageMeID, //inactive image
+			},
+			Result:            0, //simulate done, option would be busy
+			NumberOfInstances: 0, //basic ONU-G instance
+		}
+		var respOptions gopacket.SerializeOptions
+		respOptions.FixLengths = true
+		respBuffer := gopacket.NewSerializeBuffer()
+		respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
+		if respErr != nil {
+			logger.Errorw(ctx, "Cannot serialize EndSwDlResponse", log.Fields{"Err": respErr,
+				"device-id": oo.deviceID})
+			return
+		}
+		respPacket := respBuffer.Bytes()
+		logger.Debugw(ctx, "simulate EndSwDlResponse", log.Fields{"device-id": oo.deviceID,
+			"SequNo": strconv.FormatInt(int64(tid), 16),
+			"InstId": strconv.FormatInt(int64(aImageMeID), 16),
+			"result": 0})
+		go func(oo *omciCC) {
+			_ = oo.receiveMessage(ctx, respPacket)
+		}(oo)
+		//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	}()
 	return nil
 }
 
@@ -2787,41 +2789,122 @@
 	}
 	logger.Debug(ctx, "send ActivateSwRequest done")
 
-	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
+	go func() {
+		//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
+		time.Sleep(time.Millisecond * 50) //give some response time
 
-	time.Sleep(time.Millisecond * 50) //give some response time
+		respOmciLayer := &omci.OMCI{
+			TransactionID: tid,
+			MessageType:   omci.ActivateSoftwareResponseType,
+			// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+			// Length:           0x28,						// Optional, defaults to 40 octets
+		}
+		response := &omci.ActivateSoftwareResponse{
+			MeBasePacket: omci.MeBasePacket{
+				EntityClass:    me.SoftwareImageClassID,
+				EntityInstance: aImageMeID, //inactive image
+			},
+			Result: 0, //simulate done, option would be busy
+		}
+		var respOptions gopacket.SerializeOptions
+		respOptions.FixLengths = true
+		respBuffer := gopacket.NewSerializeBuffer()
+		respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
+		if respErr != nil {
+			logger.Errorw(ctx, "Cannot serialize ActivateSwResponse", log.Fields{"Err": respErr,
+				"device-id": oo.deviceID})
+			return
+		}
+		respPacket := respBuffer.Bytes()
+		logger.Debugw(ctx, "simulate ActivateSwResponse", log.Fields{"device-id": oo.deviceID,
+			"SequNo": strconv.FormatInt(int64(tid), 16),
+			"InstId": strconv.FormatInt(int64(aImageMeID), 16),
+			"result": 0})
+		go func(oo *omciCC) {
+			_ = oo.receiveMessage(ctx, respPacket)
+		}(oo)
+		//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	}()
+	return nil
+}
 
-	respOmciLayer := &omci.OMCI{
+func (oo *omciCC) sendCommitSoftware(ctx context.Context, timeout int, highPrio bool,
+	rxChan chan Message, aImageMeID uint16) error {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw(ctx, "send CommitSwRequest:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(aImageMeID), 16)})
+
+	omciLayer := &omci.OMCI{
 		TransactionID: tid,
-		MessageType:   omci.ActivateSoftwareResponseType,
+		MessageType:   omci.CommitSoftwareRequestType,
 		// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
 		// Length:           0x28,						// Optional, defaults to 40 octets
 	}
-	response := &omci.ActivateSoftwareResponse{
+	request := &omci.CommitSoftwareRequest{
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass:    me.SoftwareImageClassID,
 			EntityInstance: aImageMeID, //inactive image
 		},
-		Result: 0, //simulate done, option would be busy
 	}
-	var respOptions gopacket.SerializeOptions
-	respOptions.FixLengths = true
-	respBuffer := gopacket.NewSerializeBuffer()
-	respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
-	if respErr != nil {
-		logger.Errorw(ctx, "Cannot serialize ActivateSwResponse", log.Fields{"Err": respErr,
+
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
+	buffer := gopacket.NewSerializeBuffer()
+	err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot serialize CommitSwRequest", log.Fields{"Err": err,
 			"device-id": oo.deviceID})
-		return respErr
+		return err
 	}
-	respPacket := respBuffer.Bytes()
-	logger.Debugw(ctx, "simulate ActivateSwResponse", log.Fields{"device-id": oo.deviceID,
-		"SequNo": strconv.FormatInt(int64(tid), 16),
-		"InstId": strconv.FormatInt(int64(aImageMeID), 16),
-		"result": 0})
-	go func(oo *omciCC) {
-		_ = oo.receiveMessage(ctx, respPacket)
-	}(oo)
-	//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	outgoingPacket := buffer.Bytes()
+
+	omciRxCallbackPair := callbackPair{cbKey: tid,
+		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
+	}
+	err = oo.send(ctx, outgoingPacket, timeout, 0, highPrio, omciRxCallbackPair)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot send CommitSwRequest", log.Fields{"Err": err,
+			"device-id": oo.deviceID})
+		return err
+	}
+	logger.Debug(ctx, "send CommitSwRequest done")
+
+	go func() {
+		//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** start *****
+		time.Sleep(time.Millisecond * 50) //give some response time
+		respOmciLayer := &omci.OMCI{
+			TransactionID: tid,
+			MessageType:   omci.CommitSoftwareResponseType,
+			// DeviceIdentifier: omci.BaselineIdent,		// Optional, defaults to Baseline
+			// Length:           0x28,						// Optional, defaults to 40 octets
+		}
+		response := &omci.CommitSoftwareResponse{
+			MeBasePacket: omci.MeBasePacket{
+				EntityClass:    me.SoftwareImageClassID,
+				EntityInstance: aImageMeID, //inactive image
+			},
+			//TODO: Not yet supported by omci-lib Result: 0, //simulate done
+		}
+		var respOptions gopacket.SerializeOptions
+		respOptions.FixLengths = true
+		respBuffer := gopacket.NewSerializeBuffer()
+		respErr := gopacket.SerializeLayers(respBuffer, respOptions, respOmciLayer, response)
+		if respErr != nil {
+			logger.Errorw(ctx, "Cannot serialize CommitSwResponse", log.Fields{"Err": respErr,
+				"device-id": oo.deviceID})
+			return
+		}
+		respPacket := respBuffer.Bytes()
+		logger.Debugw(ctx, "simulate CommitSwResponse", log.Fields{"device-id": oo.deviceID,
+			"SequNo": strconv.FormatInt(int64(tid), 16),
+			"InstId": strconv.FormatInt(int64(aImageMeID), 16),
+			"result": 0})
+		go func(oo *omciCC) {
+			_ = oo.receiveMessage(ctx, respPacket)
+		}(oo)
+		//**** test simulation - as long as BBSIM does not support ONU SW upgrade *** stop *****
+	}()
 	return nil
 }
 
diff --git a/internal/pkg/onuadaptercore/omci_onu_upgrade.go b/internal/pkg/onuadaptercore/omci_onu_upgrade.go
index 7842717..618d265 100644
--- a/internal/pkg/onuadaptercore/omci_onu_upgrade.go
+++ b/internal/pkg/onuadaptercore/omci_onu_upgrade.go
@@ -54,6 +54,7 @@
 	upgradeEvRequestActivate    = "upgradeEvRequestActivate"
 	upgradeEvWaitForCommit      = "upgradeEvWaitForCommit"
 	upgradeEvCommitSw           = "upgradeEvCommitSw"
+	upgradeEvCheckCommitted     = "upgradeEvCheckCommitted"
 
 	//upgradeEvTimeoutSimple  = "upgradeEvTimeoutSimple"
 	//upgradeEvTimeoutMids    = "upgradeEvTimeoutMids"
@@ -73,6 +74,7 @@
 	upgradeStRequestingActivate = "upgradeStRequestingActivate"
 	upgradeStWaitForCommit      = "upgradeStWaitForCommit"
 	upgradeStCommitSw           = "upgradeStCommitSw"
+	upgradeStCheckCommitted     = "upgradeStCheckCommitted"
 	upgradeStResetting          = "upgradeStResetting"
 )
 
@@ -84,6 +86,7 @@
 	pDeviceHandler   *deviceHandler
 	pDownloadManager *adapterDownloadManager
 	deviceID         string
+	pOnuOmciDevice   *OnuDeviceEntry
 	pOmciCC          *omciCC
 	pOnuDB           *onuDeviceDB
 	requestEvent     OnuDeviceEvent
@@ -93,7 +96,8 @@
 	imageBuffer                       []byte
 	origImageLength                   uint32        //as also limited by OMCI
 	imageLength                       uint32        //including last bytes padding
-	omciDownloadWindowSizeLimit       uint8         //windowSize-1
+	omciDownloadWindowSizeLimit       uint8         //windowSize-1 in sections
+	omciDownloadWindowSizeLast        uint8         //number of sections in last window
 	noOfSections                      uint32        //uint32 range for sections should be sufficient for very long images
 	nextDownloadSectionsAbsolute      uint32        //number of next section to download in overall image
 	nextDownloadSectionsWindow        uint8         //number of next section to download within current window
@@ -102,17 +106,19 @@
 	inactiveImageMeID                 uint16        //ME-ID of the inactive image
 	omciSectionInterleaveMilliseconds time.Duration //DownloadSectionInterleave delay in milliseconds
 	delayEndSwDl                      bool          //flag to provide a delay between last section and EndSwDl
+	pLastTxMeInstance                 *me.ManagedEntity
 }
 
 //NewOnuUpgradeFsm is the 'constructor' for the state machine to config the PON ANI ports
 //  of ONU UNI ports via OMCI
 func NewOnuUpgradeFsm(ctx context.Context, apDeviceHandler *deviceHandler,
-	apDevOmciCC *omciCC, apOnuDB *onuDeviceDB,
+	apDevEntry *OnuDeviceEntry, apOnuDB *onuDeviceDB,
 	aRequestEvent OnuDeviceEvent, aName string, aCommChannel chan Message) *OnuUpgradeFsm {
 	instFsm := &OnuUpgradeFsm{
 		pDeviceHandler:                    apDeviceHandler,
 		deviceID:                          apDeviceHandler.deviceID,
-		pOmciCC:                           apDevOmciCC,
+		pOnuOmciDevice:                    apDevEntry,
+		pOmciCC:                           apDevEntry.PDevOmciCC,
 		pOnuDB:                            apOnuDB,
 		requestEvent:                      aRequestEvent,
 		omciDownloadWindowSizeLimit:       cOmciDownloadWindowSizeLimit,
@@ -138,6 +144,7 @@
 			{Name: upgradeEvWaitForCommit, Src: []string{upgradeStRequestingActivate}, Dst: upgradeStWaitForCommit},
 			{Name: upgradeEvCommitSw, Src: []string{upgradeStStarting, upgradeStWaitForCommit},
 				Dst: upgradeStCommitSw},
+			{Name: upgradeEvCheckCommitted, Src: []string{upgradeStCommitSw}, Dst: upgradeStCheckCommitted},
 
 			/*
 				{Name: upgradeEvTimeoutSimple, Src: []string{
@@ -148,11 +155,11 @@
 			// exceptional treatments
 			{Name: upgradeEvReset, Src: []string{upgradeStStarting, upgradeStPreparingDL, upgradeStDLSection,
 				upgradeStVerifyWindow, upgradeStDLSection, upgradeStFinalizeDL, upgradeStRequestingActivate,
-				upgradeStCommitSw}, //upgradeStWaitForCommit is not reset (later perhaps also not upgradeStWaitActivate)
+				upgradeStCommitSw, upgradeStCheckCommitted}, //upgradeStWaitForCommit is not reset (later perhaps also not upgradeStWaitActivate)
 				Dst: upgradeStResetting},
 			{Name: upgradeEvAbort, Src: []string{upgradeStStarting, upgradeStPreparingDL, upgradeStDLSection,
 				upgradeStVerifyWindow, upgradeStDLSection, upgradeStFinalizeDL, upgradeStRequestingActivate,
-				upgradeStWaitForCommit, upgradeStCommitSw},
+				upgradeStWaitForCommit, upgradeStCommitSw, upgradeStCheckCommitted},
 				Dst: upgradeStResetting},
 			{Name: upgradeEvRestart, Src: []string{upgradeStResetting}, Dst: upgradeStDisabled},
 		},
@@ -165,6 +172,7 @@
 			"enter_" + upgradeStFinalizeDL:         func(e *fsm.Event) { instFsm.enterFinalizeDL(ctx, e) },
 			"enter_" + upgradeStRequestingActivate: func(e *fsm.Event) { instFsm.enterActivateSw(ctx, e) },
 			"enter_" + upgradeStCommitSw:           func(e *fsm.Event) { instFsm.enterCommitSw(ctx, e) },
+			"enter_" + upgradeStCheckCommitted:     func(e *fsm.Event) { instFsm.enterCheckCommitted(ctx, e) },
 			"enter_" + upgradeStResetting:          func(e *fsm.Event) { instFsm.enterResetting(ctx, e) },
 			"enter_" + upgradeStDisabled:           func(e *fsm.Event) { instFsm.enterDisabled(ctx, e) },
 		},
@@ -180,12 +188,13 @@
 }
 
 //SetDownloadParams configures the needed parameters for a specific download to the ONU
-func (oFsm *OnuUpgradeFsm) SetDownloadParams(ctx context.Context, apImageDsc *voltha.ImageDownload,
-	apDownloadManager *adapterDownloadManager) error {
+func (oFsm *OnuUpgradeFsm) SetDownloadParams(ctx context.Context, aInactiveImageID uint16,
+	apImageDsc *voltha.ImageDownload, apDownloadManager *adapterDownloadManager) error {
 	pBaseFsm := oFsm.pAdaptFsm.pFsm
 	if pBaseFsm != nil && pBaseFsm.Is(upgradeStStarting) {
 		logger.Debugw(ctx, "OnuUpgradeFsm Parameter setting", log.Fields{
 			"device-id": oFsm.deviceID, "image-description": apImageDsc})
+		oFsm.inactiveImageMeID = aInactiveImageID //upgrade state machines run on configured inactive ImageId
 		oFsm.pImageDsc = apImageDsc
 		oFsm.pDownloadManager = apDownloadManager
 
@@ -219,7 +228,7 @@
 		pBaseFsm := oFsm.pAdaptFsm
 		// Can't call FSM Event directly, decoupling it
 		go func(a_pAFsm *AdapterFsm) {
-			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
 		}(pBaseFsm)
 		return
 	}
@@ -232,7 +241,7 @@
 		pBaseFsm := oFsm.pAdaptFsm
 		// Can't call FSM Event directly, decoupling it
 		go func(a_pAFsm *AdapterFsm) {
-			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
 		}(pBaseFsm)
 		return
 	}
@@ -246,7 +255,6 @@
 	}
 	oFsm.origImageLength = uint32(fileLen)
 	oFsm.imageLength = uint32(len(oFsm.imageBuffer))
-	oFsm.inactiveImageMeID = uint16(1) //just to start with, must be detected from upload data or even determined per new request?
 
 	logger.Infow(ctx, "OnuUpgradeFsm starts with StartSwDl values", log.Fields{
 		"MeId": oFsm.inactiveImageMeID, "windowSizeLimit": oFsm.omciDownloadWindowSizeLimit,
@@ -261,7 +269,7 @@
 		pBaseFsm := oFsm.pAdaptFsm
 		// Can't call FSM Event directly, decoupling it
 		go func(a_pAFsm *AdapterFsm) {
-			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
 		}(pBaseFsm)
 		return
 	}
@@ -296,7 +304,7 @@
 			pBaseFsm := oFsm.pAdaptFsm
 			// Can't call FSM Event directly, decoupling it
 			go func(a_pAFsm *AdapterFsm) {
-				_ = a_pAFsm.pFsm.Event(vlanEvReset)
+				_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
 			}(pBaseFsm)
 			return
 		}
@@ -309,23 +317,23 @@
 		if oFsm.nextDownloadSectionsAbsolute+1 >= oFsm.noOfSections {
 			windowAckRequest = 1
 			framePrint = true //debug print of last frame
-			logger.Debugw(ctx, "DlSection expect Response for last window (section)", log.Fields{
+			oFsm.omciDownloadWindowSizeLast = oFsm.nextDownloadSectionsWindow
+			logger.Infow(ctx, "DlSection expect Response for last window (section)", log.Fields{
 				"device-id": oFsm.deviceID, "DlSectionNoAbsolute": oFsm.nextDownloadSectionsAbsolute})
 		}
 		err := oFsm.pOmciCC.sendDownloadSection(log.WithSpanFromContext(context.TODO(), ctx), ConstDefaultOmciTimeout, false,
 			oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID, windowAckRequest, oFsm.nextDownloadSectionsWindow, downloadSection, framePrint)
 		if err != nil {
 			logger.Errorw(ctx, "DlSection abort: can't send section", log.Fields{
-				"device-id": oFsm.deviceID, "error": err})
+				"device-id": oFsm.deviceID, "section absolute": oFsm.nextDownloadSectionsAbsolute, "error": err})
 			//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
 			pBaseFsm := oFsm.pAdaptFsm
 			// Can't call FSM Event directly, decoupling it
 			go func(a_pAFsm *AdapterFsm) {
-				_ = a_pAFsm.pFsm.Event(vlanEvReset)
+				_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
 			}(pBaseFsm)
 			return
 		}
-
 		oFsm.nextDownloadSectionsAbsolute++ //always increase the absolute section counter after having sent one
 		if windowAckRequest == 1 {
 			pBaseFsm := oFsm.pAdaptFsm
@@ -369,7 +377,7 @@
 		pBaseFsm := oFsm.pAdaptFsm
 		// Can't call FSM Event directly, decoupling it
 		go func(a_pAFsm *AdapterFsm) {
-			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
 		}(pBaseFsm)
 		return
 	}
@@ -388,16 +396,64 @@
 		pBaseFsm := oFsm.pAdaptFsm
 		// Can't call FSM Event directly, decoupling it
 		go func(a_pAFsm *AdapterFsm) {
-			_ = a_pAFsm.pFsm.Event(vlanEvReset)
+			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
 		}(pBaseFsm)
 		return
 	}
 }
 
 func (oFsm *OnuUpgradeFsm) enterCommitSw(ctx context.Context, e *fsm.Event) {
-	logger.Infow(ctx, "OnuUpgradeFsm commit SW - not yet implemented", log.Fields{
+	if activeImageID, err := oFsm.pOnuOmciDevice.GetActiveImageMeID(ctx); err == nil {
+		//TODO!!: as long as testing with BBSIM and BBSIM not support upgrade tests following check needs to be deactivated
+		imageFit := true //TODO!!: test workaround as long as BBSIM does not fully support upgrade
+		if imageFit || activeImageID == oFsm.inactiveImageMeID {
+			logger.Infow(ctx, "OnuUpgradeFsm commit SW", log.Fields{
+				"device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID}) //more efficient activeImageID with above check
+			err := oFsm.pOmciCC.sendCommitSoftware(log.WithSpanFromContext(context.TODO(), ctx), ConstDefaultOmciTimeout, false,
+				oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID) //more efficient activeImageID with above check
+			if err != nil {
+				logger.Errorw(ctx, "CommitSw abort: can't send commit sw frame", log.Fields{
+					"device-id": oFsm.deviceID, "error": err})
+				//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				pBaseFsm := oFsm.pAdaptFsm
+				// Can't call FSM Event directly, decoupling it
+				go func(a_pAFsm *AdapterFsm) {
+					_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
+				}(pBaseFsm)
+				return
+			}
+			return
+		}
+		logger.Errorw(ctx, "OnuUpgradeFsm active ImageId <> IdToCommit", log.Fields{
+			"device-id": oFsm.deviceID, "active ID": activeImageID, "to commit ID": oFsm.inactiveImageMeID})
+		//TODO!!!: possibly send event information for aborted upgrade (not activated)??
+		pBaseFsm := oFsm.pAdaptFsm
+		// Can't call FSM Event directly, decoupling it
+		go func(a_pAFsm *AdapterFsm) {
+			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
+		}(pBaseFsm)
+		return
+	}
+	logger.Errorw(ctx, "OnuUpgradeFsm can't commit, no valid active image", log.Fields{
+		"device-id": oFsm.deviceID})
+	//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+	pBaseFsm := oFsm.pAdaptFsm
+	// Can't call FSM Event directly, decoupling it
+	go func(a_pAFsm *AdapterFsm) {
+		_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
+	}(pBaseFsm)
+}
+
+func (oFsm *OnuUpgradeFsm) enterCheckCommitted(ctx context.Context, e *fsm.Event) {
+	logger.Infow(ctx, "OnuUpgradeFsm checking committed SW", log.Fields{
 		"device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID})
-	//here should be the sending of the software commit message and staying here while waiting for the response
+	requestedAttributes := me.AttributeValueMap{"IsCommitted": 0, "IsActive": 0, "Version": ""}
+	meInstance := oFsm.pOmciCC.sendGetMe(log.WithSpanFromContext(context.TODO(), ctx),
+		me.SoftwareImageClassID, oFsm.inactiveImageMeID, requestedAttributes, ConstDefaultOmciTimeout, false, oFsm.pAdaptFsm.commChan)
+	//accept also nil as (error) return value for writing to LastTx
+	//  - this avoids misinterpretation of new received OMCI messages
+	oFsm.pLastTxMeInstance = meInstance
 }
 
 func (oFsm *OnuUpgradeFsm) enterResetting(ctx context.Context, e *fsm.Event) {
@@ -443,7 +499,7 @@
 		if !ok {
 			logger.Info(ctx, "OnuUpgradeFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.deviceID})
 			// but then we have to ensure a restart of the FSM as well - as exceptional procedure
-			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvReset)
+			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 			break loop
 		}
 		logger.Debugw(ctx, "OnuUpgradeFsm Rx Msg", log.Fields{"device-id": oFsm.deviceID})
@@ -479,12 +535,16 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for StartSwDlResponse",
 					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.StartSoftwareDownloadResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for StartSwDlResponse",
 					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			logger.Debugw(ctx, "OnuUpgradeFsm StartSwDlResponse data", log.Fields{
@@ -493,6 +553,8 @@
 				logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse result error - later: drive FSM to abort state ?",
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
 				// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
@@ -520,21 +582,26 @@
 			logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
 			// TODO!!!: possibly repeat the start request (once)?
+			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 			return
 		} //StartSoftwareDownloadResponseType
 	case omci.DownloadSectionResponseType:
 		{
-			/* TODO!!!: Have to remove the check here as current used omci-lib does not allow msg layering here
 			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDownloadSectionResponse)
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for DlSectionResponse",
 					log.Fields{"device-id": oFsm.deviceID, "omci-message": msg.OmciMsg})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.DownloadSectionResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for DlSectionResponse",
 					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			logger.Debugw(ctx, "OnuUpgradeFsm DlSectionResponse Data", log.Fields{
@@ -542,35 +609,46 @@
 			if msgObj.Result != me.Success {
 				logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse result error - later: repeat window once?", //TODO!!!
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
 				sectionNumber := msgObj.SectionNumber
-			*/
-			sectionNumber := oFsm.omciDownloadWindowSizeLimit //as long as access from omci-lib is not given above!!!
-			logger.Debugw(ctx, "DlSectionResponse received", log.Fields{
-				"window section-number": sectionNumber, "device-id": oFsm.deviceID})
-			if sectionNumber != oFsm.omciDownloadWindowSizeLimit {
-				logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error - later: repeat window once?", //TODO!!!
-					log.Fields{"device-id": oFsm.deviceID, "window-section-limit": oFsm.omciDownloadWindowSizeLimit})
-				return
-			}
+				logger.Infow(ctx, "DlSectionResponse received", log.Fields{
+					"window section-number": sectionNumber, "window": oFsm.nextDownloadWindow, "device-id": oFsm.deviceID})
 
-			oFsm.nextDownloadWindow++
-			if oFsm.nextDownloadWindow >= oFsm.noOfWindows {
-				oFsm.delayEndSwDl = true //ensure a delay for the EndSwDl message
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvEndSwDownload)
+				oFsm.nextDownloadWindow++
+				if oFsm.nextDownloadWindow >= oFsm.noOfWindows {
+					if sectionNumber != oFsm.omciDownloadWindowSizeLast {
+						logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error - later: repeat window once?", //TODO!!!
+							log.Fields{"device-id": oFsm.deviceID, "actual section": sectionNumber,
+								"expected section": oFsm.omciDownloadWindowSizeLast})
+						//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+						_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+						return
+					}
+					oFsm.delayEndSwDl = true //ensure a delay for the EndSwDl message
+					_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvEndSwDownload)
+					return
+				}
+				if sectionNumber != oFsm.omciDownloadWindowSizeLimit {
+					logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error - later: repeat window once?", //TODO!!!
+						log.Fields{"device-id": oFsm.deviceID, "window-section-limit": oFsm.omciDownloadWindowSizeLimit})
+					//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+					_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+					return
+				}
+				oFsm.nextDownloadSectionsWindow = 0
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvContinueNextWindow)
 				return
 			}
-			oFsm.nextDownloadSectionsWindow = 0
-			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvContinueNextWindow)
-			return
-			/* }
 			logger.Errorw(ctx, "OnuUpgradeFsm Omci StartSwDlResponse wrong ME instance: try again (later)?",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			// TODO!!!: possibly repeat the start request (once)?
+			// TODO!!!: possibly repeat the download (section) (once)?
+			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 			return
-			*/
 		} //DownloadSectionResponseType
 	case omci.EndSoftwareDownloadResponseType:
 		{
@@ -578,12 +656,16 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for EndSwDlResponse",
 					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.EndSoftwareDownloadResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for EndSwDlResponse",
 					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse data", log.Fields{
@@ -593,6 +675,8 @@
 				logger.Errorw(ctx, "OnuUpgradeFsm EndSwDlResponse result error - later: drive FSM to abort state ?",
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
 				// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
@@ -603,6 +687,8 @@
 			logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
 			// TODO!!!: possibly repeat the end request (once)? or verify ONU upgrade state?
+			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 			return
 		} //EndSoftwareDownloadResponseType
 	case omci.ActivateSoftwareResponseType:
@@ -611,12 +697,16 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for ActivateSw",
 					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.ActivateSoftwareResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for ActivateSw",
 					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			logger.Debugw(ctx, "OnuUpgradeFsm ActivateSwResponse data", log.Fields{
@@ -625,18 +715,123 @@
 				logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse result error - later: drive FSM to abort state ?",
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
 				// TODO!!!: error treatment?, perhaps in the end reset the FSM
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
 				logger.Debugw(ctx, "Expected ActivateSwResponse received", log.Fields{"device-id": oFsm.deviceID})
 				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvWaitForCommit)
+				//TODO:  as long as BBSIM does not fully support upgrade: simulate restart by calling the BBSIM (ONU) reboot
+				go oFsm.pDeviceHandler.rebootDevice(ctx, false, oFsm.pDeviceHandler.device)
 				return
 			}
 			logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse wrong ME instance: abort",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			// TODO!!!: error treatment?, perhaps in the end reset the FSM
+			// TODO!!!: error treatment?
+			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 			return
 		} //ActivateSoftwareResponseType
+	case omci.CommitSoftwareResponseType:
+		{
+			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCommitSoftwareResponse)
+			if msgLayer == nil {
+				logger.Errorw(ctx, "Omci Msg layer could not be detected for CommitResponse",
+					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				return
+			}
+			msgObj, msgOk := msgLayer.(*omci.CommitSoftwareResponse)
+			if !msgOk {
+				logger.Errorw(ctx, "Omci Msg layer could not be assigned for CommitResponse",
+					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				return
+			}
+			// TODO!!: not yet implemented by omci-lib:
+			/*if msgObj.Result != me.Success {
+				logger.Errorw(ctx, "OnuUpgradeFsm SwImage CommitResponse result error - later: drive FSM to abort state ?",
+					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+				// TODO!!!: error treatment?, perhaps in the end reset the FSM
+				return
+			}*/
+			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
+				logger.Debugw(ctx, "OnuUpgradeFsm Expected SwImage CommitResponse received", log.Fields{"device-id": oFsm.deviceID})
+				//verifying committed image
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvCheckCommitted)
+				return
+			}
+			logger.Errorw(ctx, "OnuUpgradeFsm SwImage CommitResponse  wrong ME instance: abort",
+				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+			// TODO!!!: error treatment?
+			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+			return
+		} //CommitSoftwareResponseType
+	case omci.GetResponseType:
+		{
+			msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
+			if msgLayer == nil {
+				logger.Errorw(ctx, "Omci Msg layer could not be detected for SwImage GetResponse",
+					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				return
+			}
+			msgObj, msgOk := msgLayer.(*omci.GetResponse)
+			if !msgOk {
+				logger.Errorw(ctx, "Omci Msg layer could not be assigned for SwImage GetResponse",
+					log.Fields{"device-id": oFsm.deviceID})
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				return
+			}
+			logger.Debugw(ctx, "OnuUpgradeFsm SwImage GetResponse data", log.Fields{
+				"device-id": oFsm.deviceID, "data-fields": msgObj})
+			if msgObj.EntityClass == oFsm.pLastTxMeInstance.GetClassID() &&
+				msgObj.EntityInstance == oFsm.pLastTxMeInstance.GetEntityID() {
+				if msgObj.Result != me.Success {
+					logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse result error - later: drive FSM to abort state ?",
+						log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
+					// TODO!!!: error treatment?, perhaps in the end reset the FSM
+					//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+					_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+					return
+				}
+			} else {
+				logger.Warnw(ctx, "OnuUpgradeFsm SwImage unexpected Entity GetResponse data - ignore",
+					log.Fields{"device-id": oFsm.deviceID})
+				return
+			}
+
+			meAttributes := msgObj.Attributes
+			imageIsCommitted := meAttributes["IsCommitted"].(uint8)
+			imageIsActive := meAttributes["IsActive"].(uint8)
+			imageVersion := trimStringFromInterface(meAttributes["Version"])
+			logger.Infow(ctx, "OnuUpgradeFsm - GetResponse Data for SoftwareImage",
+				log.Fields{"device-id": oFsm.deviceID, "entityID": msgObj.EntityInstance,
+					"version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted})
+
+			//a check on the delivered image version is not done, the ONU delivered version might be different from what might have been
+			//  indicated in the download image version string (version must be part of the image content itself)
+			//  so checking that might be quite unreliable
+			if msgObj.EntityInstance == oFsm.inactiveImageMeID && imageIsActive == swIsActive &&
+				imageIsCommitted == swIsCommitted {
+				logger.Infow(ctx, "requested SW image committed, releasing OnuUpgrade", log.Fields{"device-id": oFsm.deviceID})
+				//releasing the upgrade FSM
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvReset)
+				return
+			}
+			logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
+				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+			// TODO!!!: error treatment?
+			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+			return
+		} //GetResponseType
 	default:
 		{
 			logger.Errorw(ctx, "Rx OMCI unhandled MsgType",
diff --git a/internal/pkg/onuadaptercore/omci_vlan_config.go b/internal/pkg/onuadaptercore/omci_vlan_config.go
index a53b115..3a33a0f 100644
--- a/internal/pkg/onuadaptercore/omci_vlan_config.go
+++ b/internal/pkg/onuadaptercore/omci_vlan_config.go
@@ -332,8 +332,8 @@
 //RequestClearPersistency sets the internal flag to not clear persistency data (false=NoClear)
 func (oFsm *UniVlanConfigFsm) RequestClearPersistency(aClear bool) {
 	//mutex protection is required for possible concurrent access to FSM members
-	oFsm.mutexFlowParams.RLock()
-	defer oFsm.mutexFlowParams.RUnlock()
+	oFsm.mutexFlowParams.Lock()
+	defer oFsm.mutexFlowParams.Unlock()
 	oFsm.clearPersistency = aClear
 }
 
@@ -436,7 +436,6 @@
 	kvStoreWrite := false //default setting is to not write to kvStore immediately - will be done on FSM execution finally
 	if requestAppendRule {
 		oFsm.mutexFlowParams.Lock()
-		defer oFsm.mutexFlowParams.Unlock()
 		if oFsm.numUniFlows < cMaxAllowedFlows {
 			loFlowParams := uniVlanFlowParams{VlanRuleParams: loRuleParams}
 			loFlowParams.CookieSlice = make([]uint64, 0)
@@ -489,17 +488,21 @@
 				}
 			} // if not in the appropriate state a new entry will be automatically considered later
 			//   when the configDone state is reached
+			oFsm.mutexFlowParams.Unlock()
 		} else {
 			logger.Errorw(ctx, "UniVlanConfigFsm flow limit exceeded", log.Fields{
 				"device-id": oFsm.deviceID, "flow-number": oFsm.numUniFlows})
+			oFsm.mutexFlowParams.Unlock()
 			return fmt.Errorf(" UniVlanConfigFsm flow limit exceeded %s", oFsm.deviceID)
 		}
 	} else {
 		// no activity within the FSM for OMCI processing, the deviceReason may be updated immediately
 		kvStoreWrite = true // ensure actual data write to kvStore immediately (no FSM activity)
+		oFsm.mutexFlowParams.RLock()
 		if oFsm.numUniFlows == oFsm.configuredUniFlow {
 			//all requested rules really have been configured
 			// state transition notification is checked in deviceHandler
+			oFsm.mutexFlowParams.RUnlock()
 			if oFsm.pDeviceHandler != nil {
 				//also the related TechProfile was already configured
 				logger.Debugw(ctx, "UniVlanConfigFsm rule already set - send immediate add-success event for reason update", log.Fields{
@@ -513,16 +516,20 @@
 			logger.Debugw(ctx, "UniVlanConfigFsm rule already set but configuration ongoing, suppress early add-success event for reason update",
 				log.Fields{"device-id": oFsm.deviceID,
 					"NumberofRules": oFsm.numUniFlows, "Configured rules": oFsm.configuredUniFlow})
+			oFsm.mutexFlowParams.RUnlock()
 		}
 	}
 
 	if flowCookieModify { // some change was done to the flow entries
 		//permanently store flow config for reconcile case
+		oFsm.mutexFlowParams.RLock()
 		if err := oFsm.pDeviceHandler.storePersUniFlowConfig(ctx, oFsm.pOnuUniPort.uniID,
 			&oFsm.uniVlanFlowParamsSlice, kvStoreWrite); err != nil {
+			oFsm.mutexFlowParams.RUnlock()
 			logger.Errorw(ctx, err.Error(), log.Fields{"device-id": oFsm.deviceID})
 			return err
 		}
+		oFsm.mutexFlowParams.RUnlock()
 	}
 	return nil
 }
@@ -639,9 +646,9 @@
 					var loRemoveParams uniRemoveVlanFlowParams = uniRemoveVlanFlowParams{}
 					logger.Debugw(ctx, "UniVlanConfigFsm flow removal - full flow removal", log.Fields{
 						"device-id": oFsm.deviceID})
-					//rwCore flow recovery may be the reson for this delete, in which case the flowToBeDeleted may be the same
+					//rwCore flow recovery may be the reason for this delete, in which case the flowToBeDeleted may be the same
 					//  as the one still waiting in the FSM as toAdd but waiting for TechProfileConfig
-					//  so we have to to check that here in in this case have to abort the outstanding AddRequest and regard the current DelRequest as done
+					//  so we have to check if we have to abort the outstanding AddRequest and regard the current DelRequest as done
 					//  if the Fsm is in some other transient (config) state, we will reach the DelRequest later and correctly process it then
 					if pConfigVlanStateBaseFsm.Is(vlanStWaitingTechProf) {
 						logger.Debugw(ctx, "UniVlanConfigFsm was waiting for TechProf config with this rule, aborting the outstanding config",
@@ -990,10 +997,10 @@
 }
 
 func (oFsm *UniVlanConfigFsm) enterConfigIncrFlow(ctx context.Context, e *fsm.Event) {
+	oFsm.mutexFlowParams.Lock()
 	logger.Debugw(ctx, "UniVlanConfigFsm - start config further incremental flow", log.Fields{
 		"in state": e.FSM.Current(), "recent flow-number": oFsm.configuredUniFlow,
 		"device-id": oFsm.deviceID})
-	oFsm.mutexFlowParams.Lock()
 	oFsm.TpIDWaitingFor = 0 //reset indication to avoid misinterpretation
 
 	if oFsm.actualUniVlanConfigRule.SetVid == uint32(of.OfpVlanId_OFPVID_PRESENT) {
@@ -1013,7 +1020,6 @@
 			// 'SetVid' below is assumed to be masked already by the caller to 12 bit
 			oFsm.vlanFilterList[0] = uint16(oFsm.actualUniVlanConfigRule.SetVid)
 
-			oFsm.mutexFlowParams.Unlock()
 			vtfdFilterList := make([]uint16, cVtfdTableSize) //needed for parameter serialization
 			vtfdFilterList[0] = oFsm.vlanFilterList[0]
 			oFsm.numVlanFilterEntries = 1
@@ -1051,7 +1057,6 @@
 			// VTFD has to be created afresh with a new entity ID that has the same entity ID as the MBPCD ME for every
 			// new vlan associated with a different TP.
 			vtfdFilterList[0] = uint16(oFsm.actualUniVlanConfigRule.SetVid)
-			oFsm.mutexFlowParams.Unlock()
 
 			oFsm.numVlanFilterEntries++
 			meParams := me.ParamData{
@@ -1071,6 +1076,7 @@
 			//  (relevant to all used sendXX() methods in this (and other) FSM's)
 			oFsm.pLastTxMeInstance = meInstance
 		}
+		oFsm.mutexFlowParams.Unlock()
 		//verify response
 		err := oFsm.waitforOmciResponse(ctx)
 		if err != nil {
@@ -1084,18 +1090,25 @@
 			return
 		}
 	}
+	oFsm.mutexFlowParams.Lock()
 	oFsm.requestEventOffset = uint8(cDeviceEventOffsetAddWithKvStore) //0 offset for last flow-add activity
+	oFsm.mutexFlowParams.Unlock()
 	go func() {
+		oFsm.mutexFlowParams.RLock()
 		tpID := oFsm.actualUniVlanConfigRule.TpID
-		errEvto := oFsm.performConfigEvtocdEntries(ctx, oFsm.configuredUniFlow)
+		configuredUniFlow := oFsm.configuredUniFlow
+		oFsm.mutexFlowParams.RUnlock()
+		errEvto := oFsm.performConfigEvtocdEntries(ctx, configuredUniFlow)
 		//This is correct passing scenario
 		if errEvto == nil {
 			//TODO Possibly insert new state for multicast --> possibly another jira/later time.
 			for _, gemPort := range oFsm.pUniTechProf.getMulticastGemPorts(ctx, oFsm.pOnuUniPort.uniID, uint8(tpID)) {
+				oFsm.mutexFlowParams.RLock()
 				vlanID := oFsm.actualUniVlanConfigRule.SetVid
 				logger.Infow(ctx, "Setting multicast MEs for additional flows", log.Fields{"deviceID": oFsm.deviceID,
 					"techProfile": tpID, "gemPort": gemPort,
 					"vlanID": vlanID, "configuredUniFlow": oFsm.configuredUniFlow})
+				oFsm.mutexFlowParams.RUnlock()
 				errCreateAllMulticastME := oFsm.performSettingMulticastME(ctx, tpID, gemPort, vlanID)
 				if errCreateAllMulticastME != nil {
 					logger.Errorw(ctx, "Multicast ME create failed, aborting AniConfig FSM!",
@@ -1206,6 +1219,7 @@
 				}
 			}
 
+			oFsm.mutexFlowParams.Lock()
 			if loVlanEntryClear == 1 {
 				oFsm.vlanFilterList[0] = 0 //first entry is the only that can contain the previous only-one element
 				oFsm.numVlanFilterEntries = 0
@@ -1217,6 +1231,7 @@
 				}
 				oFsm.numVlanFilterEntries--
 			}
+			oFsm.mutexFlowParams.Unlock()
 		}
 	}
 
diff --git a/internal/pkg/onuadaptercore/onu_device_entry.go b/internal/pkg/onuadaptercore/onu_device_entry.go
index 301a973..25ffaa3 100644
--- a/internal/pkg/onuadaptercore/onu_device_entry.go
+++ b/internal/pkg/onuadaptercore/onu_device_entry.go
@@ -199,6 +199,14 @@
 	firstSwImageMeID  = 0
 	secondSwImageMeID = 1
 )
+const ( //definitions as per G.988 softwareImage::IsCommitted
+	swIsUncommitted = 0
+	swIsCommitted   = 1
+)
+const ( //definitions as per G.988 softwareImage::IsActive
+	//swIsInactive = 0  not yet used
+	swIsActive = 1
+)
 const onuDataMeID = 0
 const onugMeID = 0
 const onu2gMeID = 0
@@ -209,9 +217,15 @@
 const cEmptyMacAddrString = "000000000000"
 const cEmptySerialNumberString = "0000000000000000"
 
-type swImages struct {
-	version  string
-	isActive uint8
+type sEntrySwImageIndication struct {
+	valid       bool
+	entityID    uint16
+	version     string
+	isCommitted uint8
+}
+type sSwImageIndications struct {
+	activeEntityEntry   sEntrySwImageIndication
+	inactiveEntityEntry sEntrySwImageIndication
 }
 
 type uniPersConfig struct {
@@ -255,7 +269,7 @@
 	vendorID              string
 	serialNumber          string
 	equipmentID           string
-	swImages              [secondSwImageMeID + 1]swImages
+	onuSwImageIndications sSwImageIndications
 	activeSwVersion       string
 	macAddress            string
 	//lockDeviceEntries           sync.RWMutex
@@ -448,7 +462,7 @@
 	)
 	if onuDeviceEntry.pMibDownloadFsm == nil || onuDeviceEntry.pMibDownloadFsm.pFsm == nil {
 		logger.Errorw(ctx, "MibDownloadFsm could not be instantiated", log.Fields{"device-id": dh.deviceID})
-		// TODO some specifc error treatment - or waiting for crash ?
+		// TODO some specific error treatment - or waiting for crash ?
 	}
 
 	onuDeviceEntry.mibTemplateKVStore = onuDeviceEntry.baseDeviceHandler.setBackend(ctx, cBasePathMibTemplateKvStore)
diff --git a/internal/pkg/onuadaptercore/openonu.go b/internal/pkg/onuadaptercore/openonu.go
index e129c6f..357219b 100644
--- a/internal/pkg/onuadaptercore/openonu.go
+++ b/internal/pkg/onuadaptercore/openonu.go
@@ -362,7 +362,7 @@
 func (oo *OpenONUAC) Reboot_device(ctx context.Context, device *voltha.Device) error {
 	logger.Infow(ctx, "reboot-device", log.Fields{"device-id": device.Id})
 	if handler := oo.getDeviceHandler(ctx, device.Id, false); handler != nil {
-		go handler.rebootDevice(ctx, device)
+		go handler.rebootDevice(ctx, true, device) //reboot request with device checking
 		return nil
 	}
 	logger.Warnw(ctx, "no handler found for device-reboot", log.Fields{"device-id": device.Id})
@@ -455,16 +455,19 @@
 //Download_image requests downloading some image according to indications as given in request
 //The ImageDownload needs to be called `request`due to library reflection requirements
 func (oo *OpenONUAC) Download_image(ctx context.Context, device *voltha.Device, request *voltha.ImageDownload) (*voltha.ImageDownload, error) {
-	if !oo.pDownloadManager.imageExists(ctx, request) {
-		logger.Debugw(ctx, "start image download", log.Fields{"image-description": request})
-		// Download_image is not supposed to be blocking, anyway let's call the DownloadManager still synchronously to detect 'fast' problems
-		// the download itself is later done in background
-		err := oo.pDownloadManager.startDownload(ctx, request)
-		return request, err
+	if request != nil && (*request).Name != "" {
+		if !oo.pDownloadManager.imageExists(ctx, request) {
+			logger.Debugw(ctx, "start image download", log.Fields{"image-description": request})
+			// Download_image is not supposed to be blocking, anyway let's call the DownloadManager still synchronously to detect 'fast' problems
+			// the download itself is later done in background
+			err := oo.pDownloadManager.startDownload(ctx, request)
+			return request, err
+		}
+		// image already exists
+		logger.Debugw(ctx, "image already downloaded", log.Fields{"image-description": request})
+		return request, nil
 	}
-	// image already exists
-	logger.Debugw(ctx, "image already downloaded", log.Fields{"image-description": request})
-	return request, nil
+	return request, errors.New("invalid image definition")
 }
 
 //Get_image_download_status unimplemented
@@ -483,18 +486,21 @@
 //  according to indications as given in request and on success activate the image on the ONU
 //The ImageDownload needs to be called `request`due to library reflection requirements
 func (oo *OpenONUAC) Activate_image_update(ctx context.Context, device *voltha.Device, request *voltha.ImageDownload) (*voltha.ImageDownload, error) {
-	if oo.pDownloadManager.imageLocallyDownloaded(ctx, request) {
-		if handler := oo.getDeviceHandler(ctx, device.Id, false); handler != nil {
-			logger.Debugw(ctx, "image download on omci requested", log.Fields{
-				"image-description": request, "device-id": device.Id})
-			err := handler.doOnuSwUpgrade(ctx, request, oo.pDownloadManager)
-			return request, err
+	if request != nil && (*request).Name != "" {
+		if oo.pDownloadManager.imageLocallyDownloaded(ctx, request) {
+			if handler := oo.getDeviceHandler(ctx, device.Id, false); handler != nil {
+				logger.Debugw(ctx, "image download on omci requested", log.Fields{
+					"image-description": request, "device-id": device.Id})
+				err := handler.doOnuSwUpgrade(ctx, request, oo.pDownloadManager)
+				return request, err
+			}
+			logger.Warnw(ctx, "no handler found for image activation", log.Fields{"device-id": device.Id})
+			return request, fmt.Errorf(fmt.Sprintf("handler-not-found - device-id: %s", device.Id))
 		}
-		logger.Warnw(ctx, "no handler found for image activation", log.Fields{"device-id": device.Id})
-		return request, fmt.Errorf(fmt.Sprintf("handler-not-found - device-id: %s", device.Id))
+		logger.Debugw(ctx, "image not yet downloaded on activate request", log.Fields{"image-description": request})
+		return request, fmt.Errorf(fmt.Sprintf("image-not-yet-downloaded - device-id: %s", device.Id))
 	}
-	logger.Debugw(ctx, "image not yet downloaded on activate request", log.Fields{"image-description": request})
-	return request, fmt.Errorf(fmt.Sprintf("image-not-yet-downloaded - device-id: %s", device.Id))
+	return request, errors.New("invalid image definition")
 }
 
 //Revert_image_update unimplemented
diff --git a/vendor/github.com/opencord/omci-lib-go/VERSION b/vendor/github.com/opencord/omci-lib-go/VERSION
index 4312e0d..9f40a87 100644
--- a/vendor/github.com/opencord/omci-lib-go/VERSION
+++ b/vendor/github.com/opencord/omci-lib-go/VERSION
@@ -1 +1 @@
-0.15.2
+0.15.4
\ No newline at end of file
diff --git a/vendor/github.com/opencord/omci-lib-go/messagetypes.go b/vendor/github.com/opencord/omci-lib-go/messagetypes.go
index c237e72..6776b06 100644
--- a/vendor/github.com/opencord/omci-lib-go/messagetypes.go
+++ b/vendor/github.com/opencord/omci-lib-go/messagetypes.go
@@ -2285,13 +2285,13 @@
 	if err != nil {
 		return err
 	}
-	bytes[0] = omci.SectionNumber
 	if omci.Result > me.DeviceBusy {
 		msg := fmt.Sprintf("invalid results for Download Section response: %v, must be 0..6",
 			omci.Result)
 		return errors.New(msg)
 	}
-	bytes[1] = byte(omci.Result)
+	bytes[0] = byte(omci.Result)
+	bytes[1] = omci.SectionNumber
 	return nil
 }
 
@@ -2332,7 +2332,7 @@
 	}
 	omci.CRC32 = binary.BigEndian.Uint32(data[4:8])
 	omci.ImageSize = binary.BigEndian.Uint32(data[8:12])
-	omci.NumberOfInstances = data[13]
+	omci.NumberOfInstances = data[12]
 
 	if omci.NumberOfInstances < 1 || omci.NumberOfInstances > 9 {
 		return me.NewProcessingError(fmt.Sprintf("invalid number of Instances: %v, must be 1..9",
@@ -2341,7 +2341,7 @@
 	omci.ImageInstances = make([]uint16, omci.NumberOfInstances)
 
 	for index := 0; index < int(omci.NumberOfInstances); index++ {
-		omci.ImageInstances[index] = binary.BigEndian.Uint16(data[14+(index*2):])
+		omci.ImageInstances[index] = binary.BigEndian.Uint16(data[13+(index*2):])
 	}
 	return nil
 }
@@ -2380,11 +2380,11 @@
 	if err != nil {
 		return err
 	}
-	binary.BigEndian.PutUint32(bytes[4:8], omci.CRC32)
-	binary.BigEndian.PutUint32(bytes[8:12], omci.ImageSize)
-	bytes[13] = omci.NumberOfInstances
+	binary.BigEndian.PutUint32(bytes[0:4], omci.CRC32)
+	binary.BigEndian.PutUint32(bytes[4:8], omci.ImageSize)
+	bytes[8] = omci.NumberOfInstances
 	for index := 0; index < int(omci.NumberOfInstances); index++ {
-		binary.BigEndian.PutUint16(bytes[14+(index*2):], omci.ImageInstances[index])
+		binary.BigEndian.PutUint16(bytes[9+(index*2):], omci.ImageInstances[index])
 	}
 	return nil
 }
@@ -2478,7 +2478,7 @@
 	if omci.EntityClass != me.SoftwareImageClassID {
 		return me.NewProcessingError("invalid Entity Class for End Download response")
 	}
-	bytes, err := b.AppendBytes(3 + (3 * int(omci.NumberOfInstances)))
+	bytes, err := b.AppendBytes(2 + (3 * int(omci.NumberOfInstances)))
 	if err != nil {
 		return err
 	}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 4da7c41..0ebb307 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -55,7 +55,7 @@
 github.com/jcmturner/gofork/x/crypto/pbkdf2
 # github.com/looplab/fsm v0.1.0
 github.com/looplab/fsm
-# github.com/opencord/omci-lib-go v0.15.2
+# github.com/opencord/omci-lib-go v0.15.4
 github.com/opencord/omci-lib-go
 github.com/opencord/omci-lib-go/generated
 # github.com/opencord/voltha-lib-go/v4 v4.0.10