[VOL-4679] BBSIM: OMCI extended message set - support MIB upload

Change-Id: I291524f9d33194fb54c508e2344e53dd47370a8f
diff --git a/VERSION b/VERSION
index 41c8a73..ff3d4cc 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.12.7
+1.12.8-dev
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index bbed5d6..643bbba 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -825,9 +825,9 @@
 			o.PonPort.removeGemPortBySn(o.SerialNumber)
 		}
 	case omci.MibUploadRequestType:
-		responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
+		responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg, o.MibDb)
 	case omci.MibUploadNextRequestType:
-		responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
+		responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDb)
 	case omci.GetRequestType:
 		onuDown := o.AdminLockState == 1
 		responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId,
@@ -1655,7 +1655,7 @@
 		o.seqNumber++
 		// once the mibUpload is complete send a SetRequest for the PPTP to enable the UNI
 		// NOTE that in BBR we only enable the first UNI
-		if o.seqNumber == o.MibDb.NumberOfCommands {
+		if o.seqNumber == o.MibDb.NumberOfBaselineCommands {
 			meId := omcilib.GenerateUniPortEntityId(1)
 
 			meParams := me.ParamData{
diff --git a/internal/common/omci/mib_test.go b/internal/common/omci/mib_test.go
index 2214f2e..376e583 100644
--- a/internal/common/omci/mib_test.go
+++ b/internal/common/omci/mib_test.go
@@ -27,10 +27,6 @@
 	"gotest.tools/assert"
 )
 
-// used to verify that the first message in the MIB Sync (OnuData)
-// reports the correct MDS
-const MDS = uint8(128)
-
 func TestCreateMibResetResponse(t *testing.T) {
 	data, _ := CreateMibResetResponse(1)
 
@@ -96,18 +92,18 @@
 	// we return the corresponding entry
 	// the only exception is for OnuData in which we need to replace the MibDataSync attribute with the current value
 	mibDb := MibDb{
-		NumberOfCommands: 4,
-		items:            []MibDbEntry{},
+		NumberOfBaselineCommands: 4,
+		baselineItems:            []MibDbEntry{},
 	}
 
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.OnuDataClassID,
 		onuDataEntityId,
 		me.AttributeValueMap{me.OnuData_MibDataSync: 0},
 		nil,
 	})
 
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.CircuitPackClassID,
 		circuitPackEntityID,
 		me.AttributeValueMap{
@@ -119,7 +115,7 @@
 		nil,
 	})
 
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.AniGClassID,
 		anigEntityId,
 		me.AttributeValueMap{
@@ -143,7 +139,7 @@
 		nil,
 	})
 
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.Onu2GClassID,
 		onu2gEntityId,
 		me.AttributeValueMap{
@@ -163,7 +159,7 @@
 	// create an entry with UnkownAttributes set
 	var customPktTxId uint16 = 5
 	customPkt := []byte{0, byte(customPktTxId), 46, 10, 0, 2, 0, 0, 0, 37, 0, 1, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 40, 40, 206, 0, 226}
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.ClassID(37),
 		nil,
 		me.AttributeValueMap{},
@@ -176,7 +172,7 @@
 		want mibExpected
 	}{
 		{"mibUploadNext-0", createTestMibUploadNextArgs(t, 1, 0),
-			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 1, entityID: onuDataEntityId.ToUint16(), entityClass: me.OnuDataClassID, attributes: map[string]interface{}{me.OnuData_MibDataSync: MDS}}},
+			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 1, entityID: onuDataEntityId.ToUint16(), entityClass: me.OnuDataClassID, attributes: map[string]interface{}{me.OnuData_MibDataSync: uint8(0)}}},
 		{"mibUploadNext-1", createTestMibUploadNextArgs(t, 2, 1),
 			mibExpected{messageType: omci.MibUploadNextResponseType, transactionId: 2, entityID: circuitPackEntityID.ToUint16(), entityClass: me.CircuitPackClassID, attributes: map[string]interface{}{me.CircuitPack_Type: uint8(47), me.CircuitPack_NumberOfPorts: uint8(4)}}},
 		{"mibUploadNext-2", createTestMibUploadNextArgs(t, 3, 2),
@@ -191,7 +187,7 @@
 		t.Run(tt.name, func(t *testing.T) {
 
 			// create the packet starting from the mibUploadNextRequest
-			data, err := CreateMibUploadNextResponse(tt.args.omciPkt, tt.args.omciMsg, MDS, &mibDb)
+			data, err := CreateMibUploadNextResponse(tt.args.omciPkt, tt.args.omciMsg, &mibDb)
 			assert.NilError(t, err)
 			omciMsg, omciPkt := omciBytesToMsg(t, data)
 
@@ -225,7 +221,7 @@
 
 	// now try to get a non existing command from the DB anche expect an error
 	args := createTestMibUploadNextArgs(t, 1, 20)
-	_, err := CreateMibUploadNextResponse(args.omciPkt, args.omciMsg, MDS, &mibDb)
+	_, err := CreateMibUploadNextResponse(args.omciPkt, args.omciMsg, &mibDb)
 	assert.Error(t, err, "mibdb-does-not-contain-item")
 }
 
diff --git a/internal/common/omci/mibpackets.go b/internal/common/omci/mibpackets.go
index d22908d..a374371 100755
--- a/internal/common/omci/mibpackets.go
+++ b/internal/common/omci/mibpackets.go
@@ -18,8 +18,11 @@
 
 import (
 	"encoding/binary"
+	"encoding/hex"
 	"errors"
 	"fmt"
+	"strconv"
+
 	"github.com/google/gopacket"
 	"github.com/opencord/omci-lib-go/v2"
 	me "github.com/opencord/omci-lib-go/v2/generated"
@@ -109,23 +112,48 @@
 	return HexEncode(pkt)
 }
 
-func CreateMibUploadResponse(tid uint16, numberOfCommands uint16) ([]byte, error) {
-	request := &omci.MibUploadResponse{
+func CreateMibUploadResponse(omciMsg *omci.OMCI, mibDb *MibDb) ([]byte, error) {
+
+	isExtended := false
+	numberOfCommands := mibDb.NumberOfBaselineCommands
+	if omciMsg.DeviceIdentifier == omci.ExtendedIdent {
+		isExtended = true
+		numberOfCommands = mibDb.NumberOfExtendedCommands
+	}
+	response := &omci.MibUploadResponse{
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass: me.OnuDataClassID,
+			Extended:    isExtended,
 		},
 		NumberOfCommands: numberOfCommands,
 	}
+	omciLogger.WithFields(log.Fields{
+		"NumberOfCommands": numberOfCommands, "isExtended": isExtended}).Debug("mib-upload-response")
 
-	omciLogger.WithFields(log.Fields{"NumberOfCommands": numberOfCommands}).Debug("mib-upload-response")
+	omciLayer := &omci.OMCI{
+		TransactionID:    omciMsg.TransactionID,
+		MessageType:      omci.MibUploadResponseType,
+		DeviceIdentifier: omciMsg.DeviceIdentifier,
+	}
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
 
-	pkt, err := Serialize(omci.MibUploadResponseType, request, tid)
+	buffer := gopacket.NewSerializeBuffer()
+	err := gopacket.SerializeLayers(buffer, options, omciLayer, response)
 	if err != nil {
 		omciLogger.WithFields(log.Fields{
-			"Err": err,
-		}).Error("Cannot Serialize MibUploadResponse")
+			"Err":  err,
+			"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		}).Error("cannot-Serialize-MibUploadResponse")
 		return nil, err
 	}
+	pkt := buffer.Bytes()
+
+	log.WithFields(log.Fields{
+		"TxID": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
+		"pkt":  hex.EncodeToString(pkt),
+	}).Trace("omci-mib-upload-response")
+
 	return pkt, nil
 }
 
@@ -165,7 +193,7 @@
 	return msgObj, nil
 }
 
-func CreateMibUploadNextResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI, mds uint8, mibDb *MibDb) ([]byte, error) {
+func CreateMibUploadNextResponse(omciPkt gopacket.Packet, omciMsg *omci.OMCI, mibDb *MibDb) ([]byte, error) {
 
 	msgObj, err := ParseMibUploadNextRequest(omciPkt)
 	if err != nil {
@@ -180,65 +208,67 @@
 		"CommandSequenceNumber": msgObj.CommandSequenceNumber,
 	}).Trace("received-omci-mibUploadNext-request")
 
-	if msgObj.CommandSequenceNumber > mibDb.NumberOfCommands {
+	isExtended := false
+	numberOfCommands := mibDb.NumberOfBaselineCommands
+	if omciMsg.DeviceIdentifier == omci.ExtendedIdent {
+		isExtended = true
+		numberOfCommands = mibDb.NumberOfExtendedCommands
+	}
+	if msgObj.CommandSequenceNumber > numberOfCommands {
 		omciLogger.WithFields(log.Fields{
 			"CommandSequenceNumber": msgObj.CommandSequenceNumber,
-			"MibDbNumberOfCommands": mibDb.NumberOfCommands,
+			"MibDbNumberOfCommands": numberOfCommands,
 		}).Error("mibdb-does-not-contain-item")
 		return nil, fmt.Errorf("mibdb-does-not-contain-item")
 	}
-	currentEntry := mibDb.items[int(msgObj.CommandSequenceNumber)]
+	if isExtended {
+		pkt := SetTxIdInEncodedPacket(mibDb.extendedResponses[int(msgObj.CommandSequenceNumber)], omciMsg.TransactionID)
+		return pkt, nil
+	} else {
+		currentEntry := mibDb.baselineItems[int(msgObj.CommandSequenceNumber)]
 
-	// if packet is set then we don't need to serialize the packet, it's already done
-	if currentEntry.packet != nil {
+		// if packet is set then we don't need to serialize the packet, it's already done
+		if currentEntry.packet != nil {
+			omciLogger.WithFields(log.Fields{
+				"CommandSequenceNumber": msgObj.CommandSequenceNumber,
+				"MibDbNumberOfCommands": numberOfCommands,
+				"packet":                currentEntry.packet,
+				"request-txid":          omciMsg.TransactionID,
+			}).Info("sending-custom-packet")
+
+			// NOTE we need to replace the first two bytes of the packet with the correct transactionId
+			pkt := SetTxIdInEncodedPacket(currentEntry.packet, omciMsg.TransactionID)
+
+			return pkt, nil
+		}
+		reportedMe, meErr := me.LoadManagedEntityDefinition(currentEntry.classId, me.ParamData{
+			EntityID:   currentEntry.entityId.ToUint16(),
+			Attributes: currentEntry.params,
+		})
+
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("Error while generating %s: %v", currentEntry.classId.String(), meErr.Error())
+		}
+		response := &omci.MibUploadNextResponse{
+			MeBasePacket: omci.MeBasePacket{
+				EntityClass: me.OnuDataClassID,
+			},
+			ReportedME: *reportedMe,
+		}
+
 		omciLogger.WithFields(log.Fields{
-			"CommandSequenceNumber": msgObj.CommandSequenceNumber,
-			"MibDbNumberOfCommands": mibDb.NumberOfCommands,
-			"packet":                currentEntry.packet,
-			"request-txid":          omciMsg.TransactionID,
-		}).Info("sending-custom-packet")
+			"reportedMe": reportedMe,
+		}).Trace("created-omci-mibUploadNext-response")
 
-		// NOTE we need to replace the first two bytes of the packet with the correct transactionId
-		pkt := SetTxIdInEncodedPacket(currentEntry.packet, omciMsg.TransactionID)
+		pkt, err := Serialize(omci.MibUploadNextResponseType, response, omciMsg.TransactionID)
+
+		if err != nil {
+			omciLogger.WithFields(log.Fields{
+				"Err": err,
+			}).Fatalf("Cannot Serialize MibUploadNextRequest")
+			return nil, err
+		}
 
 		return pkt, nil
 	}
-
-	reportedMe, meErr := me.LoadManagedEntityDefinition(currentEntry.classId, me.ParamData{
-		EntityID:   currentEntry.entityId.ToUint16(),
-		Attributes: currentEntry.params,
-	})
-
-	if meErr.GetError() != nil {
-		omciLogger.Errorf("Error while generating %s: %v", currentEntry.classId.String(), meErr.Error())
-	}
-
-	if reportedMe.GetClassID() == me.OnuDataClassID {
-		// if this is ONU-Data we need to replace the MDS
-		if err := reportedMe.SetAttribute("MibDataSync", mds); err.GetError() != nil {
-			omciLogger.Errorf("Error while setting mds in %s: %v", currentEntry.classId.String(), meErr.Error())
-		}
-	}
-
-	response := &omci.MibUploadNextResponse{
-		MeBasePacket: omci.MeBasePacket{
-			EntityClass: me.OnuDataClassID,
-		},
-		ReportedME: *reportedMe,
-	}
-
-	omciLogger.WithFields(log.Fields{
-		"reportedMe": reportedMe,
-	}).Trace("created-omci-mibUploadNext-response")
-
-	pkt, err := Serialize(omci.MibUploadNextResponseType, response, omciMsg.TransactionID)
-
-	if err != nil {
-		omciLogger.WithFields(log.Fields{
-			"Err": err,
-		}).Fatalf("Cannot Serialize MibUploadNextRequest")
-		return nil, err
-	}
-
-	return pkt, nil
 }
