blob: 4956e89e1ecba7f28b95ffb54eb0e04f2f8a3c6c [file] [log] [blame]
Chip Boling6e27b352020-02-14 09:10:01 -06001/*
2 * Copyright (c) 2018 - present. Boling Consulting Solutions (bcsw.net)
Andrea Campanella7167ebb2020-02-24 09:56:38 +01003 * Copyright 2020-present Open Networking Foundation
4
Chip Boling6e27b352020-02-14 09:10:01 -06005 * 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
Andrea Campanella7167ebb2020-02-24 09:56:38 +01008
Chip Boling6e27b352020-02-14 09:10:01 -06009 * http://www.apache.org/licenses/LICENSE-2.0
Andrea Campanella7167ebb2020-02-24 09:56:38 +010010
Chip Boling6e27b352020-02-14 09:10:01 -060011 * 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 */
David K. Bainbridgeadf422d2021-04-09 16:06:41 +000017/*
Chip Boling6e27b352020-02-14 09:10:01 -060018 * NOTE: This file was generated, manual edits will be overwritten!
19 *
20 * Generated by 'goCodeGenerator.py':
21 * https://github.com/cboling/OMCI-parser/README.md
22 */
23
24package generated
25
26import (
27 "encoding/base64"
28 "encoding/binary"
29 "errors"
30 "fmt"
Chip Boling6e27b352020-02-14 09:10:01 -060031 "reflect"
32 "sort"
33 "strings"
David K. Bainbridgeadf422d2021-04-09 16:06:41 +000034
35 mapset "github.com/deckarep/golang-set"
36 "github.com/google/gopacket"
Chip Boling6e27b352020-02-14 09:10:01 -060037)
38
39// Attribute types
40type AttributeType uint8
41
42const (
43 UnknownAttributeType AttributeType = iota // Not known
44 OctetsAttributeType // Series of zero or more octets
45 StringAttributeType // Readable String
46 UnsignedIntegerAttributeType // Integer (0..max)
47 TableAttributeType // Table (of Octets)
48 SignedIntegerAttributeType // Signed integer, often expressed as 2's complement
49 PointerAttributeType // Managed Entity ID or pointer to a Managed instance
50 BitFieldAttributeType // Bitfield
51 EnumerationAttributeType // Fixed number of values (Unsigned Integers)
52 CounterAttributeType // Incrementing counter
53)
54
Chip Boling610117d2021-09-09 11:24:34 -050055// AttributeDefinitionMap is a map of attribute definitions with the attribute index (0..16)
Chip Boling6e27b352020-02-14 09:10:01 -060056// as the key
57type AttributeDefinitionMap map[uint]AttributeDefinition
58
59// AttributeDefinition defines a single specific Managed Entity's attributes
60type AttributeDefinition struct {
61 Name string
62 AttributeType AttributeType
63 Index uint
64 Mask uint16
65 DefValue interface{}
66 Size int // Size of attribute in bytes. 0 indicates variable/unknown
67 Access mapset.Set // AttributeAccess...
68 Constraint func(interface{}) *ParamError
69 Avc bool // If true, an AVC notification can occur for the attribute
70 Tca bool // If true, a threshold crossing alert alarm notification can occur for the attribute
71 Optional bool // If true, attribute is option, else mandatory
72 Deprecated bool // If true, attribute is deprecated
73}
74
Chip Boling610117d2021-09-09 11:24:34 -050075// TableRows is used by the SetTable request/response
76type TableRows struct {
77 NumRows int // Number of rows of 'AttributeDefinition.Size' length
78 Rows []byte // 0..NumRows rows of attribute data of size 'AttributeDefinition.Size'
79}
80
Chip Boling6e27b352020-02-14 09:10:01 -060081func (attr *AttributeDefinition) String() string {
82 return fmt.Sprintf("AttributeDefinition: %v (%v/%v): Size: %v, Default: %v, Access: %v",
83 attr.GetName(), attr.AttributeType, attr.GetIndex(), attr.GetSize(), attr.GetDefault(), attr.GetAccess())
84}
85
86// GetName returns the attribute's name
87func (attr AttributeDefinition) GetName() string { return attr.Name }
88
Chip Boling610117d2021-09-09 11:24:34 -050089// GetIndex returns the attribute index )0..16)
Chip Boling6e27b352020-02-14 09:10:01 -060090func (attr AttributeDefinition) GetIndex() uint { return attr.Index }
91
92// GetDefault provides the default value for an attribute if not specified
93// during its creation
94func (attr AttributeDefinition) GetDefault() interface{} { return attr.DefValue }
95
96// GetSize returns the size of the attribute. For table attributes, the size is
97// the size of a single table.
98func (attr AttributeDefinition) GetSize() int { return attr.Size }
99
100// GetAccess provides the access information (Read, Write, ...)
101func (attr AttributeDefinition) GetAccess() mapset.Set { return attr.Access }
102
103// GetConstraints returns a function that can be called for the attribute
104// that will validate the value. An appropriate error is returned if the
105// constraint fails, otherwise nil is returned to indicate that the value
106// is valid.
107func (attr AttributeDefinition) GetConstraints() func(interface{}) *ParamError {
108 return attr.Constraint
109}
110
111// IsTableAttribute returns true if the attribute is a table
112func (attr AttributeDefinition) IsTableAttribute() bool {
113 return attr.AttributeType == TableAttributeType
114}
115
116// IsCounter returns true if the attribute is a counter (usually expressed as an
117// unsigned integer)
118func (attr AttributeDefinition) IsCounter() bool {
119 return attr.AttributeType == CounterAttributeType
120}
121
122// IsBitField returns true if the attribute is a bitfield
123func (attr AttributeDefinition) IsBitField() bool {
124 return attr.AttributeType == BitFieldAttributeType
125}
126
127// IsString returns true if the attribute is a string. Strings are typically encoded
128// into fixed length files and padded with 0's
129func (attr AttributeDefinition) IsString() bool {
130 return attr.AttributeType == StringAttributeType
131}
132
133// Decode takes a slice of bytes and converts them into a value appropriate for
134// the attribute, or returns an error on failure
135func (attr *AttributeDefinition) Decode(data []byte, df gopacket.DecodeFeedback, msgType byte) (interface{}, error) {
136 if attr.IsTableAttribute() {
137 value, err := attr.tableAttributeDecode(data, df, msgType)
138 if err != nil {
139 return nil, err
140 }
141 if attr.GetConstraints() != nil {
142 if omciErr := attr.GetConstraints()(value); omciErr != nil {
143 return nil, omciErr.GetError()
144 }
145 }
146 return value, nil
147 }
148 size := attr.GetSize()
149
150 if len(data) < size {
151 df.SetTruncated()
152 return nil, NewMessageTruncatedError("packet too small for field")
153 }
154 switch attr.AttributeType {
155 case StringAttributeType, OctetsAttributeType, UnknownAttributeType:
156 value := make([]byte, size)
157 copy(value, data[:size])
158 if attr.GetConstraints() != nil {
159 if omciErr := attr.GetConstraints()(value); omciErr != nil {
160 return nil, omciErr.GetError()
161 }
162 }
163 return value, nil
164
165 default:
166 switch attr.GetSize() {
167 default:
168 value := make([]byte, size)
169 copy(value, data[:size])
170 if attr.GetConstraints() != nil {
171 if omciErr := attr.GetConstraints()(value); omciErr != nil {
172 return nil, omciErr.GetError()
173 }
174 }
175 return value, nil
176 case 1:
177 value := data[0]
178 if attr.GetConstraints() != nil {
179 if omciErr := attr.GetConstraints()(value); omciErr != nil {
180 return nil, omciErr.GetError()
181 }
182 }
183 return value, nil
184 case 2:
185 value := binary.BigEndian.Uint16(data[0:2])
186 if attr.GetConstraints() != nil {
187 if omciErr := attr.GetConstraints()(value); omciErr != nil {
188 return nil, omciErr.GetError()
189 }
190 }
191 return value, nil
192 case 4:
193 value := binary.BigEndian.Uint32(data[0:4])
194 if attr.GetConstraints() != nil {
195 if omciErr := attr.GetConstraints()(value); omciErr != nil {
196 return nil, omciErr.GetError()
197 }
198 }
199 return value, nil
200 case 8:
201 value := binary.BigEndian.Uint64(data[0:8])
202 if attr.GetConstraints() != nil {
203 omciErr := attr.GetConstraints()(value)
204 if omciErr != nil {
205 return nil, omciErr.GetError()
206 }
207 }
208 return value, nil
209 }
210 }
211}
212
213// IOctetStream interface defines a way to convert a custom type to/from an octet
214// stream.
215type IOctetStream interface {
216 ToOctetString() ([]byte, error)
217 FromOctetString([]byte) (interface{}, error)
218}
219
220// InterfaceToOctets converts an attribute value to a string of octets
221func InterfaceToOctets(input interface{}) ([]byte, error) {
222 switch values := input.(type) {
223 case []byte:
224 return values, nil
225
226 case []uint16:
227 stream := make([]byte, 2*len(values))
228 for index, value := range values {
229 binary.BigEndian.PutUint16(stream[index*2:], value)
230 }
231 return stream, nil
232
233 case []uint32:
234 stream := make([]byte, 4*len(values))
235 for index, value := range values {
236 binary.BigEndian.PutUint32(stream[index*4:], value)
237 }
238 return stream, nil
239
240 case []uint64:
241 stream := make([]byte, 8*len(values))
242 for index, value := range values {
243 binary.BigEndian.PutUint64(stream[index*8:], value)
244 }
245 return stream, nil
246
247 case IOctetStream:
248 return values.ToOctetString()
249
250 default:
251 var typeName string
252 if t := reflect.TypeOf(input); t.Kind() == reflect.Ptr {
253 typeName = "*" + t.Elem().Name()
254 } else {
255 typeName = t.Name()
256 }
257 return nil, fmt.Errorf("unable to convert input to octet string: %v", typeName)
258 }
259}
260
261// SerializeTo takes an attribute value and converts it to a slice of bytes ready
262// for transmission
263func (attr *AttributeDefinition) SerializeTo(value interface{}, b gopacket.SerializeBuffer,
264 msgType byte, bytesAvailable int) (int, error) {
265 if attr.IsTableAttribute() {
266 return attr.tableAttributeSerializeTo(value, b, msgType, bytesAvailable)
267 }
268 if value == nil {
269 return 0, fmt.Errorf("attribute: %v is nil", attr.Name)
270 }
271 size := attr.GetSize()
272 if bytesAvailable < size {
273 return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
274 }
275 bytes, err := b.AppendBytes(size)
276 if err != nil {
277 return 0, err
278 }
279 switch attr.AttributeType {
280 case StringAttributeType, OctetsAttributeType, UnknownAttributeType:
281 byteStream, err := InterfaceToOctets(value)
282 if err != nil {
283 return 0, err
284 }
285 copy(bytes, byteStream)
286
287 default:
288 switch size {
289 default:
290 byteStream, err := InterfaceToOctets(value)
291 if err != nil {
292 return 0, err
293 }
294 copy(bytes, byteStream)
295 case 1:
296 switch value.(type) {
297 case int:
298 bytes[0] = byte(value.(int))
299 default:
300 bytes[0] = value.(byte)
301 }
302 case 2:
303 switch value.(type) {
304 case int:
305 binary.BigEndian.PutUint16(bytes, uint16(value.(int)))
306 default:
307 binary.BigEndian.PutUint16(bytes, value.(uint16))
308 }
309 case 4:
310 switch value.(type) {
311 case int:
312 binary.BigEndian.PutUint32(bytes, uint32(value.(int)))
313 default:
314 binary.BigEndian.PutUint32(bytes, value.(uint32))
315 }
316 case 8:
317 switch value.(type) {
318 case int:
319 binary.BigEndian.PutUint64(bytes, uint64(value.(int)))
320 default:
321 binary.BigEndian.PutUint64(bytes, value.(uint64))
322 }
323 }
324 }
325 return size, nil
326}
327
328// BufferToTableAttributes takes the reconstructed octet buffer transmitted for
329// a table attribute (over many GetNextResponses) and converts it into the desired
330// format for each table row
331func (attr *AttributeDefinition) BufferToTableAttributes(data []byte) (interface{}, error) {
332 // Source is network byte order octets. Convert to proper array of slices
333 rowSize := attr.GetSize()
334 dataSize := len(data)
335 index := 0
336
337 switch rowSize {
338 default:
339 value := make([][]byte, dataSize/rowSize)
340 for offset := 0; offset < dataSize; offset += rowSize {
341 value[index] = make([]byte, rowSize)
342 copy(value[index], data[offset:])
343 index++
344 }
345 return value, nil
346 case 1:
347 value := make([]byte, dataSize)
348 copy(value, data)
349 return value, nil
350 case 2:
351 value := make([]uint16, dataSize/2)
352 for offset := 0; offset < dataSize; offset += rowSize {
353 value[offset] = binary.BigEndian.Uint16(data[offset:])
354 index++
355 }
356 return value, nil
357 case 4:
358 value := make([]uint32, dataSize/4)
359 for offset := 0; offset < dataSize; offset += rowSize {
360 value[offset] = binary.BigEndian.Uint32(data[offset:])
361 index++
362 }
363 return value, nil
364 case 8:
365 value := make([]uint64, dataSize/8)
366 for offset := 0; offset < dataSize; offset += rowSize {
367 value[offset] = binary.BigEndian.Uint64(data[offset:])
368 index++
369 }
370 return value, nil
371 }
372}
373
374func (attr *AttributeDefinition) tableAttributeDecode(data []byte, df gopacket.DecodeFeedback, msgType byte) (interface{}, error) {
375 // Serialization of a table depends on the type of message. A
376 // Review of ITU-T G.988 shows that access on tables are
377 // either Read and/or Write, never Set-by-Create
378 switch msgType {
379 default:
Chip Boling0e420b82021-11-17 11:06:51 -0600380 return nil, fmt.Errorf("unsupported Message Type '%v/0x%02x' for table decode",
381 MsgType(msgType&MsgTypeMask), msgType)
Chip Boling6e27b352020-02-14 09:10:01 -0600382
383 case byte(Get) | AK: // Get Response
384 // Size
385 value := binary.BigEndian.Uint32(data[0:4])
386 return value, nil
387
388 case byte(Set) | AR: // Set Request
389 fallthrough
390
391 case byte(GetNext) | AK: // Get Next Response
392 // Block of data (octets) that need to be reassembled before conversion
393 // to table/row-data. If table attribute is not explicitly given a value
394 // we have to assume the entire data buffer is the value. The receiver of
395 // this frame will need to trim off any addtional information at the end
396 // of the last frame sequence since they (and the ONU) are the only ones
397 // who know how long the data really is.
398 size := attr.GetSize()
399 if size != 0 && len(data) < attr.GetSize() {
400 df.SetTruncated()
401 return nil, NewMessageTruncatedError("packet too small for field")
Chip Boling610117d2021-09-09 11:24:34 -0500402 }
403 if size == 0 {
Chip Boling6e27b352020-02-14 09:10:01 -0600404 return nil, NewProcessingError("table attributes with no size are not supported: %v", attr.Name)
405 }
406 return data, nil
407
408 case byte(SetTable) | AR: // Set Table Request
Chip Boling610117d2021-09-09 11:24:34 -0500409 // SetTableRequestType will be composed of zero or more row of a fixed size (based on ME)
410 // and will be saved to a TableRow struct for the consumer's use
411 size := attr.GetSize()
412 if size == 0 {
413 return nil, NewProcessingError("table attributes with no size are not supported: %v", attr.Name)
414 }
415 if len(data)%size != 0 {
416 df.SetTruncated()
417 return nil, NewMessageTruncatedError("packet does not contain an integral number of rows")
418 }
419 if len(data) == 0 {
420 return TableRows{}, nil
421 }
422 rows := TableRows{
423 NumRows: len(data) / size,
424 Rows: make([]byte, len(data)),
425 }
426 copy(rows.Rows, data)
427 return rows, nil
Chip Boling6e27b352020-02-14 09:10:01 -0600428 }
Chip Boling6e27b352020-02-14 09:10:01 -0600429}
430
431func (attr *AttributeDefinition) tableAttributeSerializeTo(value interface{}, b gopacket.SerializeBuffer, msgType byte,
432 bytesAvailable int) (int, error) {
433 // Serialization of a table depends on the type of message. A
434 // Review of ITU-T G.988 shows that access on tables are
435 // either Read and/or Write, never Set-by-Create
436 switch msgType {
437 default:
Chip Boling0e420b82021-11-17 11:06:51 -0600438 return 0, fmt.Errorf("unsupported Message Type '%v/0x%02x' for table serialization",
439 MsgType(msgType&MsgTypeMask), msgType)
Chip Boling6e27b352020-02-14 09:10:01 -0600440
441 case byte(Get) | AK: // Get Response
442 // Size
443 if bytesAvailable < 4 {
444 return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
445 }
446 if dwordSize, ok := value.(uint32); ok {
447 bytes, err := b.AppendBytes(4)
448 if err != nil {
449 return 0, err
450 }
451 binary.BigEndian.PutUint32(bytes, dwordSize)
452 return 4, nil
453 }
454 return 0, errors.New("unexpected type for table serialization")
455
456 case byte(GetNext) | AK: // Get Next Response
457 // Values are already in network by order form
458 if data, ok := value.([]byte); ok {
459 if bytesAvailable < len(data) {
460 return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
461 }
462 bytes, err := b.AppendBytes(len(data))
463 if err != nil {
464 return 0, err
465 }
466 copy(bytes, data)
467 return len(data), nil
468 }
469 return 0, errors.New("unexpected type for table serialization")
470
471 case byte(Set) | AR: // Set Request
472 // TODO: For complex table types (such as extended vlan tagging config) create an
473 // interface definition. Provide a switch type to look for that as well as for
474 // value being a byte slice... For now, just byte slice provided
475 break
476
477 case byte(SetTable) | AR: // Set Table Request
Chip Boling610117d2021-09-09 11:24:34 -0500478 if rows, ok := value.(TableRows); ok {
479 size := attr.GetSize()
480 if size != 0 && len(rows.Rows)%size != 0 {
481 return 0, NewMessageTruncatedError("packet does not contain an integral number of rows")
482 }
483 if bytesAvailable < len(rows.Rows) {
484 return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
485 }
486 bytes, err := b.AppendBytes(len(rows.Rows))
487 if err != nil {
488 return 0, err
489 }
490 copy(bytes, rows.Rows)
491 return len(rows.Rows), nil
492 }
493 return 0, errors.New("unexpected type for table serialization")
Chip Boling6e27b352020-02-14 09:10:01 -0600494 }
495 size := attr.GetSize()
496 if bytesAvailable < size {
497 return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
498 }
499 bytes, err := b.AppendBytes(size)
500 if err != nil {
501 return 0, err
502 }
503 switch attr.GetSize() {
504 default:
505 copy(bytes, value.([]byte))
506 case 1:
507 switch value.(type) {
508 case int:
509 bytes[0] = byte(value.(int))
510 default:
511 bytes[0] = value.(byte)
512 }
513 case 2:
514 switch value.(type) {
515 case int:
516 binary.BigEndian.PutUint16(bytes, uint16(value.(int)))
517 default:
518 binary.BigEndian.PutUint16(bytes, value.(uint16))
519 }
520 case 4:
521 switch value.(type) {
522 case int:
523 binary.BigEndian.PutUint32(bytes, uint32(value.(int)))
524 default:
525 binary.BigEndian.PutUint32(bytes, value.(uint32))
526 }
527 case 8:
528 switch value.(type) {
529 case int:
530 binary.BigEndian.PutUint64(bytes, uint64(value.(int)))
531 default:
532 binary.BigEndian.PutUint64(bytes, value.(uint64))
533 }
534 }
535 return size, nil
536}
537
538// GetAttributeDefinitionByName searches the attribute definition map for the
539// attribute with the specified name (case insensitive)
540func GetAttributeDefinitionByName(attrMap AttributeDefinitionMap, name string) (*AttributeDefinition, error) {
541 nameLower := strings.ToLower(name)
542 for _, attrVal := range attrMap {
543 if nameLower == strings.ToLower(attrVal.GetName()) {
544 return &attrVal, nil
545 }
546 }
547 return nil, errors.New(fmt.Sprintf("attribute '%s' not found", name))
548}
549
550// GetAttributeDefinitionMapKeys is a convenience functions since we may need to
551// iterate a map in key index order. Maps in Go since v1.0 the iteration order
552// of maps have been randomized.
553func GetAttributeDefinitionMapKeys(attrMap AttributeDefinitionMap) []uint {
554 var keys []uint
555 for k := range attrMap {
556 keys = append(keys, k)
557 }
558 sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
559 return keys
560}
561
562// GetAttributeBitmap returns the attribute bitmask for a single attribute
563func GetAttributeBitmap(attrMap AttributeDefinitionMap, name string) (uint16, error) {
564 attrDef, err := GetAttributeDefinitionByName(attrMap, name)
565 if err != nil {
566 return 0, err
567 }
568 index := attrDef.GetIndex()
569 if index == 0 {
570 return 0, errors.New("managed entity ID should not be used in an attribute bitmask")
571 }
572 return uint16(1 << (16 - index)), nil
573}
574
575// GetAttributesBitmap is a convenience functions to scan a list of attributes
576// and return the bitmask that represents them
577func GetAttributesBitmap(attrMap AttributeDefinitionMap, attributes mapset.Set) (uint16, error) {
578 var mask uint16
579 for _, def := range attrMap {
580 if attributes.Contains(def.Name) {
581 mask |= def.Mask
582 attributes.Remove(def.Name)
583 }
584 }
585 if attributes.Cardinality() > 0 {
586 return 0, fmt.Errorf("unsupported attributes: %v", attributes)
587 }
588 return mask, nil
589}
590
591// GetAttributesValueMap returns the attribute value map with uninitialized values based
592// on the attribute bitmask
593func GetAttributesValueMap(attrDefs AttributeDefinitionMap, mask uint16, access mapset.Set) (AttributeValueMap, OmciErrors) {
594 attrMap := make(AttributeValueMap, 0)
595 for index, def := range attrDefs {
596 if index == 0 {
597 continue
598 }
599 checkMask := def.Mask
600 accessOk := access == nil || def.GetAccess().Intersect(access).Cardinality() > 0
601
602 if (mask&checkMask) != 0 && accessOk {
603 attrMap[def.GetName()] = nil
604 mask &= ^checkMask
605 }
606 }
607 if mask != 0 {
608 // Return map, but signaled failed attributes
609 return attrMap, NewParameterError(mask)
610 }
611 return attrMap, NewOmciSuccess()
612}
613
614///////////////////////////////////////////////////////////////////////
615// Packet definitions for attributes of various types/sizes
616func toOctets(str string) []byte {
617 data, err := base64.StdEncoding.DecodeString(str)
618 if err != nil {
619 panic(fmt.Sprintf("Invalid Base-64 string: '%v'", str))
620 }
621 return data
622}
623
624///////////////////////////////////////////////////////////////////////
625// Packet definitions for attributes of various types/sizes
626
627// ByteField returns an AttributeDefinition for an attribute that is encoded as a single
628// octet (8-bits).
629func ByteField(name string, attrType AttributeType, mask uint16, defVal uint8, access mapset.Set, avc bool,
630 optional bool, deprecated bool, index uint) AttributeDefinition {
631 return AttributeDefinition{
632 Name: name,
633 AttributeType: attrType,
634 Mask: mask,
635 Index: index,
636 DefValue: defVal,
637 Size: 1,
638 Access: access,
639 Avc: avc,
640 Optional: optional,
641 Deprecated: deprecated,
642 }
643}
644
645// Uint16Field returns an AttributeDefinition for an attribute that is encoded as two
646// octet (16-bits).
647func Uint16Field(name string, attrType AttributeType, mask uint16, defVal uint16, access mapset.Set, avc bool,
648 optional bool, deprecated bool, index uint) AttributeDefinition {
649 return AttributeDefinition{
650 Name: name,
651 AttributeType: attrType,
652 Mask: mask,
653 Index: index,
654 DefValue: defVal,
655 Size: 2,
656 Access: access,
657 Avc: avc,
658 Optional: optional,
659 Deprecated: deprecated,
660 }
661}
662
663// Uint32Field returns an AttributeDefinition for an attribute that is encoded as four
664// octet (32-bits).
665func Uint32Field(name string, attrType AttributeType, mask uint16, defVal uint32, access mapset.Set, avc bool,
666 optional bool, deprecated bool, index uint) AttributeDefinition {
667 return AttributeDefinition{
668 Name: name,
669 AttributeType: attrType,
670 Mask: mask,
671 Index: index,
672 DefValue: defVal,
673 Size: 4,
674 Access: access,
675 Avc: avc,
676 Optional: optional,
677 Deprecated: deprecated,
678 }
679}
680
681// Uint64Field returns an AttributeDefinition for an attribute that is encoded as eight
682// octet (64-bits).
683func Uint64Field(name string, attrType AttributeType, mask uint16, defVal uint64, access mapset.Set, avc bool,
684 optional bool, deprecated bool, index uint) AttributeDefinition {
685 return AttributeDefinition{
686 Name: name,
687 AttributeType: attrType,
688 Mask: mask,
689 Index: index,
690 DefValue: defVal,
691 Size: 8,
692 Access: access,
693 Avc: avc,
694 Optional: optional,
695 Deprecated: deprecated,
696 }
697}
698
699// MultiByteField returns an AttributeDefinition for an attribute that is encoded as multiple
700// octets that do not map into fields with a length that is 1, 2, 4, or 8 octets.
701func MultiByteField(name string, attrType AttributeType, mask uint16, size uint, defVal []byte, access mapset.Set, avc bool,
702 optional bool, deprecated bool, index uint) AttributeDefinition {
703 return AttributeDefinition{
704 Name: name,
705 AttributeType: attrType,
706 Mask: mask,
707 Index: index,
708 DefValue: defVal,
709 Size: int(size),
710 Access: access,
711 Avc: avc,
712 Optional: optional,
713 Deprecated: deprecated,
714 }
715}
716
717// Notes on various OMCI ME Table attribute fields. This comment will eventually be
718// removed once a good table solution is implemented. These are not all the MEs with
719// table attributes, but probably ones I care about to support initially.
720//
721// ME Notes
722// --------------------------------------------------------------------------------------------
723// Port-mapping package -> Combined Port table -> N * 25 sized rows (port (1) + ME(2) * 12)
724// ONU Remote Debug -> Reply table (N bytes)
725// ONU3-G -> Status snapshot recordtable M x N bytes
726// MCAST Gem interworkTP-> IPv4 multicast adress table (12*n) (two 2 byte fields, two 4 byte fields)
727// IPv6 multicast adress table (24*n) (various sub-fields)
728// L2 mcast gem TP -> MCAST MAC addr filtering table (11 * n) (various sub-fields)
729// MAC Bridge Port Filt -> MAC Filter table (8 * n) (3 fields, some are bits) *** BITS ***
730// MAC Bridge Port data -> Bridge Table (8*M) (vaius fields, some are bits) *** BITS ***
731// VLAN tagging filter -> Rx Vlan tag op table (16 * n) Lots of bit fields *** BITS ***
732// MCAST operations profile
733// MCAST Subscriber config info
734// MCAST subscriber monitor
735// OMCI -> Two tables (N bytes and 2*N bytes)
736// General pupose buffer -> N bytes
737// Enhanced security control (17 * N bytes), (16 * P Bytes) , (16 * Q bytes), and more...
738//
739// An early example of info to track
740
741// TableInfo is an early prototype of how to better model some tables that are
742// difficult to code.
743//
744// The Value member may be one of the following:
745// nil : Empty, no default, ...
746// value : A specific value that equates to one row, ie) 6 or toOctets("base64")
747// array : One or more rows of values. [2]uint16{2, 3}
748type TableInfo struct {
749 Value interface{} // See comment above
750 Size int // Table Row Size
751}
752
753func (t *TableInfo) String() string {
754 return fmt.Sprintf("TableInfo: Size: %d, Value(s): %v", t.Size, t.Value)
755}
756
757// TableField is used to define an attribute that is a table
758func TableField(name string, attrType AttributeType, mask uint16, tableInfo TableInfo, access mapset.Set,
759 avc bool, optional bool, deprecated bool, index uint) AttributeDefinition {
760 return AttributeDefinition{
761 Name: name,
762 AttributeType: attrType,
763 Mask: mask,
764 Index: index,
765 DefValue: tableInfo.Value,
766 Size: tableInfo.Size, //Number of elements
767 Access: access,
768 Avc: avc,
769 Optional: optional,
770 Deprecated: deprecated,
771 }
772}
773
774// UnknownField is currently not used and may be deprecated. Its original intent
775// was to be a placeholder during table attribute development
776func UnknownField(name string, mask uint16, size int, index uint) AttributeDefinition {
777 return AttributeDefinition{
778 Name: name,
779 AttributeType: UnknownAttributeType, // Stored as octet string
780 Mask: mask,
781 Index: index,
782 DefValue: nil,
783 Size: size,
784 Access: mapset.NewSet(Read, Write),
785 Avc: false,
786 Optional: false,
787 Deprecated: false,
788 }
789}
790
791// AttributeValueMap maps an attribute (by name) to its value
792type AttributeValueMap map[string]interface{}
793
794// MergeInDefaultValues will examine the Manage Entity defaults (for non-SetByCreate attributes). This
795// function is called on a MIB Create request but is provide for external use in case it is needed
796// before the MIB entry is created
797func MergeInDefaultValues(classID ClassID, attributes AttributeValueMap) OmciErrors {
798 // Get default values for non-SetByCreate attributes
799 attrDefs, err := GetAttributesDefinitions(classID)
800 if err.StatusCode() != Success {
801 return err
802 } else if attributes == nil {
803 return NewProcessingError("Invalid (nil) Attribute Value Map referenced")
804 }
805 nilAllowed := mapset.NewSet(StringAttributeType, OctetsAttributeType, TableAttributeType)
806 for index, attrDef := range attrDefs {
807 if !attrDef.Access.Contains(SetByCreate) && index != 0 &&
808 (attrDef.DefValue != nil || nilAllowed.Contains(attrDef.AttributeType)) {
809 name := attrDef.GetName()
810 if existing, found := attributes[name]; !found || existing == nil {
811 attributes[name] = attrDef.DefValue
812 }
813 }
814 }
815 return err
816}
Chip Boling610117d2021-09-09 11:24:34 -0500817
818// AttributeValueMapBufferSize will determine how much space is needed to encode all
819// of the attributes
820func AttributeValueMapBufferSize(classID ClassID, attributes AttributeValueMap, msgType uint8) (int, error) {
821 attrDefs, err := GetAttributesDefinitions(classID)
822 if err.StatusCode() != Success {
823 return 0, err
824 } else if attributes == nil {
825 return 0, NewProcessingError("Invalid (nil) Attribute Value Map referenced")
826 }
827 bufferSize := 0
828 isGetResponse := msgType == 0x29
829
830 for _, attrDef := range attrDefs {
831 if isGetResponse && attrDef.IsTableAttribute() {
832 bufferSize += 4
833 } else {
834 bufferSize += attrDef.GetSize()
835 }
836 }
837 return bufferSize, nil
838}