blob: 840a9187573dc5f1a28eefd4ab53485b4a3f7175 [file] [log] [blame]
Chip Boling610117d2021-09-09 11:24:34 -05001/*
2 * Copyright (c) 2018 - present. Boling Consulting Solutions (bcsw.net)
3 * Copyright 2020-present Open Networking Foundation
4
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8
9 * http://www.apache.org/licenses/LICENSE-2.0
10
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package omci
19
20import (
21 "encoding/binary"
22 "errors"
23 "fmt"
24 "github.com/google/gopacket"
Andrea Campanellae0cd8232021-10-15 15:10:23 +020025 me "github.com/opencord/omci-lib-go/v2/generated"
Chip Boling610117d2021-09-09 11:24:34 -050026)
27
28type GetCurrentDataRequest struct {
29 MeBasePacket
30 AttributeMask uint16
31}
32
33func (omci *GetCurrentDataRequest) String() string {
34 return fmt.Sprintf("%v, Attribute Mask: %#x",
35 omci.MeBasePacket.String(), omci.AttributeMask)
36}
37
38// LayerType returns LayerTypeGetCurrentDataRequest
39func (omci *GetCurrentDataRequest) LayerType() gopacket.LayerType {
40 return LayerTypeGetCurrentDataRequest
41}
42
43// CanDecode returns the set of layer types that this DecodingLayer can decode
44func (omci *GetCurrentDataRequest) CanDecode() gopacket.LayerClass {
45 return LayerTypeGetCurrentDataRequest
46}
47
48// NextLayerType returns the layer type contained by this DecodingLayer.
49func (omci *GetCurrentDataRequest) NextLayerType() gopacket.LayerType {
50 return gopacket.LayerTypePayload
51}
52
53// DecodeFromBytes decodes the given bytes of a Get Current Data Request into this layer
54func (omci *GetCurrentDataRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
55 // Common ClassID/EntityID decode in msgBase
56 var offset int
57 if omci.Extended {
58 offset = 6
59 } else {
60 offset = 4
61 }
62 hdrSize := offset + 2
63 err := omci.MeBasePacket.DecodeFromBytes(data, p, hdrSize)
64 if err != nil {
65 return err
66 }
67 meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
68 me.ParamData{EntityID: omci.EntityInstance})
69 if omciErr.StatusCode() != me.Success {
70 return omciErr.GetError()
71 }
72 // ME needs to support GetNext
73 if !me.SupportsMsgType(meDefinition, me.GetCurrentData) {
74 return me.NewProcessingError("managed entity does not support Get Current Data Message-Type")
75 }
76 // Note: G.988 specifies that an error code of (3) should result if more
77 // than one attribute is requested
78 omci.AttributeMask = binary.BigEndian.Uint16(data[offset:])
79 return nil
80}
81
82func decodeGetCurrentDataRequest(data []byte, p gopacket.PacketBuilder) error {
83 omci := &GetCurrentDataRequest{}
84 omci.MsgLayerType = LayerTypeGetCurrentDataRequest
85 return decodingLayerDecoder(omci, data, p)
86}
87
88func decodeGetCurrentDataRequestExtended(data []byte, p gopacket.PacketBuilder) error {
89 omci := &GetCurrentDataRequest{}
90 omci.MsgLayerType = LayerTypeGetCurrentDataRequest
91 omci.Extended = true
92 return decodingLayerDecoder(omci, data, p)
93}
94
95// SerializeTo provides serialization of an Get Current Data Request message
96func (omci *GetCurrentDataRequest) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error {
97 // Basic (common) OMCI Header is 8 octets, 10
98 err := omci.MeBasePacket.SerializeTo(b)
99 if err != nil {
100 return err
101 }
102 meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
103 me.ParamData{EntityID: omci.EntityInstance})
104 if omciErr.StatusCode() != me.Success {
105 return omciErr.GetError()
106 }
107 // ME needs to support GetNext
108 if !me.SupportsMsgType(meDefinition, me.GetCurrentData) {
109 return me.NewProcessingError("managed entity does not support Get Current Data Message-Type")
110 }
111 bytes, err := b.AppendBytes(2)
112 if err != nil {
113 return err
114 }
115 binary.BigEndian.PutUint16(bytes, omci.AttributeMask)
116 return nil
117}
118
119type GetCurrentDataResponse struct {
120 MeBasePacket
121 Result me.Results
122 AttributeMask uint16
123 UnsupportedAttributeMask uint16
124 FailedAttributeMask uint16
125 Attributes me.AttributeValueMap
126}
127
128func (omci *GetCurrentDataResponse) String() string {
129 return fmt.Sprintf("%v, Result: %d (%v), Attribute Mask: %#x, Attributes: %v",
130 omci.MeBasePacket.String(), omci.Result, omci.Result, omci.AttributeMask, omci.Attributes)
131}
132
133// LayerType returns LayerTypeGetCurrentDataResponse
134func (omci *GetCurrentDataResponse) LayerType() gopacket.LayerType {
135 return LayerTypeGetCurrentDataResponse
136}
137
138// CanDecode returns the set of layer types that this DecodingLayer can decode
139func (omci *GetCurrentDataResponse) CanDecode() gopacket.LayerClass {
140 return LayerTypeGetCurrentDataResponse
141}
142
143// NextLayerType returns the layer type contained by this DecodingLayer.
144func (omci *GetCurrentDataResponse) NextLayerType() gopacket.LayerType {
145 return gopacket.LayerTypePayload
146}
147
148// DecodeFromBytes decodes the given bytes of a Get Current Data Response into this layer
149func (omci *GetCurrentDataResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
150 // Common ClassID/EntityID decode in msgBase
151 var offset, length int
152 if omci.Extended {
153 offset = 6
154 length = 7
155 } else {
156 offset = 4
157 length = 3
158 }
159 hdrSize := offset + length
160 err := omci.MeBasePacket.DecodeFromBytes(data, p, hdrSize)
161 if err != nil {
162 return err
163 }
164 meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
165 me.ParamData{EntityID: omci.EntityInstance})
166 if omciErr.StatusCode() != me.Success {
167 return omciErr.GetError()
168 }
169 // ME needs to support Set
170 if !me.SupportsMsgType(meDefinition, me.GetCurrentData) {
171 return me.NewProcessingError("managed entity does not support Get Current Data Message-Type")
172 }
173 omci.Result = me.Results(data[offset])
174 omci.AttributeMask = binary.BigEndian.Uint16(data[offset+1:])
175 switch omci.Result {
176 case me.ProcessingError, me.NotSupported, me.UnknownEntity, me.UnknownInstance, me.DeviceBusy:
177 return nil // Done (do not try and decode attributes)
178 case me.AttributeFailure:
179 if omci.Extended {
180 omci.UnsupportedAttributeMask = binary.BigEndian.Uint16(data[offset+3:])
181 omci.FailedAttributeMask = binary.BigEndian.Uint16(data[offset+5:])
182 } else {
183 omci.UnsupportedAttributeMask = binary.BigEndian.Uint16(data[32:])
184 omci.FailedAttributeMask = binary.BigEndian.Uint16(data[34:])
185 }
186 }
187 // Attribute decode. Note that the ITU-T G.988 specification states that the
188 // Unsupported and Failed attribute masks are always present
189 // but only valid if the status code== 9. However some XGS
190 // ONUs (T&W and Alpha, perhaps more) will use these last 4
191 // octets for data if the status code == 0 in a baseline GET
192 // Response. So this behaviour is anticipated here as well
193 // and will be allowed in favor of greater interoperability.
194 omci.Attributes, err = meDefinition.DecodeAttributes(omci.AttributeMask, data[hdrSize:], p, byte(GetCurrentDataResponseType))
195 if err != nil {
196 return err
197 }
198 // Validate all attributes support read
199 for attrName := range omci.Attributes {
200 attr, err := me.GetAttributeDefinitionByName(meDefinition.GetAttributeDefinitions(), attrName)
201 if err != nil {
202 return err
203 }
204 if attr.Index != 0 && !me.SupportsAttributeAccess(*attr, me.Read) {
205 msg := fmt.Sprintf("attribute '%v' does not support read access", attrName)
206 return me.NewProcessingError(msg)
207 }
208 }
209 if eidDef, eidDefOK := meDefinition.GetAttributeDefinitions()[0]; eidDefOK {
210 omci.Attributes[eidDef.GetName()] = omci.EntityInstance
211 return nil
212 }
213 return errors.New("all Managed Entities have an EntityID attribute")
214}
215
216func decodeGetCurrentDataResponse(data []byte, p gopacket.PacketBuilder) error {
217 omci := &GetCurrentDataResponse{}
218 omci.MsgLayerType = LayerTypeGetCurrentDataResponse
219 return decodingLayerDecoder(omci, data, p)
220}
221
222func decodeGetCurrentDataResponseExtended(data []byte, p gopacket.PacketBuilder) error {
223 omci := &GetCurrentDataResponse{}
224 omci.MsgLayerType = LayerTypeGetCurrentDataResponse
225 omci.Extended = true
226 return decodingLayerDecoder(omci, data, p)
227}
228
229// SerializeTo provides serialization of an Get Current Data Message Type Response
230func (omci *GetCurrentDataResponse) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
231 // Basic (common) OMCI Header is 8 octets, 10
232 err := omci.MeBasePacket.SerializeTo(b)
233 if err != nil {
234 return err
235 }
236 meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
237 me.ParamData{EntityID: omci.EntityInstance})
238 if omciErr.StatusCode() != me.Success {
239 return omciErr.GetError()
240 }
241 // ME needs to support Get
242 if !me.SupportsMsgType(meDefinition, me.GetCurrentData) {
243 return me.NewProcessingError("managed entity does not support the Get Current Data Message-Type")
244 }
245 var resultOffset, hdrSize int
246
247 if omci.Extended {
248 resultOffset = 2
249 hdrSize = resultOffset + 1 + 2 + 2 + 2 // length + result + masks
250 } else {
251 resultOffset = 0
252 hdrSize = resultOffset + 1 + 2 // length + result + attr-mask
253 }
254 bytes, err := b.AppendBytes(hdrSize)
255 if err != nil {
256 return err
257 }
258 bytes[resultOffset] = byte(omci.Result)
259 binary.BigEndian.PutUint16(bytes[resultOffset+1:], omci.AttributeMask)
260
261 // Validate all attributes support read
262 for attrName := range omci.Attributes {
263 var attr *me.AttributeDefinition
264 attr, err = me.GetAttributeDefinitionByName(meDefinition.GetAttributeDefinitions(), attrName)
265 if err != nil {
266 return err
267 }
268 if attr.Index != 0 && !me.SupportsAttributeAccess(*attr, me.Read) {
269 msg := fmt.Sprintf("attribute '%v' does not support read access", attrName)
270 return me.NewProcessingError(msg)
271 }
272 }
273 // Attribute serialization
274 switch omci.Result {
275 default:
276 if omci.Extended {
277 binary.BigEndian.PutUint16(bytes, 7) // Length
278 binary.BigEndian.PutUint32(bytes[resultOffset+3:], 0)
279 }
280 break
281
282 case me.Success, me.AttributeFailure:
283 var available int
284 if omci.Extended {
285 available = MaxExtendedLength - 10 - 3 - 4 - 4 // Less: header, result+mask, optional-masks mic
286 } else {
287 available = MaxBaselineLength - 8 - 3 - 4 - 8 // hdr, result+mask, optional-masks, trailer
288 }
289 // Serialize to temporary buffer if we may need to reset values due to
290 // recoverable truncation errors
291 attributeBuffer := gopacket.NewSerializeBuffer()
292 var failedMask uint16
293 err, failedMask = meDefinition.SerializeAttributes(omci.Attributes, omci.AttributeMask,
294 attributeBuffer, byte(GetCurrentDataResponseType), available, opts.FixLengths)
295
296 if err != nil {
297 return err
298 }
299 if failedMask != 0 {
300 // Not all attributes would fit
301 omci.FailedAttributeMask |= failedMask
302 omci.AttributeMask &= ^failedMask
303 omci.Result = me.AttributeFailure
304
305 // Adjust already recorded values
306 bytes[resultOffset] = byte(omci.Result)
307 binary.BigEndian.PutUint16(bytes[resultOffset+1:], omci.AttributeMask)
308 }
309 if omci.Extended {
310 // Set length and any failure masks
311 binary.BigEndian.PutUint16(bytes, uint16(len(attributeBuffer.Bytes())+7))
312
313 if omci.Result == me.AttributeFailure {
314 binary.BigEndian.PutUint16(bytes[resultOffset+3:], omci.UnsupportedAttributeMask)
315 binary.BigEndian.PutUint16(bytes[resultOffset+5:], omci.FailedAttributeMask)
316 } else {
317 binary.BigEndian.PutUint32(bytes[resultOffset+3:], 0)
318 }
319 }
320 // Copy over attributes to the original serialization buffer
321 var newSpace []byte
322
323 newSpace, err = b.AppendBytes(len(attributeBuffer.Bytes()))
324 if err != nil {
325 return err
326 }
327 copy(newSpace, attributeBuffer.Bytes())
328
329 if !omci.Extended {
330 // Calculate space left. Max - msgType header - OMCI trailer - spacedUsedSoFar
331 bytesLeft := MaxBaselineLength - 4 - 8 - len(b.Bytes())
332
333 var remainingBytes []byte
334 remainingBytes, err = b.AppendBytes(bytesLeft + 4)
335
336 if err != nil {
337 return me.NewMessageTruncatedError(err.Error())
338 }
339 copy(remainingBytes, lotsOfZeros[:])
340
341 if omci.Result == me.AttributeFailure {
342 binary.BigEndian.PutUint16(remainingBytes[bytesLeft-4:bytesLeft-2], omci.UnsupportedAttributeMask)
343 binary.BigEndian.PutUint16(remainingBytes[bytesLeft-2:bytesLeft], omci.FailedAttributeMask)
344 }
345 }
346 }
347 return nil
348}