[VOL-4680] BBSIM: OMCI extended message set - support SW upgrade

Change-Id: Ic2caaefaf9eb4665e71e3f9d1f458d2232cfaf39
diff --git a/VERSION b/VERSION
index 42e8e16..166a50f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.12.9-dev
+1.12.9
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 643bbba..1e7169c 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -121,8 +121,8 @@
 
 	// OMCI params
 	MibDataSync                   uint8
-	ImageSoftwareExpectedSections int
-	ImageSoftwareReceivedSections int
+	ImageSoftwareExpectedSections uint32
+	ImageSoftwareReceivedSections uint32
 	ActiveImageEntityId           uint16
 	CommittedImageEntityId        uint16
 	StandbyImageVersion           string
diff --git a/internal/bbsim/devices/onu_omci_test.go b/internal/bbsim/devices/onu_omci_test.go
index b6db6b7..906303c 100644
--- a/internal/bbsim/devices/onu_omci_test.go
+++ b/internal/bbsim/devices/onu_omci_test.go
@@ -392,7 +392,7 @@
 	msg := makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 0, uint32(imageCrc)))
 	res := onu.handleEndSoftwareDownloadRequest(msg)
 	assert.Equal(t, res, true)
-	assert.Equal(t, onu.ImageSoftwareReceivedSections, 0)
+	assert.Equal(t, onu.ImageSoftwareReceivedSections, uint32(0))
 
 	// test EndSoftwareDownloadRequest if we received less sections than expected
 	onu.ImageSoftwareExpectedSections = 2
