Adding several updates to the Tibit Adapters

Change-Id: I15c7cf4fc4a1caaa67851fd8bab4fb2e592c20ba
diff --git a/voltha/adapters/tibit_olt/tibit_olt.py b/voltha/adapters/tibit_olt/tibit_olt.py
index 233f048..cdd2d1f 100644
--- a/voltha/adapters/tibit_olt/tibit_olt.py
+++ b/voltha/adapters/tibit_olt/tibit_olt.py
@@ -21,12 +21,21 @@
 import time
 from uuid import uuid4
 import struct
+import re
 
 import arrow
 import structlog
-from scapy.fields import StrField
+from scapy.fields import StrField, PacketField, X3BytesField
 from scapy.layers.l2 import Ether, Dot1Q
 from scapy.packet import Packet, bind_layers
+
+from scapy.fields import ByteEnumField, XShortField, XByteField, MACField, \
+    ByteField, BitEnumField, BitField, ShortField
+from scapy.fields import XLongField, StrFixedLenField, XIntField, \
+    FieldLenField, StrLenField, IntField
+
+
+
 from twisted.internet import reactor
 from twisted.internet.defer import DeferredQueue, inlineCallbacks
 from twisted.internet.task import LoopingCall
@@ -34,7 +43,11 @@
 
 from common.frameio.frameio import BpfProgramFilter, hexify
 from voltha.adapters.interface import IAdapterInterface
-from voltha.extensions.eoam.EOAM import EOAMPayload, DPoEOpcode_SetRequest
+from voltha.extensions.eoam.EOAM import EOAMPayload, EOAMEvent, EOAM_VendSpecificMsg
+from voltha.extensions.eoam.EOAM import EOAM_OmciMsg, EOAM_TibitMsg, EOAM_DpoeMsg
+from voltha.extensions.eoam.EOAM import OAM_ETHERTYPE
+from voltha.extensions.eoam.EOAM import CableLabs_OUI, Tibit_OUI, IEEE_OUI
+
 from voltha.extensions.eoam.EOAM_TLV import DOLTObject, \
      NetworkToNetworkPortObject, OLTUnicastLogicalLink, \
      PortIngressRuleClauseMatchLength01, AddStaticMacAddress, \
@@ -42,15 +55,34 @@
      PortIngressRuleResultSet, PortIngressRuleResultInsert, \
      PortIngressRuleResultCopy, PortIngressRuleResultReplace, \
      PortIngressRuleResultDelete, PortIngressRuleResultOLTQueue, \
-     PortIngressRuleResultOLTBroadcastQueue, \
-     PortIngressRuleTerminator, AddPortIngressRule, CablelabsOUI, \
+     PortIngressRuleResultOLTBroadcastQueue, PortIngressRuleResultOLTEPONQueue, \
+     PortIngressRuleTerminator, AddPortIngressRule, \
      ItuOUI, PonPortObject
 from voltha.extensions.eoam.EOAM_TLV import PortIngressRuleHeader
 from voltha.extensions.eoam.EOAM_TLV import ClauseSubtypeEnum
 from voltha.extensions.eoam.EOAM_TLV import RuleOperatorEnum
-from voltha.extensions.eoam.EOAM_TLV import DPoEVariableResponseCodes
-from voltha.extensions.eoam.EOAM_TLV import TibitOUI
-from voltha.extensions.eoam.EOAM import EOAMPayload, CablelabsOUI
+from voltha.extensions.eoam.EOAM_TLV import DPoEVariableResponseCodes, DPoEOpcodeEnum
+from voltha.extensions.eoam.EOAM_TLV import VendorName, OltMode, HardwareVersion, ManufacturerInfo
+from voltha.extensions.eoam.EOAM_TLV import TibitLinkMacTable
+from voltha.extensions.eoam.EOAM_TLV import SlowProtocolsSubtypeEnum
+from voltha.extensions.eoam.EOAM_TLV import EndOfPDU
+
+from voltha.extensions.eoam.EOAM_TLV import RxFramesGreen, \
+    TxFramesGreen, RxFrame_64, RxFrame_65_127, \
+    RxFrame_128_255, RxFrame_256_511, RxFrame_512_1023, \
+    RxFrame_1024_1518, RxFrame_1519Plus, TxFrame_64, \
+    TxFrame_65_127, TxFrame_128_255, TxFrame_256_511, \
+    TxFrame_512_1023, TxFrame_1024_1518, TxFrame_1519Plus
+
+from voltha.extensions.eoam.EOAM_TLV import RxFramesGreen, TxFramesGreen, \
+    RxFrame_64, RxFrame_65_127, RxFrame_128_255, RxFrame_256_511, \
+    RxFrame_512_1023,RxFrame_1024_1518, RxFrame_1519Plus, \
+    TxFrame_64, TxFrame_65_127, TxFrame_128_255, \
+    TxFrame_256_511, TxFrame_512_1023, TxFrame_1024_1518, \
+    TxFrame_1519Plus
+
+
+
 from voltha.core.flow_decomposer import *
 from voltha.core.logical_device_agent import mac_str_to_tuple
 from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
@@ -106,23 +138,6 @@
 # from a higher level.
 MULTICAST_VLAN = 140
 
-
-# Extract OLT MAC address: This is a good
-# example of getting the OLT mac address
-
-#for mac, device in self.device_ids.iteritems():
-#    if device == dev_id:
-#        olt_mac_address = mac
-#        log.info('packet-out', olt_mac_address=olt_mac_address)
-
-# To be removed in favor of OAM
-class TBJSON(Packet):
-    """ TBJSON 'packet' layer. """
-    name = "TBJSON"
-    fields_desc = [StrField("data", default="")]
-
-bind_layers(Ether, TBJSON, type=0xA8C8)
-
 TIBIT_COMMUNICATIONS_OUI=u'000CE2'
 SUMITOMO_ELECTRIC_INDUSTRIES_OUI=u'0025DC'
 
@@ -156,6 +171,7 @@
         self.incoming_queues = {}  # OLT mac_address -> DeferredQueue()
         self.device_ids = {}  # OLT mac_address -> device_id
         self.vlan_to_device_ids = {}  # c-vid -> (device_id, logical_device_id, mac_address)
+        self.mode = "GPON"
 
     def start(self):
         log.debug('starting', interface=self.interface)
@@ -207,103 +223,103 @@
             ping_frame = self._make_ping_frame(mac_address=olt_mac)
             self.io_port.send(ping_frame)
 
-            # wait till we receive a response
-            ## TODO add timeout mechanism so we can signal if we cannot reach
-            ##device
-            while True:
-                response = yield self.incoming_queues[olt_mac].get()
-                # verify response and if not the expected response
-                if 1: # TODO check if it is really what we expect, and wait if not
-                    break
+            # Loop until we have a Get Response or timeout
+            ack = False
+            start_time = time.time()
+            while not ack:
+                frame = yield self.incoming_queues[olt_mac].get()
+                #TODO - Need to add proper timeout functionality
+                #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
+                #    break  # don't wait forever
+
+                respType = self._get_oam_msg_type(frame)
+             
+                if (respType == RxedOamMsgTypeEnum["DPoE Get Response"]):
+                    ack = True
+                else:
+                    # Handle unexpected events/OMCI messages
+                    self._check_resp(frame)
 
         except Exception as e:
             log.exception('launch device failed', e=e)
 
-        # if we got response, we can fill out the device info, mark the device
-        # reachable
-        jdev = json.loads(response.payload.payload.body.load)
-        device.root = True
-        device.vendor = 'Tibit Communications, Inc.'
-        device.model = jdev.get('results', {}).get('device', 'DEVICE_UNKNOWN')
-        device.hardware_version = jdev['results']['datecode']
-        device.firmware_version = jdev['results']['firmware']
-        device.software_version = jdev['results']['modelversion']
-        device.serial_number = jdev['results']['manufacturer']
+        if ack:
+            # Process the Get Request message
+            self._process_ping_frame_response(device, frame)
 
-        device.connect_status = ConnectStatus.REACHABLE
-        self.adapter_agent.update_device(device)
+            # then shortly after we create some ports for the device
+            log.info('create-port')
+            nni_port = Port(
+                port_no=2,
+                label='NNI facing Ethernet port',
+                type=Port.ETHERNET_NNI,
+                admin_state=AdminState.ENABLED,
+                oper_status=OperStatus.ACTIVE
+            )
+            self.adapter_agent.add_port(device.id, nni_port)
+            self.adapter_agent.add_port(device.id, Port(
+                port_no=1,
+                label='PON port',
+                type=Port.PON_OLT,
+                admin_state=AdminState.ENABLED,
+                oper_status=OperStatus.ACTIVE
+            ))
 
-        # then shortly after we create some ports for the device
-        log.info('create-port')
-        nni_port = Port(
-            port_no=2,
-            label='NNI facing Ethernet port',
-            type=Port.ETHERNET_NNI,
-            admin_state=AdminState.ENABLED,
-            oper_status=OperStatus.ACTIVE
-        )
-        self.adapter_agent.add_port(device.id, nni_port)
-        self.adapter_agent.add_port(device.id, Port(
-            port_no=1,
-            label='PON port',
-            type=Port.PON_OLT,
-            admin_state=AdminState.ENABLED,
-            oper_status=OperStatus.ACTIVE
-        ))
+            log.info('create-logical-device')
+            # then shortly after we create the logical device with one port
+            # that will correspond to the NNI port
+            ld = LogicalDevice(
+                desc=ofp_desc(
+                    mfr_desc=device.vendor,
+                    hw_desc=device.hardware_version,
+                    sw_desc=device.software_version,
+                    serial_num=uuid4().hex,
+                    dp_desc='n/a'
+                ),
+                switch_features=ofp_switch_features(
+                    n_buffers=256,  # TODO fake for now
+                    n_tables=2,  # TODO ditto
+                    capabilities=(  # TODO and ditto
+                        OFPC_FLOW_STATS
+                        | OFPC_TABLE_STATS
+                        | OFPC_PORT_STATS
+                        | OFPC_GROUP_STATS
+                    )
+                ),
+                root_device_id=device.id
+            )
+            ld_initialized = self.adapter_agent.create_logical_device(ld)
+            cap = OFPPF_10GB_FD | OFPPF_FIBER
+            self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
+                id='nni',
+                ofp_port=ofp_port(
+                    port_no=0,
+                    hw_addr=mac_str_to_tuple(device.mac_address),
+                    name='nni',
+                    config=0,
+                    state=OFPPS_LIVE,
+                    curr=cap,
+                    advertised=cap,
+                    peer=cap,
+                    curr_speed=OFPPF_10GB_FD,
+                    max_speed=OFPPF_10GB_FD
+                ),
+                device_id=device.id,
+                device_port_no=nni_port.port_no,
+                root_port=True
+            ))
 
-        log.info('create-logical-device')
-        # then shortly after we create the logical device with one port
-        # that will correspond to the NNI port
-        ld = LogicalDevice(
-            desc=ofp_desc(
-                mfr_desc=device.vendor,
-                hw_desc=jdev['results']['device'],
-                sw_desc=jdev['results']['firmware'],
-                serial_num=uuid4().hex,
-                dp_desc='n/a'
-            ),
-            switch_features=ofp_switch_features(
-                n_buffers=256,  # TODO fake for now
-                n_tables=2,  # TODO ditto
-                capabilities=(  # TODO and ditto
-                    OFPC_FLOW_STATS
-                    | OFPC_TABLE_STATS
-                    | OFPC_PORT_STATS
-                    | OFPC_GROUP_STATS
-                )
-            ),
-            root_device_id=device.id
-        )
-        ld_initialized = self.adapter_agent.create_logical_device(ld)
-        cap = OFPPF_10GB_FD | OFPPF_FIBER
-        self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
-            id='nni',
-            ofp_port=ofp_port(
-                port_no=0,
-                hw_addr=mac_str_to_tuple(device.mac_address),
-                name='nni',
-                config=0,
-                state=OFPPS_LIVE,
-                curr=cap,
-                advertised=cap,
-                peer=cap,
-                curr_speed=OFPPF_10GB_FD,
-                max_speed=OFPPF_10GB_FD
-            ),
-            device_id=device.id,
-            device_port_no=nni_port.port_no,
-            root_port=True
-        ))
+            # and finally update to active
+            device = self.adapter_agent.get_device(device.id)
+            device.parent_id = ld_initialized.id
+            device.oper_status = OperStatus.ACTIVE
+            self.adapter_agent.update_device(device)
 
-        # and finally update to active
-        device = self.adapter_agent.get_device(device.id)
-        device.parent_id = ld_initialized.id
-        device.oper_status = OperStatus.ACTIVE
-        self.adapter_agent.update_device(device)
+            # Just transitioned to ACTIVE, wait a tenth of second
+            # before checking for ONUs
+            reactor.callLater(0.1, self._detect_onus, device)
 
-        # Just transitioned to ACTIVE, wait a tenth of second
-        # before checking for ONUs
-        reactor.callLater(0.1, self._detect_onus, device)
+        # END if ack
 
     @inlineCallbacks
     def _detect_onus(self, device):
@@ -311,111 +327,172 @@
         olt_mac = device.mac_address
         links_frame = self._make_links_frame(mac_address=olt_mac)
         self.io_port.send(links_frame)
-        while True:
-            response = yield self.incoming_queues[olt_mac].get()
-            # verify response and if not the expected response
-            if 1: # TODO check if it is really what we expect, and wait if not
-                break
 
-        jdev = json.loads(response.payload.payload.body.load)
-        onu_mac = ''
-        child_device_name = ''
-        for macid in jdev['results']:
-            if macid['macid'] is None:
-                log.info('MAC ID is NONE %s' % str(macid['macid']))
-            elif macid['macid'][:6].upper() == SUMITOMO_ELECTRIC_INDUSTRIES_OUI:
-                onu_mac_string = macid['macid']
-                log.info('SUMITOMO mac address %s' % str(macid['macid']))
-                child_device_name = 'dpoe_onu'
 
-            elif macid['macid'][:4].upper() == ADTRAN_SHORTENED_VSSN:
-                onu_mac_string = macid['macid']
-                log.info('ADTRAN mac address %s' % str(macid['macid']))
-                child_device_name = 'adtran_onu'
+        # Loop until we have a Get Response or timeout
+        ack = False
+        start_time = time.time()
+        while not ack:
 
+            frame = yield self.incoming_queues[olt_mac].get()
+
+            #TODO - Need to add proper timeout functionality
+            #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
+            #    break  # don't wait forever
+
+            respType = self._get_oam_msg_type(frame)
+ 
+            if (respType == RxedOamMsgTypeEnum["DPoE Get Response"]):
+                ack = True
             else:
-                onu_mac_string = '000c' + macid.get('macid', 'e2000000')[4:]
-                log.info('TIBIT mac address %s' % onu_mac)
-                child_device_name = 'tibit_onu'
+                # Handle unexpected events/OMCI messages
+                self._check_resp(frame)
 
-            # Convert from string to colon separated form
-            onu_mac = ':'.join(s.encode('hex') for s in onu_mac_string.decode('hex'))
-            log.info('activate-olt-for-onu-%s' % onu_mac)
-            mac_octet_4 = int(macid['macid'][-4:-2], 16)
-            vlan_id = self._olt_side_onu_activation(mac_octet_4)
-            self.adapter_agent.child_device_detected(
-                parent_device_id=device.id,
-                parent_port_no=1,
-                child_device_type=child_device_name,
-                mac_address = onu_mac,
-                proxy_address=Device.ProxyAddress(
-                    device_id=device.id,
-                    channel_id=vlan_id
-                    ),
-                    vlan=vlan_id
-                )
+        if ack:
+            #Process the Get Response
+            mac_table = [0xB7, 0x0103]
+            links = []
+            branch_leaf_pairs = [mac_table]
 
