Пример #1
0
 def _dispatchMeshDebugPacket(self, zep):
     '''
     Wraps ZEP-based debug packet, for outgoing mesh 6LoWPAN message, 
     with UDP and IPv6 headers. Then forwards as an event to the 
     Internet interface.
     '''
     
     # UDP
     udplen  = len(zep)+8
     
     udp     = [0x00,0x00]                   # src port (unused)
     udp    += [0x45,0x5a]                   # dest port (17754)
     udp    += [udplen >> 8, udplen & 0xff]  # length
     udp    += [0x00,0x00]                   # checksum
     udp    += zep
     
     # Common address for source and destination
     addr    = []
     addr   += openTun.IPV6PREFIX
     addr   += openTun.IPV6HOST
     
     # CRC See https://tools.ietf.org/html/rfc2460.
   
     # not sure if the payload contains the udp header in this case.
     udp[6:8] = u.calculatePseudoHeaderCRC(
         src         = addr,
         dst         = addr,
         length      = [0x00,0x00]+udp[4:6],
         nh          = [0x00,0x00,0x00,17],
         payload     = zep,
     )
     
     # IPv6
     ip     = [6<<4]                  # v6 + traffic class (upper nybble)
     ip    += [0x00,0x00,0x00]        # traffic class (lower nibble) + flow label
     ip    += udp[4:6]                # payload length
     ip    += [17]                    # next header (protocol)
     ip    += [8]                     # hop limit (pick a safe value)
     ip    += addr                    # source
     ip    += addr                    # destination
     ip    += udp
     
     dispatcher.send(
         sender = self.name,
         signal = 'v6ToInternet',
         data   = ip,
     )
Пример #2
0
    def _dispatchMeshDebugPacket(self, zep):
        '''
        Wraps ZEP-based debug packet, for outgoing mesh 6LoWPAN message, 
        with UDP and IPv6 headers. Then forwards as an event to the 
        Internet interface.
        '''

        # UDP
        udplen = len(zep) + 8

        udp = [0x00, 0x00]  # src port (unused)
        udp += [0x45, 0x5a]  # dest port (17754)
        udp += [udplen >> 8, udplen & 0xff]  # length
        udp += [0x00, 0x00]  # checksum
        udp += zep

        # Common address for source and destination
        addr = []
        addr += openTun.IPV6PREFIX
        addr += openTun.IPV6HOST

        # CRC See https://tools.ietf.org/html/rfc2460.

        # not sure if the payload contains the udp header in this case.
        udp[6:8] = u.calculatePseudoHeaderCRC(
            src=addr,
            dst=addr,
            length=[0x00, 0x00] + udp[4:6],
            nh=[0x00, 0x00, 0x00, 17],
            payload=zep,
        )

        # IPv6
        ip = [6 << 4]  # v6 + traffic class (upper nybble)
        ip += [0x00, 0x00, 0x00]  # traffic class (lower nibble) + flow label
        ip += udp[4:6]  # payload length
        ip += [17]  # next header (protocol)
        ip += [8]  # hop limit (pick a safe value)
        ip += addr  # source
        ip += addr  # destination
        ip += udp

        dispatcher.send(
            sender=self.name,
            signal='v6ToInternet',
            data=ip,
        )
