VOL-4366:
1. Set traffic scheduler pointer to GemPortNetworkCTP only if
   QualityOfServiceQosConfigurationFlexibility is true in ONU2G ME
2. Fix the traffic descriptor ME reference during GemPortNetworkCTP set
   operation.

Change-Id: I35898d6ea42789faac362ade920f7b17d639c04b
diff --git a/internal/pkg/onuadaptercore/omci_ani_config.go b/internal/pkg/onuadaptercore/omci_ani_config.go
index 33e323d..a236950 100644
--- a/internal/pkg/onuadaptercore/omci_ani_config.go
+++ b/internal/pkg/onuadaptercore/omci_ani_config.go
@@ -88,6 +88,10 @@
 )
 const cAniFsmIdleState = aniStConfigDone
 
+const (
+	bitTrafficSchedulerPtrSetPermitted = 0x0002 // Refer section 9.1.2 ONU-2G, table for "Quality of service (QoS) configuration flexibility" IE
+)
+
 type ponAniGemPortAttribs struct {
 	gemPortID      uint16
 	upQueueID      uint16
@@ -1642,6 +1646,33 @@
 		}
 	}
 
+	trafficSchedPtrSetSupported := false
+	loOnu2g := oFsm.pOnuDB.GetMe(me.Onu2GClassID, onu2gMeID)
+	if loOnu2g == nil {
+		logger.Errorw(ctx, "onu2g is nil, cannot read qos configuration flexibility parameter",
+			log.Fields{"device-id": oFsm.deviceID})
+		_ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
+		return
+	}
+	returnVal := loOnu2g["QualityOfServiceQosConfigurationFlexibility"]
+	if returnVal != nil {
+		if qosCfgFlexParam, err := oFsm.pOnuDB.getUint16Attrib(returnVal); err == nil {
+			trafficSchedPtrSetSupported = qosCfgFlexParam&bitTrafficSchedulerPtrSetPermitted == bitTrafficSchedulerPtrSetPermitted
+			logger.Debugw(ctx, "trafficSchedPtrSetSupported set",
+				log.Fields{"qosCfgFlexParam": qosCfgFlexParam, "trafficSchedPtrSetSupported": trafficSchedPtrSetSupported})
+		} else {
+			logger.Errorw(ctx, "Cannot extract qos configuration flexibility parameter",
+				log.Fields{"device-id": oFsm.deviceID})
+			_ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
+			return
+		}
+	} else {
+		logger.Errorw(ctx, "Cannot read qos configuration flexibility parameter",
+			log.Fields{"device-id": oFsm.deviceID})
+		_ = oFsm.pAdaptFsm.pFsm.Event(aniEvReset)
+		return
+	}
+
 	//TODO: assumption here is that ONU data uses SP setting in the T-Cont and WRR in the TrafficScheduler
 	//  if that is not the case, the reverse case could be checked and reacted accordingly or if the
 	//  complete chain is not valid, then some error should be thrown and configuration can be aborted
@@ -1659,19 +1690,37 @@
 			EntityID:   queueIndex,
 			Attributes: make(me.AttributeValueMap),
 		}