diff --git a/internal/common/omci/image.go b/internal/common/omci/image.go
index f2733cd..98e67ea 100644
--- a/internal/common/omci/image.go
+++ b/internal/common/omci/image.go
@@ -19,12 +19,17 @@
 import (
 	"encoding/hex"
 	"errors"
+	"strconv"
+
 	"github.com/google/gopacket"
 	"github.com/opencord/omci-lib-go/v2"
 	me "github.com/opencord/omci-lib-go/v2/generated"
 	log "github.com/sirupsen/logrus"
-	"math"
-	"strconv"
+)
+
+const (
+	cOmciDownloadSectionSizeBaseLine = 31   //in bytes
+	cOmciDownloadSectionSizeExtLine  = 1965 //in bytes
 )
 
 func ParseStartSoftwareDownloadRequest(omciPkt gopacket.Packet) (*omci.StartSoftwareDownloadRequest, error) {
@@ -108,15 +113,20 @@
 }
 
 func CreateStartSoftwareDownloadResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI) ([]byte, error) {
+
 	responeCode := me.Success
 	msgObj, err := ParseStartSoftwareDownloadRequest(omciPkt)
 	if err != nil {
 		responeCode = me.ProcessingError
 	}
-
+	isExtended := false
+	if omciMsg.DeviceIdentifier == omci.ExtendedIdent {
+		isExtended = true
+	}
 	omciLogger.WithFields(log.Fields{
 		"OmciMsgType":          omciMsg.MessageType,
 		"TransCorrId":          omciMsg.TransactionID,
+		"DeviceIdentifier":     omciMsg.DeviceIdentifier,
 		"EntityInstance":       msgObj.EntityInstance,
 		"WindowSize":           msgObj.WindowSize,
 		"ImageSize":            msgObj.ImageSize,
@@ -128,20 +138,31 @@
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass:    msgObj.EntityClass,
 			EntityInstance: msgObj.EntityInstance,
+			Extended:       isExtended,
 		},
 		WindowSize:        msgObj.WindowSize,
 		Result:            responeCode,
 		NumberOfInstances: 0,                        // NOTE this can't be bigger than 0 this we can populate downloadResults
 		MeResults:         []omci.DownloadResults{}, // FIXME downloadResults is not exported
 	}
+	omciLayer := &omci.OMCI{
+		TransactionID:    omciMsg.TransactionID,
+		MessageType:      omci.StartSoftwareDownloadResponseType,
+		DeviceIdentifier: omciMsg.DeviceIdentifier,
+	}
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
 
-	pkt, err := Serialize(omci.StartSoftwareDownloadResponseType, response, omciMsg.TransactionID)
+	buffer := gopacket.NewSerializeBuffer()
+	err = gopacket.SerializeLayers(buffer, options, omciLayer, response)
 	if err != nil {
 		omciLogger.WithFields(log.Fields{
-			"Err": err,
-		}).Error("cannot-Serialize-CreateResponse")
+			"Err":  err,
+			"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		}).Error("cannot-Serialize-StartSoftwareDownloadResponse")
 		return nil, err
 	}
+	pkt := buffer.Bytes()
 
 	log.WithFields(log.Fields{
 		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
@@ -158,27 +179,45 @@
 	if err != nil {
 		return nil, err
 	}
-
+	isExtended := false
+	if omciMsg.DeviceIdentifier == omci.ExtendedIdent {
+		isExtended = true
+	}
 	omciLogger.WithFields(log.Fields{
-		"OmciMsgType":    omciMsg.MessageType,
-		"TransCorrId":    omciMsg.TransactionID,
-		"EntityInstance": msgObj.EntityInstance,
-		"SectionNumber":  msgObj.SectionNumber,
+		"OmciMsgType":      omciMsg.MessageType,
+		"TransCorrId":      omciMsg.TransactionID,
+		"DeviceIdentifier": omciMsg.DeviceIdentifier,
+		"EntityInstance":   msgObj.EntityInstance,
+		"SectionNumber":    msgObj.SectionNumber,
 	}).Debug("received-download-section-request")
 
 	response := &omci.DownloadSectionResponse{
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass:    msgObj.EntityClass,
 			EntityInstance: msgObj.EntityInstance,
+			Extended:       isExtended,
 		},
 		Result:        me.Success,
 		SectionNumber: msgObj.SectionNumber,
 	}
+	omciLayer := &omci.OMCI{
+		TransactionID:    omciMsg.TransactionID,
+		MessageType:      omci.DownloadSectionResponseType,
+		DeviceIdentifier: omciMsg.DeviceIdentifier,
+	}
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
 
-	pkt, err := Serialize(omci.DownloadSectionResponseType, response, omciMsg.TransactionID)
+	buffer := gopacket.NewSerializeBuffer()
+	err = gopacket.SerializeLayers(buffer, options, omciLayer, response)
 	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err":  err,
+			"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		}).Error("cannot-Serialize-DownloadSectionResponse")
 		return nil, err
 	}
+	pkt := buffer.Bytes()
 
 	log.WithFields(log.Fields{
 		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
@@ -195,10 +234,14 @@
 	if err != nil {
 		return nil, err
 	}
-
+	isExtended := false
+	if omciMsg.DeviceIdentifier == omci.ExtendedIdent {
+		isExtended = true
+	}
 	omciLogger.WithFields(log.Fields{
 		"OmciMsgType":       omciMsg.MessageType,
 		"TransCorrId":       omciMsg.TransactionID,
+		"DeviceIdentifier":  omciMsg.DeviceIdentifier,
 		"EntityInstance":    msgObj.EntityInstance,
 		"Crc32":             msgObj.CRC32,
 		"ImageSize":         msgObj.ImageSize,
@@ -210,16 +253,30 @@
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass:    msgObj.EntityClass,
 			EntityInstance: msgObj.EntityInstance,
+			Extended:       isExtended,
 		},
 		Result:            status,
 		NumberOfInstances: 0, // NOTE this can't be bigger than 0 this we can populate downloadResults
 		//MeResults: []omci.downloadResults{}, // FIXME downloadResults is not exported
 	}
+	omciLayer := &omci.OMCI{
+		TransactionID:    omciMsg.TransactionID,
+		MessageType:      omci.EndSoftwareDownloadResponseType,
+		DeviceIdentifier: omciMsg.DeviceIdentifier,
+	}
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
 
-	pkt, err := Serialize(omci.EndSoftwareDownloadResponseType, response, omciMsg.TransactionID)
+	buffer := gopacket.NewSerializeBuffer()
+	err = gopacket.SerializeLayers(buffer, options, omciLayer, response)
 	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err":  err,
+			"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		}).Error("cannot-Serialize-EndSoftwareDownloadResponse")
 		return nil, err
 	}
+	pkt := buffer.Bytes()
 
 	log.WithFields(log.Fields{
 		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
@@ -236,26 +293,44 @@
 	if err != nil {
 		return nil, err
 	}
-
+	isExtended := false
+	if omciMsg.DeviceIdentifier == omci.ExtendedIdent {
+		isExtended = true
+	}
 	omciLogger.WithFields(log.Fields{
-		"OmciMsgType":    omciMsg.MessageType,
-		"TransCorrId":    omciMsg.TransactionID,
-		"EntityInstance": msgObj.EntityInstance,
-		"ActivateFlags":  msgObj.ActivateFlags,
+		"OmciMsgType":      omciMsg.MessageType,
+		"TransCorrId":      omciMsg.TransactionID,
+		"DeviceIdentifier": omciMsg.DeviceIdentifier,
+		"EntityInstance":   msgObj.EntityInstance,
+		"ActivateFlags":    msgObj.ActivateFlags,
 	}).Debug("received-activate-software-request")
 
 	response := &omci.ActivateSoftwareResponse{
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass:    msgObj.EntityClass,
 			EntityInstance: msgObj.EntityInstance,
+			Extended:       isExtended,
 		},
 		Result: me.Success,
 	}
+	omciLayer := &omci.OMCI{
+		TransactionID:    omciMsg.TransactionID,
+		MessageType:      omci.ActivateSoftwareResponseType,
+		DeviceIdentifier: omciMsg.DeviceIdentifier,
+	}
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
 
-	pkt, err := Serialize(omci.ActivateSoftwareResponseType, response, omciMsg.TransactionID)
+	buffer := gopacket.NewSerializeBuffer()
+	err = gopacket.SerializeLayers(buffer, options, omciLayer, response)
 	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err":  err,
+			"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		}).Error("cannot-Serialize-ActivateSoftwareResponse")
 		return nil, err
 	}
+	pkt := buffer.Bytes()
 
 	log.WithFields(log.Fields{
 		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
@@ -272,24 +347,42 @@
 	if err != nil {
 		return nil, err
 	}
-
+	isExtended := false
+	if omciMsg.DeviceIdentifier == omci.ExtendedIdent {
+		isExtended = true
+	}
 	omciLogger.WithFields(log.Fields{
-		"OmciMsgType":    omciMsg.MessageType,
-		"TransCorrId":    omciMsg.TransactionID,
-		"EntityInstance": msgObj.EntityInstance,
+		"OmciMsgType":      omciMsg.MessageType,
+		"TransCorrId":      omciMsg.TransactionID,
+		"DeviceIdentifier": omciMsg.DeviceIdentifier,
+		"EntityInstance":   msgObj.EntityInstance,
 	}).Debug("received-commit-software-request")
 
 	response := &omci.CommitSoftwareResponse{
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass:    msgObj.EntityClass,
 			EntityInstance: msgObj.EntityInstance,
+			Extended:       isExtended,
 		},
 	}
+	omciLayer := &omci.OMCI{
+		TransactionID:    omciMsg.TransactionID,
+		MessageType:      omci.CommitSoftwareResponseType,
+		DeviceIdentifier: omciMsg.DeviceIdentifier,
+	}
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
 
-	pkt, err := Serialize(omci.CommitSoftwareResponseType, response, omciMsg.TransactionID)
+	buffer := gopacket.NewSerializeBuffer()
+	err = gopacket.SerializeLayers(buffer, options, omciLayer, response)
 	if err != nil {
+		omciLogger.WithFields(log.Fields{
+			"Err":  err,
+			"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		}).Error("cannot-Serialize-CommitSoftwareResponse")
 		return nil, err
 	}
+	pkt := buffer.Bytes()
 
 	log.WithFields(log.Fields{
 		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
@@ -299,11 +392,20 @@
 	return pkt, nil
 }
 
-func ComputeDownloadSectionsCount(pkt gopacket.Packet) int {
+func ComputeDownloadSectionsCount(pkt gopacket.Packet) uint32 {
 	msgObj, err := ParseStartSoftwareDownloadRequest(pkt)
 	if err != nil {
 		omciLogger.Error("cannot-parse-start-software-download-request")
 	}
-
-	return int(math.Ceil(float64(msgObj.ImageSize) / float64(msgObj.WindowSize)))
+	var omciDownloadSectionSize uint32
+	if msgObj.Extended {
+		omciDownloadSectionSize = cOmciDownloadSectionSizeExtLine
+	} else {
+		omciDownloadSectionSize = cOmciDownloadSectionSizeBaseLine
+	}
+	noOfSections := msgObj.ImageSize / omciDownloadSectionSize
+	if msgObj.ImageSize%omciDownloadSectionSize > 0 {
+		noOfSections++
+	}
+	return noOfSections
 }
diff --git a/internal/common/omci/image_test.go b/internal/common/omci/image_test.go
index b099675..d07ad51 100644
--- a/internal/common/omci/image_test.go
+++ b/internal/common/omci/image_test.go
@@ -17,11 +17,12 @@
 package omci
 
 import (
+	"testing"
+
 	"github.com/google/gopacket"
 	"github.com/opencord/omci-lib-go/v2"
 	me "github.com/opencord/omci-lib-go/v2/generated"
 	"gotest.tools/assert"
-	"testing"
 )
 
 func omciToStartSoftwareDownloadResponse(t *testing.T, omciPkt *gopacket.Packet) *omci.StartSoftwareDownloadResponse {
@@ -89,5 +90,5 @@
 	pkt, _, _ := ParseOpenOltOmciPacket(omciReqPkt)
 
 	count := ComputeDownloadSectionsCount(pkt)
-	assert.Equal(t, count, 1058)
+	assert.Equal(t, count, uint32(1058))
 }