Пример #3
0
    def _meshToV6_notif(self, sender, signal, data):
        '''
        Converts a 6LowPAN packet into a IPv6 packet.
        
        This function dispatches the IPv6 packet with signal 'according to the destination address, protocol_type and port'.
        '''
        try:
            ipv6dic = {}
            #build lowpan dictionary from the data
            ipv6dic = self.lowpan_to_ipv6(data)
            success = True
            dispatchSignal = None

            #read next header
            if ipv6dic['next_header'] == self.IANA_IPv6HOPHEADER:
                #hop by hop header present, check flags and parse
                if (ipv6dic['hop_flags'] & self.O_FLAG) == self.O_FLAG:
                    #error -- this packet has gone downstream somewhere.
                    log.error(
                        "detected possible downstream link on upstream route from {0}"
                        .format(",".join(str(c) for c in ipv6dic['src_addr'])))
                if (ipv6dic['hop_flags'] & self.R_FLAG) == self.R_FLAG:
                    #error -- loop in the route
                    log.error(
                        "detected possible loop on upstream route from {0}".
                        format(",".join(str(c) for c in ipv6dic['src_addr'])))
                #skip the header and process the rest of the message.
                ipv6dic['next_header'] = ipv6dic['hop_next_header']

            #===================================================================

            if ipv6dic['next_header'] == self.IPV6_HEADER:
                #ipv6 header (inner)
                ipv6dic_inner = {}
                # prasing the iphc inner header and get the next_header
                ipv6dic_inner = self.lowpan_to_ipv6(
                    [ipv6dic['pre_hop'], ipv6dic['payload']])
                ipv6dic['next_header'] = ipv6dic_inner['next_header']
                ipv6dic['payload'] = ipv6dic_inner['payload']
                ipv6dic['payload_length'] = ipv6dic_inner['payload_length']
                ipv6dic['src_addr'] = ipv6dic_inner['src_addr']
                if not ipv6dic.has_key('hop_limit'):
                    ipv6dic['hop_limit'] = ipv6dic_inner['hop_limit']
                ipv6dic['dst_addr'] = ipv6dic_inner['dst_addr']
                ipv6dic['flow_label'] = ipv6dic_inner['flow_label']

            if ipv6dic['next_header'] == self.IANA_ICMPv6:
                #icmp header
                if len(ipv6dic['payload']) < 5:
                    log.critical(
                        "wrong payload lenght on ICMPv6 packet {0}".format(
                            ",".join(str(c) for c in data)))
                    print "wrong payload lenght on ICMPv6 packet {0}".format(
                        ",".join(str(c) for c in data))
                    return

                ipv6dic['icmpv6_type'] = ipv6dic['payload'][0]
                ipv6dic['icmpv6_code'] = ipv6dic['payload'][1]
                ipv6dic['icmpv6_checksum'] = ipv6dic['payload'][2:4]
                ipv6dic['app_payload'] = ipv6dic['payload'][4:]

                #this function does the job
                dispatchSignal = (tuple(ipv6dic['dst_addr']),
                                  self.PROTO_ICMPv6, ipv6dic['icmpv6_type'])

            elif ipv6dic['next_header'] == self.IANA_UDP:
                #udp header -- can be compressed.. assume first it is not compressed.
                if len(ipv6dic['payload']) < 5:
                    log.critical(
                        "wrong payload lenght on UDP packet {0}".format(
                            ",".join(str(c) for c in data)))
                    print "wrong payload lenght on UDP packet {0}".format(
                        ",".join(str(c) for c in data))
                    return

                if ipv6dic['payload'][0] & self.NHC_UDP_MASK == self.NHC_UDP_ID:

                    lowpan_nhc = ipv6dic['payload'][0]
                    udp_header_length = 0
                    newUdp = []
                    newUdp_header_length = 0

                    if lowpan_nhc & self.NHC_UDP_PORTS_MASK == self.NHC_UDP_PORTS_INLINE:
                        src_port = u.buf2int(ipv6dic['payload'][1:3])
                        dest_port = u.buf2int(ipv6dic['payload'][3:5])
                        udp_header_length = 5
                    elif lowpan_nhc & self.NHC_UDP_PORTS_MASK == self.NHC_UDP_PORTS_16S_8D:
                        src_port = u.buf2int(ipv6dic['payload'][1:3])
                        dest_port = 0xf000 + ipv6dic['payload'][3]
                        udp_header_length = 4
                    elif lowpan_nhc & self.NHC_UDP_PORTS_MASK == self.NHC_UDP_PORTS_8S_16D:
                        src_port = 0xf000 + ipv6dic['payload'][1]
                        dest_port = u.buf2int(ipv6dic['payload'][2:4])
                        udp_header_length = 4
                    elif lowpan_nhc & self.NHC_UDP_PORTS_MASK == self.NHC_UDP_PORTS_4S_4D:
                        src_port = 0xf0b0 + (
                            (ipv6dic['payload'][1] >> 4) & 0x0f)
                        dest_port = 0xf0b0 + (
                            (ipv6dic['payload'][1] >> 0) & 0x0f)
                        udp_header_length = 2

                    newUdp = [src_port >> 8, src_port & 0x00ff]
                    newUdp += [dest_port >> 8, dest_port & 0x00ff]

                    idxLen = len(newUdp)  # remember index of payload length
                    newUdp += [0x00, 0x00]  # length (placeholder)
                    newUdp_header_length += 2

                    udp_header_length += 2  # skip two bytes checksum following
                    idxCS = len(newUdp)  # remember index of checksum
                    newUdp += [0x00, 0x00]  # Checksum (placeholder)
                    newUdp_header_length += 2

                    #append payload to compute crc again
                    newUdp += ipv6dic['payload'][
                        udp_header_length:]  # data octets

                    udp_len = [
                        0, len(ipv6dic['payload'][udp_header_length:]) + 8
                    ]
                    newUdp[idxLen] = udp_len[0]
                    newUdp[idxLen + 1] = udp_len[1]

                    checksum = u.calculatePseudoHeaderCRC(
                        ipv6dic['src_addr'], ipv6dic['dst_addr'], udp_len,
                        [0, ipv6dic['next_header']], newUdp)
                    #fill crc with the right value.
                    newUdp[idxCS] = checksum[0]
                    newUdp[idxCS + 1] = checksum[1]

                    #keep fields for later processing if needed
                    ipv6dic['udp_src_port'] = u.buf2int(newUdp[0:2])
                    ipv6dic['udp_dest_port'] = u.buf2int(newUdp[2:4])
                    ipv6dic['udp_length'] = newUdp[4:6]
                    ipv6dic['udp_checksum'] = newUdp[6:8]
                    ipv6dic['app_payload'] = newUdp[8:]

                    #substitute udp header by the uncompressed header.
                    ipv6dic['payload'] = newUdp
                    ipv6dic['payload_length'] = len(newUdp)
                else:
                    #No UDP header compressed
                    ipv6dic['udp_src_port'] = u.buf2int(ipv6dic['payload'][:2])
                    ipv6dic['udp_dest_port'] = u.buf2int(
                        ipv6dic['payload'][2:4])
                    ipv6dic['udp_length'] = ipv6dic['payload'][4:6]
                    ipv6dic['udp_checksum'] = ipv6dic['payload'][6:8]
                    ipv6dic['app_payload'] = ipv6dic['payload'][8:]

                dispatchSignal = (tuple(ipv6dic['dst_addr']), self.PROTO_UDP,
                                  ipv6dic['udp_dest_port'])

            #keep payload and app_payload in case we want to assemble the message later.
            #as source address is being retrieved from the IPHC header, the signal includes it in case
            #receiver such as RPL DAO processing needs to know the source.

            success = self._dispatchProtocol(
                dispatchSignal, (ipv6dic['src_addr'], ipv6dic['app_payload']))

            if success:
                return

            # assemble the packet and dispatch it again as nobody answer
            ipv6pkt = self.reassemble_ipv6_packet(ipv6dic)

            self.dispatch('v6ToInternet', ipv6pkt)

        except (ValueError, NotImplementedError) as err:
            log.error(err)
            pass
