blob: 61ceafdfd28b1e0ce1e17767c970c9dd4de21ff5 [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"
25 me "github.com/opencord/omci-lib-go/generated"
26 "math/bits"
27)
28
29type SetTableRequest struct {
30 MeBasePacket
31 AttributeMask uint16
32 // Attributes below should be a single attribute whose value is of type TableRows
33 Attributes me.AttributeValueMap
34}
35
36func (omci *SetTableRequest) String() string {
37 return fmt.Sprintf("%v", omci.MeBasePacket.String())
38}
39
40// LayerType returns LayerTypeSetTableRequest
41func (omci *SetTableRequest) LayerType() gopacket.LayerType {
42 return LayerTypeSetTableRequest
43}
44
45// CanDecode returns the set of layer types that this DecodingLayer can decode
46func (omci *SetTableRequest) CanDecode() gopacket.LayerClass {
47 return LayerTypeSetTableRequest
48}
49
50// NextLayerType returns the layer type contained by this DecodingLayer.
51func (omci *SetTableRequest) NextLayerType() gopacket.LayerType {
52 return gopacket.LayerTypePayload
53}
54
55// DecodeFromBytes decodes the given bytes of a Set Table Request into this layer
56func (omci *SetTableRequest) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
57 // Only supported in the Extended message set
58 if !omci.Extended {
59 return me.NewNotSupportedError("baseline message set not supported by SetTable Message-Type")
60 }
61 // Common ClassID/EntityID decode in msgBase
62 hdrSize := 6 + 2
63
64 if len(data) < hdrSize {
65 p.SetTruncated()
66 return errors.New("frame too small")
67 } // Common ClassID/EntityID decode in msgBase
68 err := omci.MeBasePacket.DecodeFromBytes(data, p, 6+2)
69 if err != nil {
70 return err
71 }
72 meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
73 me.ParamData{EntityID: omci.EntityInstance})
74 if omciErr.StatusCode() != me.Success {
75 return omciErr.GetError()
76 }
77 // ME needs to support SetTable
78 if !me.SupportsMsgType(meDefinition, me.SetTable) {
79 return me.NewProcessingError("managed entity does not support SetTable Message-Type")
80 }
81 offset := hdrSize - 2
82 omci.AttributeMask = binary.BigEndian.Uint16(data[offset:])
83
84 // Only a single attribute bit can be set
85 if bits.OnesCount16(omci.AttributeMask) != 1 {
86 return me.NewProcessingError("only a single attribute can be specified for the SetTable Message-Type")
87 }
88 // Attribute decode
89 omci.Attributes, err = meDefinition.DecodeAttributes(omci.AttributeMask, data[hdrSize:], p, byte(SetTableRequestType))
90 if err != nil {
91 return err
92 }
93 // Validate that the selected attribute support write and is a table
94 for attrName := range omci.Attributes {
95 attr, err := me.GetAttributeDefinitionByName(meDefinition.GetAttributeDefinitions(), attrName)
96 if err != nil {
97 return err
98 }
99 if attr.Index != 0 && attr.Mask == omci.AttributeMask {
100 if !me.SupportsAttributeAccess(*attr, me.Write) {
101 msg := fmt.Sprintf("attribute '%v' does not support write access", attrName)
102 return me.NewProcessingError(msg)
103 }
104 if !attr.IsTableAttribute() {
105 msg := fmt.Sprintf("attribute '%v' must be a table attribute for a SetTable Message-Type", attrName)
106 return me.NewProcessingError(msg)
107 }
108 break
109 }
110 }
111 if eidDef, eidDefOK := meDefinition.GetAttributeDefinitions()[0]; eidDefOK {
112 omci.Attributes[eidDef.GetName()] = omci.EntityInstance
113 return nil
114 }
115 return me.NewProcessingError("All Managed Entities have an EntityID attribute")
116}
117
118func decodeSetTableRequest(data []byte, p gopacket.PacketBuilder) error {
119 return me.NewNotSupportedError("baseline message set not supported by SetTable Message-Type")
120}
121
122func decodeSetTableRequestExtended(data []byte, p gopacket.PacketBuilder) error {
123 omci := &SetTableRequest{}
124 omci.MsgLayerType = LayerTypeSetTableRequest
125 omci.Extended = true
126 return decodingLayerDecoder(omci, data, p)
127}
128
129// SerializeTo provides serialization of an Set Table Message Type Request
130func (omci *SetTableRequest) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error {
131 // Only Extended message set is supported for this message type
132 if !omci.Extended {
133 return me.NewNotSupportedError("only Extended Message set support for the SetTable Message-Type")
134 }
135 // Basic (common) OMCI Header
136 err := omci.MeBasePacket.SerializeTo(b)
137 if err != nil {
138 return err
139 }
140 meDefinition, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
141 me.ParamData{EntityID: omci.EntityInstance})
142 if omciErr.StatusCode() != me.Success {
143 return omciErr.GetError()
144 }
145 // ME needs to support SetTable
146 if !me.SupportsMsgType(meDefinition, me.SetTable) {
147 return me.NewProcessingError("managed entity does not support SetTable Message-Type")
148 }
149 // Only a single attribute bit can be set for this request
150 if bits.OnesCount16(omci.AttributeMask) != 1 {
151 return me.NewProcessingError("only a single attribute can be specified for the SetTable Message-Type")
152 }
153 // Find the attributes and make sure it supports a write
154 for attrName := range omci.Attributes {
155 attr, err := me.GetAttributeDefinitionByName(meDefinition.GetAttributeDefinitions(), attrName)
156 if err != nil {
157 return err
158 }
159 // Do not test for write of Entity ID in the attribute list
160 if attr.Index != 0 && attr.Mask == omci.AttributeMask {
161 // Must be a table attribute and support writes
162 if !me.SupportsAttributeAccess(*attr, me.Write) {
163 msg := fmt.Sprintf("attribute '%v' does not support write access", attrName)
164 return me.NewProcessingError(msg)
165 }
166 if !attr.IsTableAttribute() {
167 msg := fmt.Sprintf("attribute '%v' must be a table attribute for a SetTable Message-Type", attrName)
168 return me.NewProcessingError(msg)
169 }
170 break
171 }
172 }
173 // Attribute serialization
174 maskOffset := 1
175 maskOffset = 2
176 bytesAvailable := MaxExtendedLength - 12 - 4
177 attributeBuffer := gopacket.NewSerializeBuffer()
178 if attrErr, _ := meDefinition.SerializeAttributes(omci.Attributes, omci.AttributeMask, attributeBuffer,
179 byte(SetTableRequestType), bytesAvailable, false); attrErr != nil {
180 return attrErr
181 }
182 bytes, err := b.AppendBytes(maskOffset + 2 + len(attributeBuffer.Bytes()))
183 if err != nil {
184 return err
185 }
186 // Encode the length nd attribute mask
187 binary.BigEndian.PutUint16(bytes, uint16(len(attributeBuffer.Bytes())+2))
188 binary.BigEndian.PutUint16(bytes[maskOffset:], omci.AttributeMask)
189 copy(bytes[maskOffset+2:], attributeBuffer.Bytes())
190 return nil
191}
192
193type SetTableResponse struct {
194 MeBasePacket
195 Result me.Results
196}
197
198func (omci *SetTableResponse) String() string {
199 return fmt.Sprintf("%v", omci.MeBasePacket.String())
200}
201
202// LayerType returns LayerTypeSetTableResponse
203func (omci *SetTableResponse) LayerType() gopacket.LayerType {
204 return LayerTypeSetTableResponse
205}
206
207// CanDecode returns the set of layer types that this DecodingLayer can decode
208func (omci *SetTableResponse) CanDecode() gopacket.LayerClass {
209 return LayerTypeSetTableResponse
210}
211
212// NextLayerType returns the layer type contained by this DecodingLayer.
213func (omci *SetTableResponse) NextLayerType() gopacket.LayerType {
214 return gopacket.LayerTypePayload
215}
216
217// DecodeFromBytes decodes the given bytes of a Set Table Response into this layer
218func (omci *SetTableResponse) DecodeFromBytes(data []byte, p gopacket.PacketBuilder) error {
219 // Common ClassID/EntityID decode in msgBase
220 err := omci.MeBasePacket.DecodeFromBytes(data, p, 6+1)
221 if err != nil {
222 return err
223 }
224 entity, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
225 me.ParamData{EntityID: omci.EntityInstance})
226 if omciErr.StatusCode() != me.Success {
227 return omciErr.GetError()
228 }
229 // ME needs to support SetTable
230 if !me.SupportsMsgType(entity, me.SetTable) {
231 return me.NewProcessingError("managed entity does not support the SetTable Message-Type")
232 }
233 omci.Result = me.Results(data[6])
234 if omci.Result == 7 || omci.Result == 8 || omci.Result >= 9 {
235 msg := fmt.Sprintf("invalid SetTable results code: %v, must be 0..6, 9", omci.Result)
236 return errors.New(msg)
237 }
238 return nil
239}
240
241func decodeSetTableResponse(data []byte, p gopacket.PacketBuilder) error {
242 return me.NewNotSupportedError("baseline message set not supported by SetTable Message-Type")
243}
244
245func decodeSetTableResponseExtended(data []byte, p gopacket.PacketBuilder) error {
246 omci := &SetTableResponse{}
247 omci.MsgLayerType = LayerTypeSetTableResponse
248 omci.Extended = true
249 return decodingLayerDecoder(omci, data, p)
250}
251
252// SerializeTo provides serialization of an Set Table Message Type Response
253func (omci *SetTableResponse) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error {
254 // Basic (common) OMCI Header
255 err := omci.MeBasePacket.SerializeTo(b)
256 if err != nil {
257 return err
258 }
259 entity, omciErr := me.LoadManagedEntityDefinition(omci.EntityClass,
260 me.ParamData{EntityID: omci.EntityInstance})
261 if omciErr.StatusCode() != me.Success {
262 return omciErr.GetError()
263 }
264 // ME needs to support SetTable
265 if !me.SupportsMsgType(entity, me.SetTable) {
266 return me.NewProcessingError("managed entity does not support the SetTable Message-Type")
267 }
268 offset := 2
269 length := 1
270 bytes, err := b.AppendBytes(offset + length)
271 if err != nil {
272 return err
273 }
274 if omci.Result == 7 || omci.Result == 8 || omci.Result >= 9 {
275 msg := fmt.Sprintf("invalid SetTable results code: %v, must be 0..6, 9", omci.Result)
276 return errors.New(msg)
277 }
278 // TODO: Section A.1.1 (page 505) of ITU-G.988-202003 specifies that:
279 // When the result-reason code in a response message indicates an exception (i.e., its
280 // value is not 0), the response message is permitted to include vendor-specific
281 // additional information. The rules for additional error information are as follows.
282 //
283 // 1. Additional error information is optional for the ONU to insert.
284 // 2. Additional information may or may not be represented in textual form.
285 // 3. The semantics of additional error information are specific to the ONU vendor.
286 // 4. The ONU must not rely on the OLT being able to detect or interpret additional
287 // error information.
288 // 5. Additional error information may occupy only padding bytes (baseline message set)
289 // or only uncommitted trailing bytes (extended message set).
290 // 6. In get, get current data and get next responses, the attribute mask controls the
291 // padding definition.
292 // 7. No additional error information is permitted in responses to start download and
293 // end download messages that are directed to multiple target MEs, as indicated by
294 // 0xFFFF in the target ME identifier.
295 //
296 // TODO: Add this capability to all appropriate response serializations and validate for
297 // decodes the information is available through the Payload() function of the message-type
298
299 binary.BigEndian.PutUint16(bytes, uint16(1))
300 bytes[offset] = byte(omci.Result)
301 return nil
302}