-            ## Automatically setup default downstream control frames flow (in this case VLAN 4000)
-            ## on the OLT for the new ONU/ONT device
-            Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
-            Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
-            packet_out_rule = (
-                Ether(dst=device.mac_address) /
-                Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
-                EOAMPayload(
-                    body=TibitOUI() / DPoEOpcode_SetRequest() /
-                    NetworkToNetworkPortObject()/
-                    PortIngressRuleHeader(precedence=13)/
-                    PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
-                                                       operator=Operator['=='],
-                                                       match=TIBIT_PACKET_OUT_VLAN)/
-                    PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
-                                                       operator=Operator['=='], match=vlan_id)/
-                    PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=int(onu_mac_string[4:], 16))/
-                    PortIngressRuleResultForward()/
-                    PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
-                    PortIngressRuleTerminator()/
-                    AddPortIngressRule()))
-
-            self.io_port.send(str(packet_out_rule))
-            
-            # Get and process the Set Response
-            ack = False
-            start_time = time.time()
-
-            # Loop until we have a set response or timeout
-            while not ack:
-                frame = yield self.incoming_queues[olt_mac].get()
-                #TODO - Need to add propoer timeout functionality
-                #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
-                #    break  # don't wait forever
-
-                respType = self._voltha_get_oam_msg_type(frame)
-                log.info('Received OAM Message 0x %s' % str(respType))
-
-                #Check that the message received is a Set Response
-                if (respType == RxedOamMsgTypeEnum["DPoE Set Response"]):
+            for pair in branch_leaf_pairs:
+                temp_pair = pair
+                (rc, value) = (self._get_value_from_msg(frame, pair[0], pair[1]))
+                temp_pair.append(rc)
+                temp_pair.append(value)
+                if rc:
+                    overall_rc = True
+                else: 
+                    log.info('Failed to get valid response for Branch 0x{:X} Leaf 0x{:0>4X} '.format(temp_pair[0], temp_pair[1]))
                     ack = True
-                else:
-                    # Handle unexpected events/OMCI messages
-                    self._voltha_check_resp(frame)
 
