VOL-775: Decode of VLAN Tagging Filter Data ME is invalid

Change-Id: Iad560baa1e9c864ee97262a07f4904b6d4604fb0
diff --git a/tests/utests/voltha/extensions/omci/test_mib_db_dict.py b/tests/utests/voltha/extensions/omci/test_mib_db_dict.py
index be42733..229809f 100644
--- a/tests/utests/voltha/extensions/omci/test_mib_db_dict.py
+++ b/tests/utests/voltha/extensions/omci/test_mib_db_dict.py
@@ -461,6 +461,25 @@
         self.assertTrue(all(isinstance(data[k], type(attributes[k])) for k in attributes.keys()))
         self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
 
+    def test_list_field_serialization(self):
+        self.db.start()
+        self.db.add(_DEVICE_ID)
+
+        class_id = VlanTaggingFilterData.class_id
+        inst_id = 0
+        vlan_filter_list = [0] * 12
+        vlan_filter_list[0] = 0x1234
+
+        attributes = {
+            'vlan_filter_list': vlan_filter_list,        # FieldListField
+            'forward_operation': 0,
+            'number_of_entries': 1
+        }
+        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
+        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
+        self.assertTrue(all(isinstance(data[k], type(attributes[k])) for k in attributes.keys()))
+        self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
+
     def test_complex_json_serialization(self):
         self.db.start()
         self.db.add(_DEVICE_ID)
diff --git a/tests/utests/voltha/extensions/omci/test_mib_db_ext.py b/tests/utests/voltha/extensions/omci/test_mib_db_ext.py
index 725da65..f84a757 100644
--- a/tests/utests/voltha/extensions/omci/test_mib_db_ext.py
+++ b/tests/utests/voltha/extensions/omci/test_mib_db_ext.py
@@ -459,6 +459,24 @@
         self.assertTrue(all(isinstance(data[k], type(attributes[k])) for k in attributes.keys()))
         self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
 
+    def test_list_field_serialization(self):
+        self.db.start()
+        self.db.add(_DEVICE_ID)
+
+        class_id = VlanTaggingFilterData.class_id
+        inst_id = 0
+        vlan_filter_list = [0] * 12
+        vlan_filter_list[0] = 0x1234
+
+        attributes = {
+            'vlan_filter_list': vlan_filter_list,        # FieldListField
+            'forward_operation': 0,
+            'number_of_entries': 1
+        }
+        self.db.set(_DEVICE_ID, class_id, inst_id, attributes)
+        data = self.db.query(_DEVICE_ID, class_id, inst_id, attributes.keys())
+        self.assertTrue(all(isinstance(data[k], type(attributes[k])) for k in attributes.keys()))
+        self.assertTrue(all(data[k] == attributes[k] for k in attributes.keys()))
 
     def test_complex_json_serialization(self):
         self.db.start()
diff --git a/tests/utests/voltha/extensions/omci/test_omci.py b/tests/utests/voltha/extensions/omci/test_omci.py
index 496d493..dd5108e 100644
--- a/tests/utests/voltha/extensions/omci/test_omci.py
+++ b/tests/utests/voltha/extensions/omci/test_omci.py
@@ -1,3 +1,18 @@
+#
+# Copyright 2017 the original author or authors.
+#
+# 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.
+#
 from unittest import TestCase, main
 
 from voltha.extensions.omci.omci import *
@@ -374,6 +389,9 @@
         ref = '001F440A005421010400000000000000' \
               '00000000000000000000000000000000' \
               '100100000000000000000028'
+        vlan_filter_list = [0] * 12
+        vlan_filter_list[0] = 0x0400
+
         frame = OmciFrame(
             transaction_id=31,
             message_type=OmciCreate.message_id,
@@ -381,7 +399,7 @@
                 entity_class=VlanTaggingFilterData.class_id,
                 entity_id=0x2101,
                 data=dict(
-                    vlan_filter_0=0x0400,
+                    vlan_filter_list=vlan_filter_list,
                     forward_operation=0x10,
                     number_of_entries=1
                 )
diff --git a/voltha/adapters/broadcom_onu/broadcom_onu.py b/voltha/adapters/broadcom_onu/broadcom_onu.py
index 2811eb6..d72f9de 100644
--- a/voltha/adapters/broadcom_onu/broadcom_onu.py
+++ b/voltha/adapters/broadcom_onu/broadcom_onu.py
@@ -75,7 +75,7 @@
         self.descriptor = Adapter(
             id=self.name,
             vendor='Voltha project',
-            version='0.44',
+            version='0.45',
             config=AdapterConfig(log_level=LogLevel.INFO)
         )
         self.devices_handlers = dict()  # device_id -> BroadcomOnuHandler()
@@ -307,6 +307,7 @@
     def unsuppress_alarm(self, filter):
         raise NotImplementedError()
 
+
 class BroadcomOnuHandler(object):
 
     def __init__(self, adapter, device_id):
@@ -405,7 +406,6 @@
         # Handle next event
         reactor.callLater(0, self.handle_onu_events)
 
-
     def activate(self, device):
         self.log.info('activating')
 
@@ -921,6 +921,8 @@
                                              entity_id,
                                              vlan_id,
                                              fwd_operation):