diff --git a/internal/common/omci/onu_mib_db.go b/internal/common/omci/onu_mib_db.go
index 08322ca..57ca215 100644
--- a/internal/common/omci/onu_mib_db.go
+++ b/internal/common/omci/onu_mib_db.go
@@ -20,6 +20,9 @@
 	"bytes"
 	"encoding/binary"
 	"encoding/hex"
+	"fmt"
+	"strings"
+
 	"github.com/google/gopacket"
 	"github.com/opencord/bbsim/internal/common"
 	"github.com/opencord/omci-lib-go/v2"
@@ -37,12 +40,23 @@
 }
 
 type MibDb struct {
-	NumberOfCommands uint16
-	items            []MibDbEntry
+	NumberOfBaselineCommands uint16
+	NumberOfExtendedCommands uint16
+	baselineItems            []MibDbEntry
+	extendedResponses        [][]byte
 }
 
 type EntityID []byte
 
+const (
+	unknownMePktReportedMeHdr     string = "002500018000"
+	unknownMePktAttributes        string = "0102030405060708090A0B0C0D0E0F101112131415161718191A"
+	unknownAttribPktReportedMeHdr string = "0101000007FD"
+	unknownAttribPktAttributes    string = "00400801000800000006007F07003F00010001000100"
+	extRespMsgContentsLenStart           = 8
+	extRespMsgContentsLenEnd             = 10
+)
+
 func (e EntityID) ToString() string {
 	return hex.EncodeToString(e)
 }