Пример #4
0
    def _meshToV6_notif(self,sender,signal,data):
        '''
        Converts a 6LowPAN packet into a IPv6 packet.

        This function dispatches the IPv6 packet with signal 'according to the destination address, protocol_type and port'.
        '''
        try:
            ipv6dic={}
            #build lowpan dictionary from the data
            ipv6dic = self.lowpan_to_ipv6(data)
            success = True
            dispatchSignal = None

            hopbyhop_header_present = False

            #read next header
            if ipv6dic['next_header']==self.IANA_IPv6HOPHEADER:
                # mark hop by hop header present, check hop_flags after obtaining src_addr in IPV6 header. 
                hopbyhop_header_present = True
                #skip the header and process the rest of the message.
                ipv6dic['next_header']  = ipv6dic['hop_next_header']

            #===================================================================

            if ipv6dic['next_header']==self.IPV6_HEADER:
                #ipv6 header (inner)
                ipv6dic_inner = {}
                # parsing the iphc inner header and get the next_header
                ipv6dic_inner = self.lowpan_to_ipv6([ipv6dic['pre_hop'],ipv6dic['payload']])
                ipv6dic['next_header'] = ipv6dic_inner['next_header']
                ipv6dic['payload'] = ipv6dic_inner['payload']
                ipv6dic['payload_length'] = ipv6dic_inner['payload_length']
                ipv6dic['src_addr'] = ipv6dic_inner['src_addr']
                if not ipv6dic.has_key('hop_limit'):
                    ipv6dic['hop_limit'] = ipv6dic_inner['hop_limit']
                ipv6dic['dst_addr'] = ipv6dic_inner['dst_addr']
                ipv6dic['flow_label'] = ipv6dic_inner['flow_label']

                if hopbyhop_header_present:
                    #hop by hop header present, check hop_flags
                    if (ipv6dic['hop_flags'] & self.O_FLAG) == self.O_FLAG:
                        #error -- this packet has gone downstream somewhere.
                        log.error("detected possible downstream link on upstream route from {0}".format(",".join(str(c) for c in ipv6dic['src_addr'])))
                    if (ipv6dic['hop_flags'] & self.R_FLAG) == self.R_FLAG:
                        #error -- loop in the route
                        log.error("detected possible loop on upstream route from {0}".format(",".join(str(c) for c in ipv6dic['src_addr'])))

            if ipv6dic['next_header']==self.IANA_ICMPv6:
                #icmp header
                if len(ipv6dic['payload'])<5:
                    log.critical("wrong payload lenght on ICMPv6 packet {0}".format(",".join(str(c) for c in data)))
                    print "wrong payload lenght on ICMPv6 packet {0}".format(",".join(str(c) for c in data))
                    return


                ipv6dic['icmpv6_type']=ipv6dic['payload'][0]
                ipv6dic['icmpv6_code']=ipv6dic['payload'][1]
                ipv6dic['icmpv6_checksum']=ipv6dic['payload'][2:4]
                ipv6dic['app_payload']=ipv6dic['payload'][4:]

                #this function does the job
                dispatchSignal=(tuple(ipv6dic['dst_addr']),self.PROTO_ICMPv6,ipv6dic['icmpv6_type'])

            elif ipv6dic['next_header']==self.IANA_UDP:
                #udp header -- can be compressed.. assume first it is not compressed.
                if len(ipv6dic['payload'])<5:
                    log.critical("wrong payload lenght on UDP packet {0}".format(",".join(str(c) for c in data)))
                    print "wrong payload lenght on UDP packet {0}".format(",".join(str(c) for c in data))
                    return

                if ipv6dic['payload'][0] & self.NHC_UDP_MASK==self.NHC_UDP_ID:

                    lowpan_nhc            = ipv6dic['payload'][0]
                    udp_header_length     = 0
                    newUdp                = []
                    newUdp_header_length  = 0

                    if lowpan_nhc & self.NHC_UDP_PORTS_MASK == self.NHC_UDP_PORTS_INLINE:
                        src_port  = u.buf2int(ipv6dic['payload'][1:3])
                        dest_port = u.buf2int(ipv6dic['payload'][3:5])
                        udp_header_length = 5
                    elif lowpan_nhc & self.NHC_UDP_PORTS_MASK == self.NHC_UDP_PORTS_16S_8D:
                        src_port  = u.buf2int(ipv6dic['payload'][1:3])
                        dest_port = 0xf000 + ipv6dic['payload'][3]
                        udp_header_length = 4
                    elif lowpan_nhc & self.NHC_UDP_PORTS_MASK == self.NHC_UDP_PORTS_8S_16D:
                        src_port  = 0xf000 + ipv6dic['payload'][1]
                        dest_port = u.buf2int(ipv6dic['payload'][2:4])
                        udp_header_length = 4
                    elif lowpan_nhc & self.NHC_UDP_PORTS_MASK == self.NHC_UDP_PORTS_4S_4D:
                        src_port  = 0xf0b0 +((ipv6dic['payload'][1] >> 4) & 0x0f)
                        dest_port = 0xf0b0 +((ipv6dic['payload'][1] >> 0) & 0x0f)
                        udp_header_length = 2

                    newUdp  =  [src_port  >>8 , src_port  & 0x00ff]
                    newUdp  += [dest_port >>8 , dest_port & 0x00ff]

                    idxLen = len(newUdp) # remember index of payload length
                    newUdp += [0x00,0x00] # length (placeholder)
                    newUdp_header_length += 2

                    udp_header_length += 2 # skip two bytes checksum following
                    idxCS = len(newUdp) # remember index of checksum
                    newUdp += [0x00,0x00] # Checksum (placeholder)
                    newUdp_header_length += 2

                    #append payload to compute crc again
                    newUdp += ipv6dic['payload'][udp_header_length:] # data octets

                    udp_len  = [0, len(ipv6dic['payload'][udp_header_length:])+8]
                    newUdp[idxLen]   = udp_len[0]
                    newUdp[idxLen+1] = udp_len[1]

                    checksum = u.calculatePseudoHeaderCRC(ipv6dic['src_addr'],ipv6dic['dst_addr'],udp_len,[0,ipv6dic['next_header']],newUdp)
                    #fill crc with the right value.
                    newUdp[idxCS]   = checksum[0]
                    newUdp[idxCS+1] = checksum[1]

                    #keep fields for later processing if needed
                    ipv6dic['udp_src_port']       = u.buf2int(newUdp[0:2])
                    ipv6dic['udp_dest_port']      = u.buf2int(newUdp[2:4])
                    ipv6dic['udp_length']         = newUdp[4:6]
                    ipv6dic['udp_checksum']       = newUdp[6:8]
                    ipv6dic['app_payload']        = newUdp[8:]

                    #substitute udp header by the uncompressed header.
                    ipv6dic['payload']        = newUdp
                    ipv6dic['payload_length'] = len(newUdp)
                else:
                    #No UDP header compressed
                    ipv6dic['udp_src_port']=u.buf2int(ipv6dic['payload'][:2])
                    ipv6dic['udp_dest_port']=u.buf2int(ipv6dic['payload'][2:4])
                    ipv6dic['udp_length']=ipv6dic['payload'][4:6]
                    ipv6dic['udp_checksum']=ipv6dic['payload'][6:8]
                    ipv6dic['app_payload']=ipv6dic['payload'][8:]

                dispatchSignal=(tuple(ipv6dic['dst_addr']),self.PROTO_UDP,ipv6dic['udp_dest_port'])

            #keep payload and app_payload in case we want to assemble the message later.
            #as source address is being retrieved from the IPHC header, the signal includes it in case
            #receiver such as RPL DAO processing needs to know the source.

            success = self._dispatchProtocol(dispatchSignal,(ipv6dic['src_addr'],ipv6dic['app_payload']))

            if success:
                return

            # assemble the packet and dispatch it again as nobody answer
            ipv6pkt=self.reassemble_ipv6_packet(ipv6dic)

            self.dispatch('v6ToInternet',ipv6pkt)

        except (ValueError,IndexError,NotImplementedError) as err:
            log.error(err)
            pass