+        vlan_filter_list = [0] * 12
+        vlan_filter_list[0] = vlan_id
         frame = OmciFrame(
             transaction_id=self.get_tx_id(),
             message_type=OmciCreate.message_id,
@@ -928,7 +930,7 @@
                 entity_class=VlanTaggingFilterData.class_id,
                 entity_id=entity_id,
                 data=dict(
-                    vlan_filter_0=vlan_id,
+                    vlan_filter_list=vlan_filter_list,
                     forward_operation=fwd_operation,
                     number_of_entries=1
                 )
@@ -939,8 +941,10 @@
     def send_set_vlan_tagging_filter_data(self,
                                           entity_id,
                                           vlan_id):
+        vlan_filter_list = [0] * 12
+        vlan_filter_list[0] = vlan_id
         data = dict(
-            vlan_filter_0=vlan_id,
+            vlan_filter_list=vlan_filter_list,
             forward_operation=0x10,
             number_of_entries=1
         )
@@ -1459,8 +1463,6 @@
         self.send_set_multicast_operations_profile_ds_igmp_mcast_tci(0x201, 4, cvid)
         yield self.wait_for_response()
 
-
-
     def add_uni_port(self, device, parent_logical_device_id,
                      name, parent_port_num=None):
         self.log.info('adding-logical-port', device_id=device.id,
@@ -1526,7 +1528,6 @@
         self.adapter_agent.delete_logical_port_by_id(parent_logical_device_id,
                                                      'uni-{}'.format(port_no))
 
-
     @inlineCallbacks
     def delete_v_ont_ani(self, data):
         self.log.info('deleting-v_ont_ani')
diff --git a/voltha/extensions/omci/database/mib_db_ext.py b/voltha/extensions/omci/database/mib_db_ext.py
index 832a821..c0eebab 100644
--- a/voltha/extensions/omci/database/mib_db_ext.py
+++ b/voltha/extensions/omci/database/mib_db_ext.py
@@ -17,7 +17,7 @@
 from voltha.protos.omci_mib_db_pb2 import MibInstanceData, MibClassData, \
     MibDeviceData, MibAttributeData
 from voltha.extensions.omci.omci_entities import *
-from scapy.fields import StrField
+from scapy.fields import StrField, FieldListField
 
 
 class MibDbExternal(MibDbApi):
@@ -126,6 +126,9 @@
                 #
                 str_value = str(value)
 
+            elif isinstance(field, FieldListField):
+                str_value = json.dumps(value, separators=(',', ':'))
+
             else:
                 self.log.warning('default-conversion', type=type(field),
                                  class_id=class_id, attribute=attr_name, value=str(value))
@@ -180,6 +183,9 @@
             elif isinstance(field, BitField):
                 value = long(str_value)
 
+            elif isinstance(field, FieldListField):
+                value = json.loads(str_value)
+
             else:
                 self.log.warning('default-conversion', type=type(field),
                                  class_id=class_id, attribute=attr_name, value=str_value)
diff --git a/voltha/extensions/omci/omci_entities.py b/voltha/extensions/omci/omci_entities.py
index a7cec7d..1a29ecf 100644
--- a/voltha/extensions/omci/omci_entities.py
+++ b/voltha/extensions/omci/omci_entities.py
@@ -19,7 +19,7 @@
 from binascii import hexlify
 import json
 from scapy.fields import ByteField, ShortField, MACField, BitField, IPField
-from scapy.fields import IntField, StrFixedLenField, LongField
+from scapy.fields import IntField, StrFixedLenField, LongField, FieldListField
 from scapy.packet import Packet
 
 from voltha.extensions.omci.omci_defs import OmciUninitializedFieldError, \
@@ -424,18 +424,9 @@
     class_id = 84
     attributes = [
         ECA(ShortField("managed_entity_id", None), {AA.R, AA.SBC}),
-        ECA(ShortField("vlan_filter_0", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_1", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_2", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_3", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_4", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_5", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_6", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_7", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_8", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_9", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_10", None), {AA.R, AA.W, AA.SBC}),
-        ECA(ShortField("vlan_filter_11", None), {AA.R, AA.W, AA.SBC}),
+        ECA(FieldListField("vlan_filter_list", None,
+                           ShortField('', 0), count_from=lambda _: 12),
+            {AA.R, AA.W, AA.SBC}),
         ECA(ByteField("forward_operation", None), {AA.R, AA.W, AA.SBC},
             range_check=lambda x: 0x00 <= x <= 0x21),
         ECA(ByteField("number_of_entries", None), {AA.R, AA.W, AA.SBC})
diff --git a/voltha/extensions/omci/omci_me.py b/voltha/extensions/omci/omci_me.py
index 431ea41..1e7c183 100644
--- a/voltha/extensions/omci/omci_me.py
+++ b/voltha/extensions/omci/omci_me.py
@@ -627,17 +627,23 @@
             data = dict()
 
             if vlan_tcis is not None:
+                num_tcis = len(vlan_tcis)
+
+                assert 0 <= num_tcis <= 12, 'Number of VLAN TCI values is 0..12'
                 assert all(isinstance(tci, int) and 0 <= tci <= 0xFFFF
                            for tci in vlan_tcis), "VLAN TCI's are 0..0xFFFF"
-                assert 1 <= len(vlan_tcis) <= 12, 'Number of VLAN TCI values is 1..12'
 
-                for index in range(0, len(vlan_tcis)):
-                    data['vlan_filter_{}'.format(index)] = vlan_tcis[index]
+                if num_tcis > 0:
+                    vlan_filter_list = [0] * 12
+                    for index in range(0, num_tcis):
+                        vlan_filter_list[index] = vlan_tcis[index]
 
-                data['number_of_entries'] = len(vlan_tcis)
+                    data['vlan_filter_list'] = vlan_filter_list
+                data['number_of_entries'] = num_tcis
 
             if forward_operation is not None:
-                assert 0 <= forward_operation <= 0x21, 'forwarding_operation must be 0x00..0x21'
+                assert 0 <= forward_operation <= 0x21, \
+                    'forwarding_operation must be 0x00..0x21'
                 data['forward_operation'] = forward_operation
 
         super(VlanTaggingFilterDataFrame, self).__init__(VlanTaggingFilterData,