blob: 923fc0263406caab5da245b97749d3d874c6fc04 [file] [log] [blame]
/*
* Copyright (c) 2018 - present. Boling Consulting Solutions (bcsw.net)
* Copyright 2020-present Open Networking Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package omci
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
me "github.com/opencord/omci-lib-go/v2/generated"
)
func decodeTestRequest(data []byte, p gopacket.PacketBuilder) error {
// Peek at Managed Entity Type
if len(data) < 8 {
p.SetTruncated()
return errors.New("frame too small")
}
classID := binary.BigEndian.Uint16(data)
// Is it a Managed Entity class we support customized decode of?
switch me.ClassID(classID) {
default:
omci := &TestRequest{}
omci.MsgLayerType = LayerTypeTestRequest
return decodingLayerDecoder(omci, data, p)
case me.AniGClassID, me.ReAniGClassID, me.PhysicalPathTerminationPointReUniClassID,
me.ReUpstreamAmplifierClassID, me.ReDownstreamAmplifierClassID:
omci := &OpticalLineSupervisionTestRequest{}
omci.MsgLayerType = LayerTypeTestRequest
return decodingLayerDecoder(omci, data, p)
}
}
// TestRequest message
type TestRequest struct {
MeBasePacket
Payload []byte
}
func (omci *TestRequest) String() string {
return fmt.Sprintf("%v, Request: %v octets", omci.MeBasePacket.String(), len(omci.Payload))
}
// LayerType returns LayerTypeTestRequest
func (omci *TestRequest) LayerType() gopacket.LayerType {
return LayerTypeTestRequest
}
// CanDecode returns the set of layer types that this DecodingLayer can decode
func (omci *TestRequest) CanDecode() gopacket.LayerClass {
return LayerTypeTestRequest
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (omci *TestRequest) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func (omci *TestRequest) TestRequest() []byte {
return omci.Payload
}
// DecodeFromBytes decodes the given bytes of a Test Request into this layer
func (omci *TestRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
// Common ClassID/EntityID decode in msgBase
err := omci.MeBasePacket.DecodeFromBytes(data, p, 4)
if err != nil {
return err
}
omci.Payload = make([]byte, MaxTestRequestLength)
copy(omci.Payload, omci.MeBasePacket.Payload)
return nil
}
// SerializeTo provides serialization of an Test Request message
func (omci *TestRequest) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error {
// Basic (common) OMCI Header is 8 octets, 10
err := omci.MeBasePacket.SerializeTo(b)
if err != nil {
return err
}
if omci.Payload == nil {
return errors.New("test results payload is missing")
}
if len(omci.Payload) > MaxTestRequestLength {
msg := fmt.Sprintf("Invalid Test Request payload size. Received %v bytes, expected %v",
len(omci.Payload), MaxTestRequestLength)
return errors.New(msg)
}
bytes, err := b.AppendBytes(len(omci.Payload))
if err != nil {
return err
}
copy(bytes, omci.Payload)
return nil
}
type OpticalLineSupervisionTestRequest struct {
MeBasePacket
SelectTest uint8 // Bitfield
GeneralPurposeBuffer uint16 // Pointer to General Purpose Buffer ME
VendorSpecificParameters uint16 // Pointer to Octet String ME
}
func (omci *OpticalLineSupervisionTestRequest) String() string {
return fmt.Sprintf("Optical Line Supervision Test Result: SelectTest: %#x, Buffer: %#x, Params: %#x",
omci.SelectTest, omci.GeneralPurposeBuffer, omci.VendorSpecificParameters)
}
// LayerType returns LayerTypeTestRequest
func (omci *OpticalLineSupervisionTestRequest) LayerType() gopacket.LayerType {
return LayerTypeTestRequest
}
// CanDecode returns the set of layer types that this DecodingLayer can decode
func (omci *OpticalLineSupervisionTestRequest) CanDecode() gopacket.LayerClass {
return LayerTypeTestRequest
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (omci *OpticalLineSupervisionTestRequest) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func (omci *OpticalLineSupervisionTestRequest) TestRequest() []byte {
return omci.Payload
}
// DecodeFromBytes decodes the given bytes of a Test Result Notification into this layer
func (omci *OpticalLineSupervisionTestRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
// Common ClassID/EntityID decode in msgBase
err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+5)
if err != nil {
return err
}
omci.SelectTest = data[4]
omci.GeneralPurposeBuffer = binary.BigEndian.Uint16(data[5:])
omci.VendorSpecificParameters = binary.BigEndian.Uint16(data[7:])
return nil
}
// SerializeTo provides serialization of an Test Result notification message
func (omci *OpticalLineSupervisionTestRequest) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error {
// Basic (common) OMCI Header is 8 octets, 10
err := omci.MeBasePacket.SerializeTo(b)
if err != nil {
return err
}
bytes, err := b.AppendBytes(8)
if err != nil {
return err
}
bytes[0] = omci.SelectTest
binary.BigEndian.PutUint16(bytes[1:], omci.GeneralPurposeBuffer)
binary.BigEndian.PutUint16(bytes[3:], omci.VendorSpecificParameters)
return nil
}
// TestResponse message
type TestResponse struct {
MeBasePacket
Result me.Results
}
func (omci *TestResponse) String() string {
return fmt.Sprintf("%v, Results: %d (%v)", omci.MeBasePacket.String(), omci.Result, omci.Result)
}
// LayerType returns LayerTypeTestResponse
func (omci *TestResponse) LayerType() gopacket.LayerType {
return LayerTypeTestResponse
}
// CanDecode returns the set of layer types that this DecodingLayer can decode
func (omci *TestResponse) CanDecode() gopacket.LayerClass {
return LayerTypeTestResponse
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (omci *TestResponse) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// DecodeFromBytes decodes the given bytes of a Test Response into this layer
func (omci *TestResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
// Common ClassID/EntityID decode in msgBase
err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+1)
if err != nil {
return err
}
meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
me.ParamData{EntityID: omci.EntityInstance})
if omciErr.StatusCode() != me.Success {
return omciErr.GetError()
}
// ME needs to support Test requests
if !me.SupportsMsgType(meDefinition, me.Test) {
return me.NewProcessingError("managed entity does not support Test Message-Type")
}
omci.Result = me.Results(data[4])
return nil
}
func decodeTestResponse(data []byte, p gopacket.PacketBuilder) error {
omci := &TestResponse{}
omci.MsgLayerType = LayerTypeTestResponse
return decodingLayerDecoder(omci, data, p)
}
// SerializeTo provides serialization of an Test Response message
func (omci *TestResponse) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error {
// Basic (common) OMCI Header is 8 octets, 10
err := omci.MeBasePacket.SerializeTo(b)
if err != nil {
return err
}
entity, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
me.ParamData{EntityID: omci.EntityInstance})
if omciErr.StatusCode() != me.Success {
return omciErr.GetError()
}
// ME needs to support Set
if !me.SupportsMsgType(entity, me.Test) {
return me.NewProcessingError("managed entity does not support the Test Message-Type")
}
bytes, err := b.AppendBytes(1)
if err != nil {
return err
}
bytes[0] = byte(omci.Result)
if omci.Result > me.DeviceBusy {
msg := fmt.Sprintf("invalid results code: %v, must be 0..6", omci.Result)
return errors.New(msg)
}
return nil
}
func decodeTestResult(data []byte, p gopacket.PacketBuilder) error {
// Peek at Managed Entity Type
if len(data) < 8 {
p.SetTruncated()
return errors.New("frame too small")
}
classID := binary.BigEndian.Uint16(data)
// Is it a Managed Entity class we support customized decode of?
switch me.ClassID(classID) {
default:
omci := &TestResultNotification{}
omci.MsgLayerType = LayerTypeTestResult
return decodingLayerDecoder(omci, data, p)
case me.AniGClassID, me.ReAniGClassID, me.PhysicalPathTerminationPointReUniClassID,
me.ReUpstreamAmplifierClassID, me.ReDownstreamAmplifierClassID:
omci := &OpticalLineSupervisionTestResult{}
omci.MsgLayerType = LayerTypeTestResult
return decodingLayerDecoder(omci, data, p)
}
}
func decodeTestResultExtended(data []byte, p gopacket.PacketBuilder) error {
// Peek at Managed Entity Type
if len(data) < 8 {
p.SetTruncated()
return errors.New("frame too small")
}
classID := binary.BigEndian.Uint16(data)
// Is it a Managed Entity class we support customized decode of?
switch me.ClassID(classID) {
default:
omci := &TestResultNotification{}
omci.MsgLayerType = LayerTypeTestResult
omci.Extended = true
return decodingLayerDecoder(omci, data, p)
case me.AniGClassID, me.ReAniGClassID, me.PhysicalPathTerminationPointReUniClassID,
me.ReUpstreamAmplifierClassID, me.ReDownstreamAmplifierClassID:
omci := &OpticalLineSupervisionTestResult{}
omci.MsgLayerType = LayerTypeTestResult
omci.Extended = true
return decodingLayerDecoder(omci, data, p)
}
}
type TestResultNotification struct {
MeBasePacket
Payload []byte
}
func (omci *TestResultNotification) TestResults() []byte {
return omci.Payload
}
func (omci *TestResultNotification) String() string {
return fmt.Sprintf("%v, Payload: %v octets", omci.MeBasePacket.String(), len(omci.Payload))
}
// LayerType returns LayerTypeTestResult
func (omci *TestResultNotification) LayerType() gopacket.LayerType {
return LayerTypeTestResult
}
// CanDecode returns the set of layer types that this DecodingLayer can decode
func (omci *TestResultNotification) CanDecode() gopacket.LayerClass {
return LayerTypeTestResult
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (omci *TestResultNotification) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// DecodeFromBytes decodes the given bytes of a Test Result Notification into this layer
func (omci *TestResultNotification) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
// Common ClassID/EntityID decode in msgBase
payloadOffset := 4
if omci.Extended {
payloadOffset = 6
}
err := omci.MeBasePacket.DecodeFromBytes(data, p, payloadOffset)
if err != nil {
return err
}
meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
me.ParamData{EntityID: omci.EntityInstance})
if omciErr.StatusCode() != me.Success {
return omciErr.GetError()
}
// ME needs to support Test requests
if !me.SupportsMsgType(meDefinition, me.Test) {
return me.NewProcessingError("managed entity does not support Test Message-Type")
}
if omci.Extended {
if len(data) < 6 {
p.SetTruncated()
return errors.New("frame too small")
}
length := binary.BigEndian.Uint16(data[4:])
if len(data) < 6+int(length) {
p.SetTruncated()
return errors.New("frame too small")
}
omci.Payload = make([]byte, length)
copy(omci.Payload, data[6:])
} else {
omci.Payload = make([]byte, MaxTestResultsLength)
copy(omci.Payload, omci.MeBasePacket.Payload)
}
return nil
}
// SerializeTo provides serialization of an Test Result notification message
func (omci *TestResultNotification) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error {
// Basic (common) OMCI Header is 8 octets
err := omci.MeBasePacket.SerializeTo(b)
if err != nil {
return err
}
meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
me.ParamData{EntityID: omci.EntityInstance})
if omciErr.StatusCode() != me.Success {
return omciErr.GetError()
}
// ME needs to support Test requests
if !me.SupportsMsgType(meDefinition, me.Test) {
return me.NewProcessingError("managed entity does not support Test Message-Type")
}
if omci.Payload == nil {
return errors.New("test results payload is missing")
}
payloadOffset := 0
maxSize := MaxTestResultsLength
if omci.Extended {
payloadOffset = 2
maxSize = MaxExtendedLength - 10 - 4
}
if len(omci.Payload) > maxSize {
msg := fmt.Sprintf("Invalid Test Results payload size. Received %v bytes, max expected %v",
len(omci.Payload), maxSize)
return errors.New(msg)
}
bytes, err := b.AppendBytes(len(omci.Payload) + payloadOffset)
if err != nil {
return err
}
if omci.Extended {
binary.BigEndian.PutUint16(bytes, uint16(len(omci.Payload)))
}
copy(bytes[payloadOffset:], omci.Payload)
return nil
}
// OpticalLineSupervisionTestResult provides a Optical Specific test results
// message decode for the associated Managed Entities
type OpticalLineSupervisionTestResult struct {
MeBasePacket
PowerFeedVoltageType uint8 // Type = 1
PowerFeedVoltage uint16 // value
ReceivedOpticalPowerType uint8 // Type = 3
ReceivedOpticalPower uint16 // value
MeanOpticalLaunchType uint8 // Type = 5
MeanOpticalLaunch uint16 // value
LaserBiasCurrentType uint8 // Type = 9
LaserBiasCurrent uint16 // value
TemperatureType uint8 // Type = 12
Temperature uint16 // value
GeneralPurposeBuffer uint16 // Pointer to General Purpose Buffer ME
}
func (omci *OpticalLineSupervisionTestResult) String() string {
return fmt.Sprintf("Optical Line Supervision Test Result")
}
// LayerType returns LayerTypeTestResult
func (omci *OpticalLineSupervisionTestResult) LayerType() gopacket.LayerType {
return LayerTypeTestResult
}
// CanDecode returns the set of layer types that this DecodingLayer can decode
func (omci *OpticalLineSupervisionTestResult) CanDecode() gopacket.LayerClass {
return LayerTypeTestResult
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (omci *OpticalLineSupervisionTestResult) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func (omci *OpticalLineSupervisionTestResult) TestResults() []byte {
return omci.MeBasePacket.Payload
}
// DecodeFromBytes decodes the given bytes of a Test Result Notification into this layer
func (omci *OpticalLineSupervisionTestResult) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
// Common ClassID/EntityID decode in msgBase
payloadOffset := 4
if omci.Extended {
payloadOffset = 6
}
err := omci.MeBasePacket.DecodeFromBytes(data, p, payloadOffset+17)
if err != nil {
return err
}
meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
me.ParamData{EntityID: omci.EntityInstance})
if omciErr.StatusCode() != me.Success {
return omciErr.GetError()
}
// ME needs to support Test requests
if !me.SupportsMsgType(meDefinition, me.Test) {
return me.NewProcessingError("managed entity does not support Test Message-Type")
}
// Note: Unsupported tests will have a type = 0 and the value should be zero
// as well, but that constraint is not enforced at this time.
// Type = 1
omci.PowerFeedVoltageType = data[payloadOffset]
omci.PowerFeedVoltage = binary.BigEndian.Uint16(data[payloadOffset+1:])
// Type = 3
omci.ReceivedOpticalPowerType = data[payloadOffset+3]
omci.ReceivedOpticalPower = binary.BigEndian.Uint16(data[payloadOffset+4:])
// Type = 5
omci.MeanOpticalLaunchType = data[payloadOffset+6]
omci.MeanOpticalLaunch = binary.BigEndian.Uint16(data[payloadOffset+7:])
// Type = 9
omci.LaserBiasCurrentType = data[payloadOffset+9]
omci.LaserBiasCurrent = binary.BigEndian.Uint16(data[payloadOffset+10:])
// Type = 12
omci.TemperatureType = data[payloadOffset+12]
omci.Temperature = binary.BigEndian.Uint16(data[payloadOffset+13:])
omci.GeneralPurposeBuffer = binary.BigEndian.Uint16(data[payloadOffset+15:])
return nil
}
// SerializeTo provides serialization of an Test Result notification message
func (omci *OpticalLineSupervisionTestResult) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error {
// Basic (common) OMCI Header is 8 octets, 10
err := omci.MeBasePacket.SerializeTo(b)
if err != nil {
return err
}
meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
me.ParamData{EntityID: omci.EntityInstance})
if omciErr.StatusCode() != me.Success {
return omciErr.GetError()
}
// ME needs to support Test requests
if !me.SupportsMsgType(meDefinition, me.Test) {
return me.NewProcessingError("managed entity does not support Test Message-Type")
}
payloadOffset := 0
if omci.Extended {
payloadOffset = 2
}
bytes, err := b.AppendBytes(payloadOffset + 17)
if err != nil {
return err
}
if omci.Extended {
binary.BigEndian.PutUint16(bytes, 17)
}
bytes[payloadOffset] = omci.PowerFeedVoltageType
binary.BigEndian.PutUint16(bytes[payloadOffset+1:], omci.PowerFeedVoltage)
bytes[payloadOffset+3] = omci.ReceivedOpticalPowerType
binary.BigEndian.PutUint16(bytes[payloadOffset+4:], omci.ReceivedOpticalPower)
bytes[payloadOffset+6] = omci.MeanOpticalLaunchType
binary.BigEndian.PutUint16(bytes[payloadOffset+7:], omci.MeanOpticalLaunch)
bytes[payloadOffset+9] = omci.LaserBiasCurrentType
binary.BigEndian.PutUint16(bytes[payloadOffset+10:], omci.LaserBiasCurrent)
bytes[payloadOffset+12] = omci.TemperatureType
binary.BigEndian.PutUint16(bytes[payloadOffset+13:], omci.Temperature)
binary.BigEndian.PutUint16(bytes[payloadOffset+15:], omci.GeneralPurposeBuffer)
return nil
}