Пример #5
0
    def _sendDIO(self):
        """
        Send a DIO.
        """

        # don't send DIO if I didn't discover the DAGroot's EUI64
        if not self.dagRootEui64:
            return

        # the list of bytes to be sent to the DAGroot.
        # - [8B]       destination MAC address
        # - [variable] IPHC+ header
        dio = []

        # next hop: broadcast address
        nextHop = [0xFF] * 8

        # IPHC header
        dio += [0x78]  # dispatch byte
        dio += [0x33]  # dam sam
        idxNH = len(dio)
        dio += [0x3A]  # next header (0x3A=ICMPv6)
        dio += [0x00]  # HLIM

        # ICMPv6 header
        idxICMPv6 = len(dio)  # remember where ICMPv6 starts
        dio += [155]  # ICMPv6 type (155=RPL)
        dio += [0x01]  # ICMPv6 CODE (for RPL 0x01=DIO)
        idxICMPv6CS = len(dio)  # remember where ICMPv6 checksum starts
        dio += [0x00, 0x00]  # placeholder for checksum (filled out later)

        # DIO header
        dio += [0x00]  # instance ID
        dio += [0x00]  # version number
        dio += [0x00, 0x00]  # rank
        dio += [self.DIO_OPT_GROUNDED | self.MOP_DIO_A | self.MOP_DIO_B | self.MOP_DIO_C]  # options: G | 0 | MOP | Prf
        dio += [0x00]  # DTSN
        dio += [0x00]  # flags
        dio += [0x00]  # reserved

        # DODAGID
        with self.stateLock:
            idxSrc = len(dio)  # this is a little hack as the source is the dodag
            dio += self.networkPrefix
            dio += self.dagRootEui64

        # wireshark calculates the IPv6 source and destination from the
        # 6LoWPAN header. It is lot aware of the network prefix and uses
        # link-local addresses. We do the same in this implementation to avoid
        # checksum errors in Wireshark.
        wiresharkSrc = [0xFE, 0x80] + [0x00] * 6 + [dio[idxSrc + 8] | 0x02] + dio[idxSrc + 9 : idxSrc + 16]
        wiresharkDst = [0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0xFF, 0xFF]

        # calculate ICMPv6 checksum over ICMPv6header+ (RFC4443)
        checksum = u.calculatePseudoHeaderCRC(
            src=wiresharkSrc,
            dst=wiresharkDst,
            length=[0x00, 0x00, 0x00, len(dio[idxICMPv6:])],
            nh=[0x00] + dio[idxNH : idxNH + 1],
            payload=dio[idxICMPv6:],
        )

        dio[idxICMPv6CS] = checksum[0]
        dio[idxICMPv6CS + 1] = checksum[1]

        # log
        if log.isEnabledFor(logging.DEBUG):
            log.debug("sending DIO {0}".format(u.formatBuf(dio)))

        # dispatch
        self.dispatch(signal="bytesToMesh", data=(nextHop, dio))
