Import of https://github.com/cboling/omci at commit 7495182a09db38a9b6454a4a457fdd111c1618ac
Change-Id: I3250449080300b21b9d81c64dcc33f98f2e4cd1b
diff --git a/generated/attribute.go b/generated/attribute.go
new file mode 100644
index 0000000..bc2a7dd
--- /dev/null
+++ b/generated/attribute.go
@@ -0,0 +1,773 @@
+/*
+ * Copyright (c) 2018 - present. Boling Consulting Solutions (bcsw.net)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * NOTE: This file was generated, manual edits will be overwritten!
+ *
+ * Generated by 'goCodeGenerator.py':
+ * https://github.com/cboling/OMCI-parser/README.md
+ */
+
+package generated
+
+import (
+ "encoding/base64"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "github.com/deckarep/golang-set"
+ "github.com/google/gopacket"
+ "reflect"
+ "sort"
+ "strings"
+)
+
+// Attribute types
+type AttributeType uint8
+
+const (
+ UnknownAttributeType AttributeType = iota // Not known
+ OctetsAttributeType // Series of zero or more octets
+ StringAttributeType // Readable String
+ UnsignedIntegerAttributeType // Integer (0..max)
+ TableAttributeType // Table (of Octets)
+ SignedIntegerAttributeType // Signed integer, often expressed as 2's complement
+ PointerAttributeType // Managed Entity ID or pointer to a Managed instance
+ BitFieldAttributeType // Bitfield
+ EnumerationAttributeType // Fixed number of values (Unsigned Integers)
+ CounterAttributeType // Incrementing counter
+)
+
+// AttributeDefinitionMap is a map of attribute definitions with the attribute index (0..15)
+// as the key
+type AttributeDefinitionMap map[uint]AttributeDefinition
+
+// AttributeDefinition defines a single specific Managed Entity's attributes
+type AttributeDefinition struct {
+ Name string
+ AttributeType AttributeType
+ Index uint
+ Mask uint16
+ DefValue interface{}
+ Size int // Size of attribute in bytes. 0 indicates variable/unknown
+ Access mapset.Set // AttributeAccess...
+ Constraint func(interface{}) *ParamError
+ Avc bool // If true, an AVC notification can occur for the attribute
+ Tca bool // If true, a threshold crossing alert alarm notification can occur for the attribute
+ Optional bool // If true, attribute is option, else mandatory
+ Deprecated bool // If true, attribute is deprecated
+}
+
+func (attr *AttributeDefinition) String() string {
+ return fmt.Sprintf("AttributeDefinition: %v (%v/%v): Size: %v, Default: %v, Access: %v",
+ attr.GetName(), attr.AttributeType, attr.GetIndex(), attr.GetSize(), attr.GetDefault(), attr.GetAccess())
+}
+
+// GetName returns the attribute's name
+func (attr AttributeDefinition) GetName() string { return attr.Name }
+
+// GetIndex returns the attribute index )0..15)
+func (attr AttributeDefinition) GetIndex() uint { return attr.Index }
+
+// GetDefault provides the default value for an attribute if not specified
+// during its creation
+func (attr AttributeDefinition) GetDefault() interface{} { return attr.DefValue }
+
+// GetSize returns the size of the attribute. For table attributes, the size is
+// the size of a single table.
+func (attr AttributeDefinition) GetSize() int { return attr.Size }
+
+// GetAccess provides the access information (Read, Write, ...)
+func (attr AttributeDefinition) GetAccess() mapset.Set { return attr.Access }
+
+// GetConstraints returns a function that can be called for the attribute
+// that will validate the value. An appropriate error is returned if the
+// constraint fails, otherwise nil is returned to indicate that the value
+// is valid.
+func (attr AttributeDefinition) GetConstraints() func(interface{}) *ParamError {
+ return attr.Constraint
+}
+
+// IsTableAttribute returns true if the attribute is a table
+func (attr AttributeDefinition) IsTableAttribute() bool {
+ return attr.AttributeType == TableAttributeType
+}
+
+// IsCounter returns true if the attribute is a counter (usually expressed as an
+// unsigned integer)
+func (attr AttributeDefinition) IsCounter() bool {
+ return attr.AttributeType == CounterAttributeType
+}
+
+// IsBitField returns true if the attribute is a bitfield
+func (attr AttributeDefinition) IsBitField() bool {
+ return attr.AttributeType == BitFieldAttributeType
+}
+
+// IsString returns true if the attribute is a string. Strings are typically encoded
+// into fixed length files and padded with 0's
+func (attr AttributeDefinition) IsString() bool {
+ return attr.AttributeType == StringAttributeType
+}
+
+// Decode takes a slice of bytes and converts them into a value appropriate for
+// the attribute, or returns an error on failure
+func (attr *AttributeDefinition) Decode(data []byte, df gopacket.DecodeFeedback, msgType byte) (interface{}, error) {
+ if attr.IsTableAttribute() {
+ value, err := attr.tableAttributeDecode(data, df, msgType)
+ if err != nil {
+ return nil, err
+ }
+ if attr.GetConstraints() != nil {
+ if omciErr := attr.GetConstraints()(value); omciErr != nil {
+ return nil, omciErr.GetError()
+ }
+ }
+ return value, nil
+ }
+ size := attr.GetSize()
+
+ if len(data) < size {
+ df.SetTruncated()
+ return nil, NewMessageTruncatedError("packet too small for field")
+ }
+ switch attr.AttributeType {
+ case StringAttributeType, OctetsAttributeType, UnknownAttributeType:
+ value := make([]byte, size)
+ copy(value, data[:size])
+ if attr.GetConstraints() != nil {
+ if omciErr := attr.GetConstraints()(value); omciErr != nil {
+ return nil, omciErr.GetError()
+ }
+ }
+ return value, nil
+
+ default:
+ switch attr.GetSize() {
+ default:
+ value := make([]byte, size)
+ copy(value, data[:size])
+ if attr.GetConstraints() != nil {
+ if omciErr := attr.GetConstraints()(value); omciErr != nil {
+ return nil, omciErr.GetError()
+ }
+ }
+ return value, nil
+ case 1:
+ value := data[0]
+ if attr.GetConstraints() != nil {
+ if omciErr := attr.GetConstraints()(value); omciErr != nil {
+ return nil, omciErr.GetError()
+ }
+ }
+ return value, nil
+ case 2:
+ value := binary.BigEndian.Uint16(data[0:2])
+ if attr.GetConstraints() != nil {
+ if omciErr := attr.GetConstraints()(value); omciErr != nil {
+ return nil, omciErr.GetError()
+ }
+ }
+ return value, nil
+ case 4:
+ value := binary.BigEndian.Uint32(data[0:4])
+ if attr.GetConstraints() != nil {
+ if omciErr := attr.GetConstraints()(value); omciErr != nil {
+ return nil, omciErr.GetError()
+ }
+ }
+ return value, nil
+ case 8:
+ value := binary.BigEndian.Uint64(data[0:8])
+ if attr.GetConstraints() != nil {
+ omciErr := attr.GetConstraints()(value)
+ if omciErr != nil {
+ return nil, omciErr.GetError()
+ }
+ }
+ return value, nil
+ }
+ }
+}
+
+// IOctetStream interface defines a way to convert a custom type to/from an octet
+// stream.
+type IOctetStream interface {
+ ToOctetString() ([]byte, error)
+ FromOctetString([]byte) (interface{}, error)
+}
+
+// InterfaceToOctets converts an attribute value to a string of octets
+func InterfaceToOctets(input interface{}) ([]byte, error) {
+ switch values := input.(type) {
+ case []byte:
+ return values, nil
+
+ case []uint16:
+ stream := make([]byte, 2*len(values))
+ for index, value := range values {
+ binary.BigEndian.PutUint16(stream[index*2:], value)
+ }
+ return stream, nil
+
+ case []uint32:
+ stream := make([]byte, 4*len(values))
+ for index, value := range values {
+ binary.BigEndian.PutUint32(stream[index*4:], value)
+ }
+ return stream, nil
+
+ case []uint64:
+ stream := make([]byte, 8*len(values))
+ for index, value := range values {
+ binary.BigEndian.PutUint64(stream[index*8:], value)
+ }
+ return stream, nil
+
+ case IOctetStream:
+ return values.ToOctetString()
+
+ default:
+ var typeName string
+ if t := reflect.TypeOf(input); t.Kind() == reflect.Ptr {
+ typeName = "*" + t.Elem().Name()
+ } else {
+ typeName = t.Name()
+ }
+ return nil, fmt.Errorf("unable to convert input to octet string: %v", typeName)
+ }
+}
+
+// SerializeTo takes an attribute value and converts it to a slice of bytes ready
+// for transmission
+func (attr *AttributeDefinition) SerializeTo(value interface{}, b gopacket.SerializeBuffer,
+ msgType byte, bytesAvailable int) (int, error) {
+ if attr.IsTableAttribute() {
+ return attr.tableAttributeSerializeTo(value, b, msgType, bytesAvailable)
+ }
+ if value == nil {
+ return 0, fmt.Errorf("attribute: %v is nil", attr.Name)
+ }
+ size := attr.GetSize()
+ if bytesAvailable < size {
+ return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
+ }
+ bytes, err := b.AppendBytes(size)
+ if err != nil {
+ return 0, err
+ }
+ switch attr.AttributeType {
+ case StringAttributeType, OctetsAttributeType, UnknownAttributeType:
+ byteStream, err := InterfaceToOctets(value)
+ if err != nil {
+ return 0, err
+ }
+ copy(bytes, byteStream)
+
+ default:
+ switch size {
+ default:
+ byteStream, err := InterfaceToOctets(value)
+ if err != nil {
+ return 0, err
+ }
+ copy(bytes, byteStream)
+ case 1:
+ switch value.(type) {
+ case int:
+ bytes[0] = byte(value.(int))
+ default:
+ bytes[0] = value.(byte)
+ }
+ case 2:
+ switch value.(type) {
+ case int:
+ binary.BigEndian.PutUint16(bytes, uint16(value.(int)))
+ default:
+ binary.BigEndian.PutUint16(bytes, value.(uint16))
+ }
+ case 4:
+ switch value.(type) {
+ case int:
+ binary.BigEndian.PutUint32(bytes, uint32(value.(int)))
+ default:
+ binary.BigEndian.PutUint32(bytes, value.(uint32))
+ }
+ case 8:
+ switch value.(type) {
+ case int:
+ binary.BigEndian.PutUint64(bytes, uint64(value.(int)))
+ default:
+ binary.BigEndian.PutUint64(bytes, value.(uint64))
+ }
+ }
+ }
+ return size, nil
+}
+
+// BufferToTableAttributes takes the reconstructed octet buffer transmitted for
+// a table attribute (over many GetNextResponses) and converts it into the desired
+// format for each table row
+func (attr *AttributeDefinition) BufferToTableAttributes(data []byte) (interface{}, error) {
+ // Source is network byte order octets. Convert to proper array of slices
+ rowSize := attr.GetSize()
+ dataSize := len(data)
+ index := 0
+
+ switch rowSize {
+ default:
+ value := make([][]byte, dataSize/rowSize)
+ for offset := 0; offset < dataSize; offset += rowSize {
+ value[index] = make([]byte, rowSize)
+ copy(value[index], data[offset:])
+ index++
+ }
+ return value, nil
+ case 1:
+ value := make([]byte, dataSize)
+ copy(value, data)
+ return value, nil
+ case 2:
+ value := make([]uint16, dataSize/2)
+ for offset := 0; offset < dataSize; offset += rowSize {
+ value[offset] = binary.BigEndian.Uint16(data[offset:])
+ index++
+ }
+ return value, nil
+ case 4:
+ value := make([]uint32, dataSize/4)
+ for offset := 0; offset < dataSize; offset += rowSize {
+ value[offset] = binary.BigEndian.Uint32(data[offset:])
+ index++
+ }
+ return value, nil
+ case 8:
+ value := make([]uint64, dataSize/8)
+ for offset := 0; offset < dataSize; offset += rowSize {
+ value[offset] = binary.BigEndian.Uint64(data[offset:])
+ index++
+ }
+ return value, nil
+ }
+}
+
+func (attr *AttributeDefinition) tableAttributeDecode(data []byte, df gopacket.DecodeFeedback, msgType byte) (interface{}, error) {
+ // Serialization of a table depends on the type of message. A
+ // Review of ITU-T G.988 shows that access on tables are
+ // either Read and/or Write, never Set-by-Create
+ switch msgType {
+ default:
+ return nil, fmt.Errorf("unsupported Message Type '%v' for table serialization", msgType)
+
+ case byte(Get) | AK: // Get Response
+ // Size
+ value := binary.BigEndian.Uint32(data[0:4])
+ return value, nil
+
+ case byte(Set) | AR: // Set Request
+ fallthrough
+
+ case byte(GetNext) | AK: // Get Next Response
+ // Block of data (octets) that need to be reassembled before conversion
+ // to table/row-data. If table attribute is not explicitly given a value
+ // we have to assume the entire data buffer is the value. The receiver of
+ // this frame will need to trim off any addtional information at the end
+ // of the last frame sequence since they (and the ONU) are the only ones
+ // who know how long the data really is.
+ size := attr.GetSize()
+ if size != 0 && len(data) < attr.GetSize() {
+ df.SetTruncated()
+ return nil, NewMessageTruncatedError("packet too small for field")
+ } else if size == 0 {
+ return nil, NewProcessingError("table attributes with no size are not supported: %v", attr.Name)
+ }
+ return data, nil
+
+ case byte(SetTable) | AR: // Set Table Request
+ // TODO: Only baseline supported at this time
+ return nil, errors.New("attribute encode for set-table-request not yet supported")
+ }
+ return nil, errors.New("TODO")
+}
+
+func (attr *AttributeDefinition) tableAttributeSerializeTo(value interface{}, b gopacket.SerializeBuffer, msgType byte,
+ bytesAvailable int) (int, error) {
+ // Serialization of a table depends on the type of message. A
+ // Review of ITU-T G.988 shows that access on tables are
+ // either Read and/or Write, never Set-by-Create
+ switch msgType {
+ default:
+ return 0, fmt.Errorf("unsupported Message Type '%v' for table serialization", msgType)
+
+ case byte(Get) | AK: // Get Response
+ // Size
+ if bytesAvailable < 4 {
+ return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
+ }
+ if dwordSize, ok := value.(uint32); ok {
+ bytes, err := b.AppendBytes(4)
+ if err != nil {
+ return 0, err
+ }
+ binary.BigEndian.PutUint32(bytes, dwordSize)
+ return 4, nil
+ }
+ return 0, errors.New("unexpected type for table serialization")
+
+ case byte(GetNext) | AK: // Get Next Response
+ // Values are already in network by order form
+ if data, ok := value.([]byte); ok {
+ if bytesAvailable < len(data) {
+ return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
+ }
+ bytes, err := b.AppendBytes(len(data))
+ if err != nil {
+ return 0, err
+ }
+ copy(bytes, data)
+ return len(data), nil
+ }
+ return 0, errors.New("unexpected type for table serialization")
+
+ case byte(Set) | AR: // Set Request
+ // TODO: For complex table types (such as extended vlan tagging config) create an
+ // interface definition. Provide a switch type to look for that as well as for
+ // value being a byte slice... For now, just byte slice provided
+ break
+
+ case byte(SetTable) | AR: // Set Table Request
+ // TODO: Only baseline supported at this time
+ return 0, errors.New("attribute encode for set-table-request not yet supported")
+ }
+ size := attr.GetSize()
+ if bytesAvailable < size {
+ return 0, NewMessageTruncatedError(fmt.Sprintf("not enough space for attribute: %v", attr.Name))
+ }
+ bytes, err := b.AppendBytes(size)
+ if err != nil {
+ return 0, err
+ }
+ switch attr.GetSize() {
+ default:
+ copy(bytes, value.([]byte))
+ case 1:
+ switch value.(type) {
+ case int:
+ bytes[0] = byte(value.(int))
+ default:
+ bytes[0] = value.(byte)
+ }
+ case 2:
+ switch value.(type) {
+ case int:
+ binary.BigEndian.PutUint16(bytes, uint16(value.(int)))
+ default:
+ binary.BigEndian.PutUint16(bytes, value.(uint16))
+ }
+ case 4:
+ switch value.(type) {
+ case int:
+ binary.BigEndian.PutUint32(bytes, uint32(value.(int)))
+ default:
+ binary.BigEndian.PutUint32(bytes, value.(uint32))
+ }
+ case 8:
+ switch value.(type) {
+ case int:
+ binary.BigEndian.PutUint64(bytes, uint64(value.(int)))
+ default:
+ binary.BigEndian.PutUint64(bytes, value.(uint64))
+ }
+ }
+ return size, nil
+}
+
+// GetAttributeDefinitionByName searches the attribute definition map for the
+// attribute with the specified name (case insensitive)
+func GetAttributeDefinitionByName(attrMap AttributeDefinitionMap, name string) (*AttributeDefinition, error) {
+ nameLower := strings.ToLower(name)
+ for _, attrVal := range attrMap {
+ if nameLower == strings.ToLower(attrVal.GetName()) {
+ return &attrVal, nil
+ }
+ }
+ return nil, errors.New(fmt.Sprintf("attribute '%s' not found", name))
+}
+
+// GetAttributeDefinitionMapKeys is a convenience functions since we may need to
+// iterate a map in key index order. Maps in Go since v1.0 the iteration order
+// of maps have been randomized.
+func GetAttributeDefinitionMapKeys(attrMap AttributeDefinitionMap) []uint {
+ var keys []uint
+ for k := range attrMap {
+ keys = append(keys, k)
+ }
+ sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
+ return keys
+}
+
+// GetAttributeBitmap returns the attribute bitmask for a single attribute
+func GetAttributeBitmap(attrMap AttributeDefinitionMap, name string) (uint16, error) {
+ attrDef, err := GetAttributeDefinitionByName(attrMap, name)
+ if err != nil {
+ return 0, err
+ }
+ index := attrDef.GetIndex()
+ if index == 0 {
+ return 0, errors.New("managed entity ID should not be used in an attribute bitmask")
+ }
+ return uint16(1 << (16 - index)), nil
+}
+
+// GetAttributesBitmap is a convenience functions to scan a list of attributes
+// and return the bitmask that represents them
+func GetAttributesBitmap(attrMap AttributeDefinitionMap, attributes mapset.Set) (uint16, error) {
+ var mask uint16
+ for _, def := range attrMap {
+ if attributes.Contains(def.Name) {
+ mask |= def.Mask
+ attributes.Remove(def.Name)
+ }
+ }
+ if attributes.Cardinality() > 0 {
+ return 0, fmt.Errorf("unsupported attributes: %v", attributes)
+ }
+ return mask, nil
+}
+
+// GetAttributesValueMap returns the attribute value map with uninitialized values based
+// on the attribute bitmask
+func GetAttributesValueMap(attrDefs AttributeDefinitionMap, mask uint16, access mapset.Set) (AttributeValueMap, OmciErrors) {
+ attrMap := make(AttributeValueMap, 0)
+ for index, def := range attrDefs {
+ if index == 0 {
+ continue
+ }
+ checkMask := def.Mask
+ accessOk := access == nil || def.GetAccess().Intersect(access).Cardinality() > 0
+
+ if (mask&checkMask) != 0 && accessOk {
+ attrMap[def.GetName()] = nil
+ mask &= ^checkMask
+ }
+ }
+ if mask != 0 {
+ // Return map, but signaled failed attributes
+ return attrMap, NewParameterError(mask)
+ }
+ return attrMap, NewOmciSuccess()
+}
+
+///////////////////////////////////////////////////////////////////////
+// Packet definitions for attributes of various types/sizes
+func toOctets(str string) []byte {
+ data, err := base64.StdEncoding.DecodeString(str)
+ if err != nil {
+ panic(fmt.Sprintf("Invalid Base-64 string: '%v'", str))
+ }
+ return data
+}
+
+///////////////////////////////////////////////////////////////////////
+// Packet definitions for attributes of various types/sizes
+
+// ByteField returns an AttributeDefinition for an attribute that is encoded as a single
+// octet (8-bits).
+func ByteField(name string, attrType AttributeType, mask uint16, defVal uint8, access mapset.Set, avc bool,
+ optional bool, deprecated bool, index uint) AttributeDefinition {
+ return AttributeDefinition{
+ Name: name,
+ AttributeType: attrType,
+ Mask: mask,
+ Index: index,
+ DefValue: defVal,
+ Size: 1,
+ Access: access,
+ Avc: avc,
+ Optional: optional,
+ Deprecated: deprecated,
+ }
+}
+
+// Uint16Field returns an AttributeDefinition for an attribute that is encoded as two
+// octet (16-bits).
+func Uint16Field(name string, attrType AttributeType, mask uint16, defVal uint16, access mapset.Set, avc bool,
+ optional bool, deprecated bool, index uint) AttributeDefinition {
+ return AttributeDefinition{
+ Name: name,
+ AttributeType: attrType,
+ Mask: mask,
+ Index: index,
+ DefValue: defVal,
+ Size: 2,
+ Access: access,
+ Avc: avc,
+ Optional: optional,
+ Deprecated: deprecated,
+ }
+}
+
+// Uint32Field returns an AttributeDefinition for an attribute that is encoded as four
+// octet (32-bits).
+func Uint32Field(name string, attrType AttributeType, mask uint16, defVal uint32, access mapset.Set, avc bool,
+ optional bool, deprecated bool, index uint) AttributeDefinition {
+ return AttributeDefinition{
+ Name: name,
+ AttributeType: attrType,
+ Mask: mask,
+ Index: index,
+ DefValue: defVal,
+ Size: 4,
+ Access: access,
+ Avc: avc,
+ Optional: optional,
+ Deprecated: deprecated,
+ }
+}
+
+// Uint64Field returns an AttributeDefinition for an attribute that is encoded as eight
+// octet (64-bits).
+func Uint64Field(name string, attrType AttributeType, mask uint16, defVal uint64, access mapset.Set, avc bool,
+ optional bool, deprecated bool, index uint) AttributeDefinition {
+ return AttributeDefinition{
+ Name: name,
+ AttributeType: attrType,
+ Mask: mask,
+ Index: index,
+ DefValue: defVal,
+ Size: 8,
+ Access: access,
+ Avc: avc,
+ Optional: optional,
+ Deprecated: deprecated,
+ }
+}
+
+// MultiByteField returns an AttributeDefinition for an attribute that is encoded as multiple
+// octets that do not map into fields with a length that is 1, 2, 4, or 8 octets.
+func MultiByteField(name string, attrType AttributeType, mask uint16, size uint, defVal []byte, access mapset.Set, avc bool,
+ optional bool, deprecated bool, index uint) AttributeDefinition {
+ return AttributeDefinition{
+ Name: name,
+ AttributeType: attrType,
+ Mask: mask,
+ Index: index,
+ DefValue: defVal,
+ Size: int(size),
+ Access: access,
+ Avc: avc,
+ Optional: optional,
+ Deprecated: deprecated,
+ }
+}
+
+// Notes on various OMCI ME Table attribute fields. This comment will eventually be
+// removed once a good table solution is implemented. These are not all the MEs with
+// table attributes, but probably ones I care about to support initially.
+//
+// ME Notes
+// --------------------------------------------------------------------------------------------
+// Port-mapping package -> Combined Port table -> N * 25 sized rows (port (1) + ME(2) * 12)
+// ONU Remote Debug -> Reply table (N bytes)
+// ONU3-G -> Status snapshot recordtable M x N bytes
+// MCAST Gem interworkTP-> IPv4 multicast adress table (12*n) (two 2 byte fields, two 4 byte fields)
+// IPv6 multicast adress table (24*n) (various sub-fields)
+// L2 mcast gem TP -> MCAST MAC addr filtering table (11 * n) (various sub-fields)
+// MAC Bridge Port Filt -> MAC Filter table (8 * n) (3 fields, some are bits) *** BITS ***
+// MAC Bridge Port data -> Bridge Table (8*M) (vaius fields, some are bits) *** BITS ***
+// VLAN tagging filter -> Rx Vlan tag op table (16 * n) Lots of bit fields *** BITS ***
+// MCAST operations profile
+// MCAST Subscriber config info
+// MCAST subscriber monitor
+// OMCI -> Two tables (N bytes and 2*N bytes)
+// General pupose buffer -> N bytes
+// Enhanced security control (17 * N bytes), (16 * P Bytes) , (16 * Q bytes), and more...
+//
+// An early example of info to track
+
+// TableInfo is an early prototype of how to better model some tables that are
+// difficult to code.
+//
+// The Value member may be one of the following:
+// nil : Empty, no default, ...
+// value : A specific value that equates to one row, ie) 6 or toOctets("base64")
+// array : One or more rows of values. [2]uint16{2, 3}
+type TableInfo struct {
+ Value interface{} // See comment above
+ Size int // Table Row Size
+}
+
+func (t *TableInfo) String() string {
+ return fmt.Sprintf("TableInfo: Size: %d, Value(s): %v", t.Size, t.Value)
+}
+
+// TableField is used to define an attribute that is a table
+func TableField(name string, attrType AttributeType, mask uint16, tableInfo TableInfo, access mapset.Set,
+ avc bool, optional bool, deprecated bool, index uint) AttributeDefinition {
+ return AttributeDefinition{
+ Name: name,
+ AttributeType: attrType,
+ Mask: mask,
+ Index: index,
+ DefValue: tableInfo.Value,
+ Size: tableInfo.Size, //Number of elements
+ Access: access,
+ Avc: avc,
+ Optional: optional,
+ Deprecated: deprecated,
+ }
+}
+
+// UnknownField is currently not used and may be deprecated. Its original intent
+// was to be a placeholder during table attribute development
+func UnknownField(name string, mask uint16, size int, index uint) AttributeDefinition {
+ return AttributeDefinition{
+ Name: name,
+ AttributeType: UnknownAttributeType, // Stored as octet string
+ Mask: mask,
+ Index: index,
+ DefValue: nil,
+ Size: size,
+ Access: mapset.NewSet(Read, Write),
+ Avc: false,
+ Optional: false,
+ Deprecated: false,
+ }
+}
+
+// AttributeValueMap maps an attribute (by name) to its value
+type AttributeValueMap map[string]interface{}
+
+// MergeInDefaultValues will examine the Manage Entity defaults (for non-SetByCreate attributes). This
+// function is called on a MIB Create request but is provide for external use in case it is needed
+// before the MIB entry is created
+func MergeInDefaultValues(classID ClassID, attributes AttributeValueMap) OmciErrors {
+ // Get default values for non-SetByCreate attributes
+ attrDefs, err := GetAttributesDefinitions(classID)
+ if err.StatusCode() != Success {
+ return err
+ } else if attributes == nil {
+ return NewProcessingError("Invalid (nil) Attribute Value Map referenced")
+ }
+ nilAllowed := mapset.NewSet(StringAttributeType, OctetsAttributeType, TableAttributeType)
+ for index, attrDef := range attrDefs {
+ if !attrDef.Access.Contains(SetByCreate) && index != 0 &&
+ (attrDef.DefValue != nil || nilAllowed.Contains(attrDef.AttributeType)) {
+ name := attrDef.GetName()
+ if existing, found := attributes[name]; !found || existing == nil {
+ attributes[name] = attrDef.DefValue
+ }
+ }
+ }
+ return err
+}