VOL-4044: Initial support for Test Request, Result, and Notfication baseline decode & serialization
Change-Id: I4f64ef6c1ccf63cc747a76d6b5a201d9c43215d8
diff --git a/README.md b/README.md
index fa5499f..959990a 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
# OMCI
OMCI gopacket library supports the encoding and decoding of ITU G.988 OMCI
-messages.
+messages. Support for the Baseline Message Set has been completed and work
+is underway to support the Extended Message Set format.
## Message Types supported and under unit test
The following OMCI message types currently have been coded and are covered
@@ -22,6 +23,13 @@
- MibResetRequest
- MibResetResponse
- SynchronizeTimeRequest
+ - DownloadSectionRequest
+ - DownloadSectionResponse
+ - EndSoftwareDownloadRequest
+ - EndSoftwareDownloadResponse
+ - CommitSoftwareRequest
+ - CommitSoftwareResponse
+ - AlarmNotification
## Message Types supported but lacking full unit test
The following OMCI message types currently have been coded and are partially covered
@@ -38,46 +46,80 @@
- StartSoftwareDownloadRequest
- GetNextRequest
- GetNextResponse
+ - TestResult
+ - TestRequest
+ - TestResponse
## Message Types supported but lacking any unit test
The following OMCI message types currently have been coded but do not
have any unit test coverage.
- StartSoftwareDownloadResponse
- - DownloadSectionRequest
- - DownloadSectionResponse
- - EndSoftwareDownloadRequest
- - EndSoftwareDownloadResponse
- ActivateSoftwareRequest
- ActivateSoftwareResponse
- - CommitSoftwareRequest
- - CommitSoftwareResponse
- GetCurrentDataRequest
- GetCurrentDataResponse
- - AlarmNotification
## Message Types not yet supported
The following OMCI message types currently have not been coded.
- - TestResult
- - TestRequest
- - TestResponse
- SetTableRequest
- SetTableResponse
+## Extended Message Set Support
+
+As mentioned earlier, support for the Extended Message Set is underway. Currently,
+the following Message Types have this support and are covered by unit tests:
+
+ - GetRequest
+ - GetResponse
+
+### Upcoming message types that will be supported
+
+The following provides a list of message types that will eventually support the _Extended Message Set_
+in the expected order of implementation. The priority was chosen based on speed improvement requests
+of operations and ease of implementation.
+
+ - DownloadSectionRequest/Response
+ - AlarmNotification
+ - AttributeValueChange
+ - TestResult
+
+ - GetCurrentDataRequest/Response
+ - MibResetRequest/Response
+ - RebootRequest/Response
+ - SynchronizeTimeRequest/Response
+ - CreateRequest/Response
+ - DeleteRequest/Response
+ - SetRequest/Response
+
+ - MibUploadRequest/Response
+ - MibUploadNextRequest/Response
+ - GetAllAlarmsRequest/Response
+ - GetAllAlarmsNextRequest/Response
+ - GetNextRequest/Response
+
+ - StartSoftwareDownloadRequest/Response
+ - EndSoftwareDownloadRequest/Response
+ - CommitSoftwareRequest/Response
+ - ActivateSoftwareRequest/Response
+
+ - SetTableRequest/Response
+ - TestRequest/Response
+
## Current user-test coverage
-The _coverage.sh_ and _coverage.cmd_ scripts can be used to create code coverage support for the
-library. The current coverage (as of 2/11/2020) is:
+The _**make** test_ command can be used to create code coverage support for the
+library. The current coverage for version 1.0.0 (as of 4/21/2021) is:
| File | Statement Coverage |
| --------------: | :---: |
| layers.go | 100% |
-| mebase.go | 87.5% |
-| meframe.go | 54.8% |
-| messagetypes.go | 48.1% |
-| omci.go | 81.6% |
+| mebase.go | 91.7% |
+| meframe.go | 50.8% |
+| messagetypes.go | 59.1% |
+| omci.go | 79.0% |
## Other outstanding items
@@ -85,26 +127,12 @@
would be needed or useful in a first official release of this library. Some changes are
to be done in the generated OMCI ME code as well.
- - Specific examples of how to use this library (expand upon DecodeEncode.go examples)
- Include unknown ME examples and how to catch various common or expected errors. Until
- this is available, please take a look at how this library is used in my
- [onumock](https://github.com/cboling/onumock/README.md). There is a utilities subdirectory
- in the _onumock_ project that has some examples. One is a **very** crude OLT simulator that
- I wrote to help test the ONU Mock.
- - Support optional msg-types. (This was very recently fixed in the code generator).
- Constraint checking (these are not yet fully parsed/provided by the OMCI code generated
structs). This feature will hopefully be available in the near future.
- - Add Alarm Table Support (generated MEs also)
- Add AVC flag for appropriate attributes
- - Support of the extended message format
- - For serialization, check early for message size exceeded
- Add some type of logging support
-The following would be 'nice' to have but are not necessary for initial code release
- - Extended message support
- - MIC Encode/Decode support
-
-Also searching through the code for _TODO_ statements will also yeild additional areas of
+Also searching through the code for _TODO_ statements will also yield additional areas of
work to be performed.
## What is not provided by this library
@@ -114,7 +142,7 @@
the creation of OMCI frames and handling decoded frames from the PON.
For an OLT-side OMCI stack, you would still need to write:
- - OMCI CC sender & receiver with appropriate timeout support
+ - OMCI CC sender & receiver (stop & wait protocol) with appropriate timeout support
- OLT State machines to support
- MIB Uploads/Audits/Resynchronization (and a MIB database implemention),
- More sophisticated get & get-next support to make handle of MEs with
@@ -123,7 +151,7 @@
- OMCI ME/Msg-Type capabilities inquiry,
- Performance Monitoring collection (and initial time synchronization),
- Service implementation
-
+
For an ONU-side OMCI stack, you would still need to write:
- OMCC implementation,
- MIB Database,
diff --git a/VERSION b/VERSION
index 3eefcb9..9084fa2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.0
+1.1.0
diff --git a/meframe.go b/meframe.go
index 37f04a5..c13554c 100644
--- a/meframe.go
+++ b/meframe.go
@@ -43,7 +43,7 @@
encoderMap[MibUploadRequestType] = MibUploadRequestFrame
encoderMap[MibUploadNextRequestType] = MibUploadNextRequestFrame
encoderMap[MibResetRequestType] = MibResetRequestFrame
- encoderMap[TestRequestType] = TestRequestFrame
+ //encoderMap[TestRequestType] = TestRequestFrame
encoderMap[StartSoftwareDownloadRequestType] = StartSoftwareDownloadRequestFrame
encoderMap[DownloadSectionRequestType] = DownloadSectionRequestFrame
encoderMap[EndSoftwareDownloadRequestType] = EndSoftwareDownloadRequestFrame
@@ -63,7 +63,7 @@
encoderMap[MibUploadResponseType] = MibUploadResponseFrame
encoderMap[MibUploadNextResponseType] = MibUploadNextResponseFrame
encoderMap[MibResetResponseType] = MibResetResponseFrame
- encoderMap[TestResponseType] = TestResponseFrame
+ //encoderMap[TestResponseType] = TestResponseFrame
encoderMap[StartSoftwareDownloadResponseType] = StartSoftwareDownloadResponseFrame
encoderMap[DownloadSectionResponseType] = DownloadSectionResponseFrame
encoderMap[EndSoftwareDownloadResponseType] = EndSoftwareDownloadResponseFrame
@@ -76,7 +76,7 @@
encoderMap[SetTableResponseType] = SetTableResponseFrame
encoderMap[AlarmNotificationType] = AlarmNotificationFrame
encoderMap[AttributeValueChangeType] = AttributeValueChangeFrame
- encoderMap[TestResultType] = TestResultFrame
+ //encoderMap[TestResultType] = TestResultFrame
}
type options struct {
@@ -934,55 +934,55 @@
return meLayer, errors.New("todo: Not implemented")
}
-func TestRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
- if opt.frameFormat == ExtendedIdent {
- return nil, errors.New("Extended message set for this message type is not supported")
- }
- mask, err := checkAttributeMask(m, opt.attributeMask)
- if err != nil {
- return nil, err
- }
- // Common for all MEs
- meLayer := &TestRequest{
- MeBasePacket: MeBasePacket{
- EntityClass: m.GetClassID(),
- EntityInstance: m.GetEntityID(),
- Extended: opt.frameFormat == ExtendedIdent,
- },
- }
- // Get payload space available
- maxPayload := maxPacketAvailable(m, opt)
+//func TestRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+// if opt.frameFormat == ExtendedIdent {
+// return nil, errors.New("Extended message set for this message type is not supported")
+// }
+// mask, err := checkAttributeMask(m, opt.attributeMask)
+// if err != nil {
+// return nil, err
+// }
+// // Common for all MEs
+// meLayer := &TestRequest{
+// MeBasePacket: MeBasePacket{
+// EntityClass: m.GetClassID(),
+// EntityInstance: m.GetEntityID(),
+// Extended: opt.frameFormat == ExtendedIdent,
+// },
+// }
+// // Get payload space available
+// maxPayload := maxPacketAvailable(m, opt)
+//
+// // TODO: Lots of work to do
+//
+// fmt.Println(mask, maxPayload)
+// return meLayer, errors.New("todo: Not implemented")
+//}
- // TODO: Lots of work to do
-
- fmt.Println(mask, maxPayload)
- return meLayer, errors.New("todo: Not implemented")
-}
-
-func TestResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
- if opt.frameFormat == ExtendedIdent {
- return nil, errors.New("Extended message set for this message type is not supported")
- }
- mask, err := checkAttributeMask(m, opt.attributeMask)
- if err != nil {
- return nil, err
- }
- // Common for all MEs
- meLayer := &TestResponse{
- MeBasePacket: MeBasePacket{
- EntityClass: m.GetClassID(),
- EntityInstance: m.GetEntityID(),
- Extended: opt.frameFormat == ExtendedIdent,
- },
- }
- // Get payload space available
- maxPayload := maxPacketAvailable(m, opt)
-
- // TODO: Lots of work to do
-
- fmt.Println(mask, maxPayload)
- return meLayer, errors.New("todo: Not implemented")
-}
+//func TestResponseFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+// if opt.frameFormat == ExtendedIdent {
+// return nil, errors.New("Extended message set for this message type is not supported")
+// }
+// mask, err := checkAttributeMask(m, opt.attributeMask)
+// if err != nil {
+// return nil, err
+// }
+// // Common for all MEs
+// meLayer := &TestResponse{
+// MeBasePacket: MeBasePacket{
+// EntityClass: m.GetClassID(),
+// EntityInstance: m.GetEntityID(),
+// Extended: opt.frameFormat == ExtendedIdent,
+// },
+// }
+// // Get payload space available
+// maxPayload := maxPacketAvailable(m, opt)
+//
+// // TODO: Lots of work to do
+//
+// fmt.Println(mask, maxPayload)
+// return meLayer, errors.New("todo: Not implemented")
+//}
func StartSoftwareDownloadRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
if opt.frameFormat == ExtendedIdent {
@@ -1419,30 +1419,30 @@
return meLayer, nil
}
-func TestResultFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
- if opt.frameFormat == ExtendedIdent {
- return nil, errors.New("Extended message set for this message type is not supported")
- }
- mask, err := checkAttributeMask(m, opt.attributeMask)
- if err != nil {
- return nil, err
- }
- // Common for all MEs
- meLayer := &TestResultMsg{
- MeBasePacket: MeBasePacket{
- EntityClass: m.GetClassID(),
- EntityInstance: m.GetEntityID(),
- Extended: opt.frameFormat == ExtendedIdent,
- },
- }
- // Get payload space available
- maxPayload := maxPacketAvailable(m, opt)
-
- // TODO: Lots of work to do
-
- fmt.Println(mask, maxPayload)
- return meLayer, errors.New("todo: Not implemented")
-}
+//func TestResultFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
+// if opt.frameFormat == ExtendedIdent {
+// return nil, errors.New("Extended message set for this message type is not supported")
+// }
+// mask, err := checkAttributeMask(m, opt.attributeMask)
+// if err != nil {
+// return nil, err
+// }
+// // Common for all MEs
+// meLayer := &TestResultNotification{
+// MeBasePacket: MeBasePacket{
+// EntityClass: m.GetClassID(),
+// EntityInstance: m.GetEntityID(),
+// Extended: opt.frameFormat == ExtendedIdent,
+// },
+// }
+// // Get payload space available
+// maxPayload := maxPacketAvailable(m, opt)
+//
+// // TODO: Lots of work to do
+//
+// fmt.Println(mask, maxPayload)
+// return meLayer, errors.New("todo: Not implemented")
+//}
func GetCurrentDataRequestFrame(m *me.ManagedEntity, opt options) (gopacket.SerializableLayer, error) {
if opt.frameFormat == ExtendedIdent {
diff --git a/messagetypes.go b/messagetypes.go
index 0d48458..456bef8 100644
--- a/messagetypes.go
+++ b/messagetypes.go
@@ -70,6 +70,7 @@
GetCurrentDataResponseType = MessageType(byte(me.GetCurrentData) | me.AK)
SetTableRequestType = MessageType(byte(me.SetTable) | me.AR)
SetTableResponseType = MessageType(byte(me.SetTable) | me.AK)
+
// Autonomous ONU messages
AlarmNotificationType = MessageType(byte(me.AlarmNotification))
AttributeValueChangeType = MessageType(byte(me.AttributeValueChange))
@@ -1629,7 +1630,7 @@
}
omci.Result = me.Results(data[4])
if omci.Result > me.DeviceBusy {
- msg := fmt.Sprintf("invalid results code: %v, must be 0..8", omci.Result)
+ msg := fmt.Sprintf("invalid results code: %v, must be 0..6", omci.Result)
return errors.New(msg)
}
return nil
@@ -1937,30 +1938,54 @@
return err
}
-/////////////////////////////////////////////////////////////////////////////
-// TestRequest: TODO: Not yet implemented
+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 = LayerTypeTestResult
+ return decodingLayerDecoder(omci, data, p)
+
+ case me.AniGClassID, me.ReAniGClassID, me.PhysicalPathTerminationPointReUniClassID,
+ me.ReUpstreamAmplifierClassID, me.ReDownstreamAmplifierClassID:
+ omci := &OpticalLineSupervisionTestRequest{}
+ omci.MsgLayerType = LayerTypeTestResult
+ return decodingLayerDecoder(omci, data, p)
+ }
+}
+
+// TestRequest message
type TestRequest struct {
MeBasePacket
+ Payload []byte
}
func (omci *TestRequest) String() string {
- return fmt.Sprintf("%v", omci.MeBasePacket.String())
+ return fmt.Sprintf("%v, Request: %v octets", omci.MeBasePacket.String(), len(omci.Payload))
+}
+
+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+5)
+ err := omci.MeBasePacket.DecodeFromBytes(data, p, 4)
if err != nil {
return err
}
- return errors.New("need to implement") // TODO: Fix me) // return nil
-}
-func decodeTestRequest(data []byte, p gopacket.PacketBuilder) error {
- omci := &TestRequest{}
- omci.MsgLayerType = LayerTypeTestRequest
- return decodingLayerDecoder(omci, data, p)
+ omci.Payload = make([]byte, MaxTestRequestLength)
+ copy(omci.Payload, omci.MeBasePacket.Payload)
+ return nil
}
// SerializeTo provides serialization of an Test Request message
@@ -1970,17 +1995,81 @@
if err != nil {
return err
}
- return errors.New("need to implement") // TODO: Fix me) // omci.cachedME.SerializeTo(mask, b)
+ 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
}
-/////////////////////////////////////////////////////////////////////////////
-// TestResponse: TODO: Not yet implemented
+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)
+}
+
+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, opts 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", omci.MeBasePacket.String())
+ return fmt.Sprintf("%v, Results: %d (%v)", omci.MeBasePacket.String(), omci.Result, omci.Result)
}
// DecodeFromBytes decodes the given bytes of a Test Response into this layer
@@ -1990,7 +2079,18 @@
if err != nil {
return err
}
- return errors.New("need to implement") // TODO: Fix me) // return nil
+ 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 {
@@ -2006,7 +2106,26 @@
if err != nil {
return err
}
- return errors.New("need to implement") // TODO: Fix me) // omci.cachedME.SerializeTo(mask, b)
+ 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
}
/////////////////////////////////////////////////////////////////////////////
@@ -3027,7 +3146,7 @@
}
omci.Result = me.Results(data[4])
if omci.Result > me.DeviceBusy {
- msg := fmt.Sprintf("invalid results code: %v, must be 0..8", omci.Result)
+ msg := fmt.Sprintf("invalid results code: %v, must be 0..6", omci.Result)
return errors.New(msg)
}
omci.SuccessResults = data[5]
@@ -3411,40 +3530,204 @@
return nil
}
-/////////////////////////////////////////////////////////////////////////////
-//
-type TestResultMsg struct {
- MeBasePacket
+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 (omci *TestResultMsg) String() string {
- return fmt.Sprintf("%v", omci.MeBasePacket.String())
+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))
}
// DecodeFromBytes decodes the given bytes of a Test Result Notification into this layer
-func (omci *TestResultMsg) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
+func (omci *TestResultNotification) 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
}
- return errors.New("need to implement") // TODO: Fix me) // return nil
-}
-func decodeTestResult(data []byte, p gopacket.PacketBuilder) error {
- omci := &TestResultMsg{}
- omci.MsgLayerType = LayerTypeTestResult
- return decodingLayerDecoder(omci, data, p)
+ 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.Payload = make([]byte, MaxTestResultsLength)
+ copy(omci.Payload, omci.MeBasePacket.Payload)
+ return nil
}
// SerializeTo provides serialization of an Test Result notification message
-func (omci *TestResultMsg) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+func (omci *TestResultNotification) SerializeTo(b gopacket.SerializeBuffer, opts 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")
+ }
+ if len(omci.Payload) > MaxTestResultsLength {
+ msg := fmt.Sprintf("Invalid Test Results payload size. Received %v bytes, expected %v",
+ len(omci.Payload), MaxTestResultsLength)
+ return errors.New(msg)
+ }
+ bytes, err := b.AppendBytes(len(omci.Payload))
+ if err != nil {
+ return err
+ }
+
+ copy(bytes, 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")
+}
+
+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
+ err := omci.MeBasePacket.DecodeFromBytes(data, p, 4+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[4]
+ omci.PowerFeedVoltage = binary.BigEndian.Uint16(data[5:])
+
+ // Type = 3
+ omci.ReceivedOpticalPowerType = data[7]
+ omci.ReceivedOpticalPower = binary.BigEndian.Uint16(data[8:])
+
+ // Type = 5
+ omci.MeanOpticalLaunchType = data[10]
+ omci.MeanOpticalLaunch = binary.BigEndian.Uint16(data[11:])
+
+ // Type = 9
+ omci.LaserBiasCurrentType = data[13]
+ omci.LaserBiasCurrent = binary.BigEndian.Uint16(data[14:])
+
+ // Type = 12
+ omci.TemperatureType = data[16]
+ omci.Temperature = binary.BigEndian.Uint16(data[17:])
+
+ omci.GeneralPurposeBuffer = binary.BigEndian.Uint16(data[19:])
+ return nil
+}
+
+// SerializeTo provides serialization of an Test Result notification message
+func (omci *OpticalLineSupervisionTestResult) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
// Basic (common) OMCI Header is 8 octets, 10
err := omci.MeBasePacket.SerializeTo(b)
if err != nil {
return err
}
- return errors.New("need to implement") // TODO: Fix me) // omci.cachedME.SerializeTo(mask, b)
+ 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")
+ }
+ bytes, err := b.AppendBytes(17)
+ if err != nil {
+ return err
+ }
+
+ bytes[0] = omci.PowerFeedVoltageType
+ binary.BigEndian.PutUint16(bytes[1:], omci.PowerFeedVoltage)
+ bytes[3] = omci.ReceivedOpticalPowerType
+ binary.BigEndian.PutUint16(bytes[4:], omci.ReceivedOpticalPower)
+ bytes[6] = omci.MeanOpticalLaunchType
+ binary.BigEndian.PutUint16(bytes[7:], omci.MeanOpticalLaunch)
+ bytes[9] = omci.LaserBiasCurrentType
+ binary.BigEndian.PutUint16(bytes[10:], omci.LaserBiasCurrent)
+ bytes[12] = omci.TemperatureType
+ binary.BigEndian.PutUint16(bytes[13:], omci.Temperature)
+ binary.BigEndian.PutUint16(bytes[15:], omci.GeneralPurposeBuffer)
+ return nil
}
/////////////////////////////////////////////////////////////////////////////
diff --git a/messagetypes_test.go b/messagetypes_test.go
index 514bc79..9a9d2e7 100644
--- a/messagetypes_test.go
+++ b/messagetypes_test.go
@@ -271,7 +271,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -376,7 +376,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -436,7 +436,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -495,7 +495,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -555,7 +555,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -615,7 +615,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -685,7 +685,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -934,7 +934,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -994,7 +994,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1055,7 +1055,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1114,7 +1114,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1200,7 +1200,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1261,7 +1261,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1320,7 +1320,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1380,7 +1380,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1507,7 +1507,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1570,7 +1570,7 @@
//assert.NotNil(t, packet)
//
//omciLayer := packet.Layer(LayerTypeOMCI)
- //assert.NotNil(t, packet)
+ //assert.NotNil(t, omciLayer)
//
//omciMsg, ok := omciLayer.(*OMCI)
//assert.True(t, ok)
@@ -1637,7 +1637,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1676,7 +1676,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1825,7 +1825,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1891,7 +1891,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -1960,7 +1960,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2024,7 +2024,7 @@
//assert.NotNil(t, packet)
//
//omciLayer := packet.Layer(LayerTypeOMCI)
- //assert.NotNil(t, packet)
+ //assert.NotNil(t, omciLayer)
//
//omciMsg, ok := omciLayer.(*OMCI)
//assert.True(t, ok)
@@ -2084,7 +2084,7 @@
//assert.NotNil(t, packet)
//
//omciLayer := packet.Layer(LayerTypeOMCI)
- //assert.NotNil(t, packet)
+ //assert.NotNil(t, omciLayer)
//
//omciMsg, ok := omciLayer.(*OMCI)
//assert.True(t, ok)
@@ -2144,7 +2144,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2203,7 +2203,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2265,7 +2265,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2322,7 +2322,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2391,7 +2391,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2450,7 +2450,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2512,7 +2512,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2574,7 +2574,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2639,7 +2639,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2719,7 +2719,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2774,7 +2774,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2801,7 +2801,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2837,7 +2837,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2907,7 +2907,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -2989,7 +2989,7 @@
assert.Equal(t, omciMsg.Length, uint16(40))
// before bugfix for this JIRA, the following call returned 'nil' Failure was
- // occuring before this at during getResposne decoding.
+ // occurring before this at during getResponse decoding.
msgLayer := packet.Layer(LayerTypeGetResponse)
assert.NotNil(t, msgLayer)
@@ -3000,9 +3000,6 @@
assert.Equal(t, response.AttributeMask, uint16(0xFFFC))
}
-// TODO: Create notification tests for all of the following types
-//TestResult,
-
func TestJira3863(t *testing.T) {
goodMessage := "81a9240a013880010700000000000000000000000000000000000000000000000000000000000000000000283f73ddea"
data, err := stringToPacket(goodMessage)
@@ -3012,7 +3009,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -3041,7 +3038,7 @@
assert.NotNil(t, packet)
omciLayer := packet.Layer(LayerTypeOMCI)
- assert.NotNil(t, packet)
+ assert.NotNil(t, omciLayer)
omciMsg, ok := omciLayer.(*OMCI)
assert.True(t, ok)
@@ -3257,5 +3254,399 @@
assert.Equal(t, strings.ToLower(goodMessage), reconstituted)
}
+func TestGenericTestResultDecode(t *testing.T) {
+ // ONU-G ME for this test with just made up data
+ payload := "1234567890123456789012345678901234567890123456789012345678901234"
+ goodMessage := "00001b0a01000000" + payload + "00000028"
+ data, err := stringToPacket(goodMessage)
+ assert.NoError(t, err)
+
+ packet := gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
+ assert.NotNil(t, packet)
+
+ omciLayer := packet.Layer(LayerTypeOMCI)
+ assert.NotNil(t, omciLayer)
+
+ omciMsg, ok := omciLayer.(*OMCI)
+ assert.True(t, ok)
+ assert.Equal(t, omciMsg.TransactionID, uint16(0x0000))
+ assert.Equal(t, omciMsg.MessageType, TestResultType)
+ assert.Equal(t, omciMsg.DeviceIdentifier, BaselineIdent)
+ assert.Equal(t, uint16(40), omciMsg.Length)
+
+ msgLayer := packet.Layer(LayerTypeTestResult)
+ assert.NotNil(t, msgLayer)
+
+ // This is a generic struct since we do not do detailed decode
+ generic, ok2 := msgLayer.(*TestResultNotification)
+ assert.True(t, ok2)
+ assert.NotNil(t, generic)
+ assert.NotNil(t, generic.MeBasePacket.Payload) // Next three all same data
+ assert.NotNil(t, generic.Payload)
+ assert.NotNil(t, generic.TestResults())
+
+ base := generic.MeBasePacket
+ assert.Equal(t, me.OnuGClassID, base.EntityClass)
+ assert.Equal(t, uint16(0), base.EntityInstance)
+
+ // For the generic Test Result, get the payload data which is all the data in
+ // the test notification past the Entity Instance value.
+ payloadData, payloadErr := stringToPacket(payload)
+ assert.NotNil(t, payloadData)
+ assert.NoError(t, payloadErr)
+ assert.Equal(t, payloadData, base.Payload)
+ assert.Equal(t, payloadData, generic.Payload)
+
+ // Verify string output for message
+ packetString := packet.String()
+ assert.NotZero(t, len(packetString))
+}
+
+func TestOpticalLineSupervisionTestResultDecode(t *testing.T) {
+ // ANI-G ME for this test with just made up data
+ payload := "010034" + "030067" + "050091" + "090034" + "0c0067" + "8901" + "000000000000000000000000000000"
+ goodMessage := "00001b0a01078001" + payload + "00000028"
+ data, err := stringToPacket(goodMessage)
+ assert.NoError(t, err)
+
+ packet := gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
+ assert.NotNil(t, packet)
+
+ omciLayer := packet.Layer(LayerTypeOMCI)
+ assert.NotNil(t, omciLayer)
+
+ omciMsg, ok := omciLayer.(*OMCI)
+ assert.True(t, ok)
+ assert.Equal(t, omciMsg.TransactionID, uint16(0x0000))
+ assert.Equal(t, omciMsg.MessageType, TestResultType)
+ assert.Equal(t, omciMsg.DeviceIdentifier, BaselineIdent)
+ assert.Equal(t, uint16(40), omciMsg.Length)
+
+ msgLayer := packet.Layer(LayerTypeTestResult)
+ assert.NotNil(t, msgLayer)
+
+ // This is a optical line test results
+ optical, ok2 := msgLayer.(*OpticalLineSupervisionTestResult)
+ assert.True(t, ok2)
+ assert.NotNil(t, optical)
+
+ // Get the Managed Entity class ID and instance ID from the base packet
+ base := optical.MeBasePacket
+ assert.Equal(t, me.AniGClassID, base.EntityClass)
+ assert.Equal(t, uint16(0x8001), base.EntityInstance)
+
+ assert.Equal(t, uint8(1), optical.PowerFeedVoltageType)
+ assert.Equal(t, uint16(0x34), optical.PowerFeedVoltage)
+
+ assert.Equal(t, uint8(3), optical.ReceivedOpticalPowerType)
+ assert.Equal(t, uint16(0x67), optical.ReceivedOpticalPower)
+
+ assert.Equal(t, uint8(5), optical.MeanOpticalLaunchType)
+ assert.Equal(t, uint16(0x91), optical.MeanOpticalLaunch)
+
+ assert.Equal(t, uint8(9), optical.LaserBiasCurrentType)
+ assert.Equal(t, uint16(0x34), optical.LaserBiasCurrent)
+
+ assert.Equal(t, uint8(12), optical.TemperatureType)
+ assert.Equal(t, uint16(0x67), optical.Temperature)
+
+ assert.Equal(t, uint16(0x8901), optical.GeneralPurposeBuffer)
+
+ // Verify string output for message
+ packetString := packet.String()
+ assert.NotZero(t, len(packetString))
+}
+
+func TestGenericTestResultSerialize(t *testing.T) {
+ payload := "1234567891234567890123456789012345678901234567890123456789012345"
+ goodMessage := "00001b0a01000000" + payload + "00000028"
+
+ omciLayer := &OMCI{
+ // TransactionID: 0x0c, // Optional for notifications since TID always 0x0000
+ MessageType: TestResultType,
+ // DeviceIdentifier: omci.BaselineIdent, // Optional, defaults to Baseline
+ // Length: 0x28, // Optional, defaults to 40 octets
+ }
+ data, derr := stringToPacket(payload)
+ assert.NoError(t, derr)
+
+ request := &TestResultNotification{
+ MeBasePacket: MeBasePacket{
+ EntityClass: me.OnuGClassID,
+ EntityInstance: uint16(0),
+ },
+ Payload: data,
+ }
+ // Test serialization back to former string
+ var options gopacket.SerializeOptions
+ options.FixLengths = true
+
+ buffer := gopacket.NewSerializeBuffer()
+ err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+ assert.NoError(t, err)
+
+ outgoingPacket := buffer.Bytes()
+ reconstituted := packetToString(outgoingPacket)
+ assert.Equal(t, strings.ToLower(goodMessage), reconstituted)
+}
+
+func TestOpticalLineSupervisionTestResultSerialize(t *testing.T) {
+ // ANI-G ME for this test with just made up data
+ payload := "010034" + "030067" + "050091" + "090034" + "0c0067" + "8901" + "000000000000000000000000000000"
+ goodMessage := "00001b0a01078001" + payload + "00000028"
+
+ omciLayer := &OMCI{
+ // TransactionID: 0x0c, // Optional for notifications since TID always 0x0000
+ MessageType: TestResultType,
+ // DeviceIdentifier: omci.BaselineIdent, // Optional, defaults to Baseline
+ // Length: 0x28, // Optional, defaults to 40 octets
+ }
+ request := &OpticalLineSupervisionTestResult{
+ MeBasePacket: MeBasePacket{
+ EntityClass: me.AniGClassID,
+ EntityInstance: uint16(0x8001),
+ },
+ PowerFeedVoltageType: uint8(1),
+ PowerFeedVoltage: uint16(0x34),
+ ReceivedOpticalPowerType: uint8(3),
+ ReceivedOpticalPower: uint16(0x67),
+ MeanOpticalLaunchType: uint8(5),
+ MeanOpticalLaunch: uint16(0x91),
+ LaserBiasCurrentType: uint8(9),
+ LaserBiasCurrent: uint16(0x34),
+ TemperatureType: uint8(12),
+ Temperature: uint16(0x67),
+ GeneralPurposeBuffer: uint16(0x8901),
+ }
+ // Test serialization back to former string
+ var options gopacket.SerializeOptions
+ options.FixLengths = true
+
+ buffer := gopacket.NewSerializeBuffer()
+ err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+ assert.NoError(t, err)
+
+ outgoingPacket := buffer.Bytes()
+ reconstituted := packetToString(outgoingPacket)
+ assert.Equal(t, strings.ToLower(goodMessage), reconstituted)
+}
+
+func TestGenericTestRequestDecode(t *testing.T) {
+ // ONU-G ME for this test with just made up data
+ payload := "1234567890523456789012345678901234567890123456789012345678901234"
+ goodMessage := "0123520a01000000" + payload + "00000028"
+ data, err := stringToPacket(goodMessage)
+ assert.NoError(t, err)
+
+ packet := gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
+ assert.NotNil(t, packet)
+
+ omciLayer := packet.Layer(LayerTypeOMCI)
+ assert.NotNil(t, omciLayer)
+
+ omciMsg, ok := omciLayer.(*OMCI)
+ assert.True(t, ok)
+ assert.Equal(t, uint16(0x0123), omciMsg.TransactionID)
+ assert.Equal(t, TestRequestType, omciMsg.MessageType)
+ assert.Equal(t, BaselineIdent, omciMsg.DeviceIdentifier)
+ assert.Equal(t, uint16(40), omciMsg.Length)
+
+ msgLayer := packet.Layer(LayerTypeTestResult)
+ assert.NotNil(t, msgLayer)
+
+ // This is a generic struct since we do not do detailed decode
+ generic, ok2 := msgLayer.(*TestRequest)
+ assert.True(t, ok2)
+ assert.NotNil(t, generic)
+ assert.NotNil(t, generic.MeBasePacket.Payload) // Next three all same data
+ assert.NotNil(t, generic.Payload)
+ assert.NotNil(t, generic.TestRequest())
+
+ base := generic.MeBasePacket
+ assert.Equal(t, me.OnuGClassID, base.EntityClass)
+ assert.Equal(t, uint16(0), base.EntityInstance)
+
+ // For the generic Test Result, get the payload data which is all the data in
+ // the test notification past the Entity Instance value.
+ payloadData, payloadErr := stringToPacket(payload)
+ assert.NotNil(t, payloadData)
+ assert.NoError(t, payloadErr)
+ assert.Equal(t, payloadData, base.Payload)
+ assert.Equal(t, payloadData, generic.Payload)
+
+ // Verify string output for message
+ packetString := packet.String()
+ assert.NotZero(t, len(packetString))
+}
+
+func TestOpticalLineSupervisionTestRequestDecode(t *testing.T) {
+ // ANI-G ME for this test with just made up data
+ payload := "01" + "1234" + "5678" + "000000000000000000000000000000000000000000000000000000"
+ goodMessage := "0ddd520a01078001" + payload + "00000028"
+ data, err := stringToPacket(goodMessage)
+ assert.NoError(t, err)
+
+ packet := gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
+ assert.NotNil(t, packet)
+
+ omciLayer := packet.Layer(LayerTypeOMCI)
+ assert.NotNil(t, omciLayer)
+
+ omciMsg, ok := omciLayer.(*OMCI)
+ assert.True(t, ok)
+ assert.Equal(t, uint16(0x0ddd), omciMsg.TransactionID)
+ assert.Equal(t, TestRequestType, omciMsg.MessageType)
+ assert.Equal(t, BaselineIdent, omciMsg.DeviceIdentifier)
+ assert.Equal(t, uint16(40), omciMsg.Length)
+
+ msgLayer := packet.Layer(LayerTypeTestResult)
+ assert.NotNil(t, msgLayer)
+
+ // This is a optical line test results
+ optical, ok2 := msgLayer.(*OpticalLineSupervisionTestRequest)
+ assert.True(t, ok2)
+ assert.NotNil(t, optical)
+
+ // Get the Managed Entity class ID and instance ID from the base packet
+ base := optical.MeBasePacket
+ assert.Equal(t, me.AniGClassID, base.EntityClass)
+ assert.Equal(t, uint16(0x8001), base.EntityInstance)
+
+ assert.Equal(t, uint8(1), optical.SelectTest)
+ assert.Equal(t, uint16(0x1234), optical.GeneralPurposeBuffer)
+ assert.Equal(t, uint16(0x5678), optical.VendorSpecificParameters)
+
+ // Verify string output for message
+ packetString := packet.String()
+ assert.NotZero(t, len(packetString))
+}
+
+func TestGenericTestRequestSerialize(t *testing.T) {
+ payload := "1234567891234567890123456789012345678901234567890123456789012345"
+ goodMessage := "eeee520a01000000" + payload + "00000028"
+
+ omciLayer := &OMCI{
+ TransactionID: 0xeeee,
+ MessageType: TestRequestType,
+ // DeviceIdentifier: omci.BaselineIdent, // Optional, defaults to Baseline
+ // Length: 0x28, // Optional, defaults to 40 octets
+ }
+ data, derr := stringToPacket(payload)
+ assert.NoError(t, derr)
+
+ request := &TestRequest{
+ MeBasePacket: MeBasePacket{
+ EntityClass: me.OnuGClassID,
+ EntityInstance: uint16(0),
+ },
+ Payload: data,
+ }
+ // Test serialization back to former string
+ var options gopacket.SerializeOptions
+ options.FixLengths = true
+
+ buffer := gopacket.NewSerializeBuffer()
+ err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+ assert.NoError(t, err)
+
+ outgoingPacket := buffer.Bytes()
+ reconstituted := packetToString(outgoingPacket)
+ assert.Equal(t, strings.ToLower(goodMessage), reconstituted)
+}
+
+func TestOpticalLineSupervisionTestRequestSerialize(t *testing.T) {
+ // ANI-G ME for this test with just made up data
+ payload := "01" + "1234" + "5678" + "000000000000000000000000000000000000000000000000000000"
+ goodMessage := "bbbb520a01078001" + payload + "00000028"
+
+ omciLayer := &OMCI{
+ TransactionID: 0xbbbb,
+ MessageType: TestRequestType,
+ // DeviceIdentifier: omci.BaselineIdent, // Optional, defaults to Baseline
+ // Length: 0x28, // Optional, defaults to 40 octets
+ }
+ request := &OpticalLineSupervisionTestRequest{
+ MeBasePacket: MeBasePacket{
+ EntityClass: me.AniGClassID,
+ EntityInstance: uint16(0x8001),
+ },
+ SelectTest: uint8(1),
+ GeneralPurposeBuffer: uint16(0x1234),
+ VendorSpecificParameters: uint16(0x5678),
+ }
+ // Test serialization back to former string
+ var options gopacket.SerializeOptions
+ options.FixLengths = true
+
+ buffer := gopacket.NewSerializeBuffer()
+ err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+ assert.NoError(t, err)
+
+ outgoingPacket := buffer.Bytes()
+ reconstituted := packetToString(outgoingPacket)
+ assert.Equal(t, strings.ToLower(goodMessage), reconstituted)
+}
+
+func TestTestResponseDecode(t *testing.T) {
+ goodMessage := "0001320A01000000000000000000000000000000000000000000000000000000000000000000000000000028"
+ data, err := stringToPacket(goodMessage)
+ assert.NoError(t, err)
+
+ packet := gopacket.NewPacket(data, LayerTypeOMCI, gopacket.NoCopy)
+ assert.NotNil(t, packet)
+
+ omciLayer := packet.Layer(LayerTypeOMCI)
+ assert.NotNil(t, omciLayer)
+
+ omciMsg, ok := omciLayer.(*OMCI)
+ assert.True(t, ok)
+ assert.Equal(t, TestResponseType, omciMsg.MessageType)
+ assert.Equal(t, uint16(40), omciMsg.Length)
+
+ msgLayer := packet.Layer(LayerTypeTestResponse)
+
+ assert.NotNil(t, msgLayer)
+
+ response, ok2 := msgLayer.(*TestResponse)
+ assert.True(t, ok2)
+ assert.NotNil(t, response)
+ assert.Equal(t, me.OnuGClassID, response.EntityClass)
+ assert.Equal(t, uint16(0), response.EntityInstance)
+ assert.Equal(t, me.Success, response.Result)
+
+ // Verify string output for message
+ packetString := packet.String()
+ assert.NotZero(t, len(packetString))
+}
+
+func TestTestResponseSerialize(t *testing.T) {
+ goodMessage := "0001320A01000000000000000000000000000000000000000000000000000000000000000000000000000028"
+
+ omciLayer := &OMCI{
+ TransactionID: 0x01,
+ MessageType: TestResponseType,
+ // DeviceIdentifier: omci.BaselineIdent, // Optional, defaults to Baseline
+ // Length: 0x28, // Optional, defaults to 40 octets
+ }
+ request := &TestResponse{
+ MeBasePacket: MeBasePacket{
+ EntityClass: me.OnuGClassID,
+ // Default Instance ID is 0
+ },
+ Result: me.Success,
+ }
+ // Test serialization back to former string
+ var options gopacket.SerializeOptions
+ options.FixLengths = true
+
+ buffer := gopacket.NewSerializeBuffer()
+ err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+ assert.NoError(t, err)
+
+ outgoingPacket := buffer.Bytes()
+ reconstituted := packetToString(outgoingPacket)
+ assert.Equal(t, strings.ToLower(goodMessage), reconstituted)
+}
+
// TODO: Also remember to add extended message tests to the meframe_test.go
// unit tests as more message types are supported
diff --git a/omci.go b/omci.go
index a303a65..b2995d0 100644
--- a/omci.go
+++ b/omci.go
@@ -86,10 +86,18 @@
const MaxAttributeMibUploadNextBaselineLength = MaxBaselineLength - 14 - 8
// MaxAttributeGetNextBaselineLength is the maximum payload size for attributes for
-// a Baseline MIB Get Next message. This is just the attribute portion of the
-// message contents and does not include the Result Code & Attribute Mask.
+// a Baseline MIB Get Next message for the baseline message set. This is just the
+// attribute portion of the message contents and does not include the Result Code & Attribute Mask.
const MaxAttributeGetNextBaselineLength = MaxBaselineLength - 11 - 8
+// MaxTestRequestLength is the maximum payload size for test request message
+// for the baseline message set.
+const MaxTestRequestLength = MaxBaselineLength - 8 - 8
+
+// MaxTestResultsLength is the maximum payload size for test results message
+// for the baseline message set.
+const MaxTestResultsLength = MaxBaselineLength - 8 - 8
+
// MaxManagedEntityMibUploadNextExtendedLength is the maximum payload size for ME
// entries for an Extended MIB Upload Next message. Extended messages differ from
// the baseline as multiple MEs can be reported in a single frame, just not multiple
@@ -115,7 +123,6 @@
DeviceIdentifier DeviceIdent
ResponseExpected bool // Significant for Download Section Request only
Payload []byte // TODO: Deprecated. Use layers.BaseLayer.Payload
- padding []byte // TODO: Deprecated. Never Used
Length uint16
MIC uint32
}
@@ -157,25 +164,24 @@
func decodeOMCI(data []byte, p gopacket.PacketBuilder) error {
// Allow baseline messages without Length & MIC, but no less
- if len(data) < 4 {
+ if len(data) < 10 {
+ p.SetTruncated()
return errors.New("frame header too small")
}
+ omci := &OMCI{}
+
switch DeviceIdent(data[3]) {
default:
- return errors.New("unsupported message type")
+ return errors.New("unsupported message set/device identifier")
case BaselineIdent:
if len(data) < MaxBaselineLength-8 {
+ p.SetTruncated()
return errors.New("frame too small")
}
- omci := &OMCI{}
return omci.DecodeFromBytes(data, p)
case ExtendedIdent:
- if len(data) < 10 {
- return errors.New("extended frame header too small")
- }
- omci := &OMCI{}
return omci.DecodeFromBytes(data, p)
}
}