VOL-4337: Code upgrade for 3/2020 G.988 support and remaining Extended Message Set support

Change-Id: I6c5e1a167216ad9b51e9da89460e9909465ae1bc
diff --git a/omci.go b/omci.go
index 2f6d2d9..75b1e41 100644
--- a/omci.go
+++ b/omci.go
@@ -33,7 +33,7 @@
 // DeviceIdent identifies the OMCI message format. Currently either baseline or extended.
 type DeviceIdent byte
 
-// LayerTypeOmci provide a gopacket LayerType for OMCI messages
+// LayerTypeOMCI provides a gopacket LayerType for OMCI messages
 var (
 	LayerTypeOMCI gopacket.LayerType
 )
@@ -53,7 +53,7 @@
 	// G-PON OLTs and ONUs support the baseline message set
 	BaselineIdent DeviceIdent = 0x0A
 
-	// ExtendedIdent messager are up to 1920 octets but may not be supported by all ONUs or OLTs.
+	// ExtendedIdent messages are up to 1920 octets but may not be supported by all ONUs or OLTs.
 	ExtendedIdent DeviceIdent = 0x0B
 )
 
@@ -136,12 +136,6 @@
 }
 
 func (omci *OMCI) String() string {
-	//msgType := me.MsgType(byte(omci.MessageType) & me.MsgTypeMask)
-	//if me.IsAutonomousNotification(msgType) {
-	//	return fmt.Sprintf("OMCI: Type: %v:", msgType)
-	//} else if byte(omci.MessageType)&me.AK == me.AK {
-	//	return fmt.Sprintf("OMCI: Type: %v Response", msgType)
-	//}
 	return fmt.Sprintf("Type: %v, TID: %d (%#x), Ident: %v",
 		omci.MessageType, omci.TransactionID, omci.TransactionID, omci.DeviceIdentifier)
 }
@@ -151,6 +145,19 @@
 	return LayerTypeOMCI
 }
 
+// CanDecode returns the layers that this class can decode
+func (omci *OMCI) CanDecode() gopacket.LayerClass {
+	return LayerTypeOMCI
+}
+
+// NextLayerType returns the layer type contained by this DecodingLayer.
+func (omci *OMCI) NextLayerType() gopacket.LayerType {
+	if next, ok := nextLayerMapping[omci.MessageType]; ok {
+		return next
+	}
+	return gopacket.LayerTypePayload
+}
+
 // LayerContents returns the OMCI specific layer information
 func (omci *OMCI) LayerContents() []byte {
 	b := make([]byte, 4)
@@ -160,19 +167,9 @@
 	return b
 }
 
-// CanDecode returns the layers that this class can decode
-func (omci *OMCI) CanDecode() gopacket.LayerClass {
-	return LayerTypeOMCI
-}
-
-// NextLayerType returns the layer type contained by this DecodingLayer.
-func (omci *OMCI) NextLayerType() gopacket.LayerType {
-	return gopacket.LayerTypeZero
-}
-
 func decodeOMCI(data []byte, p gopacket.PacketBuilder) error {
 	// Allow baseline messages without Length & MIC, but no less
-	if len(data) < 10 {
+	if len(data) < 4 {
 		p.SetTruncated()
 		return errors.New("frame header too small")
 	}
@@ -185,11 +182,17 @@
 	case BaselineIdent:
 		if len(data) < MaxBaselineLength-8 {
 			p.SetTruncated()
-			return errors.New("frame too small")
+			return fmt.Errorf("frame too small. OMCI baseline frame length %v, %v required",
+				len(data), MaxBaselineLength-8)
 		}
 		return omci.DecodeFromBytes(data, p)
 
 	case ExtendedIdent:
+		if len(data) < 10 {
+			p.SetTruncated()
+			return fmt.Errorf("frame too small. OMCI minimal extended frame length %v, 10 required",
+				len(data))
+		}
 		return omci.DecodeFromBytes(data, p)
 	}
 }
@@ -219,10 +222,7 @@
 
 // DecodeFromBytes will decode the OMCI layer of a packet/message
 func (omci *OMCI) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
-	if len(data) < 10 {
-		p.SetTruncated()
-		return errors.New("frame too small")
-	}
+	// Minimal Baseline and Extended message set length has already been checked
 	omci.TransactionID = binary.BigEndian.Uint16(data[0:])
 	omci.MessageType = MessageType(data[2])
 	omci.DeviceIdentifier = DeviceIdent(data[3])
@@ -272,7 +272,10 @@
 			//return errors.New(msg)
 		}
 	}
-	omci.BaseLayer = layers.BaseLayer{data[:4], data[4:eomOffset]}
+	omci.BaseLayer = layers.BaseLayer{
+		Contents: data[:4],
+		Payload:  data[4:eomOffset],
+	}
 	p.AddLayer(omci)
 	nextLayer, err := MsgTypeToNextLayer(omci.MessageType, omci.DeviceIdentifier == ExtendedIdent)
 	if err != nil {
@@ -290,10 +293,16 @@
 		return err
 	}
 	// OMCI layer error checks
-	isNotification := (int(omci.MessageType) & ^me.MsgTypeMask) == 0
-	if omci.TransactionID == 0 && !isNotification {
+	// Self-initiated Test Results have a TID of 0, OLT-requested do not.
+	isNotification := omci.MessageType == AlarmNotificationType ||
+		omci.MessageType == AttributeValueChangeType
+
+	if omci.TransactionID == 0 && !isNotification && omci.MessageType != TestResultType {
 		return errors.New("omci Transaction ID is zero for non-Notification type message")
 	}
+	if omci.TransactionID != 0 && isNotification {
+		return errors.New("omci Transaction ID is not zero for Notification type message")
+	}
 	if omci.DeviceIdentifier == 0 {
 		omci.DeviceIdentifier = BaselineIdent // Allow uninitialized device identifier
 	}