-            # Verify Set Response
-            if ack:
-                (rc,branch,leaf,status) = self._voltha_check_set_resp(frame)
-                if (rc == True):
-                    log.info('Set Response had no errors')
-                else:
-                    raise Exception('Set Respose had errors')
-                    log.info('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
+            if mac_table[rc]:
+                value = mac_table.pop()
+                macLen = 0
+                while (macLen < len(value)):
+                    macAddr = struct.unpack_from(">6B", value, macLen)
+                    linkAddr = "".join([hex(i).lstrip("0x").zfill(2) for i in macAddr])
 
-            # also record the vlan_id -> (device_id, logical_device_id, linkid) for
-            # later use.  The linkid is the macid returned.
-            self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id, macid.get('macid', 0))
+                    if linkAddr is None:
+                        log.info('MAC Addr is NONE')
+                    elif linkAddr[:6].upper() == SUMITOMO_ELECTRIC_INDUSTRIES_OUI:
+                        onu_mac_string = linkAddr 
+                        log.info('SUMITOMO mac address %s' % str(linkAddr))
+                        child_device_name = 'dpoe_onu'
+                    elif linkAddr[:4].upper() == ADTRAN_SHORTENED_VSSN:
+                        onu_mac_string = linkAddr 
+                        log.info('ADTRAN mac address %s' % str(linkAddr))
+                        child_device_name = 'adtran_onu'
+                    else:
+                        onu_mac_string = '000c' + linkAddr[4:]
+                        log.info('TIBIT mac address %s' % onu_mac_string)
+                        child_device_name = 'tibit_onu'
+
+                    if linkAddr is not None:
+                        # Convert from string to colon separated form
+                        onu_mac = ':'.join(s.encode('hex') for s in onu_mac_string.decode('hex'))
+                        log.info('activate-olt-for-onu-%s' % onu_mac)
+                        mac_octet_4 = int(linkAddr[-4:-2], 16)
+                        vlan_id = self._olt_side_onu_activation(mac_octet_4)
+
+                        macLen += 6
+                
+                        ## Automatically setup default downstream control frames flow (in this case VLAN 4000)
+                        ## on the OLT for the new ONU/ONT device
+                        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
+                        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
+
+                        if self.mode.upper()[0] == "G":  # GPON
+                            vssn = "TBIT"
+                            link = int(onu_mac_string[4:12], 16)
+                            resultOltQueue = "PortIngressRuleResultOLTQueue(unicastvssn=vssn, unicastlink=link)"
+                        else:                       # EPON
+                            vssn = int(onu_mac_string[0:8].rjust(8,"0"), 16)
+                            link = int((onu_mac_string[8:10]+"02").ljust(8,"0"), 16)
+                            resultOltQueue = "PortIngressRuleResultOLTEPONQueue(unicastvssn=vssn, unicastlink=link)"
+
+                        packet_out_rule = (
+                            Ether(dst=device.mac_address) /
+                            Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
+                            EOAMPayload() / EOAM_VendSpecificMsg(oui=Tibit_OUI) /
+                            EOAM_TibitMsg(dpoe_opcode=0x03,
+                                body=NetworkToNetworkPortObject()/
+                                PortIngressRuleHeader(precedence=13)/
+                                PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
+                                                                   operator=Operator['=='],
+                                                                   match=TIBIT_PACKET_OUT_VLAN)/
+                                PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
+                                                                   operator=Operator['=='], match=vlan_id)/
+                                eval(resultOltQueue)/
+                                PortIngressRuleResultForward()/
+                                PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
+                                PortIngressRuleTerminator()/
+                                AddPortIngressRule())/
+                            EndOfPDU()
+                            )
+
+                        self.io_port.send(str(packet_out_rule))
+
+                        # Get and process the Set Response
+                        ack = False
+                        start_time = time.time()
+
+                        # Loop until we have a set response or timeout
+                        while not ack:
+
+                            frame = yield self.incoming_queues[olt_mac].get()
+                            #TODO - Need to add proper timeout functionality
+                            #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
+                            #    break  # don't wait forever
+
+                            respType = self._get_oam_msg_type(frame)
+
+                            #Check that the message received is a Set Response
+                            if (respType == RxedOamMsgTypeEnum["DPoE Set Response"]):
+                                ack = True
+                            else:
+                                # Handle unexpected events/OMCI messages
+                                self._check_resp(frame)
+
+                        # Verify Set Response
+                        if ack:
+                            (rc,branch,leaf,status) = self._check_set_resp(frame)
+                            if (rc == True):
+                                log.info('Set Response had no errors')
+
+                                # also record the vlan_id -> (device_id, logical_device_id, linkid) for
+                                # later use.  The linkid is the macid returned.
+
+                                self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id, linkAddr)
+
+
+                                self.adapter_agent.child_device_detected(
+                                    parent_device_id=device.id,
+                                    parent_port_no=1,
+                                    child_device_type=child_device_name,
+                                    mac_address = onu_mac,
+                                    proxy_address=Device.ProxyAddress(
+                                        device_id=device.id,
+                                        channel_id=vlan_id
+                                        ),
+                                        vlan=vlan_id
+                                )
+
+                            else:
+                                log.info('Set Response had errors')
+                                log.info('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
+
+                    # END linkAddr is not none
+            else:
+                log.info('No links were found in the MAC Table')
+            # END if mac_table[rc]
+        #END if ack
 
         ### KPI Metrics - Work in progress feature - Disabling for now
         ### Give the ONUs a chance to arrive before starting metric collection
-        ###    reactor.callLater(5.0, self.start_kpi_collection, device.id)
+
+        # TODO - Disable Stats Reporting for the moment
+        # reactor.callLater(5.0, self.start_kpi_collection, device.id)
+
 
     def _olt_side_onu_activation(self, serial):
         """
@@ -492,21 +569,158 @@
                 self.incoming_queues[response.src].put(response)
 
     def _make_ping_frame(self, mac_address):
-        # Create a json packet
-        json_operation_str = '{\"operation\":\"version\"}'
-        frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
+        frame = (
+            Ether(dst=mac_address) /
+            Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
+            EOAMPayload() / EOAM_VendSpecificMsg(oui=Tibit_OUI) /
+            EOAM_TibitMsg(dpoe_opcode=0x01,body=VendorName() /
+                                                OltMode() /
+                                                HardwareVersion() /
+                                                ManufacturerInfo()
+                                                ) /
+            EndOfPDU()
+            )
+
         return str(frame)
 
+    def _process_ping_frame_response(self, device, frame):
+
+        vendor = [0xD7, 0x0011]
+        oltMode = [0xB7, 0x0101]
+        hw_version = [0xD7, 0x0013]
+        manufacturer =  [0xD7, 0x0006]
+        branch_leaf_pairs = [vendor, oltMode, hw_version, manufacturer]
+                    
+        for pair in branch_leaf_pairs:
+            temp_pair = pair
+            (rc, value) = (self._get_value_from_msg(frame, pair[0], pair[1]))
+            temp_pair.append(rc)
+            temp_pair.append(value)
+            if rc:
+                overall_rc = True
+            else: 
+                log.info('Failed to get valid response for Branch 0x{:X} Leaf 0x{:0>4X} '.format(temp_pair[0], temp_pair[1]))
+                ack = True
+
+        if vendor[rc]:
+            device.vendor = vendor.pop()
+        else:
+            device.vendor = "UNKNOWN"
+            
+        # mode: 3 = EPON OLT, 7 = GPON OLT
+        # mode: 2 = EPON ONU, 6 = GPON ONU    
+        if oltMode[rc]:
+            value = oltMode.pop()
+            mode = "UNKNOWN"
+            self.mode = "UNKNOWN"
+
+            if value == 7:
+                mode = "10G GPON OLT"
+                self.mode = "GPON"
+            if value == 3:
+                mode = "10G EPON OLT"
+                self.mode = "EPON"
+            if value == 1:
+                mode = "10G Point to Point"
+                self.mode = "Unsupported"
+
+            device.model = mode
+
+        else:
+            device.model = "UNKNOWN"
+            self.mode = "UNKNOWN"
+
+        log.info("OLT Mode is {}".format(self.mode))
+                
+        if hw_version[rc]:
+            device.hardware_version = hw_version.pop()
+        else:
+            device.hardware_version = "UNKNOWN"
+
+        if manufacturer[rc]:
+            manu_value = manufacturer.pop()
+            device.firmware_version = re.search('\Firmware: (.+?) ', manu_value).group(1)
+            device.software_version = re.search('\Build: (.+?) ', manu_value).group(1)
+            device.serial_number = re.search('\Serial #: (.+?) ', manu_value).group(1)
+        else:
+            device.firmware_version = "UNKNOWN"
+            device.software_version = "UNKNOWN"
+            device.serial_number = "UNKNOWN"
+        device.root = True
+        device.connect_status = ConnectStatus.REACHABLE
+
     def _make_links_frame(self, mac_address):
-        # Create a json packet
-        json_operation_str = '{\"operation\":\"links\"}'
-        frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
+        frame = (
+            Ether(dst=mac_address) /
+            Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
+            EOAMPayload() / EOAM_VendSpecificMsg(oui=Tibit_OUI) /
+            EOAM_TibitMsg(dpoe_opcode=0x01,body=TibitLinkMacTable()
+                            )/
+            EndOfPDU()
+            )
         return str(frame)
 
-    def _make_stats_frame(self, mac_address, itype, link):
-        # Create a json packet
-        json_operation_str = ('{\"operation\":\"stats\",\"parameters\":{\"itype\":\"%s\",\"iinst\",\"0\",\"macid\":\"%s\"}}' % (itype, link))
-        frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
+    def _make_link_stats_frame(self, olt_mac_address, onu_mac_address):
+
+        if self.mode.upper()[0] == "G":  # GPON
+            vssn = "TBIT"
+            link = int(onu_mac_address[4:12], 16)
+        else:                       # EPON
+            vssn = int(onu_mac_address[0:8].rjust(8,"0"), 16)
+            link = int((onu_mac_address[8:10]+"02").ljust(8,"0"), 16)
+        frame = (
+            Ether(dst=olt_mac_address) /
+            Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
+            EOAMPayload() / EOAM_VendSpecificMsg(oui=Tibit_OUI) /
+            EOAM_TibitMsg(dpoe_opcode=0x01,
+                          body=OLTUnicastLogicalLink(unicastvssn=vssn, unicastlink=link)/
+                                #RxFramesGreen()/
+                                #TxFramesGreen()/
+                                RxFrame_64()/
+                                RxFrame_65_127()/
+                                RxFrame_128_255()/
+                                RxFrame_256_511()/
+                                RxFrame_512_1023()/
+                                RxFrame_1024_1518()/
+                                RxFrame_1519Plus()/
+                                TxFrame_64()/
+                                TxFrame_65_127()/
+                                TxFrame_128_255()/
+                                TxFrame_256_511()/
+                                TxFrame_512_1023()/
+                                TxFrame_1024_1518()/
+                                TxFrame_1519Plus()
+                            )/
+            EndOfPDU()
+            )
+
+        return str(frame)
+
+    def _make_nni_stats_frame(self, mac_address):
+        frame = (
+            Ether(dst=mac_address) /
+            Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
+            EOAMPayload() / EOAM_VendSpecificMsg(oui=Tibit_OUI) /
+            EOAM_TibitMsg(dpoe_opcode=0x01, body=NetworkToNetworkPortObject()/
+                                #RxFramesGreen()/
+                                #TxFramesGreen()/
+                                RxFrame_64()/
+                                RxFrame_65_127()/
+                                RxFrame_128_255()/
+                                RxFrame_256_511()/
+                                RxFrame_512_1023()/
+                                RxFrame_1024_1518()/
+                                RxFrame_1519Plus()/
+                                TxFrame_64()/
+                                TxFrame_65_127()/
+                                TxFrame_128_255()/
+                                TxFrame_256_511()/
+                                TxFrame_512_1023()/
+                                TxFrame_1024_1518()/
+                                TxFrame_1519Plus()
+                            )/
+            EndOfPDU()
+            )
         return str(frame)
 
     def abandon_device(self, device):
@@ -613,9 +827,19 @@
                                 dn_req /= PortIngressRuleResultOLTBroadcastQueue()
                             elif _inner_vid is not None:
                                 serial = _inner_vid - 200
-                                link = (0xe222 << 16) | (serial << 8)
-                                dn_req /= PortIngressRuleResultOLTQueue(unicastvssn="TBIT",
-                                                                        unicastlink=link)
+                                mac_address = self.vlan_to_device_ids[_inner_vid][2].upper()
+
+                                if self.mode.upper()[0] == "G":  # GPON
+                                    vssn = "TBIT"
+                                    link = int(mac_address[4:12], 16)
+                                    resultOltQueue = "PortIngressRuleResultOLTQueue(unicastvssn=vssn, unicastlink=link)"
+                                else:                       # EPON
+                                    vssn = int(mac_address[0:8].rjust(8,"0"), 16)
+                                    link = int((mac_address[8:10]+"02").ljust(8,"0"), 16)
+                                    resultOltQueue = "PortIngressRuleResultOLTEPONQueue(unicastvssn=vssn, unicastlink=link)"
+
+                                dn_req /= eval(resultOltQueue)
+
                             elif _inner_vid is None:
                                 log.info('#### action.type == OUTPUT INNER VID is NONE ####')
 
@@ -626,7 +850,7 @@
                                 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
                                                                              operator=Operator['=='], match=_outer_vid)
                             else:
-                                dn_req /= PortIngressRuleResultDelete(fieldcode=Clause['S-VLAN Tag'])
+                                dn_req /= PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])
                                 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
                                                                              operator=Operator['=='], match=_outer_vid)
                                 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
@@ -660,8 +884,9 @@
                     msg = (
                         Ether(dst=device.mac_address) /
                         Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
-                        EOAMPayload(
-                            body=TibitOUI() / DPoEOpcode_SetRequest() / dn_req)
+                        EOAMPayload() / EOAM_VendSpecificMsg(oui=Tibit_OUI) /
+                        EOAM_TibitMsg(dpoe_opcode = 0x03, body=dn_req)/
+                        EndOfPDU()
                     )
 
                     self.io_port.send(str(msg))
@@ -673,27 +898,26 @@
                     # Loop until we have a set response or timeout
                     while not ack:
                         frame = yield self.incoming_queues[olt_mac].get()
-                        #TODO - Need to add propoer timeout functionality
+                        #TODO - Need to add proper timeout functionality
                         #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
                         #    break  # don't wait forever
 
-                        respType = self._voltha_get_oam_msg_type(frame)
-                        log.info('Received OAM Message 0x %s' % str(respType))
+                        respType = self._get_oam_msg_type(frame)
 
                         #Check that the message received is a Set Response
                         if (respType == RxedOamMsgTypeEnum["DPoE Set Response"]):
                             ack = True
                         else:
                             # Handle unexpected events/OMCI messages
-                            self._voltha_check_resp(frame)
+                            self._check_resp(frame)
 
                     # Verify Set Response
                     if ack:
-                        (rc,branch,leaf,status) = self._voltha_check_set_resp(frame)
+                        (rc,branch,leaf,status) = self._check_set_resp(frame)
                         if (rc == True):
                             log.info('Set Response had no errors')
                         else:
-                            raise Exception('Set Respose had errors')
+                            log.info('Set Response had errors')
                             log.info('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
 
                 elif in_port == 1:
@@ -747,9 +971,19 @@
                                 operator=Operator['=='], match=_vlan_vid)
 
                             serial = _vlan_vid - 200
-                            link = (0xe222 << 16) | (serial << 8)
-                            up_req_link /= OLTUnicastLogicalLink(unicastvssn='TBIT', unicastlink=link)
+                            mac_address = self.vlan_to_device_ids[_vlan_vid][2].upper()
 
+                            if self.mode.upper()[0] == "G":  # GPON
+                                vssn = "TBIT"
+                                link = int(mac_address[4:12], 16)
+                                logical_link = "OLTUnicastLogicalLink(unicastvssn=vssn, unicastlink=link)"
+                            else:                       # EPON
+                                vssn = int(mac_address[0:8].rjust(8,"0"), 16)
+                                link = int((mac_address[8:10]+"02").ljust(8,"0"), 16)
+                                logical_link = "OLTEPONUnicastLogicalLink(unicastvssn=vssn, unicastlink=link)"
+
+                            up_req_link /= eval(logical_link)
+                            
                             up_req_link /= PortIngressRuleClauseMatchLength02(
                                 fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
                                 operator=Operator['=='], match=_vlan_vid)
@@ -831,8 +1065,9 @@
                     msg = (
                         Ether(dst=device.mac_address) /
                         Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
-                        EOAMPayload(
-                            body=TibitOUI() / DPoEOpcode_SetRequest() / up_req)
+                        EOAMPayload() / EOAM_VendSpecificMsg(oui=Tibit_OUI) /
+                        EOAM_TibitMsg(dpoe_opcode = 0x03, body=up_req)/
+                        EndOfPDU()
                     )
 
                     self.io_port.send(str(msg))
@@ -844,27 +1079,26 @@
                     # Loop until we have a set response or timeout
                     while not ack:
                         frame = yield self.incoming_queues[olt_mac].get()
-                        #TODO - Need to add propoer timeout functionality
+                        #TODO - Need to add proper timeout functionality
                         #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
                         #    break  # don't wait forever
 
-                        respType = self._voltha_get_oam_msg_type(frame)
-                        log.info('Received OAM Message 0x %s' % str(respType))
+                        respType = self._get_oam_msg_type(frame)
 
                         #Check that the message received is a Set Response
                         if (respType == RxedOamMsgTypeEnum["DPoE Set Response"]):
                             ack = True
                         else:
                             # Handle unexpected events/OMCI messages
-                            self._voltha_check_resp(frame)
+                            self._check_resp(frame)
 
                     # Verify Set Response
                     if ack:
-                        (rc,branch,leaf,status) = self._voltha_check_set_resp(frame)
+                        (rc,branch,leaf,status) = self._check_set_resp(frame)
                         if (rc == True):
                             log.info('Set Response had no errors')
                         else:
-                            raise Exception('Set Respose had errors')
+                            log.info('Set Respose had errors')
                             log.info('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
 
                 else:
@@ -882,7 +1116,7 @@
 
         mac_address = self.vlan_to_device_ids[proxy_address.channel_id][2].upper()
 
-        if mac_address.startswith(TIBIT_SHORTENED_VSSN):
+        if mac_address.startswith(TIBIT_SHORTENED_VSSN) or self.mode.upper()[0] == "E":
             # Send straight OAM
             frame = Ether(dst=device.mac_address) / \
               Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) / \
@@ -890,11 +1124,12 @@
               msg
         else:
             # Use the standard to send OMCI over OAM
-            encapsulated_omci = EOAMPayload(body=ItuOUI()/msg)
+            encapsulated_omci = EOAM_OmciMsg(body=msg)
 
             frame = Ether(dst=device.mac_address) / \
               Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) / \
               Dot1Q(vlan=proxy_address.channel_id, prio=TIBIT_MGMT_PRIORITY) / \
+              EOAMPayload() / EOAM_VendSpecificMsg(oui=IEEE_OUI) / \
               encapsulated_omci
 
         self.io_port.send(str(frame))
@@ -920,7 +1155,7 @@
         self.io_port.send(str(frame))
 
     def receive_inter_adapter_message(self, msg):
-        raise NotImplementedError()
+        raise NotImplementedError()    
 
     def suppress_alarm(self, filter):
         raise NotImplementedError()
@@ -937,43 +1172,106 @@
         @inlineCallbacks
         def _collect(device_id, prefix):
 
-            pon_port_metrics = {}
-            links = []
+            pon_port_metrics = []
+            pon_metrics_list = {}
+            nni_metrics = []
+
+            branch_leaf_pairs = [
+                            #[0xD7, 0x0201,], [0xD7, 0x0202], 
+                            [0xD7, 0x0204, "rx_64"], [0xD7, 0x0205, "rx_65_127"], 
+                            [0xD7, 0x0206, "rx_128_255"], [0xD7, 0x0207, "rx_256_511"],
+                            [0xD7, 0x0208, "rx_512_1023"], [0xD7, 0x0209, "rx_1024_1518"],
+                            [0xD7, 0x020A, "rx_1519_9k"], [0xD7, 0x020B, "tx_64"],
+                            [0xD7, 0x020C, "tx_65_127"], [0xD7, 0x020D, "tx_128_255"],
+                            [0xD7, 0x020E, "tx_256_511"], [0xD7, 0x020F, "tx_512_1023"],
+                            [0xD7, 0x0210, "tx_1024_1518"], [0xD7, 0x0211, "tx_1519_9k"]]
+
             olt_mac = next((mac for mac, device in self.device_ids.iteritems() if device == device_id), None)
-            links   = [v[TIBIT_ONU_LINK_INDEX] for _,v,_ in self.vlan_to_device_ids.iteritems()]
 
             try:
                 # Step 1: gather metrics from device
-                log.info('link stats frame', links=links)
-                for link in links:
-                    stats_frame = self._make_stats_frame(mac_address=olt_mac, itype='olt', link=link)
-                    self.io_port.send(stats_frame)
 
-                    ## Add timeout mechanism so we can signal if we cannot reach
-                    ## device
-                    while True:
-                        response = yield self.incoming_queues[olt_mac].get()
-                        jdict = json.loads(response.payload.payload.body.load)
-                        pon_port_metrics[link] = {k: int(v,16) for k,v in jdict['results'].iteritems()}
-                        # verify response and if not the expected response
-                        if 1: # TODO check if it is really what we expect, and wait if not
-                            break
+                #for each link on this OLT
+                for vlan_id in self.vlan_to_device_ids:
+
+                    log.info('link stats frame', links=self.vlan_to_device_ids[vlan_id])
+
+                    # send out link_stats_frame
+                    mac_address = self.vlan_to_device_ids[vlan_id][2].upper()
+
+                    link_stats_frame = self._make_link_stats_frame(olt_mac_address=olt_mac, onu_mac_address=mac_address)
+        
+                    self.io_port.send(link_stats_frame)
+
+                    # Loop until we have a Get Response or timeout
+                    ack = False
+                    start_time = time.time()
+                    while not ack:
+                        frame = yield self.incoming_queues[olt_mac].get()
+                        #TODO - Need to add proper timeout functionality
+                        #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
+                        #    break  # don't wait forever
+
+                        respType = self._get_oam_msg_type(frame)
+                 
+                        if (respType == RxedOamMsgTypeEnum["DPoE Get Response"]):
+                            ack = True
+                        else:
+                            # Handle unexpected events/OMCI messages
+                            self._check_resp(frame)
+
+                    if ack:
+                        # Process the Get Request message
+                        log.info('Received Link Stats Get Response Frame')
+
+                        for pair in branch_leaf_pairs:
+                            (rc, value) = (self._get_value_from_msg(frame, pair[0], pair[1]))
+
+                            if rc:
+                                log.info('Response for Branch 0x{:X} Leaf 0x{:0>4X} '.format(pair[0], pair[1]))
+                                pon_port_metrics.append((pair[2],value))
+                            else:
+                                log.info('Failed to get valid response for Branch 0x{:X} Leaf 0x{:0>4X} '.format(pair[0], pair[1]))
+
+                        pon_metrics_list[vlan_id] = pon_port_metrics
+
+                #end looping on each vlan_id
 
                 log.info('nni stats frame')
-                olt_nni_link = ''.join(l for l in olt_mac.split(':'))
-                stats_frame = self._make_stats_frame(mac_address=olt_mac, itype='eth', link=olt_nni_link)
-                self.io_port.send(stats_frame)
 
-                ## Add timeout mechanism so we can signal if we cannot reach
-                ## device
-                while True:
-                    response = yield self.incoming_queues[olt_mac].get()
-                    jdict = json.loads(response.payload.payload.body.load)
-                    nni_port_metrics = {k: int(v,16) for k,v in jdict['results'].iteritems()}
-                    # verify response and if not the expected response
-                    if 1: # TODO check if it is really what we expect, and wait if not
-                        break
+                link_stats_frame = self._make_nni_stats_frame(mac_address=olt_mac)
+                self.io_port.send(link_stats_frame)
 
+                # Loop until we have a Get Response or timeout
+                ack = False
+                start_time = time.time()
+                while not ack:
+                    frame = yield self.incoming_queues[olt_mac].get()
+                    #TODO - Need to add proper timeout functionality
+                    #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
+                    #    break  # don't wait forever
+
+                    respType = self._get_oam_msg_type(frame)
+             
+                    if (respType == RxedOamMsgTypeEnum["DPoE Get Response"]):
+                        ack = True
+                    else:
+                        # Handle unexpected events/OMCI messages
+                        self._check_resp(frame)
+
+                if ack:
+                    # Process the Get Response message
+                    log.info('Recieved NNI Stats Get Response Frame')
+                                
+                    for pair in branch_leaf_pairs:
+                        (rc, value) = (self._get_value_from_msg(frame, pair[0], pair[1]))
+                        if rc:
+                            log.info('Response for Branch 0x{:X} Leaf 0x{:0>4X} '.format(pair[0], pair[1]))
+                            nni_metrics.append((pair[2],value))
+                        else:
+                            log.info('Failed to get valid response for Branch 0x{:X} Leaf 0x{:0>4X} '.format(temp_pair[0], temp_pair[1]))
+
+                #Need to replace with actual data
                 olt_metrics = dict(
                     cpu_util=20 + 5 * random.random(),
                     buffer_util=10 + 10 * random.random()
@@ -986,12 +1284,12 @@
                     # CPU Metrics (example)
                     prefix: MetricValuePairs(metrics=olt_metrics),
                     # OLT NNI port
-                    prefix + '.nni': MetricValuePairs(metrics=nni_port_metrics)
+                    prefix + '.nni': MetricValuePairs(metrics=nni_metrics)
                     }
 
-                for link in links:
+                for link in pon_metrics_list:
                     # PON link ports
-                    prefixes[prefix + '.pon.{}'.format(link)] = MetricValuePairs(metrics=pon_port_metrics[link])
+                    prefixes[prefix + '.pon.{}'.format(link)] = MetricValuePairs(metrics=pon_metrics_list[link])
 
                 kpi_event = KpiEvent(
                     type=KpiEventType.slice,
@@ -1009,175 +1307,67 @@
         lc = LoopingCall(_collect, device_id, prefix)
         lc.start(interval=15)  # TODO make this configurable
 
-    def _voltha_get_oam_msg_type(self, frame):
+
+    # Methods for Get / Set  Response Processing from eoam_messages
+
+
+    def _get_oam_msg_type(self, frame):
+
         respType = RxedOamMsgTypeEnum["Unknown"]
         recv_frame = frame
-        payload = recv_frame.payload
-        if hasattr(payload, 'body'):
-            loadstr       = payload.body.load
-            bytesRead = 0;
-            if (payload.opcode == 0xFE):
 
-                # Extract the OUI
-                (oui_hi, oui_lo) = struct.unpack_from('>BH', loadstr, bytesRead)
-                oui = (oui_hi << 16) | oui_lo
-                log.debug('oui: 0x %06x' % oui)
-                bytesRead += 3
-
-                # If this is the ITU OUI, then there is an embedded OMCI message
-                if (oui == 0x0019A7):
-                    respType = RxedOamMsgTypeEnum["OMCI Message"]
-
-                # Treat Cablelabs OUI and Tibit OUI as the same
-                elif ((oui == 0x001000) or (oui == 0x2AEA15)):
-
-                    (dpoeOpcode) = struct.unpack_from('>B', loadstr, bytesRead)[0]
-#                    log.info('DPoE Opcode:    {} ({:0>2X})'.format(DPoEOpcodeEnum[dpoeOpcode], dpoeOpcode))
-                    bytesRead += 1
-
-                    # Get Response
-                    if (dpoeOpcode == 0x02):
-                        respType = RxedOamMsgTypeEnum["DPoE Get Response"]
-
-                    # Set Response
-                    elif (dpoeOpcode == 0x04):
-                        respType = RxedOamMsgTypeEnum["DPoE Set Response"]
-
-                    # File Transfer ACK
-                    elif (dpoeOpcode == 0x09):
-                        respType = RxedOamMsgTypeEnum["DPoE File Transfer"]
-
-                else:
-                    log.info('Unsupported OAM OUI 0x{:0>6X}'.format(oui))
-
-            # Handle OAM Event Notification
-            elif (payload.opcode == 0x01):
-                respType = RxedOamMsgTypeEnum["Event Notification"]
+        if recv_frame.haslayer(EOAMPayload):
+            if recv_frame.haslayer(EOAMEvent):
+                recv_frame = RxedOamMsgTypeEnum["Event Notification"]
+            elif recv_frame.haslayer(EOAM_OmciMsg):
+                respType = RxedOamMsgTypeEnum["OMCI Message"]
             else:
-                log.info('Unsupported OAM Opcode {}'.format(payload.opcode))
+                dpoeOpcode = 0x00
+                if recv_frame.haslayer(EOAM_TibitMsg):
+                    dpoeOpcode = recv_frame.getlayer(EOAM_TibitMsg).dpoe_opcode;
+                elif recv_frame.haslayer(EOAM_DpoeMsg):
+                    dpoeOpcode = recv_frame.getlayer(EOAM_DpoeMsg).dpoe_opcode;
+
+                # Get Response
+                if (dpoeOpcode == 0x02):
+                    respType = RxedOamMsgTypeEnum["DPoE Get Response"]
+
+                # Set Response
+                elif (dpoeOpcode == 0x04):
+                    respType = RxedOamMsgTypeEnum["DPoE Set Response"]
+
+                # File Transfer ACK
+                elif (dpoeOpcode == 0x09):
+                    respType = RxedOamMsgTypeEnum["DPoE File Transfer"]
+                else:
+                    log.info('Unsupported DPoE Opcode {:0>2X}'.format(dpoeOpcode))
         else:
-            log.debug('received frame has no payload')
+            log.info('Invalid OAM Header')
+
+        log.info('Received OAM Message 0x %s' % str(respType))
 
         return respType
 
 
-    def _voltha_check_set_resp(self, frame):
-        rc = False
-        branch = 0
-        leaf = 0
-        status = 0
-
+    def _get_value_from_msg(self, frame, branch, leaf):
+        retVal = False
+        value = 0
         recv_frame = frame
-        payload = recv_frame.payload
-        if hasattr(payload, 'body'):
-            loadstr   = payload.body.load
-            bytesRead = 0;
-            #if self.report_obj is not None:
-            #    self.report_obj.log_result(data="OAM Opcode", actual=hex(payload.opcode), expected=hex(0xFE), criteria="==")
-            if (payload.opcode == 0xFE):
 
-                # Extract the OUI
-                (oui_hi, oui_lo) = struct.unpack_from('>BH', loadstr, bytesRead)
-                oui = (oui_hi << 16) | oui_lo
-                log.info('oui: 0x %06x' % oui)
-                bytesRead += 3
-
-                # Treat Cablelabs OUI and Tibit OUI as the same
-                if ((oui == 0x001000) or (oui == 0x2AEA15)):
-                    (dpoeOpcode) = struct.unpack_from('>B', loadstr, bytesRead)[0]
-                    bytesRead += 1
-
-                    startOfTlvs = bytesRead
-                    # Set Response
-                    if (dpoeOpcode == 0x04):
-                        test =1
-                        (rc,branch,leaf,status) = self._voltha_check_set_resp_attrs(loadstr, startOfTlvs)
-                        if (rc == True):
-                            log.info('Set Response had no errors')
-                        else:
-                            log.debug('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
-                    else:
-                        log.info('Unsupported DPoE Opcode: {} ({:0>2X})'.format(DPoEOpcodeEnum[dpoeOpcode], dpoeOpcode))
-                else:
-                    log.info('Unsupported OAM OUI 0x{:0>6X}'. format(oui))
+        if recv_frame.haslayer(EOAMPayload):
+            payload = recv_frame.payload
+            if hasattr(payload, 'body'):
+                loadstr = payload.body.load
+                # Get a specific TLV value
+                (retVal,bytesRead,value,retbranch,retleaf) = self._handle_get_value(loadstr, 0, branch, leaf)
             else:
-                log.info('Unsupported OAM Opcode {}'.format(payload.opcode))
+                log.info('received frame has no payload')
         else:
-            log.debug('received frame has no payload')
-
-        return rc,branch,leaf,status
-    
-
-    def _voltha_check_resp(self, frame):
-        recv_frame = frame
-        payload = recv_frame.payload
-        if hasattr(payload, 'body'):
-            loadstr   = payload.body.load
-            bytesRead = 0;
-            if (payload.opcode == 0xFE):
-                
-                # Extract the OUI
-                (oui_hi, oui_lo) = struct.unpack_from('>BH', loadstr, bytesRead)
-                oui = (oui_hi << 16) | oui_lo
-                log.info('oui: 0x %06x' % oui)
-                bytesRead += 3
-
-                # If this is the ITU OUI, then there is an embedded OMCI message
-                if (oui == 0x0019A7):
-                    self._voltha_handle_omci(loadstr,bytesRead)
-
-                # Treat Cablelabs OUI and Tibit OUI as the same
-                elif ((oui == 0x001000) or (oui == 0x2AEA15)):
-                    log.debug('Recieved Response OUI 0x{:0>6X}'. format(oui))
-                else:
-                    log.info('Unsupported OAM OUI 0x{:0>6X}'. format(oui))
-
-            # Handle OAM Event Notification
-            elif (payload.opcode == 0x01):
-                self._voltha_handle_oam_event(loadstr, bytesRead)
-            else:
-                log.info('Unsupported OAM Opcode {}'.format(payload.opcode))
-
-        else:
-            log.debug('received frame has no payload')
+            log.info('Invalid OAM Header')
+        return retVal,value,
 
 
-    def _voltha_handle_oam_event(self, loadstr, startOfEvent):
-        bytesRead = startOfEvent
-        (seq_num, tlv_type, ev_len, oui_hi, oui_lo) = struct.unpack_from('>HBBBH', loadstr, bytesRead)
-        oui = (oui_hi << 16) | oui_lo
-
-        log.info('seq_num:        0x%04x' % seq_num)
-        log.info('tlv_type:       0x%' % tlv_type)
-        log.info('ev_len:         0x%x' % ev_len)
-        log.info('oui:            0x%06x"'% oui)
-
-        if (tlv_type != 0xFE):
-            log.debug('unexpected tlv_type 0x%x (expected 0xFE)' % tlv_type)
-        elif (oui == 0x001000):
-            log.debug('DPoE Event')
-            ## TODO - Handle DPoE Event/Alarm
-        elif (oui == 0x2AEA15):
-            log.debug('Tibit-specific Event')
-
-            # TODO - Handle addition/removal of links
-
-            bytesRead = 7
-
-            # TODO - Check OUI and parse Source and Reference Object Contexts
-    
-
-    def _voltha_handle_omci(self, loadstr, startOfEvent):
-        bytesRead = startOfEvent
-#        (seq_num, tlv_type, ev_len, oui_hi, oui_lo) = struct.unpack_from('>BBBBBH', loadstr, bytesRead)
-
-        log.debug('OMCI Message')
-
-        # TODO - Handle OMCI message
-
-
-
-    def _voltha_handle_get_value(self, loadstr, startOfTlvs, queryBranch, queryLeaf):
+    def _handle_get_value(self, loadstr, startOfTlvs, queryBranch, queryLeaf):
         retVal = False;
         value = 0
         branch = 0
@@ -1187,12 +1377,10 @@
 
         while (bytesRead <= loadstrlen):
             (branch, leaf) = struct.unpack_from('>BH', loadstr, bytesRead)
-#            log.info('Branch/Leaf        0x{:0>2X}/0x{:0>4X}'.format(branch, leaf))
 
             if (branch != 0):
                 bytesRead += 3
                 length = struct.unpack_from('>B', loadstr, bytesRead)[0]
-#                log.info('Length:            0x{:0>2X} ({})'.format(length,length))
                 bytesRead += 1
 
                 if (length == 1):
@@ -1215,8 +1403,6 @@
                         valStr = ">{}s".format(length)
                         value = struct.unpack_from(valStr, loadstr, bytesRead)[0]
 
-#                log.info('Value:             {}'.format(value))
-
                 if (length > 0):
                     bytesRead += length
 
@@ -1235,7 +1421,89 @@
 
         return retVal,bytesRead,value,branch,leaf
 
-    def _voltha_check_set_resp_attrs(self, loadstr, startOfTlvs):
+
+    def _check_set_resp(self, frame):
+        rc = False
+        branch = 0
+        leaf = 0
+        status = 0
+        recv_frame = frame
+        if recv_frame.haslayer(EOAMPayload):
+            payload = recv_frame.payload
+            if hasattr(payload, 'body'):
+                loadstr = payload.body.load
+                # Get a specific TLV value
+                (rc,branch,leaf,status) = self._check_set_resp_attrs(loadstr, 0)
+            else:
+                log.info('received frame has no payload')
+        else:
+            log.info('Invalid OAM Header')
+        return rc,branch,leaf,status
+
+
+
+    def _check_resp(self, frame):
+        respType = RxedOamMsgTypeEnum["Unknown"]
+        recv_frame = frame
+        if recv_frame.haslayer(EOAMPayload):
+
+            if recv_frame.haslayer(EOAMEvent):
+                self.handle_oam_event(recv_frame)
+            elif recv_frame.haslayer(EOAM_OmciMsg):
+                 self.handle_omci(recv_frame)
+            else:
+                dpoeOpcode = 0x00
+                if recv_frame.haslayer(EOAM_TibitMsg):
+                    dpoeOpcode = recv_frame.getlayer(EOAM_TibitMsg).dpoe_opcode;
+                elif recv_frame.haslayer(EOAM_DpoeMsg):
+                    dpoeOpcode = recv_frame.getlayer(EOAM_DpoeMsg).dpoe_opcode;
+
+                if hasattr(recv_frame, 'body'):
+                    payload = recv_frame.payload
+                    loadstr = payload.body.load
+
+                # Get Response
+                if (dpoeOpcode == 0x02):
+                    # Get a specific TLV value
+                    branch = 0xD7
+                    leaf = 0x0006
+                    (rc,bytesRead,value,retbranch,retleaf) = self._handle_get_value(loadstr, startOfTlvs, branch, leaf)
+                    if (rc == True):
+                        log.info('Branch 0x{:X} Leaf 0x{:0>4X}  value = {}'.format(branch, leaf, value))
+                    else:
+                        log.info('Branch 0x{:X} Leaf 0x{:0>4X}  no value'.format(branch, leaf))
+
+                    # Walk through all TLV values
+                    bytesRead = 0
+                    rc = True
+                    while(rc == True):
+                        branch = 0
+                        leaf = 0
+                        (rc,bytesRead,value,branch,leaf) = self._handle_get_value(loadstr, bytesRead, branch, leaf)
+                        if (rc == True):
+                            log.info('Branch 0x{:0>2X} Leaf 0x{:0>4X}  value = {}'.format(branch, leaf, value))
+                        elif (branch != 0):
+                            log.info('Branch 0x{:0>2X} Leaf 0x{:0>4X}  no value'.format(branch, leaf))
+
+                # Set Response
+                elif (dpoeOpcode == 0x04):
+                    (rc,branch,leaf,status) = self._check_set_resp_attrs(loadstr, 0)
+                    if (rc == True):
+                        log.info('Set Response had no errors')
+                    else:
+                        log.info('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
+
+                # File Transfer ACK
+                elif (dpoeOpcode == 0x09):
+                    rc = self._handle_fx_ack(loadstr, bytesRead, block_number)
+                else:
+                    log.info('Unsupported DPoE Opcode {:0>2X}'.format(dpoeOpcode))
+        else:
+            log.info('Invalid OAM Header')
+
+        return respType    
+
+    def _check_set_resp_attrs(self, loadstr, startOfTlvs):
         retVal = True;
         branch = 0
         leaf = 0
@@ -1245,16 +1513,16 @@
 
         while (bytesRead <= loadstrlen):
             (branch, leaf) = struct.unpack_from('>BH', loadstr, bytesRead)
-#            log.info('Branch/Leaf        0x{:0>2X}/0x{:0>4X}'.format(branch, leaf))
+#            print "Branch/Leaf        0x{:0>2X}/0x{:0>4X}".format(branch, leaf)
 
             if (branch != 0):
                 bytesRead += 3
                 length = struct.unpack_from('>B', loadstr, bytesRead)[0]
-#                log.info('Length:            0x{:0>2X} ({})'.format(length,length))
+#                print "Length:            0x{:0>2X} ({})".format(length,length)
                 bytesRead += 1
 
                 if (length >= 0x80):
-                    log.debug('Branch 0x{:0>2X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[length]))
+                    log.info('Branch 0x{:0>2X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[length]))
                     if (length > 0x80):
                         retVal = False;
                         break;
@@ -1266,24 +1534,21 @@
 
         return retVal,branch,leaf,length
 
-
-
-    def _voltha_handle_fx_ack(self, loadstr, startOfXfer, block_number):
+        
+    def _handle_fx_ack(self, loadstr, startOfXfer, block_number):
         retVal = False
         (fx_opcode, acked_block, response_code) = struct.unpack_from('>BHB', loadstr, startOfXfer)
 
-        log.debug('fx_opcode:      0x%x' % fx_opcode)
-        log.debug('acked_block:    0x%x' % acked_block)
-        log.debug('response_code:  0x%x' % response_code)
-
+        #print "fx_opcode:      0x%x" % fx_opcode
+        #print "acked_block:    0x%x" % acked_block
+        #print "response_code:  0x%x" % response_code
 
 
         if (fx_opcode != 0x03):
-            log.debug('unexpected fx_opcode 0x%x (expected 0x03)' % fx_opcode)
+            log.info('unexpected fx_opcode 0x%x (expected 0x03)' % fx_opcode)
         elif (acked_block != block_number):
-            log.debug('unexpected acked_block 0x%x (expected 0x%x)' % (acked_block, block_number))
+            log.info('unexpected acked_block 0x%x (expected 0x%x)' % (acked_block, block_number))
         elif (response_code != 0):
-            log.debug('unexpected response_code 0x%x (expected 0x00)' % response_code)
+            log.info('unexpected response_code 0x%x (expected 0x00)' % response_code)
         else:
-            retVal = True;
-
+            retVal = True;    
\ No newline at end of file
diff --git a/voltha/adapters/tibit_onu/tibit_onu.py b/voltha/adapters/tibit_onu/tibit_onu.py
index 6062007..5801101 100644
--- a/voltha/adapters/tibit_onu/tibit_onu.py
+++ b/voltha/adapters/tibit_onu/tibit_onu.py
@@ -63,9 +63,11 @@
 from voltha.extensions.eoam.EOAM_TLV import ClauseSubtypeEnum
 from voltha.extensions.eoam.EOAM_TLV import RuleOperatorEnum
 from voltha.extensions.eoam.EOAM_TLV import DPoEVariableResponseCodes
-from voltha.extensions.eoam.EOAM_TLV import TibitOUI
+from voltha.extensions.eoam.EOAM_TLV import DPoEOpcode_MulticastRegister, MulticastRegisterSet
 
-from voltha.extensions.eoam.EOAM import EOAMPayload, CablelabsOUI
+from voltha.extensions.eoam.EOAM import EOAMPayload, EOAMEvent, EOAM_VendSpecificMsg
+from voltha.extensions.eoam.EOAM import EOAM_OmciMsg, EOAM_TibitMsg, EOAM_DpoeMsg
+from voltha.extensions.eoam.EOAM import EOAMPayload, CableLabs_OUI, Tibit_OUI
 from voltha.extensions.eoam.EOAM import DPoEOpcode_GetRequest, DPoEOpcode_SetRequest
 from voltha.extensions.eoam.EOAM import mcastIp2McastMac
 
@@ -212,16 +214,18 @@
             device_port_no=uni_port.port_no
         ))
 
-
         # simulate a proxied message sending and receving a reply
         reply = yield self._message_exchange(device)
 
+        # TODO - Need to add validation of reply and decide what to do upon failure
+
         # and finally update to "ACTIVE"
         device = self.adapter_agent.get_device(device.id)
         device.oper_status = OperStatus.ACTIVE
         self.adapter_agent.update_device(device)
 
-        self.start_kpi_collection(device.id)
+        # TODO - Disable Stats Reporting for the moment
+        #self.start_kpi_collection(device.id)
 
     def abandon_device(self, device):
         raise NotImplementedError(0
@@ -259,8 +263,13 @@
 
             if in_port == 2:
                 log.info('#### Upstream Rule ####')
-                dn_req = EOAMPayload(body=TibitOUI() /
-                                     DPoEOpcode_SetRequest())
+
+                up_req = (
+                    EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
+                    EOAM_DpoeMsg(dpoe_opcode=0x03)
+                    )
+
+                #TODO - There is no body to the message above, is there ever an Upstream Rule
 
                 for field in get_ofb_fields(flow):
 
@@ -365,15 +374,14 @@
                         b = int(hex(_ipv4_dst)[4:6], 16)
                         c = int(hex(_ipv4_dst)[6:8], 16)
                         d = int(hex(_ipv4_dst)[8:], 16)
-                        dn_req = EOAMPayload(body=TibitOUI() /
-                                          DPoEOpcode_SetRequest() /
-                                          AddStaticMacAddress(
-                                              mac=mcastIp2McastMac('%d.%d.%d.%d' % (a,b,c,d)))
-                                          )
-
-                        # send message
+                        dn_req = (
+                            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
+                            EOAM_DpoeMsg(dpoe_opcode=0x03, body=AddStaticMacAddress(mac=mcastIp2McastMac('%d.%d.%d.%d' % (a,b,c,d)))
+                            ))
                         
-                        log.info('ONU-send-proxied-message')
+                        # send message
+
+                        log.info('ONU-send-proxied-message to Set Static IP MCAST address for ONU: {}'.format(device.mac_address))
                         self.adapter_agent.send_proxied_message(device.proxy_address,
                                                                 dn_req)
 
@@ -388,7 +396,7 @@
                             #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
                             #    break  # don't wait forever
 
-                            respType = self._voltha_get_oam_msg_type(frame)
+                            respType = self._get_oam_msg_type(frame)
                             log.info('Received OAM Message 0x %s' % str(respType))
 
                             #Check that the message received is a Set Response
@@ -396,17 +404,16 @@
                                 ack = True
                             else:
                                 # Handle unexpected events/OMCI messages
-                                self._voltha_check_resp(frame)
+                                self._check_resp(frame)
 
                         # Verify Set Response
                         if ack:
-                            (rc,branch,leaf,status) = self._voltha_check_set_resp(frame)
-                            log.info('REturn from Set resp')
+                            log.info('ONU-response received for Set Static IP MCAST address for ONU: {}'.format(device.mac_address))
+                            (rc,branch,leaf,status) = self._check_set_resp(frame)
                             if (rc == True):
                                 log.info('Set Response had no errors')
                             else:
-                                log.info('Set Respose had errors')
-                                log.info('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
+                                log.info('Set Response had errors - Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
 
                     else:
                         raise NotImplementedError('field.type={}'.format(
@@ -467,32 +474,36 @@
             _ = yield self.incoming_messages.get()
 
         # construct message
-        msg = EOAMPayload(body=TibitOUI() /
-                          DPoEOpcode_GetRequest() /
-                          DeviceId()
-                          )
+        msg = (
+            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
+            EOAM_DpoeMsg(dpoe_opcode=0x01,body=DeviceId())
+            )
 
         # send message
-        log.info('ONU-send-proxied-message')
+        log.info('ONU-send-proxied-message to Get Device Id for ONU: {}'.format(device.mac_address))
 
         self.adapter_agent.send_proxied_message(device.proxy_address, msg)
 
         # wait till we detect incoming message
         yield self.incoming_messages.get()
 
+        log.info('ONU-response received for Get Device Id for ONU: {}'.format(device.mac_address))
+
+        #TODO Add a timeout to the above, if we do not recieve a message
+
+        #The above get request/ get response is done to verify the message exchange is
+        #functioning correctly, there is nothing to store from the response
+
         # construct install of igmp query address
-        msg = EOAMPayload(body=TibitOUI() /
-                          DPoEOpcode_SetRequest() /
-                          AddStaticMacAddress(mac='01:00:5e:00:00:01')
-                          )
+        msg = (
+            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
+            EOAM_DpoeMsg(dpoe_opcode=0x03,body=AddStaticMacAddress(mac='01:00:5e:00:00:01')
+            ))
 
         # send message
-        log.info('ONU-send-proxied-message')
+        log.info('ONU-send-proxied-message to Set Static IGMP MAC address for ONU: {}'.format(device.mac_address))
         self.adapter_agent.send_proxied_message(device.proxy_address, msg)
 
-        # wait till we detect incoming message
-        #frame = yield self.incoming_messages.get()
-
         # Get and process the Set Response
         ack = False
         start_time = time.time()
@@ -504,7 +515,7 @@
             #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
             #    break  # don't wait forever
 
-            respType = self._voltha_get_oam_msg_type(frame)
+            respType = self._get_oam_msg_type(frame)
             log.info('Received OAM Message 0x %s' % str(respType))
 
             #Check that the message received is a Set Response
@@ -512,17 +523,31 @@
                 ack = True
             else:
                 # Handle unexpected events/OMCI messages
-                self._voltha_check_resp(frame)
+                self._check_resp(frame)
 
         # Verify Set Response
         if ack:
-            (rc,branch,leaf,status) = self._voltha_check_set_resp(frame)
-            log.info('REturn from Set resp')
+            log.info('ONU-response received for Set Static IGMP MAC address for ONU: {}'.format(device.mac_address))
+            (rc,branch,leaf,status) = self._check_set_resp(frame)
             if (rc == True):
                 log.info('Set Response had no errors')
             else:
-                log.info('Set Respose had errors')
-                log.info('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
+                log.info('Set Response had errors - Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
+
+        # construct multicast LLID set
+        # TODO - This is needed to support multicast traffic for GPON. This should only be done for a 
+        #        a GPON ONU and the UnicastLink value needs to come from the OLT. This will work only for
+        #        a single GPON ONU.
+        msg = (
+            EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
+            EOAM_DpoeMsg(dpoe_opcode=0x06,body=MulticastRegisterSet(MulticastLink=0x10bc, UnicastLink=0x1008)
+            ))
+
+        # send message
+        log.info('ONU-send-proxied-message to Set Static IGMP MAC address for ONU: {}'.format(device.mac_address))
+        self.adapter_agent.send_proxied_message(device.proxy_address, msg)
+
+        # The MulticastRegisterSet does not currently return a response. Just hope it worked.
 
         # by returning we allow the device to be shown as active, which
         # indirectly verified that message passing works
@@ -593,170 +618,65 @@
         lc = LoopingCall(_collect, device_id, prefix)
         lc.start(interval=15)  # TODO make this configurable
 
-    def _voltha_get_oam_msg_type(self, frame):
+
+# Methods for Get / Set  Response Processing from eoam_messages
+
+
+    def _get_oam_msg_type(self, frame):
+
         respType = RxedOamMsgTypeEnum["Unknown"]
         recv_frame = frame
-        payload = recv_frame.payload
-        if hasattr(payload, 'body'):
-            loadstr       = payload.body.load
-            bytesRead = 0;
-            if (payload.opcode == 0xFE):
 
-                # Extract the OUI
-                (oui_hi, oui_lo) = struct.unpack_from('>BH', loadstr, bytesRead)
-                oui = (oui_hi << 16) | oui_lo
-                log.debug('oui: 0x %06x' % oui)
-                bytesRead += 3
-
-                # If this is the ITU OUI, then there is an embedded OMCI message
-                if (oui == 0x0019A7):
-                    respType = RxedOamMsgTypeEnum["OMCI Message"]
-
-                # Treat Cablelabs OUI and Tibit OUI as the same
-                elif ((oui == 0x001000) or (oui == 0x2AEA15)):
-
-                    (dpoeOpcode) = struct.unpack_from('>B', loadstr, bytesRead)[0]
-                    bytesRead += 1
-
-                    # Get Response
-                    if (dpoeOpcode == 0x02):
-                        respType = RxedOamMsgTypeEnum["DPoE Get Response"]
-
-                    # Set Response
-                    elif (dpoeOpcode == 0x04):
-                        respType = RxedOamMsgTypeEnum["DPoE Set Response"]
-
-                    # File Transfer ACK
-                    elif (dpoeOpcode == 0x09):
-                        respType = RxedOamMsgTypeEnum["DPoE File Transfer"]
-
-                else:
-                    log.info('Unsupported OAM OUI 0x{:0>6X}'.format(oui))
-
-            # Handle OAM Event Notification
-            elif (payload.opcode == 0x01):
-                respType = RxedOamMsgTypeEnum["Event Notification"]
+        if recv_frame.haslayer(EOAMPayload):
+            if recv_frame.haslayer(EOAMEvent):
+                recv_frame = RxedOamMsgTypeEnum["Event Notification"]
+            elif recv_frame.haslayer(EOAM_OmciMsg):
+                respType = RxedOamMsgTypeEnum["OMCI Message"]
             else:
-                log.info('Unsupported OAM Opcode {}'.format(payload.opcode))
+                dpoeOpcode = 0x00
+                if recv_frame.haslayer(EOAM_TibitMsg):
+                    dpoeOpcode = recv_frame.getlayer(EOAM_TibitMsg).dpoe_opcode;
+                elif recv_frame.haslayer(EOAM_DpoeMsg):
+                    dpoeOpcode = recv_frame.getlayer(EOAM_DpoeMsg).dpoe_opcode;
+
+                # Get Response
+                if (dpoeOpcode == 0x02):
+                    respType = RxedOamMsgTypeEnum["DPoE Get Response"]
+
+                # Set Response
+                elif (dpoeOpcode == 0x04):
+                    respType = RxedOamMsgTypeEnum["DPoE Set Response"]
+
+                # File Transfer ACK
+                elif (dpoeOpcode == 0x09):
+                    respType = RxedOamMsgTypeEnum["DPoE File Transfer"]
+                else:
+                    log.info('Unsupported DPoE Opcode {:0>2X}'.format(dpoeOpcode))
         else:
-            log.debug('received frame has no payload')
+            log.info('Invalid OAM Header')
 
         return respType
 
 
-    def _voltha_check_set_resp(self, frame):
-        rc = False
-        branch = 0
-        leaf = 0
-        status = 0
-
+    def _get_value_from_msg(self, frame, branch, leaf):
+        retVal = False
+        value = 0
         recv_frame = frame
-        payload = recv_frame.payload
-        if hasattr(payload, 'body'):
-            loadstr   = payload.body.load
-            bytesRead = 0;
-            if (payload.opcode == 0xFE):
 
-                # Extract the OUI
-                (oui_hi, oui_lo) = struct.unpack_from('>BH', loadstr, bytesRead)
-                oui = (oui_hi << 16) | oui_lo
-                log.info('oui: 0x %06x' % oui)
-                bytesRead += 3
-
-                # Treat Cablelabs OUI and Tibit OUI as the same
-                if ((oui == 0x001000) or (oui == 0x2AEA15)):
-                    (dpoeOpcode) = struct.unpack_from('>B', loadstr, bytesRead)[0]
-                    bytesRead += 1
-
-                    startOfTlvs = bytesRead
-                    # Set Response
-                    if (dpoeOpcode == 0x04):
-                        test =1
-                        (rc,branch,leaf,status) = self._voltha_check_set_resp_attrs(loadstr, startOfTlvs)
-                        if (rc == True):
-                            log.info('Set Response had no errors')
-                        else:
-                            log.debug('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
-                    else:
-                        log.info('Unsupported DPoE Opcode: {} ({:0>2X})'.format(DPoEOpcodeEnum[dpoeOpcode], dpoeOpcode))
-                else:
-                    log.info('Unsupported OAM OUI 0x{:0>6X}'. format(oui))
+        if recv_frame.haslayer(EOAMPayload):
+            payload = recv_frame.payload
+            if hasattr(payload, 'body'):
+                loadstr = payload.body.load
+                # Get a specific TLV value
+                (retVal,bytesRead,value,retbranch,retleaf) = self._handle_get_value(loadstr, 0, branch, leaf)
             else:
-                log.info('Unsupported OAM Opcode {}'.format(payload.opcode))
+                log.info('received frame has no payload')
         else:
-            log.debug('received frame has no payload')
-
-        return rc,branch,leaf,status
-    
-
-    def _voltha_check_resp(self, frame):
-        recv_frame = frame
-        payload = recv_frame.payload
-        if hasattr(payload, 'body'):
-            loadstr   = payload.body.load
-            bytesRead = 0;
-            if (payload.opcode == 0xFE):
-                
-                # Extract the OUI
-                (oui_hi, oui_lo) = struct.unpack_from('>BH', loadstr, bytesRead)
-                oui = (oui_hi << 16) | oui_lo
-                log.info('oui: 0x %06x' % oui)
-                bytesRead += 3
-
-                # If this is the ITU OUI, then there is an embedded OMCI message
-                if (oui == 0x0019A7):
-                    self._voltha_handle_omci(loadstr,bytesRead)
-
-                # Treat Cablelabs OUI and Tibit OUI as the same
-                elif ((oui == 0x001000) or (oui == 0x2AEA15)):
-                    log.debug('Recieved Response OUI 0x{:0>6X}'. format(oui))
-                else:
-                    log.info('Unsupported OAM OUI 0x{:0>6X}'. format(oui))
-
-            # Handle OAM Event Notification
-            elif (payload.opcode == 0x01):
-                self._voltha_handle_oam_event(loadstr, bytesRead)
-            else:
-                log.info('Unsupported OAM Opcode {}'.format(payload.opcode))
-
-        else:
-            log.debug('received frame has no payload')
+            log.info('Invalid OAM Header')
+        return retVal,value,
 
 
-    def _voltha_handle_oam_event(self, loadstr, startOfEvent):
-        bytesRead = startOfEvent
-        (seq_num, tlv_type, ev_len, oui_hi, oui_lo) = struct.unpack_from('>HBBBH', loadstr, bytesRead)
-        oui = (oui_hi << 16) | oui_lo
-
-        log.info('seq_num:        0x%04x' % seq_num)
-        log.info('tlv_type:       0x%' % tlv_type)
-        log.info('ev_len:         0x%x' % ev_len)
-        log.info('oui:            0x%06x"'% oui)
-
-        if (tlv_type != 0xFE):
-            log.debug('unexpected tlv_type 0x%x (expected 0xFE)' % tlv_type)
-        elif (oui == 0x001000):
-            log.debug('DPoE Event')
-            ## TODO - Handle DPoE Event/Alarm
-        elif (oui == 0x2AEA15):
-            log.debug('Tibit-specific Event')
-
-            # TODO - Handle addition/removal of links
-
-            bytesRead = 7
-
-            # TODO - Check OUI and parse Source and Reference Object Contexts
-    
-
-    def _voltha_handle_omci(self, loadstr, startOfEvent):
-        bytesRead = startOfEvent
-        log.debug('OMCI Message')
-
-        # TODO - Handle OMCI message
-
-
-
-    def _voltha_handle_get_value(self, loadstr, startOfTlvs, queryBranch, queryLeaf):
+    def _handle_get_value(self, loadstr, startOfTlvs, queryBranch, queryLeaf):
         retVal = False;
         value = 0
         branch = 0
@@ -810,7 +730,89 @@
 
         return retVal,bytesRead,value,branch,leaf
 
-    def _voltha_check_set_resp_attrs(self, loadstr, startOfTlvs):
+
+    def _check_set_resp(self, frame):
+        rc = False
+        branch = 0
+        leaf = 0
+        status = 0
+        recv_frame = frame
+        if recv_frame.haslayer(EOAMPayload):
+            payload = recv_frame.payload
+            if hasattr(payload, 'body'):
+                loadstr = payload.body.load
+                # Get a specific TLV value
+                (rc,branch,leaf,status) = self._check_set_resp_attrs(loadstr, 0)
+            else:
+                log.info('received frame has no payload')
+        else:
+            log.info('Invalid OAM Header')
+        return rc,branch,leaf,status
+
+
+
+    def _check_resp(self, frame):
+        respType = RxedOamMsgTypeEnum["Unknown"]
+        recv_frame = frame
+        if recv_frame.haslayer(EOAMPayload):
+
+            if recv_frame.haslayer(EOAMEvent):
+                self.handle_oam_event(recv_frame)
+            elif recv_frame.haslayer(EOAM_OmciMsg):
+                 self.handle_omci(recv_frame)
+            else:
+                dpoeOpcode = 0x00
+                if recv_frame.haslayer(EOAM_TibitMsg):
+                    dpoeOpcode = recv_frame.getlayer(EOAM_TibitMsg).dpoe_opcode;
+                elif recv_frame.haslayer(EOAM_DpoeMsg):
+                    dpoeOpcode = recv_frame.getlayer(EOAM_DpoeMsg).dpoe_opcode;
+
+                if hasattr(recv_frame, 'body'):
+                    payload = recv_frame.payload
+                    loadstr = payload.body.load
+
+                # Get Response
+                if (dpoeOpcode == 0x02):
+                    # Get a specific TLV value
+                    branch = 0xD7
+                    leaf = 0x0006
+                    (rc,bytesRead,value,retbranch,retleaf) = self._handle_get_value(loadstr, startOfTlvs, branch, leaf)
+                    if (rc == True):
+                        log.info('Branch 0x{:X} Leaf 0x{:0>4X}  value = {}'.format(branch, leaf, value))
+                    else:
+                        log.info('Branch 0x{:X} Leaf 0x{:0>4X}  no value'.format(branch, leaf))
+
+                    # Walk through all TLV values
+                    bytesRead = 0
+                    rc = True
+                    while(rc == True):
+                        branch = 0
+                        leaf = 0
+                        (rc,bytesRead,value,branch,leaf) = self._handle_get_value(loadstr, bytesRead, branch, leaf)
+                        if (rc == True):
+                            log.info('Branch 0x{:0>2X} Leaf 0x{:0>4X}  value = {}'.format(branch, leaf, value))
+                        elif (branch != 0):
+                            log.info('Branch 0x{:0>2X} Leaf 0x{:0>4X}  no value'.format(branch, leaf))
+
+                # Set Response
+                elif (dpoeOpcode == 0x04):
+                    (rc,branch,leaf,status) = self._check_set_resp_attrs(loadstr, 0)
+                    if (rc == True):
+                        log.info('Set Response had no errors')
+                    else:
+                        log.info('Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
+
+                # File Transfer ACK
+                elif (dpoeOpcode == 0x09):
+                    rc = self._handle_fx_ack(loadstr, bytesRead, block_number)
+                else:
+                    log.info('Unsupported DPoE Opcode {:0>2X}'.format(dpoeOpcode))
+        else:
+            log.info('Invalid OAM Header')
+
+        return respType    
+
+    def _check_set_resp_attrs(self, loadstr, startOfTlvs):
         retVal = True;
         branch = 0
         leaf = 0
@@ -820,14 +822,16 @@
 
         while (bytesRead <= loadstrlen):
             (branch, leaf) = struct.unpack_from('>BH', loadstr, bytesRead)
+#            print "Branch/Leaf        0x{:0>2X}/0x{:0>4X}".format(branch, leaf)
 
             if (branch != 0):
                 bytesRead += 3
                 length = struct.unpack_from('>B', loadstr, bytesRead)[0]
+#                print "Length:            0x{:0>2X} ({})".format(length,length)
                 bytesRead += 1
 
                 if (length >= 0x80):
-                    log.debug('Branch 0x{:0>2X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[length]))
+                    log.info('Branch 0x{:0>2X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[length]))
                     if (length > 0x80):
                         retVal = False;
                         break;
@@ -839,26 +843,22 @@
 
         return retVal,branch,leaf,length
 
-
-
-    def _voltha_handle_fx_ack(self, loadstr, startOfXfer, block_number):
+        
+    def _handle_fx_ack(self, loadstr, startOfXfer, block_number):
         retVal = False
         (fx_opcode, acked_block, response_code) = struct.unpack_from('>BHB', loadstr, startOfXfer)
 
-        log.debug('fx_opcode:      0x%x' % fx_opcode)
-        log.debug('acked_block:    0x%x' % acked_block)
-        log.debug('response_code:  0x%x' % response_code)
-
+        #print "fx_opcode:      0x%x" % fx_opcode
+        #print "acked_block:    0x%x" % acked_block
+        #print "response_code:  0x%x" % response_code
 
 
         if (fx_opcode != 0x03):
-            log.debug('unexpected fx_opcode 0x%x (expected 0x03)' % fx_opcode)
+            log.info('unexpected fx_opcode 0x%x (expected 0x03)' % fx_opcode)
         elif (acked_block != block_number):
-            log.debug('unexpected acked_block 0x%x (expected 0x%x)' % (acked_block, block_number))
+            log.info('unexpected acked_block 0x%x (expected 0x%x)' % (acked_block, block_number))
         elif (response_code != 0):
-            log.debug('unexpected response_code 0x%x (expected 0x00)' % response_code)
+            log.info('unexpected response_code 0x%x (expected 0x00)' % response_code)
         else:
-            retVal = True;
-
-
-
+            retVal = True;    
+    
\ No newline at end of file
diff --git a/voltha/extensions/eoam/EOAM.py b/voltha/extensions/eoam/EOAM.py
index 9e6b709..56511d1 100644
--- a/voltha/extensions/eoam/EOAM.py
+++ b/voltha/extensions/eoam/EOAM.py
@@ -1,497 +1,551 @@
-#!/usr/bin/env python
-#--------------------------------------------------------------------------#
-# Copyright (C) 2015 - 2016 by Tibit Communications, Inc.                  #
-# All rights reserved.                                                     #
-#                                                                          #
-#    _______ ____  _ ______                                                #
-#   /_  __(_) __ )(_)_  __/                                                #
-#    / / / / __  / / / /                                                   #
-#   / / / / /_/ / / / /                                                    #
-#  /_/ /_/_____/_/ /_/                                                     #
-#                                                                          #
-#--------------------------------------------------------------------------#
-""" EOAM protocol implementation in scapy """
-
-TIBIT_VERSION_NUMBER = '1.1.4'
-
-import argparse
-import logging
-import time
-from hexdump import hexdump
-
-logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
-from scapy.layers.l2 import Ether, Dot1Q
-from scapy.sendrecv import sendp
-from scapy.fields import PacketField
-from scapy.packet import bind_layers
-
-import fcntl, socket, struct # for get hw address
-
-# TODO should remove import *
-from EOAM_TLV import *
-
-EOAM_MULTICAST_ADDRESS = '01:80:c2:00:00:02'
-IGMP_MULTICAST_ADDRESS = '01:00:5e:00:00:01'   # for test
-
-class EOAM():
-    """ EOAM frame layer """
-    def __init__(self, ctag=None, dryrun=False, stag=None,
-                 verbose=False, etype='8809',
-                 dst=EOAM_MULTICAST_ADDRESS,
-                 hexdump=False, interface='eth0',
-                 sleep=2.0):
-        self.verbose = verbose
-        self.dst = dst
-        self.dryrun = dryrun
-        self.hexdump = hexdump
-        self.interface = interface
-        self.etype = int(etype, 16)
-        self.stag = stag
-        self.ctag = ctag
-        self.sleep = sleep
-        if (self.verbose == True):
-            print("=== Settings ================")
-            print("ctag      = %s" % self.ctag)
-            print("stag      = %s" % self.stag)
-            print("dst       = %s" % self.dst)
-            print("dryrun    = %s" % self.dryrun)
-            print("hexdump   = %s" % self.hexdump)
-            print("interface = %s" % self.interface)
-            print("etype     = 0x%04x" % self.etype)
-            print("verbose   = %s" % self.verbose)
-            print("sleep     = %d" % self.sleep)
-            print("=== END Settings ============")
-
-    def send_frame(self, frame_body, slow_protocol=True):
-        PACKET = Ether()
-        PACKET.dst = self.dst
-        PACKET.src = self.getHwAddr(self.interface)
-        if self.stag:
-            # WARNING: September/2016: This should be 0x88a8, but the Intel 10G
-            # hardware I am currently using does not support receiving a TPID of
-            # 0x88a8. So, I send double CTAGs, and I usually set this to 0x8100.
-            # (NOTE: The Intel hardware can send a TPID of 0x88a8)
-            PACKET.type = 0x8100
-            if self.ctag:
-                PACKET/=Dot1Q(type=0x8100,vlan=int(self.stag))
-                PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))
-            else:
-                PACKET/=Dot1Q(prio=7,type=self.etype,vlan=int(self.stag))
-        else:
-            if self.ctag:
-                PACKET.type = 0x8100
-                PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))
-            else:
-                PACKET.type = self.etype
-#            PACKET/=Dot1Q(type=self.etype, vlan=int(self.ctag))
-        if slow_protocol:
-            PACKET /= SlowProtocolsSubtype()/FlagsBytes()/OAMPDU()
-            PACKET /= frame_body
-            PACKET /= EndOfPDU()
-        else:
-            PACKET.lastlayer().type = 0xA8C8
-            PACKET /= frame_body
-
-        if (self.verbose == True):
-            PACKET.show()
-            print '###[ Frame Length %d (before padding) ]###' % len(PACKET)
-        if (self.hexdump == True):
-            print hexdump(str(PACKET))
-        if (self.dryrun != True):
-            sendp(PACKET, iface=self.interface)
-            time.sleep(self.sleep)
-        return PACKET
-
-    def get_request(self, TLV):
-        return self.send_frame(CablelabsOUI()/DPoEOpcode_GetRequest()/TLV)
-
-    def set_request(self, TLV):
-        return self.send_frame(CablelabsOUI()/DPoEOpcode_SetRequest()/TLV)
-
-    def send_multicast_register(self, TLV):
-        '''
-        Note, for mulicast, the standard specifies a register message
-        with ActionFlags of either Register or Deregister
-        '''
-        return self.send_frame(CablelabsOUI()/DPoEOpcode_MulticastRegister()/TLV)
-
-    def set_request_broadcom(self, TLV):
-        return self.send_frame(BroadcomOUI()/DPoEOpcode_SetRequest()/TLV)
-
-    def getHwAddr(self, ifname):
-        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-        info = fcntl.ioctl(s.fileno(), 0x8927,  struct.pack('256s', ifname[:15]))
-        return ':'.join(['%02x' % ord(char) for char in info[18:24]])
-
-
-class EOAMPayload(Packet):
-    name = 'EOAM Payload'
-    fields_desc = [
-        ByteEnumField("subtype", 0x03, SlowProtocolsSubtypeEnum),
-        XShortField("flags", 0x0050),
-        XByteField("opcode", 0xfe),
-        PacketField("body", None, Packet),
-        BitEnumField("type", 0x00, 7, TLV_dictionary),
-        BitField("length", 0x00, 9)
-    ]
-
-bind_layers(Ether, EOAMPayload, type=0xA8C8)
-
-def mcastIp2McastMac(ip):
-    """ Convert a dot-notated IPv4 multicast address string into an multicast MAC address"""
-    digits = [int(d) for d in ip.split('.')]
-    return '01:00:5e:%02x:%02x:%02x' % (digits[1] & 0x7f, digits[2] & 0xff, digits[3] & 0xff)
-
-
-class TBJSON(Packet):
-    """ TBJSON 'packet' layer. """
-    name = "TBJSON"
-    fields_desc = [StrField("data", default="")]
-
-bind_layers(Ether, TBJSON, type=0xA8C8)
-
-
-if __name__ == "__main__":
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-d', '--dst', dest='dst', action='store', default=EOAM_MULTICAST_ADDRESS,
-                        help='MAC destination (default: %s)' % EOAM_MULTICAST_ADDRESS)
-    parser.add_argument('-e', '--etype', dest='etype', action='store', default='8809',
-                        help='EtherType value (default: 0x8809)')
-    parser.add_argument('-i', '--interface', dest='interface', action='store', default='eth0',
-                        help='ETH interface to send (default: eth0)')
-    parser.add_argument('-s', '--stag', dest='stag', action='store', default=None,
-                        help='STAG value (default: None)')
-    parser.add_argument('-c', '--ctag', dest='ctag', action='store', default=None,
-                        help='CTAG value (default: None)')
-    parser.add_argument('-p', '--sleep', dest='sleep', action='store', default='1.0', type=float,
-                        help='SLEEP time after frame (default: 1.0 secs)')
-    parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', default=False,
-                        help='verbose frame print out')
-    parser.add_argument('-x', '--hexdump', dest='hexdump', action='store_true', default=False,
-                        help='Hexdump the frame')
-    parser.add_argument('-y', '--dryrun', dest='dryrun', action='store_true', default=False,
-                        help='Dry run test, dont send - just print')
-
-    parser.add_argument('-t', '--test', dest='test', action='store_true', default=False,
-                        help='Run commands under test')
-    parser.add_argument('-r', '--critical', dest='critical', action='store_true', default=False,
-                        help='Send the critical OAM set of set_request()')
-    parser.add_argument('-ta', '--test_add', dest='test_add', action='store_true', default=False,
-                        help='Run commands under test')
-    parser.add_argument('-tc', '--test_clr', dest='test_clr', action='store_true', default=False,
-                        help='Run commands under test')
-    parser.add_argument('-te', '--test_eapol', dest='test_eapol', action='store_true', default=False,
-                        help='Run commands under test')
-    parser.add_argument('-ti', '--test_igmp', dest='test_igmp', action='store_true', default=False,
-                        help='Run commands under test')
-    parser.add_argument('-th', '--test_dhcp', dest='test_dhcp', action='store_true', default=False,
-                        help='Run commands under test')
-    parser.add_argument('-tu', '--test_upstream', dest='test_upstream', action='store_true', default=False,
-                        help='Run commands under test')
-    parser.add_argument('-td', '--test_downstream', dest='test_downstream', action='store_true', default=False,
-                        help='Run commands under test')
-    parser.add_argument('-tm', '--test_multicast', dest='test_multicast', action='store_true', default=False,
-                        help='Run commands under test')
-    parser.add_argument('-tp', '--test_ping', dest='test_ping', action='store_true', default=False,
-                        help='Issue a test ping to get JSON data on device version')
-
-    args = parser.parse_args()
-
-    if (args.dryrun == True):
-        args.sleep = 0.0
-
-    eoam = EOAM(
-        dryrun=args.dryrun,
-        dst=args.dst,
-        etype=args.etype,
-        hexdump=args.hexdump,
-        interface=args.interface,
-        stag=args.stag,
-        ctag=args.ctag,
-        verbose=args.verbose,
-        sleep=args.sleep
-        )
-
-    if (not args.critical
-        and not args.test
-        and not args.test_add
-        and not args.test_clr
-        and not args.test_eapol
-        and not args.test_igmp
-        and not args.test_dhcp
-        and not args.test_upstream
-        and not args.test_downstream
-        and not args.test_multicast
-        and not args.test_ping):
-        print 'WARNING: *** No frames sent, please specify \'test\' or \'critical\', etc.  See --help'
-
-
-    if (args.test == True):
-        print 'SET - Multicast Register Message 01'
-        eoam.send_multicast_register(MulticastRegisterSet(MulticastLink=0x3fe0, UnicastLink=0x1008))
-
-        print 'SET - Multicast Deregister Message 02'
-        eoam.send_multicast_register(MulticastRegisterSet(ActionFlags="Deregister",MulticastLink=0x3fe0, UnicastLink=0x1008))
-
-    if (args.test_clr == True):
-        print 'Set - Clear Static MAC Table -- User Port Object'
-        eoam.set_request(ClearStaticMacTable())
-
-    if (args.test_add == True):
-        print 'SET Add Static MAC Address -- User Port Object'
-        eoam.set_request(AddStaticMacAddress(mac=mcastIp2McastMac('230.10.10.10')))
-        time.sleep(1)
-        eoam.set_request(AddStaticMacAddress(mac=mcastIp2McastMac('231.11.11.11')))
-
-#        print 'SET Delete Static MAC Address -- User Port Object'
-#        eoam.set_request(DeleteStaticMacAddress(mac=IGMP_MULTICAST_ADDRESS))
-
-    if (args.test_eapol == True):
-        #################################################################################
-        ## EAPOL
-        #################################################################################
-        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
-        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
-
-        print 'SET - Port Ingress Rule -- PON Port Object -- EAPOL'
-        eoam.set_request(PonPortObject()/
-                         PortIngressRuleHeader(precedence=32)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],
-                                                            operator=Operator['=='], match=0x888e)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4090)/
-                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         AddPortIngressRule())
-
-        time.sleep(3)
-
-        print 'Delete - Port Ingress Rule -- PON Port Object -- EAPOL'
-        eoam.set_request(PonPortObject()/
-                         PortIngressRuleHeader(precedence=32)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],
-                                                            operator=Operator['=='], match=0x888e)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4090)/
-                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         DeletePortIngressRule())
-
-    if (args.test_igmp == True):
-        #################################################################################
-        ## IGMP
-        #################################################################################
-        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
-        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
-
-        print 'SET - Port Ingress Rule -- PON Port Object -- IGMP'
-        eoam.set_request(PonPortObject()/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],
-                                                            operator=Operator['=='], match=0x0800)/
-                         PortIngressRuleClauseMatchLength01(fieldcode=Clause['IPv4/IPv6 Protocol Type'],
-                                                            operator=Operator['=='], match=0x02)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4000)/
-                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         AddPortIngressRule())
-
-        time.sleep(3)
-
-        print 'Delete - Port Ingress Rule -- PON Port Object -- IGMP'
-        eoam.set_request(PonPortObject()/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],
-                                                            operator=Operator['=='], match=0x0800)/
-                         PortIngressRuleClauseMatchLength01(fieldcode=Clause['IPv4/IPv6 Protocol Type'],
-                                                            operator=Operator['=='], match=0x02)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4000)/
-                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         DeletePortIngressRule())
-
-    if (args.test_dhcp == True):
-        #################################################################################
-        ## DHCP
-        #################################################################################
-        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
-        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
-
-        print 'SET - Port Ingress Rule -- PON Port Object -- DHCP'
-        eoam.set_request(PonPortObject()/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],
-                                                            operator=Operator['=='], match=0x0800)/
-                         PortIngressRuleClauseMatchLength01(fieldcode=Clause['IPv4/IPv6 Protocol Type'],
-                                                            operator=Operator['=='], match=0x11)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP source port'],
-                                                            operator=Operator['=='], match=0x0044)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP destination port'],
-                                                            operator=Operator['=='], match=0x0043)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4000)/
-                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         AddPortIngressRule())
-
-        time.sleep(3)
-
-        print 'Delete - Port Ingress Rule -- PON Port Object -- DHCP'
-        eoam.set_request(PonPortObject()/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],
-                                                            operator=Operator['=='], match=0x0800)/
-                         PortIngressRuleClauseMatchLength01(fieldcode=Clause['IPv4/IPv6 Protocol Type'],
-                                                            operator=Operator['=='], match=0x11)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP source port'],
-                                                            operator=Operator['=='], match=0x0044)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP destination port'],
-                                                            operator=Operator['=='], match=0x0043)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4000)/
-                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         DeletePortIngressRule())
-
-    if (args.test_upstream == True):
-        #################################################################################
-        ## UPSTREAM
-        #################################################################################
-        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
-        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
-
-        print 'SET - Port Ingress Rule -- OLT Unicast Logical Link -- Upstream Traffic'
-        eoam.set_request(PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
-                                                            operator=Operator['=='], match=0x00f1)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultCopy(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1)/
-                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=1000)/
-                         PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag'])/
-                         OLTUnicastLogicalLink(unicastvssn="TBIT", unicastlink=0xe2222900)/
-                         PortIngressRuleTerminator()/
-                         AddPortIngressRule())
-
-
-        time.sleep(3)
-
-        print 'DELETE - Port Ingress Rule -- OLT Unicast Logical Link -- Upstream Traffic'
-        eoam.set_request(OLTUnicastLogicalLink(unicastvssn="TBIT", unicastlink=0xe2222900)/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
-                                                            operator=Operator['=='], match=0x00f1)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultCopy(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1)/
-                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=1000)/
-                         PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         DeletePortIngressRule())
-
-    if (args.test_downstream == True):
-        #################################################################################
-        ## DOWNSTREAM
-        #################################################################################
-        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
-        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
-
-        print 'SET - Port Ingress Rule -- NNI Port Object -- Downstream Traffic -- 4000/241'
-        eoam.set_request(NetworkToNetworkPortObject()/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
-                                                            operator=Operator['=='], match=0x0fa0)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
-                                                            operator=Operator['=='], match=0x00f1)/
-                         PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=0xe2222900)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         AddPortIngressRule())
-
-        time.sleep(1)
-
-        print 'SET - Port Ingress Rule -- NNI Port Object -- Downstream Traffic -- 1000/241'
-        eoam.set_request(NetworkToNetworkPortObject()/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
-                                                            operator=Operator['=='], match=0x03e8)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
-                                                            operator=Operator['=='], match=0x00f1)/
-                         PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=0xe2222900)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         AddPortIngressRule())
-
-
-        time.sleep(1)
-
-        print 'SET - Port Ingress Rule -- NNI Port Object -- Downstream Traffic -- 4000/203'
-        eoam.set_request(NetworkToNetworkPortObject()/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
-                                                            operator=Operator['=='], match=0x0fa0)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
-                                                            operator=Operator['=='], match=0x00CB)/
-                         PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=0xe2220300)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         AddPortIngressRule())
-
-        time.sleep(1)
-
-        print 'SET - Port Ingress Rule -- NNI Port Object -- Downstream Traffic -- 1000/203'
-        eoam.set_request(NetworkToNetworkPortObject()/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
-                                                            operator=Operator['=='], match=0x03e8)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
-                                                            operator=Operator['=='], match=0x00cb)/
-                         PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=0xe2220300)/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         AddPortIngressRule())
-
-    if (args.test_multicast == True):
-        #################################################################################
-        ## MULTICAST
-        #################################################################################
-        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
-        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
-
-        print 'SET - Port Ingress Rule -- NNI Port Object -- Downstream Multicast Traffic'
-        eoam.set_request(NetworkToNetworkPortObject()/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
-                                                            operator=Operator['=='], match=0x008c)/
-                         PortIngressRuleResultOLTBroadcastQueue()/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         AddPortIngressRule())
-
-
-        time.sleep(3)
-
-        print 'DELETE - Port Ingress Rule -- NNI Port Object -- Downstream Multicast Traffic'
-        eoam.set_request(NetworkToNetworkPortObject()/
-                         PortIngressRuleHeader(precedence=13)/
-                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
-                                                            operator=Operator['=='], match=0x008c)/
-                         PortIngressRuleResultOLTBroadcastQueue()/
-                         PortIngressRuleResultForward()/
-                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
-                         PortIngressRuleTerminator()/
-                         DeletePortIngressRule())
-
-
-    if (args.test_ping == True):
-        json_operation_str = '{\"operation\":\"version\"}'
-        for i in range(10000):
-            eoam.send_frame(TBJSON(data='json %s' % json_operation_str), False)
-
+#!/usr/bin/env python

+#--------------------------------------------------------------------------#

+# Copyright (C) 2015 - 2016 by Tibit Communications, Inc.                  #

+# All rights reserved.                                                     #

+#                                                                          #

+#    _______ ____  _ ______                                                #

+#   /_  __(_) __ )(_)_  __/                                                #

+#    / / / / __  / / / /                                                   #

+#   / / / / /_/ / / / /                                                    #

+#  /_/ /_/_____/_/ /_/                                                     #

+#                                                                          #

+#--------------------------------------------------------------------------#

+""" EOAM protocol implementation in scapy """

+

+TIBIT_VERSION_NUMBER = '1.1.4'

+

+import argparse

+import logging

+import time

+from hexdump import hexdump

+

+logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

+from scapy.layers.l2 import Ether, Dot1Q

+from scapy.sendrecv import sendp

+from scapy.fields import PacketField

+from scapy.packet import bind_layers

+from scapy.fields import StrField, X3BytesField

+from scapy.packet import Packet

+from scapy.fields import ByteEnumField, XShortField, XByteField, MACField, \

+    ByteField, BitEnumField, BitField, ShortField

+from scapy.fields import XLongField, StrFixedLenField, XIntField, \

+    FieldLenField, StrLenField, IntField

+

+import fcntl, socket, struct # for get hw address

+

+# TODO should remove import *

+from EOAM_TLV import *

+

+OAM_ETHERTYPE = 0xA8C8

+CableLabs_OUI = 0x001000

+Tibit_OUI = 0x2AEA15

+IEEE_OUI = 0x0019A7

+

+EOAM_MULTICAST_ADDRESS = '01:80:c2:00:00:02'

+IGMP_MULTICAST_ADDRESS = '01:00:5e:00:00:01'   # for test

+

+class EOAM():

+    """ EOAM frame layer """

+    def __init__(self, ctag=None, dryrun=False, stag=None,

+                 verbose=False, etype='8809',

+                 dst=EOAM_MULTICAST_ADDRESS,

+                 hexdump=False, interface='eth0',

+                 sleep=2.0):

+        self.verbose = verbose

+        self.dst = dst

+        self.dryrun = dryrun

+        self.hexdump = hexdump

+        self.interface = interface

+        self.etype = int(etype, 16)

+        self.stag = stag

+        self.ctag = ctag

+        self.sleep = sleep

+        if (self.verbose == True):

+            print("=== Settings ================")

+            print("ctag      = %s" % self.ctag)

+            print("stag      = %s" % self.stag)

+            print("dst       = %s" % self.dst)

+            print("dryrun    = %s" % self.dryrun)

+            print("hexdump   = %s" % self.hexdump)

+            print("interface = %s" % self.interface)

+            print("etype     = 0x%04x" % self.etype)

+            print("verbose   = %s" % self.verbose)

+            print("sleep     = %d" % self.sleep)

+            print("=== END Settings ============")

+

+    def send_frame(self, frame_body, slow_protocol=True):

+        PACKET = Ether()

+        PACKET.dst = self.dst

+        PACKET.src = self.getHwAddr(self.interface)

+        if self.stag:

+            # WARNING: September/2016: This should be 0x88a8, but the Intel 10G

+            # hardware I am currently using does not support receiving a TPID of

+            # 0x88a8. So, I send double CTAGs, and I usually set this to 0x8100.

+            # (NOTE: The Intel hardware can send a TPID of 0x88a8)

+            PACKET.type = 0x8100

+            if self.ctag:

+                PACKET/=Dot1Q(type=0x8100,vlan=int(self.stag))

+                PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))

+            else:

+                PACKET/=Dot1Q(prio=7,type=self.etype,vlan=int(self.stag))

+        else:

+            if self.ctag:

+                PACKET.type = 0x8100

+                PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))

+            else:

+                PACKET.type = self.etype

+#            PACKET/=Dot1Q(type=self.etype, vlan=int(self.ctag))

+        if slow_protocol:

+            PACKET /= SlowProtocolsSubtype()/FlagsBytes()/OAMPDU()

+            PACKET /= frame_body

+            PACKET /= EndOfPDU()

+        else:

+            PACKET.lastlayer().type = 0xA8C8

+            PACKET /= frame_body

+

+        if (self.verbose == True):

+            PACKET.show()

+            print '###[ Frame Length %d (before padding) ]###' % len(PACKET)

+        if (self.hexdump == True):

+            print hexdump(str(PACKET))

+        if (self.dryrun != True):

+            sendp(PACKET, iface=self.interface)

+            time.sleep(self.sleep)

+        return PACKET

+

+    def get_request(self, TLV):

+        return self.send_frame(CablelabsOUI()/DPoEOpcode_GetRequest()/TLV)

+

+    def set_request(self, TLV):

+        return self.send_frame(CablelabsOUI()/DPoEOpcode_SetRequest()/TLV)

+

+    def send_multicast_register(self, TLV):

+        '''

+        Note, for mulicast, the standard specifies a register message

+        with ActionFlags of either Register or Deregister

+        '''

+        return self.send_frame(CablelabsOUI()/DPoEOpcode_MulticastRegister()/TLV)

+

+    def set_request_broadcom(self, TLV):

+        return self.send_frame(BroadcomOUI()/DPoEOpcode_SetRequest()/TLV)

+

+    def getHwAddr(self, ifname):

+        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

+        info = fcntl.ioctl(s.fileno(), 0x8927,  struct.pack('256s', ifname[:15]))

+        return ':'.join(['%02x' % ord(char) for char in info[18:24]])

+

+

+#TODO - This is duplicated from eoam_messages.py and renamed to EOAMRespPayload

+class EOAMPayload(Packet):

+    name = 'EOAM Payload'

+    fields_desc = [

+        ByteEnumField("subtype", 0x03, SlowProtocolsSubtypeEnum),

+        XShortField("flags", 0x0050),

+        XByteField("opcode", 0xfe),

+#        PacketField("body", None, Packet),

+    ]

+

+bind_layers(Ether, EOAMPayload, type=OAM_ETHERTYPE)

+

+

+#TODO - This is duplicated from eoam_messages.py

+class EOAMEvent(Packet):

+    name = 'EOAM Event'

+    fields_desc = [

+        XShortField("sequence", 0x0001),

+        XByteField("tlv_type", 0xfe),

+        XByteField("length", 0x01),

+        X3BytesField("oui", 0x001000),

+        PacketField("body", None, Packet),

+    ]

+

+bind_layers(EOAMPayload, EOAMEvent, opcode=0x01)

+

+#TODO - This is duplicated from eoam_messages.py

+class EOAM_VendSpecificMsg(Packet):

+    name = "Vendor-Specific OAM"

+    fields_desc  = [

+        X3BytesField("oui", 0x001000),

+    ]

+

+bind_layers(EOAMPayload, EOAM_VendSpecificMsg, opcode=0xFE)

+

+#TODO - This is duplicated from eoam_messages.py

+class EOAM_OmciMsg(Packet):

+    name = "OAM-encapsulated OMCI Message"

+    fields_desc  = [

+        PacketField("body", None, Packet),

+    ]

+

+bind_layers(EOAM_VendSpecificMsg, EOAM_OmciMsg, oui=0x0019A7)

+

+#TODO - This is duplicated from eoam_messages.py

+class EOAM_TibitMsg(Packet):

+    name = "Tibit OAM Message"

+    fields_desc  = [

+        ByteEnumField("dpoe_opcode", 0x01, DPoEOpcodeEnum),

+        PacketField("body", None, Packet),

+    ]

+

+bind_layers(EOAM_VendSpecificMsg, EOAM_TibitMsg, oui=0x2AEA15)

+

+#TODO - This is duplicated from eoam_messages.py

+class EOAM_DpoeMsg(Packet):

+    name = "DPoE OAM Message"

+    fields_desc  = [

+        ByteEnumField("dpoe_opcode", 0x01, DPoEOpcodeEnum),

+        PacketField("body", None, Packet),

+    ]

+

+bind_layers(EOAM_VendSpecificMsg, EOAM_DpoeMsg, oui=0x001000)

+

+def mcastIp2McastMac(ip):

+    """ Convert a dot-notated IPv4 multicast address string into an multicast MAC address"""

+    digits = [int(d) for d in ip.split('.')]

+    return '01:00:5e:%02x:%02x:%02x' % (digits[1] & 0x7f, digits[2] & 0xff, digits[3] & 0xff)

+

+

+if __name__ == "__main__":

+    parser = argparse.ArgumentParser()

+    parser.add_argument('-d', '--dst', dest='dst', action='store', default=EOAM_MULTICAST_ADDRESS,

+                        help='MAC destination (default: %s)' % EOAM_MULTICAST_ADDRESS)

+    parser.add_argument('-e', '--etype', dest='etype', action='store', default='8809',

+                        help='EtherType value (default: 0x8809)')

+    parser.add_argument('-i', '--interface', dest='interface', action='store', default='eth0',

+                        help='ETH interface to send (default: eth0)')

+    parser.add_argument('-s', '--stag', dest='stag', action='store', default=None,

+                        help='STAG value (default: None)')

+    parser.add_argument('-c', '--ctag', dest='ctag', action='store', default=None,

+                        help='CTAG value (default: None)')

+    parser.add_argument('-p', '--sleep', dest='sleep', action='store', default='1.0', type=float,

+                        help='SLEEP time after frame (default: 1.0 secs)')

+    parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', default=False,

+                        help='verbose frame print out')

+    parser.add_argument('-x', '--hexdump', dest='hexdump', action='store_true', default=False,

+                        help='Hexdump the frame')

+    parser.add_argument('-y', '--dryrun', dest='dryrun', action='store_true', default=False,

+                        help='Dry run test, dont send - just print')

+

+    parser.add_argument('-t', '--test', dest='test', action='store_true', default=False,

+                        help='Run commands under test')

+    parser.add_argument('-r', '--critical', dest='critical', action='store_true', default=False,

+                        help='Send the critical OAM set of set_request()')

+    parser.add_argument('-ta', '--test_add', dest='test_add', action='store_true', default=False,

+                        help='Run commands under test')

+    parser.add_argument('-tc', '--test_clr', dest='test_clr', action='store_true', default=False,

+                        help='Run commands under test')

+    parser.add_argument('-te', '--test_eapol', dest='test_eapol', action='store_true', default=False,

+                        help='Run commands under test')

+    parser.add_argument('-ti', '--test_igmp', dest='test_igmp', action='store_true', default=False,

+                        help='Run commands under test')

+    parser.add_argument('-th', '--test_dhcp', dest='test_dhcp', action='store_true', default=False,

+                        help='Run commands under test')

+    parser.add_argument('-tu', '--test_upstream', dest='test_upstream', action='store_true', default=False,

+                        help='Run commands under test')

+    parser.add_argument('-td', '--test_downstream', dest='test_downstream', action='store_true', default=False,

+                        help='Run commands under test')

+    parser.add_argument('-tm', '--test_multicast', dest='test_multicast', action='store_true', default=False,

+                        help='Run commands under test')

+    parser.add_argument('-tp', '--test_ping', dest='test_ping', action='store_true', default=False,

+                        help='Issue a test ping to get JSON data on device version')

+

+    args = parser.parse_args()

+

+    if (args.dryrun == True):

+        args.sleep = 0.0

+

+    eoam = EOAM(

+        dryrun=args.dryrun,

+        dst=args.dst,

+        etype=args.etype,

+        hexdump=args.hexdump,

+        interface=args.interface,

+        stag=args.stag,

+        ctag=args.ctag,

+        verbose=args.verbose,

+        sleep=args.sleep

+        )

+

+    if (not args.critical

+        and not args.test

+        and not args.test_add

+        and not args.test_clr

+        and not args.test_eapol

+        and not args.test_igmp

+        and not args.test_dhcp

+        and not args.test_upstream

+        and not args.test_downstream

+        and not args.test_multicast

+        and not args.test_ping):

+        print 'WARNING: *** No frames sent, please specify \'test\' or \'critical\', etc.  See --help'

+

+

+    if (args.test == True):

+        print 'SET - Multicast Register Message 01'

+        eoam.send_multicast_register(MulticastRegisterSet(MulticastLink=0x3fe0, UnicastLink=0x1008))

+

+        print 'SET - Multicast Deregister Message 02'

+        eoam.send_multicast_register(MulticastRegisterSet(ActionFlags="Deregister",MulticastLink=0x3fe0, UnicastLink=0x1008))

+

+    if (args.test_clr == True):

+        print 'Set - Clear Static MAC Table -- User Port Object'

+        eoam.set_request(ClearStaticMacTable())

+

+    if (args.test_add == True):

+        print 'SET Add Static MAC Address -- User Port Object'

+        eoam.set_request(AddStaticMacAddress(mac=mcastIp2McastMac('230.10.10.10')))

+        time.sleep(1)

+        eoam.set_request(AddStaticMacAddress(mac=mcastIp2McastMac('231.11.11.11')))

+

+#        print 'SET Delete Static MAC Address -- User Port Object'

+#        eoam.set_request(DeleteStaticMacAddress(mac=IGMP_MULTICAST_ADDRESS))

+

+    if (args.test_eapol == True):

+        #################################################################################

+        ## EAPOL

+        #################################################################################

+        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}

+        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

+

+        print 'SET - Port Ingress Rule -- PON Port Object -- EAPOL'

+        eoam.set_request(PonPortObject()/

+                         PortIngressRuleHeader(precedence=32)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],

+                                                            operator=Operator['=='], match=0x888e)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4090)/

+                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         AddPortIngressRule())

+

+        time.sleep(3)

+

+        print 'Delete - Port Ingress Rule -- PON Port Object -- EAPOL'

+        eoam.set_request(PonPortObject()/

+                         PortIngressRuleHeader(precedence=32)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],

+                                                            operator=Operator['=='], match=0x888e)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4090)/

+                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         DeletePortIngressRule())

+

+    if (args.test_igmp == True):

+        #################################################################################

+        ## IGMP

+        #################################################################################

+        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}

+        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

+

+        print 'SET - Port Ingress Rule -- PON Port Object -- IGMP'

+        eoam.set_request(PonPortObject()/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],

+                                                            operator=Operator['=='], match=0x0800)/

+                         PortIngressRuleClauseMatchLength01(fieldcode=Clause['IPv4/IPv6 Protocol Type'],

+                                                            operator=Operator['=='], match=0x02)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4000)/

+                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         AddPortIngressRule())

+

+        time.sleep(3)

+

+        print 'Delete - Port Ingress Rule -- PON Port Object -- IGMP'

+        eoam.set_request(PonPortObject()/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],

+                                                            operator=Operator['=='], match=0x0800)/

+                         PortIngressRuleClauseMatchLength01(fieldcode=Clause['IPv4/IPv6 Protocol Type'],

+                                                            operator=Operator['=='], match=0x02)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4000)/

+                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         DeletePortIngressRule())

+

+    if (args.test_dhcp == True):

+        #################################################################################

+        ## DHCP

+        #################################################################################

+        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}

+        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

+

+        print 'SET - Port Ingress Rule -- PON Port Object -- DHCP'

+        eoam.set_request(PonPortObject()/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],

+                                                            operator=Operator['=='], match=0x0800)/

+                         PortIngressRuleClauseMatchLength01(fieldcode=Clause['IPv4/IPv6 Protocol Type'],

+                                                            operator=Operator['=='], match=0x11)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP source port'],

+                                                            operator=Operator['=='], match=0x0044)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP destination port'],

+                                                            operator=Operator['=='], match=0x0043)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4000)/

+                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         AddPortIngressRule())

+

+        time.sleep(3)

+

+        print 'Delete - Port Ingress Rule -- PON Port Object -- DHCP'

+        eoam.set_request(PonPortObject()/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['L2 Type/Len'],

+                                                            operator=Operator['=='], match=0x0800)/

+                         PortIngressRuleClauseMatchLength01(fieldcode=Clause['IPv4/IPv6 Protocol Type'],

+                                                            operator=Operator['=='], match=0x11)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP source port'],

+                                                            operator=Operator['=='], match=0x0044)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP destination port'],

+                                                            operator=Operator['=='], match=0x0043)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=4000)/

+                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         DeletePortIngressRule())

+

+    if (args.test_upstream == True):

+        #################################################################################

+        ## UPSTREAM

+        #################################################################################

+        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}

+        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

+

+        print 'SET - Port Ingress Rule -- OLT Unicast Logical Link -- Upstream Traffic'

+        eoam.set_request(PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,

+                                                            operator=Operator['=='], match=0x00f1)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultCopy(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1)/

+                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=1000)/

+                         PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag'])/

+                         OLTUnicastLogicalLink(unicastvssn="TBIT", unicastlink=0xe2222900)/

+                         PortIngressRuleTerminator()/

+                         AddPortIngressRule())

+

+

+        time.sleep(3)

+

+        print 'DELETE - Port Ingress Rule -- OLT Unicast Logical Link -- Upstream Traffic'

+        eoam.set_request(OLTUnicastLogicalLink(unicastvssn="TBIT", unicastlink=0xe2222900)/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,

+                                                            operator=Operator['=='], match=0x00f1)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultCopy(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1)/

+                         PortIngressRuleResultSet(fieldcode=Clause['C-VLAN Tag'], value=1000)/

+                         PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         DeletePortIngressRule())

+

+    if (args.test_downstream == True):

+        #################################################################################

+        ## DOWNSTREAM

+        #################################################################################

+        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}

+        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

+

+        print 'SET - Port Ingress Rule -- NNI Port Object -- Downstream Traffic -- 4000/241'

+        eoam.set_request(NetworkToNetworkPortObject()/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,

+                                                            operator=Operator['=='], match=0x0fa0)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,

+                                                            operator=Operator['=='], match=0x00f1)/

+                         PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=0xe2222900)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         AddPortIngressRule())

+

+        time.sleep(1)

+

+        print 'SET - Port Ingress Rule -- NNI Port Object -- Downstream Traffic -- 1000/241'

+        eoam.set_request(NetworkToNetworkPortObject()/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,

+                                                            operator=Operator['=='], match=0x03e8)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,

+                                                            operator=Operator['=='], match=0x00f1)/

+                         PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=0xe2222900)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         AddPortIngressRule())

+

+

+        time.sleep(1)

+

+        print 'SET - Port Ingress Rule -- NNI Port Object -- Downstream Traffic -- 4000/203'

+        eoam.set_request(NetworkToNetworkPortObject()/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,

+                                                            operator=Operator['=='], match=0x0fa0)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,

+                                                            operator=Operator['=='], match=0x00CB)/

+                         PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=0xe2220300)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         AddPortIngressRule())

+

+        time.sleep(1)

+

+        print 'SET - Port Ingress Rule -- NNI Port Object -- Downstream Traffic -- 1000/203'

+        eoam.set_request(NetworkToNetworkPortObject()/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,

+                                                            operator=Operator['=='], match=0x03e8)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,

+                                                            operator=Operator['=='], match=0x00cb)/

+                         PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=0xe2220300)/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         AddPortIngressRule())

+

+    if (args.test_multicast == True):

+        #################################################################################

+        ## MULTICAST

+        #################################################################################

+        Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}

+        Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}

+

+        print 'SET - Port Ingress Rule -- NNI Port Object -- Downstream Multicast Traffic'

+        eoam.set_request(NetworkToNetworkPortObject()/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,

+                                                            operator=Operator['=='], match=0x008c)/

+                         PortIngressRuleResultOLTBroadcastQueue()/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         AddPortIngressRule())

+

+

+        time.sleep(3)

+

+        print 'DELETE - Port Ingress Rule -- NNI Port Object -- Downstream Multicast Traffic'

+        eoam.set_request(NetworkToNetworkPortObject()/

+                         PortIngressRuleHeader(precedence=13)/

+                         PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,

+                                                            operator=Operator['=='], match=0x008c)/

+                         PortIngressRuleResultOLTBroadcastQueue()/

+                         PortIngressRuleResultForward()/

+                         PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/

+                         PortIngressRuleTerminator()/

+                         DeletePortIngressRule())

+

+

+    if (args.test_ping == True):

+        json_operation_str = '{\"operation\":\"version\"}'

+        for i in range(10000):

+            eoam.send_frame(TBJSON(data='json %s' % json_operation_str), False)

+

diff --git a/voltha/extensions/eoam/EOAM_TLV.py b/voltha/extensions/eoam/EOAM_TLV.py
index f0861cd..545490b 100644
--- a/voltha/extensions/eoam/EOAM_TLV.py
+++ b/voltha/extensions/eoam/EOAM_TLV.py
@@ -133,6 +133,11 @@
     name = "DPoE Opcode"
     fields_desc  = [ByteEnumField("opcode", 0x07, DPoEOpcodeEnum)]
 
+class DPoEOpcode_FileTransfer(Packet):
+    """ DPoE Opcode"""
+    name = "DPoE Opcode"
+    fields_desc  = [ByteEnumField("opcode", 0x09, DPoEOpcodeEnum)]
+
 class MulticastRegisterSetSumitomo01(Packet):
     """ Multicast Register: Multicast Register Set Sumitomo 01 """
     name = "Multicast Register: Multicast Register Set Sumitomo 01"
@@ -157,11 +162,6 @@
                    XShortField("UnicastLink", 0x0000),
                    ]
 
-class TibitOpcode_OmciMessage(Packet):
-    """ DPoE Opcode"""
-    name = "Tibit Opcode"
-    fields_desc  = [ByteEnumField("opcode", 0xA0, DPoEOpcodeEnum)]
-
 ####
 #### PORT OBJECTS
 ####
@@ -898,6 +898,9 @@
     name = "Variable Descriptor: FEC Mode"
     fields_desc = [XByteField("branch", 0xD7),
                    XShortField("leaf", 0x0605),
+                   XByteField("length", 2),
+                   XByteField("downstream", 0x01),
+                   XByteField("upstream", 0x01),
                    ]
 
 class MediaType(Packet):
@@ -1087,10 +1090,28 @@
                    XByteField("instance", 0),
                    XByteField("pon", 0),
                    StrField("unicastvssn", "TBIT"),
-                   XIntField("unicastlink", 0xe2222900),
+                   XIntField("unicastlink", 0x00000000),
                    XByteField("pad", 0),
                    ]
 
+class PortIngressRuleResultOLTEPONQueue(Packet):
+    """ Variable Descriptor: Port Ingress Rule Result OLT Queue """
+    name = "Variable Descriptor: Port Ingress Rule Result OLT Queue"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0501),
+                   ByteField("length", 15),
+                   XByteField("result", 3),
+                   XByteField("oltqueuerule", 0x13),
+                   XShortField("objecttype", 0x0001),
+                   XByteField("instance", 0),
+                   XByteField("pon", 0),
+                   XIntField("unicastvssn", 0x00000000),
+                   XIntField("unicastlink", 0x00000000),
+                   XByteField("pad", 0),
+                   ]
+
+
+
 # __TIBIT_OLT_OAM__: Defined by Tibit
 class PortIngressRuleResultOLTBroadcastQueue(Packet):
     """ Variable Descriptor: Port Ingress Rule Result OLT Broadcast Queue """
@@ -1260,6 +1281,15 @@
                    XShortField("leaf", 0x0101),
                    ]
 
+class OltModeSet(Packet):
+    """ Variable Descriptor: OLT Mode """
+    name = "Variable Descriptor: "
+    fields_desc = [XByteField("branch", 0xB7),
+                   XShortField("leaf", 0x0101),
+                   XByteField("length", 1),
+                   XByteField("value", 0),
+                   ]
+
 class OltPonAdminState(Packet):
     """ Variable Descriptor: OLT PON Admin State """
     name = "Variable Descriptor: "
@@ -1299,6 +1329,66 @@
                    XShortField("value", 0x1234),
                   ]
 
+class OnuMode(Packet):
+    """ Variable Descriptor: ONU Mode """
+    name = "Variable Descriptor: "
+    fields_desc = [XByteField("branch", 0xB7),
+                   XShortField("leaf", 0x0105),
+                   ]
+
+class OnuModeSet(Packet):
+    """ Variable Descriptor: ONU Mode """
+    name = "Variable Descriptor: "
+    fields_desc = [XByteField("branch", 0xB7),
+                   XShortField("leaf", 0x0105),
+                   XByteField("length", 1),
+                   XByteField("value", 0),
+                   ]
+
+class TibitGrantSpacing(Packet):
+    """ Variable Descriptor: Grant Spacing """
+    name = "Variable Descriptor: "
+    fields_desc = [XByteField("branch", 0xB7),
+                   XShortField("leaf", 0x0106),
+                   ]
+
+class TibitGrantSpacingSet(Packet):
+    """ Variable Descriptor: Grant Spacing """
+    name = "Variable Descriptor: "
+    fields_desc = [XByteField("branch", 0xB7),
+                   XShortField("leaf", 0x0106),
+                   XByteField("length", 1),
+                   XByteField("value", 0),
+                   ]                   
+
+class TibitBurstOverheadProfiles(Packet):
+    """ Variable Descriptor: Burst Overhead Profiles """
+    name = "Variable Descriptor: "
+    fields_desc = [XByteField("branch", 0xB7),
+                   XShortField("leaf", 0x0107),
+                   ]
+
+class TibitBurstOverheadProfilesSet(Packet):
+    """ Variable Descriptor: Burst Overhead Profiles """
+    name = "Variable Descriptor: "
+    fields_desc = [XByteField("branch", 0xB7),
+                   XShortField("leaf", 0x0107),
+                   # Length is one + 5 for each entry
+                   XByteField("length", 6),
+                   XByteField("num_profiles", 1),
+                   ]
+
+class TibitBurstOverheadProfilesEntry(Packet):
+    """ Variable Descriptor: Burst Overhead Profile Entry """
+    name = "Burst Profile Entry:"
+    fields_desc = [XByteField("laser_on_time", 0x28),
+                   XByteField("laser_off_time", 0x28),
+                   XShortField("sync_time", 0x0040),
+                   XByteField("us_fec", 1),
+                   ]
+
+
+
 UpstreamSlaSubtypeEnum = { 0x00: "Terminator",
                            0x01: "Header",
                            0x02: "Max Grant Period",