-		if (kv.Value).(uint16) == cu16StrictPrioWeight {
-			//StrictPrio indication
-			logger.Debugw(ctx, "uniPonAniConfigFsm Tx Set::PrioQueue to StrictPrio", log.Fields{
-				"EntitytId": strconv.FormatInt(int64(queueIndex), 16),
-				"device-id": oFsm.deviceID})
-			meParams.Attributes["TrafficSchedulerPointer"] = 0 //ensure T-Cont defined StrictPrio scheduling
+		if trafficSchedPtrSetSupported {
+			if (kv.Value).(uint16) == cu16StrictPrioWeight {
+				//StrictPrio indication
+				logger.Debugw(ctx, "uniPonAniConfigFsm Tx Set::PrioQueue to StrictPrio", log.Fields{
+					"EntitytId": strconv.FormatInt(int64(queueIndex), 16),
+					"device-id": oFsm.deviceID})
+				meParams.Attributes["TrafficSchedulerPointer"] = 0 //ensure T-Cont defined StrictPrio scheduling
+			} else {
+				//WRR indication
+				logger.Debugw(ctx, "uniPonAniConfigFsm Tx Set::PrioQueue to WRR", log.Fields{
+					"EntitytId": strconv.FormatInt(int64(queueIndex), 16),
+					"Weight":    kv.Value,
+					"device-id": oFsm.deviceID})
+				meParams.Attributes["TrafficSchedulerPointer"] = loTrafficSchedulerEID //ensure assignment of the relevant trafficScheduler
+				meParams.Attributes["Weight"] = uint8(kv.Value.(uint16))
+			}
 		} else {
-			//WRR indication
-			logger.Debugw(ctx, "uniPonAniConfigFsm Tx Set::PrioQueue to WRR", log.Fields{
+			// setting Traffic Scheduler (TS) pointer is not supported unless we point to another TS that points to the same TCONT.
+			// For now lets use TS that is hardwired in the ONU and just update the weight in case of WRR, which in fact is all we need at the moment.
+			// The code could get unnecessarily convoluted if we provide the flexibility try to find and point to another TS that points to the same TCONT.
+			if (kv.Value).(uint16) == cu16StrictPrioWeight { // SP case, nothing to be done. Proceed to the next queue
+				logger.Debugw(ctx, "uniPonAniConfigFsm Tx Set::PrioQueue to StrictPrio, traffic sched ptr set unsupported", log.Fields{
+					"EntitytId": strconv.FormatInt(int64(queueIndex), 16),
+					"device-id": oFsm.deviceID})
+				continue
+			}
+			// WRR case, update weight.
+			logger.Debugw(ctx, "uniPonAniConfigFsm Tx Set::PrioQueue to WRR, traffic sched ptr set unsupported", log.Fields{
 				"EntitytId": strconv.FormatInt(int64(queueIndex), 16),
 				"Weight":    kv.Value,
 				"device-id": oFsm.deviceID})
-			meParams.Attributes["TrafficSchedulerPointer"] = loTrafficSchedulerEID //ensure assignment of the relevant trafficScheduler
 			meParams.Attributes["Weight"] = uint8(kv.Value.(uint16))
 		}
 		oFsm.mutexPLastTxMeInstance.Lock()
diff --git a/internal/pkg/onuadaptercore/omci_vlan_config.go b/internal/pkg/onuadaptercore/omci_vlan_config.go
index c828804..c6311e4 100644
--- a/internal/pkg/onuadaptercore/omci_vlan_config.go
+++ b/internal/pkg/onuadaptercore/omci_vlan_config.go
@@ -3064,7 +3064,8 @@
 		return err
 	}
 
-	err = oFsm.setTrafficDescriptorToGemPortNWCTP(ctx, gemPortID)
+	// Note: in the below request the gemport entity id is same as the gemport id and the traffic descriptor entity id is also same as gemport id
+	err = oFsm.setTrafficDescriptorToGemPortNWCTP(ctx, gemPortID, gemPortID)
 	if err != nil {
 		logger.Errorw(ctx, "Traffic Descriptor set failed to Gem Port Network CTP, aborting VlanConfig FSM!", log.Fields{"device-id": oFsm.deviceID})
 		return err
@@ -3074,12 +3075,13 @@
 	return nil
 }
 
-func (oFsm *UniVlanConfigFsm) setTrafficDescriptorToGemPortNWCTP(ctx context.Context, gemPortID uint16) error {
-	logger.Debugw(ctx, "Starting Set Traffic Descriptor to GemPortNWCTP", log.Fields{"device-id": oFsm.deviceID, "gem-port-id": gemPortID})
+func (oFsm *UniVlanConfigFsm) setTrafficDescriptorToGemPortNWCTP(ctx context.Context, gemPortEntityID uint16, trafficDescriptorEntityID uint16) error {
+	logger.Debugw(ctx, "Starting Set Traffic Descriptor to GemPortNWCTP",
+		log.Fields{"device-id": oFsm.deviceID, "gem-port-entity-id": gemPortEntityID, "traffic-descriptor-entity-id": trafficDescriptorEntityID})
 	meParams := me.ParamData{
-		EntityID: gemPortID,
+		EntityID: gemPortEntityID,
 		Attributes: me.AttributeValueMap{
-			"TrafficManagementPointerForUpstream": gemPortID,
+			"TrafficDescriptorProfilePointerForUpstream": trafficDescriptorEntityID,
 		},
 	}
 	oFsm.mutexPLastTxMeInstance.Lock()
diff --git a/internal/pkg/onuadaptercore/onu_device_db.go b/internal/pkg/onuadaptercore/onu_device_db.go
index 17f352b..00a1945 100644
--- a/internal/pkg/onuadaptercore/onu_device_db.go
+++ b/internal/pkg/onuadaptercore/onu_device_db.go
@@ -106,23 +106,24 @@
 		//JSON numbers by default are unmarshaled into values of float64 type if type information is not present
 		return uint32(meAttribute.(float64)), nil
 	case reflect.Uint32:
-		return uint32(meAttribute.(uint32)), nil
+		return meAttribute.(uint32), nil
 	default:
-		return uint32(0), fmt.Errorf(fmt.Sprintf("wrong interface-type received-%s", onuDeviceDB.pOnuDeviceEntry.deviceID))
+		return uint32(0), fmt.Errorf(fmt.Sprintf("wrong-interface-type-%v-received-for-device-%s", reflect.TypeOf(meAttribute).Kind(), onuDeviceDB.pOnuDeviceEntry.deviceID))
 	}
 }
 
-/*
 func (onuDeviceDB *onuDeviceDB) getUint16Attrib(meAttribute interface{}) (uint16, error) {
 
 	switch reflect.TypeOf(meAttribute).Kind() {
+	case reflect.Float64:
+		//JSON numbers by default are unmarshaled into values of float64 type if type information is not present
+		return uint16(meAttribute.(float64)), nil
 	case reflect.Uint16:
 		return meAttribute.(uint16), nil
 	default:
-		return uint16(0), fmt.Errorf(fmt.Sprintf("wrong interface-type received-%s", onuDeviceDB.pOnuDeviceEntry.deviceID))
+		return uint16(0), fmt.Errorf(fmt.Sprintf("wrong-interface-type-%v-received-for-device-%s", reflect.TypeOf(meAttribute).Kind(), onuDeviceDB.pOnuDeviceEntry.deviceID))
 	}
 }
-*/
 
 func (onuDeviceDB *onuDeviceDB) getSortedInstKeys(ctx context.Context, meClassID me.ClassID) []uint16 {