@@ -102,11 +116,11 @@
 func GenerateMibDatabase(ethUniPortCount int, potsUniPortCount int, technology common.PonTechnology) (*MibDb, error) {
 
 	mibDb := MibDb{
-		items: []MibDbEntry{},
+		baselineItems: []MibDbEntry{},
 	}
 
 	// the first element to return is the ONU-Data
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.OnuDataClassID,
 		EntityID{0x00, 0x00},
 		me.AttributeValueMap{me.OnuData_MibDataSync: 0}, // FIXME this needs to be parametrized before sending the response
@@ -134,7 +148,7 @@
 		aniCPType = gPonUnitType
 	}
 
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.CircuitPackClassID,
 		circuitPackEntityID,
 		me.AttributeValueMap{
@@ -145,7 +159,7 @@
 		},
 		nil,
 	})
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.CircuitPackClassID,
 		circuitPackEntityID,
 		me.AttributeValueMap{
@@ -156,7 +170,7 @@
 		},
 		nil,
 	})
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.CircuitPackClassID,
 		circuitPackEntityID,
 		me.AttributeValueMap{
@@ -168,7 +182,7 @@
 		},
 		nil,
 	})
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.CircuitPackClassID,
 		circuitPackEntityID,
 		me.AttributeValueMap{
@@ -178,7 +192,7 @@
 	})
 
 	// ANI-G
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.AniGClassID,
 		EntityID{tcontSlotId, aniGId},
 		me.AttributeValueMap{
@@ -204,7 +218,7 @@
 
 	// circuitPack Ethernet
 	// NOTE the circuit pack is divided in multiple messages as too big to fit in a single one
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.CircuitPackClassID,
 		circuitPackEntityID,
 		me.AttributeValueMap{
@@ -215,7 +229,7 @@
 		},
 		nil,
 	})
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.CircuitPackClassID,
 		circuitPackEntityID,
 		me.AttributeValueMap{
@@ -226,7 +240,7 @@
 		},
 		nil,
 	})
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.CircuitPackClassID,
 		circuitPackEntityID,
 		me.AttributeValueMap{
@@ -238,7 +252,7 @@
 		},
 		nil,
 	})