Пример #6
0
    def _sendDIO(self):
        '''
        Send a DIO.
        '''

        # don't send DIO if I didn't discover the DAGroot's EUI64
        if not self.dagRootEui64:
            return

        # the list of bytes to be sent to the DAGroot.
        # - [8B]       destination MAC address
        # - [variable] IPHC+ header
        dio = []

        # next hop: broadcast address
        nextHop = [0xff] * 8

        # IPHC header
        dio += [0x78]  # dispatch byte
        dio += [0x33]  # dam sam
        idxNH = len(dio)
        dio += [0x3A]  # next header (0x3A=ICMPv6)
        dio += [0x00]  # HLIM

        # ICMPv6 header
        idxICMPv6 = len(dio)  # remember where ICMPv6 starts
        dio += [155]  # ICMPv6 type (155=RPL)
        dio += [0x01]  # ICMPv6 CODE (for RPL 0x01=DIO)
        idxICMPv6CS = len(dio)  # remember where ICMPv6 checksum starts
        dio += [0x00, 0x00]  # placeholder for checksum (filled out later)

        # DIO header
        dio += [0x00]  # instance ID
        dio += [0x00]  # version number
        dio += [0x00, 0x00]  # rank
        dio += [
            self.DIO_OPT_GROUNDED | self.MOP_DIO_A | self.MOP_DIO_B
            | self.MOP_DIO_C
        ]  # options: G | 0 | MOP | Prf
        dio += [0x00]  # DTSN
        dio += [0x00]  # flags
        dio += [0x00]  # reserved

        # DODAGID
        with self.stateLock:
            idxSrc = len(
                dio)  # this is a little hack as the source is the dodag
            dio += self.networkPrefix
            dio += self.dagRootEui64

        # wireshark calculates the IPv6 source and destination from the
        # 6LoWPAN header. It is lot aware of the network prefix and uses
        # link-local addresses. We do the same in this implementation to avoid
        # checksum errors in Wireshark.
        wiresharkSrc = [0xfe, 0x80] + [0x00] * 6 + [
            dio[idxSrc + 8] | 0x02
        ] + dio[idxSrc + 9:idxSrc + 16]
        wiresharkDst = [
            0xfe,
            0x80,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0xff,
            0xfe,
            0x00,
            0xff,
            0xff,
        ]

        # calculate ICMPv6 checksum over ICMPv6header+ (RFC4443)
        checksum = u.calculatePseudoHeaderCRC(
            src=wiresharkSrc,
            dst=wiresharkDst,
            length=[0x00, 0x00, 0x00, len(dio[idxICMPv6:])],
            nh=[0x00] + dio[idxNH:idxNH + 1],
            payload=dio[idxICMPv6:],
        )

        dio[idxICMPv6CS] = checksum[0]
        dio[idxICMPv6CS + 1] = checksum[1]

        # log
        if log.isEnabledFor(logging.DEBUG):
            log.debug('sending DIO {0}'.format(u.formatBuf(dio)))

        # dispatch
        self.dispatch(signal='bytesToMesh', data=(nextHop, dio))