blob: de20130992ba3a0bf95e44f7160f85c876dbfd22 [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:
380 return nil, fmt.Errorf("unsupported Message Type '%v' for table serialization", msgType)
381
382 case byte(Get) | AK: // Get Response
383 // Size
384 value := binary.BigEndian.Uint32(data[0:4])
385 return value, nil
386
387 case byte(Set) | AR: // Set Request
388 fallthrough
389
390 case byte(GetNext) | AK: // Get Next Response
391 // Block of data (octets) that need to be reassembled before conversion
392 // to table/row-data. If table attribute is not explicitly given a value
393 // we have to assume the entire data buffer is the value. The receiver of
394 // this frame will need to trim off any addtional information at the end
395 // of the last frame sequence since they (and the ONU) are the only ones
396 // who know how long the data really is.
397 size := attr.GetSize()
398 if size != 0 && len(data) < attr.GetSize() {
399 df.SetTruncated()
400 return nil, NewMessageTruncatedError("packet too small for field")
Chip Boling610117d2021-09-09 11:24:34 -0500401 }
402 if size == 0 {
Chip Boling6e27b352020-02-14 09:10:01 -0600403 return nil, NewProcessingError("table attributes with no size are not supported: %v", attr.Name)
404 }
405 return data, nil
406
407 case byte(SetTable) | AR: // Set Table Request
Chip Boling610117d2021-09-09 11:24:34 -0500408 // SetTableRequestType will be composed of zero or more row of a fixed size (based on ME)
409 // and will be saved to a TableRow struct for the consumer's use
410 size := attr.GetSize()
411 if size == 0 {
412 return nil, NewProcessingError("table attributes with no size are not supported: %v", attr.Name)
413 }
414 if len(data)%size != 0 {
415 df.SetTruncated()
416 return nil, NewMessageTruncatedError("packet does not contain an integral number of rows")
417 }
418 if len(data) == 0 {
419 return TableRows{}, nil
420 }
421 rows := TableRows{
422 NumRows: len(data) / size,
423 Rows: make([]byte, len(data)),
424 }
425 copy(rows.Rows, data)
426 return rows, nil
Chip Boling6e27b352020-02-14 09:10:01 -0600427 }
Chip Boling6e27b352020-02-14 09:10:01 -0600428}
429
430func (attr *AttributeDefinition) tableAttributeSerializeTo(value interface{}, b gopacket.SerializeBuffer, msgType byte,
431 bytesAvailable int) (int, error) {
432 // Serialization of a table depends on the type of message. A
433 // Review of ITU-T G.988 shows that access on tables are
434 // either Read and/or Write, never Set-by-Create
435 switch msgType {
436 default:
437 return 0, fmt.Errorf("unsupported Message Type '%v' for table serialization", msgType)
438
439 case byte(Get) | AK: // Get Response
440 // Size
441 if bytesAvailable < 4 {
442 return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
443 }
444 if dwordSize, ok := value.(uint32); ok {
445 bytes, err := b.AppendBytes(4)
446 if err != nil {
447 return 0, err
448 }
449 binary.BigEndian.PutUint32(bytes, dwordSize)
450 return 4, nil
451 }
452 return 0, errors.New("unexpected type for table serialization")
453
454 case byte(GetNext) | AK: // Get Next Response
455 // Values are already in network by order form
456 if data, ok := value.([]byte); ok {
457 if bytesAvailable < len(data) {
458 return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
459 }
460 bytes, err := b.AppendBytes(len(data))
461 if err != nil {
462 return 0, err
463 }
464 copy(bytes, data)
465 return len(data), nil
466 }
467 return 0, errors.New("unexpected type for table serialization")
468
469 case byte(Set) | AR: // Set Request
470 // TODO: For complex table types (such as extended vlan tagging config) create an
471 // interface definition. Provide a switch type to look for that as well as for
472 // value being a byte slice... For now, just byte slice provided
473 break
474
475 case byte(SetTable) | AR: // Set Table Request
Chip Boling610117d2021-09-09 11:24:34 -0500476 if rows, ok := value.(TableRows); ok {
477 size := attr.GetSize()
478 if size != 0 && len(rows.Rows)%size != 0 {
479 return 0, NewMessageTruncatedError("packet does not contain an integral number of rows")
480 }
481 if bytesAvailable < len(rows.Rows) {
482 return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
483 }
484 bytes, err := b.AppendBytes(len(rows.Rows))
485 if err != nil {
486 return 0, err
487 }
488 copy(bytes, rows.Rows)
489 return len(rows.Rows), nil
490 }
491 return 0, errors.New("unexpected type for table serialization")
Chip Boling6e27b352020-02-14 09:10:01 -0600492 }
493 size := attr.GetSize()
494 if bytesAvailable < size {
495 return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
496 }
497 bytes, err := b.AppendBytes(size)
498 if err != nil {
499 return 0, err
500 }
501 switch attr.GetSize() {
502 default:
503 copy(bytes, value.([]byte))
504 case 1:
505 switch value.(type) {
506 case int:
507 bytes[0] = byte(value.(int))
508 default:
509 bytes[0] = value.(byte)
510 }
511 case 2:
512 switch value.(type) {
513 case int:
514 binary.BigEndian.PutUint16(bytes, uint16(value.(int)))
515 default:
516 binary.BigEndian.PutUint16(bytes, value.(uint16))
517 }
518 case 4:
519 switch value.(type) {
520 case int:
521 binary.BigEndian.PutUint32(bytes, uint32(value.(int)))
522 default:
523 binary.BigEndian.PutUint32(bytes, value.(uint32))
524 }
525 case 8:
526 switch value.(type) {
527 case int:
528 binary.BigEndian.PutUint64(bytes, uint64(value.(int)))
529 default:
530 binary.BigEndian.PutUint64(bytes, value.(uint64))
531 }
532 }
533 return size, nil
534}
535
536// GetAttributeDefinitionByName searches the attribute definition map for the
537// attribute with the specified name (case insensitive)
538func GetAttributeDefinitionByName(attrMap AttributeDefinitionMap, name string) (*AttributeDefinition, error) {
539 nameLower := strings.ToLower(name)
540 for _, attrVal := range attrMap {
541 if nameLower == strings.ToLower(attrVal.GetName()) {
542 return &attrVal, nil
543 }
544 }
545 return nil, errors.New(fmt.Sprintf("attribute '%s' not found", name))
546}
547
548// GetAttributeDefinitionMapKeys is a convenience functions since we may need to
549// iterate a map in key index order. Maps in Go since v1.0 the iteration order
550// of maps have been randomized.
551func GetAttributeDefinitionMapKeys(attrMap AttributeDefinitionMap) []uint {
552 var keys []uint
553 for k := range attrMap {
554 keys = append(keys, k)
555 }
556 sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
557 return keys
558}
559
560// GetAttributeBitmap returns the attribute bitmask for a single attribute
561func GetAttributeBitmap(attrMap AttributeDefinitionMap, name string) (uint16, error) {
562 attrDef, err := GetAttributeDefinitionByName(attrMap, name)
563 if err != nil {
564 return 0, err
565 }
566 index := attrDef.GetIndex()
567 if index == 0 {
568 return 0, errors.New("managed entity ID should not be used in an attribute bitmask")
569 }
570 return uint16(1 << (16 - index)), nil
571}
572
573// GetAttributesBitmap is a convenience functions to scan a list of attributes
574// and return the bitmask that represents them
575func GetAttributesBitmap(attrMap AttributeDefinitionMap, attributes mapset.Set) (uint16, error) {
576 var mask uint16
577 for _, def := range attrMap {
578 if attributes.Contains(def.Name) {
579 mask |= def.Mask
580 attributes.Remove(def.Name)
581 }
582 }
583 if attributes.Cardinality() > 0 {
584 return 0, fmt.Errorf("unsupported attributes: %v", attributes)
585 }
586 return mask, nil
587}
588
589// GetAttributesValueMap returns the attribute value map with uninitialized values based
590// on the attribute bitmask
591func GetAttributesValueMap(attrDefs AttributeDefinitionMap, mask uint16, access mapset.Set) (AttributeValueMap, OmciErrors) {
592 attrMap := make(AttributeValueMap, 0)
593 for index, def := range attrDefs {
594 if index == 0 {
595 continue
596 }
597 checkMask := def.Mask
598 accessOk := access == nil || def.GetAccess().Intersect(access).Cardinality() > 0
599
600 if (mask&checkMask) != 0 && accessOk {
601 attrMap[def.GetName()] = nil
602 mask &= ^checkMask
603 }
604 }
605 if mask != 0 {
606 // Return map, but signaled failed attributes
607 return attrMap, NewParameterError(mask)
608 }
609 return attrMap, NewOmciSuccess()
610}
611
612///////////////////////////////////////////////////////////////////////
613// Packet definitions for attributes of various types/sizes
614func toOctets(str string) []byte {
615 data, err := base64.StdEncoding.DecodeString(str)
616 if err != nil {
617 panic(fmt.Sprintf("Invalid Base-64 string: '%v'", str))
618 }
619 return data
620}
621
622///////////////////////////////////////////////////////////////////////
623// Packet definitions for attributes of various types/sizes
624
625// ByteField returns an AttributeDefinition for an attribute that is encoded as a single
626// octet (8-bits).
627func ByteField(name string, attrType AttributeType, mask uint16, defVal uint8, access mapset.Set, avc bool,
628 optional bool, deprecated bool, index uint) AttributeDefinition {
629 return AttributeDefinition{
630 Name: name,
631 AttributeType: attrType,
632 Mask: mask,
633 Index: index,
634 DefValue: defVal,
635 Size: 1,
636 Access: access,
637 Avc: avc,
638 Optional: optional,
639 Deprecated: deprecated,
640 }
641}
642
643// Uint16Field returns an AttributeDefinition for an attribute that is encoded as two
644// octet (16-bits).
645func Uint16Field(name string, attrType AttributeType, mask uint16, defVal uint16, access mapset.Set, avc bool,
646 optional bool, deprecated bool, index uint) AttributeDefinition {
647 return AttributeDefinition{
648 Name: name,
649 AttributeType: attrType,
650 Mask: mask,
651 Index: index,
652 DefValue: defVal,
653 Size: 2,
654 Access: access,
655 Avc: avc,
656 Optional: optional,
657 Deprecated: deprecated,
658 }
659}
660
661// Uint32Field returns an AttributeDefinition for an attribute that is encoded as four
662// octet (32-bits).
663func Uint32Field(name string, attrType AttributeType, mask uint16, defVal uint32, access mapset.Set, avc bool,
664 optional bool, deprecated bool, index uint) AttributeDefinition {
665 return AttributeDefinition{
666 Name: name,
667 AttributeType: attrType,
668 Mask: mask,
669 Index: index,
670 DefValue: defVal,
671 Size: 4,
672 Access: access,
673 Avc: avc,
674 Optional: optional,
675 Deprecated: deprecated,
676 }
677}
678
679// Uint64Field returns an AttributeDefinition for an attribute that is encoded as eight
680// octet (64-bits).
681func Uint64Field(name string, attrType AttributeType, mask uint16, defVal uint64, access mapset.Set, avc bool,
682 optional bool, deprecated bool, index uint) AttributeDefinition {
683 return AttributeDefinition{
684 Name: name,
685 AttributeType: attrType,
686 Mask: mask,
687 Index: index,
688 DefValue: defVal,
689 Size: 8,
690 Access: access,
691 Avc: avc,
692 Optional: optional,
693 Deprecated: deprecated,
694 }
695}
696
697// MultiByteField returns an AttributeDefinition for an attribute that is encoded as multiple
698// octets that do not map into fields with a length that is 1, 2, 4, or 8 octets.
699func MultiByteField(name string, attrType AttributeType, mask uint16, size uint, defVal []byte, access mapset.Set, avc bool,
700 optional bool, deprecated bool, index uint) AttributeDefinition {
701 return AttributeDefinition{
702 Name: name,
703 AttributeType: attrType,
704 Mask: mask,
705 Index: index,
706 DefValue: defVal,
707 Size: int(size),
708 Access: access,
709 Avc: avc,
710 Optional: optional,
711 Deprecated: deprecated,
712 }
713}
714
715// Notes on various OMCI ME Table attribute fields. This comment will eventually be
716// removed once a good table solution is implemented. These are not all the MEs with
717// table attributes, but probably ones I care about to support initially.
718//
719// ME Notes
720// --------------------------------------------------------------------------------------------
721// Port-mapping package -> Combined Port table -> N * 25 sized rows (port (1) + ME(2) * 12)
722// ONU Remote Debug -> Reply table (N bytes)
723// ONU3-G -> Status snapshot recordtable M x N bytes
724// MCAST Gem interworkTP-> IPv4 multicast adress table (12*n) (two 2 byte fields, two 4 byte fields)
725// IPv6 multicast adress table (24*n) (various sub-fields)
726// L2 mcast gem TP -> MCAST MAC addr filtering table (11 * n) (various sub-fields)
727// MAC Bridge Port Filt -> MAC Filter table (8 * n) (3 fields, some are bits) *** BITS ***
728// MAC Bridge Port data -> Bridge Table (8*M) (vaius fields, some are bits) *** BITS ***
729// VLAN tagging filter -> Rx Vlan tag op table (16 * n) Lots of bit fields *** BITS ***
730// MCAST operations profile
731// MCAST Subscriber config info
732// MCAST subscriber monitor
733// OMCI -> Two tables (N bytes and 2*N bytes)
734// General pupose buffer -> N bytes
735// Enhanced security control (17 * N bytes), (16 * P Bytes) , (16 * Q bytes), and more...
736//
737// An early example of info to track
738
739// TableInfo is an early prototype of how to better model some tables that are
740// difficult to code.
741//
742// The Value member may be one of the following:
743// nil : Empty, no default, ...
744// value : A specific value that equates to one row, ie) 6 or toOctets("base64")
745// array : One or more rows of values. [2]uint16{2, 3}
746type TableInfo struct {
747 Value interface{} // See comment above
748 Size int // Table Row Size
749}
750
751func (t *TableInfo) String() string {
752 return fmt.Sprintf("TableInfo: Size: %d, Value(s): %v", t.Size, t.Value)
753}
754
755// TableField is used to define an attribute that is a table
756func TableField(name string, attrType AttributeType, mask uint16, tableInfo TableInfo, access mapset.Set,
757 avc bool, optional bool, deprecated bool, index uint) AttributeDefinition {
758 return AttributeDefinition{
759 Name: name,
760 AttributeType: attrType,
761 Mask: mask,
762 Index: index,
763 DefValue: tableInfo.Value,
764 Size: tableInfo.Size, //Number of elements
765 Access: access,
766 Avc: avc,
767 Optional: optional,
768 Deprecated: deprecated,
769 }
770}
771
772// UnknownField is currently not used and may be deprecated. Its original intent
773// was to be a placeholder during table attribute development
774func UnknownField(name string, mask uint16, size int, index uint) AttributeDefinition {
775 return AttributeDefinition{
776 Name: name,
777 AttributeType: UnknownAttributeType, // Stored as octet string
778 Mask: mask,
779 Index: index,
780 DefValue: nil,
781 Size: size,
782 Access: mapset.NewSet(Read, Write),
783 Avc: false,
784 Optional: false,
785 Deprecated: false,
786 }
787}
788
789// AttributeValueMap maps an attribute (by name) to its value
790type AttributeValueMap map[string]interface{}
791
792// MergeInDefaultValues will examine the Manage Entity defaults (for non-SetByCreate attributes). This
793// function is called on a MIB Create request but is provide for external use in case it is needed
794// before the MIB entry is created
795func MergeInDefaultValues(classID ClassID, attributes AttributeValueMap) OmciErrors {
796 // Get default values for non-SetByCreate attributes
797 attrDefs, err := GetAttributesDefinitions(classID)
798 if err.StatusCode() != Success {
799 return err
800 } else if attributes == nil {
801 return NewProcessingError("Invalid (nil) Attribute Value Map referenced")
802 }
803 nilAllowed := mapset.NewSet(StringAttributeType, OctetsAttributeType, TableAttributeType)
804 for index, attrDef := range attrDefs {
805 if !attrDef.Access.Contains(SetByCreate) && index != 0 &&
806 (attrDef.DefValue != nil || nilAllowed.Contains(attrDef.AttributeType)) {
807 name := attrDef.GetName()
808 if existing, found := attributes[name]; !found || existing == nil {
809 attributes[name] = attrDef.DefValue
810 }
811 }
812 }
813 return err
814}
Chip Boling610117d2021-09-09 11:24:34 -0500815
816// AttributeValueMapBufferSize will determine how much space is needed to encode all
817// of the attributes
818func AttributeValueMapBufferSize(classID ClassID, attributes AttributeValueMap, msgType uint8) (int, error) {
819 attrDefs, err := GetAttributesDefinitions(classID)
820 if err.StatusCode() != Success {
821 return 0, err
822 } else if attributes == nil {
823 return 0, NewProcessingError("Invalid (nil) Attribute Value Map referenced")
824 }
825 bufferSize := 0
826 isGetResponse := msgType == 0x29
827
828 for _, attrDef := range attrDefs {
829 if isGetResponse && attrDef.IsTableAttribute() {
830 bufferSize += 4
831 } else {
832 bufferSize += attrDef.GetSize()
833 }
834 }
835 return bufferSize, nil
836}