-	mibDb.items = append(mibDb.items, MibDbEntry{
+	mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 		me.CircuitPackClassID,
 		circuitPackEntityID,
 		me.AttributeValueMap{
@@ -250,7 +264,7 @@
 	if potsUniPortCount > 0 {
 		// circuitPack POTS
 		// NOTE the circuit pack is divided in multiple messages as too big to fit in a single one
-		mibDb.items = append(mibDb.items, MibDbEntry{
+		mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 			me.CircuitPackClassID,
 			circuitPackEntityID,
 			me.AttributeValueMap{
@@ -261,7 +275,7 @@
 			},
 			nil,
 		})
-		mibDb.items = append(mibDb.items, MibDbEntry{
+		mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 			me.CircuitPackClassID,
 			circuitPackEntityID,
 			me.AttributeValueMap{
@@ -272,7 +286,7 @@
 			},
 			nil,
 		})
-		mibDb.items = append(mibDb.items, MibDbEntry{
+		mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 			me.CircuitPackClassID,
 			circuitPackEntityID,
 			me.AttributeValueMap{
@@ -284,7 +298,7 @@
 			},
 			nil,
 		})
-		mibDb.items = append(mibDb.items, MibDbEntry{
+		mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 			me.CircuitPackClassID,
 			circuitPackEntityID,
 			me.AttributeValueMap{
@@ -303,7 +317,7 @@
 
 		if i <= ethUniPortCount {
 			// first, create the correct amount of ethernet UNIs, the same is done in onu.go
-			mibDb.items = append(mibDb.items, MibDbEntry{
+			mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 				me.PhysicalPathTerminationPointEthernetUniClassID,
 				uniEntityId,
 				me.AttributeValueMap{
@@ -327,7 +341,7 @@
 			})
 		} else {
 			// the remaining ones are pots UNIs, the same is done in onu.go
-			mibDb.items = append(mibDb.items, MibDbEntry{
+			mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 				me.PhysicalPathTerminationPointPotsUniClassID,
 				uniEntityId,
 				me.AttributeValueMap{
@@ -349,7 +363,7 @@
 			})
 		}
 
-		mibDb.items = append(mibDb.items, MibDbEntry{
+		mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 			me.UniGClassID,
 			uniEntityId,
 			me.AttributeValueMap{
@@ -369,7 +383,7 @@
 			queueEntityId := EntityID{cardHolderSlotID, byte(j)}
 
 			// we first report the PriorityQueue without any attribute
-			mibDb.items = append(mibDb.items, MibDbEntry{
+			mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 				me.PriorityQueueClassID,
 				queueEntityId, //was not reported in the original implementation
 				me.AttributeValueMap{},
@@ -379,7 +393,7 @@
 			// then we report it with the required attributes
 			// In the downstream direction, the first byte is the slot number and the second byte is the port number of the queue's destination port.
 			relatedPort := append(uniEntityId, 0x00, byte(j))
-			mibDb.items = append(mibDb.items, MibDbEntry{
+			mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 				me.PriorityQueueClassID,
 				queueEntityId, //was not reported in the original implementation
 				me.AttributeValueMap{
@@ -405,7 +419,7 @@
 	for i := 1; i <= tconts; i++ {
 		tcontEntityId := EntityID{tcontSlotId, byte(i)}
 
-		mibDb.items = append(mibDb.items, MibDbEntry{
+		mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 			me.TContClassID,
 			tcontEntityId,
 			me.AttributeValueMap{
@@ -415,7 +429,7 @@
 		})
 
 		tsEntityId := EntityID{cardHolderSlotID, byte(i)}
-		mibDb.items = append(mibDb.items, MibDbEntry{
+		mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 			me.TrafficSchedulerClassID,
 			tsEntityId, //was not reported in the original implementation
 			me.AttributeValueMap{
@@ -434,7 +448,7 @@
 			// EntityID = tcontSlotId + Uni EntityID (8001)
 
 			// we first report the PriorityQueue without any attribute
-			mibDb.items = append(mibDb.items, MibDbEntry{
+			mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 				me.PriorityQueueClassID,
 				queueEntityId, //was not reported in the original implementation
 				me.AttributeValueMap{},
@@ -444,7 +458,7 @@
 			// then we report it with the required attributes
 			// In the upstream direction, the first 2 bytes are the ME ID of the associated T- CONT, the first byte of which is a slot number, the second byte a T-CONT number.
 			relatedPort := append(tcontEntityId, 0x00, byte(j))
-			mibDb.items = append(mibDb.items, MibDbEntry{
+			mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 				me.PriorityQueueClassID,
 				queueEntityId, //was not reported in the original implementation
 				me.AttributeValueMap{
@@ -500,7 +514,7 @@
 		}
 	}
 
-	mibDb.items = append(mibDb.items, onu2g)
+	mibDb.baselineItems = append(mibDb.baselineItems, onu2g)
 
 	if common.Config.BBSim.InjectOmciUnknownMe {
 		// NOTE the TxID is actually replaced
@@ -515,10 +529,8 @@
 
 		//omciHdr := "00032e0a"
 		msgHdr := "00020000"
-		reportedMeHdr := "002500018000"
-		attr := "0102030405060708090A0B0C0D0E0F101112131415161718191A"
 		trailer := "0000002828ce00e2"
-		msg := omciHdr + msgHdr + reportedMeHdr + attr + trailer
+		msg := omciHdr + msgHdr + unknownMePktReportedMeHdr + unknownMePktAttributes + trailer
 		data, err := hex.DecodeString(msg)
 		if err != nil {
 			omciLogger.Fatal("cannot-create-custom-packet")
@@ -526,7 +538,7 @@
 
 		packet := gopacket.NewPacket(data, omci.LayerTypeOMCI, gopacket.Lazy)
 
-		mibDb.items = append(mibDb.items, MibDbEntry{
+		mibDb.baselineItems = append(mibDb.baselineItems, MibDbEntry{
 			me.ClassID(37), // G.988 "Intentionally left blank"
 			nil,
 			me.AttributeValueMap{},
@@ -534,7 +546,126 @@
 		})
 	}
 
-	mibDb.NumberOfCommands = uint16(len(mibDb.items))
+	mibDb.NumberOfBaselineCommands = uint16(len(mibDb.baselineItems))
 
+	// Create extended MIB upload responses
+	omciLayer := &omci.OMCI{
+		TransactionID:    0xFFFF, //to be replaced later on
+		MessageType:      omci.MibUploadNextResponseType,
+		DeviceIdentifier: omci.ExtendedIdent,
+	}
+	var i uint16 = 0
+	for i < mibDb.NumberOfBaselineCommands {
+		currentEntry := mibDb.baselineItems[i]
+		for mibDb.baselineItems[i].packet != nil {
+			// Skip any entry with a predefined packet currently used for MEs with unknown ClassID or unknown attributes.
+			// This information will be added later to the last extended response packet
+			i++
+			currentEntry = mibDb.baselineItems[i]
+		}
+		reportedME, meErr := me.LoadManagedEntityDefinition(currentEntry.classId, me.ParamData{
+			EntityID:   currentEntry.entityId.ToUint16(),
+			Attributes: currentEntry.params,
+		})
+		if meErr.GetError() != nil {
+			omciLogger.Errorf("Error while generating reportedME %s: %v", currentEntry.classId.String(), meErr.Error())
+		}
+		request := &omci.MibUploadNextResponse{
+			MeBasePacket: omci.MeBasePacket{
+				EntityClass:    me.OnuDataClassID,
+				EntityInstance: uint16(0),
+				Extended:       true,
+			},
+			ReportedME:    *reportedME,
+			AdditionalMEs: make([]me.ManagedEntity, 0),
+		}
+		i++
+		var outgoingPacket []byte
+		var outgoingPacketLen = 0
+	addMeLoop:
+		for outgoingPacketLen <= omci.MaxExtendedLength-omci.MaxBaselineLength && i < mibDb.NumberOfBaselineCommands {
+			currentEntry := mibDb.baselineItems[i]
+			for mibDb.baselineItems[i].packet != nil {
+				// Skip any entry with a predefined packet currently used for MEs with unknown ClassID or unknown attributes.
+				// This information will be added later to the last extended response packet
+				i++
+				if i < mibDb.NumberOfBaselineCommands {
+					currentEntry = mibDb.baselineItems[i]
+				} else {
+					break addMeLoop
+				}
+			}
+			additionalME, meErr := me.LoadManagedEntityDefinition(currentEntry.classId, me.ParamData{
+				EntityID:   currentEntry.entityId.ToUint16(),
+				Attributes: currentEntry.params,
+			})
+			if meErr.GetError() != nil {
+				omciLogger.Errorf("Error while generating additionalME %s: %v", currentEntry.classId.String(), meErr.Error())
+			}
+			request.AdditionalMEs = append(request.AdditionalMEs, *additionalME)
+
+			var options gopacket.SerializeOptions
+			options.FixLengths = true
+
+			buffer := gopacket.NewSerializeBuffer()
+			omciErr := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+			if omciErr != nil {
+				omciLogger.Errorf("Error while serializing generating additionalME %s: %v", currentEntry.classId.String(), omciErr)
+			}
+			outgoingPacket = buffer.Bytes()
+			outgoingPacketLen = len(outgoingPacket)
+			i++
+		}
+		mibDb.extendedResponses = append(mibDb.extendedResponses, outgoingPacket)
+		mibDb.NumberOfExtendedCommands = uint16(len(mibDb.extendedResponses))
+
+		outgoingPacketString := strings.ToLower(hex.EncodeToString(mibDb.extendedResponses[mibDb.NumberOfExtendedCommands-1]))
+		omciLogger.Debugf("Extended MIB upload response respNo: %d length: %d  string: %s", mibDb.NumberOfExtendedCommands, outgoingPacketLen, outgoingPacketString)
+	}
+	// Currently, there is enough space in the last extended response to add potential MEs with unknown ClassID or unknown attributes, if requested.
+	if common.Config.BBSim.InjectOmciUnknownMe {
+		var err error
+		mibDb.extendedResponses[mibDb.NumberOfExtendedCommands-1], err = AppendAdditionalMEs(mibDb.extendedResponses[mibDb.NumberOfExtendedCommands-1], unknownMePktReportedMeHdr, unknownMePktAttributes)
+		if err != nil {
+			omciLogger.Fatal(err)
+		} else {
+			outgoingPacketString := strings.ToLower(hex.EncodeToString(mibDb.extendedResponses[mibDb.NumberOfExtendedCommands-1]))
+			omciLogger.Debugf("Reponse with unknown ME added: %s", outgoingPacketString)
+		}
+	}
+	if common.Config.BBSim.InjectOmciUnknownAttributes {
+		var err error
+		mibDb.extendedResponses[mibDb.NumberOfExtendedCommands-1], err = AppendAdditionalMEs(mibDb.extendedResponses[mibDb.NumberOfExtendedCommands-1], unknownAttribPktReportedMeHdr, unknownAttribPktAttributes)
+		if err != nil {
+			omciLogger.Fatal(err)
+		} else {
+			outgoingPacketString := strings.ToLower(hex.EncodeToString(mibDb.extendedResponses[mibDb.NumberOfExtendedCommands-1]))
+			omciLogger.Debugf("Reponse with unknown attributes added: %s", outgoingPacketString)
+		}
+	}
 	return &mibDb, nil
 }
+
+func AppendAdditionalMEs(srcSlice []byte, reportedMeHdr string, attributes string) ([]byte, error) {
+	attribBytes, err := hex.DecodeString(attributes)
+	if err != nil {
+		return nil, fmt.Errorf("cannot-decode-attributes-string")
+	}
+	attribBytesLen := len(attribBytes)
+	attribBytesLenStr := fmt.Sprintf("%04X", attribBytesLen)
+	msg := attribBytesLenStr + reportedMeHdr + attributes
+	data, err := hex.DecodeString(msg)
+	if err != nil {
+		return nil, fmt.Errorf("cannot-decode-attributes")
+	}
+	dstSlice := make([]byte, len(srcSlice))
+	copy(dstSlice, srcSlice)
+	dstSlice = append(dstSlice[:], data[:]...)
+	messageContentsLen := binary.BigEndian.Uint16(dstSlice[extRespMsgContentsLenStart:extRespMsgContentsLenEnd])
+	dataLen := len(data)
+	newMessageContentsLen := messageContentsLen + uint16(dataLen)
+	newLenSlice := make([]byte, 2)
+	binary.BigEndian.PutUint16(newLenSlice, newMessageContentsLen)
+	copy(dstSlice[extRespMsgContentsLenStart:extRespMsgContentsLenEnd], newLenSlice[0:2])
+	return dstSlice, nil
+}
diff --git a/internal/common/omci/onu_mib_db_test.go b/internal/common/omci/onu_mib_db_test.go
index e1c1213..75bcf7d 100644
--- a/internal/common/omci/onu_mib_db_test.go
+++ b/internal/common/omci/onu_mib_db_test.go
@@ -18,9 +18,10 @@
 
 import (
 	"fmt"
+	"testing"
+
 	"github.com/google/gopacket"
 	"github.com/opencord/bbsim/internal/common"
-	"testing"
 
 	"github.com/opencord/omci-lib-go/v2"
 	me "github.com/opencord/omci-lib-go/v2/generated"
@@ -76,10 +77,10 @@
 
 	assert.NoError(t, err)
 	assert.NotNil(t, mibDb)
-	assert.Equal(t, expectedItems, int(mibDb.NumberOfCommands))
+	assert.Equal(t, expectedItems, int(mibDb.NumberOfBaselineCommands))
 
 	// now try to serialize all messages to check on the attributes
-	for _, entry := range mibDb.items {
+	for _, entry := range mibDb.baselineItems {
 		reportedMe, meErr := me.LoadManagedEntityDefinition(entry.classId, me.ParamData{
 			EntityID:   entry.entityId.ToUint16(),
 			Attributes: entry.params,
@@ -119,10 +120,10 @@
 
 	assert.NoError(t, err)
 	assert.NotNil(t, mibDb)
-	assert.Equal(t, expectedItems, int(mibDb.NumberOfCommands))
+	assert.Equal(t, expectedItems, int(mibDb.NumberOfBaselineCommands))
 
 	// now try to serialize all messages to check on the attributes
-	for _, entry := range mibDb.items {
+	for _, entry := range mibDb.baselineItems {
 		reportedMe, meErr := me.LoadManagedEntityDefinition(entry.classId, me.ParamData{
 			EntityID:   entry.entityId.ToUint16(),
 			Attributes: entry.params,
@@ -157,9 +158,9 @@
 
 	assert.NoError(t, err)
 	assert.NotNil(t, mibDb)
-	assert.Equal(t, expectedMibEntries, int(mibDb.NumberOfCommands))
+	assert.Equal(t, expectedMibEntries, int(mibDb.NumberOfBaselineCommands))
 
-	entry := mibDb.items[expectedMibEntries-1] // select the last entry, it's the hardcoded packet
+	entry := mibDb.baselineItems[expectedMibEntries-1] // select the last entry, it's the hardcoded packet
 	fmt.Println(entry.packet)
 	assert.NotNil(t, entry)
 	assert.Equal(t, me.ClassID(37), entry.classId)