Example #1
0
    async def render_post(self, request):
        # Incoming TLVs parsing
        logging.info('in %s ntf: %s' %
                     (URI.A_AE, ThreadTLV.sub_tlvs_str(request.payload)))

        # Message not handled by Secondary BBR
        if not 'primary' in db.get('bbr_status'):
            return COAP_NO_RESPONSE

        # Find sub TLVs
        dua = None
        eid = None
        value = ThreadTLV.get_value(request.payload, TLV.A_TARGET_EID)
        if value:
            dua = ipaddress.IPv6Address(bytes(value))
        value = ThreadTLV.get_value(request.payload, TLV.A_ML_EID)
        if value:
            eid = value.hex()
        if not dua or not eid:
            return COAP_NO_RESPONSE

        # Don't process notifications for different prefixes than DUA
        dua_prefix = ipaddress.IPv6Address(db.get('prefix').split('/')[0])
        if dua.packed[:8] != dua_prefix.packed[:8]:
            return COAP_NO_RESPONSE

        # Remove entry if it's registered with different EID
        entry_eid, _, dad = DUA_HNDLR.find_eid(dua.compressed)
        if not dad and entry_eid != eid:
            DUA_HNDLR.remove_entry(dua=dua)

        return COAP_NO_RESPONSE
Example #2
0
def _get_b_ba_params(payload):
    '''Extract paramters from a BB.ans or PRO_BB.ntf payload'''
    dua = None
    eid = None
    rloc16 = None
    elapsed = None
    net_name = None
    value = ThreadTLV.get_value(payload, TLV.A_TARGET_EID)
    if value:
        dua = ipaddress.IPv6Address(bytes(value)).compressed
        value = ThreadTLV.get_value(payload, TLV.A_ML_EID)
    if value:
        eid = value.hex()
    value = ThreadTLV.get_value(payload, TLV.A_RLOC16)

    if value:
        rloc16 = value.hex()
    value = ThreadTLV.get_value(payload, TLV.A_TIME_SINCE_LAST_TRANSACTION)
    if value:
        elapsed = struct.unpack('!I', value)[0]
    value = ThreadTLV.get_value(payload, TLV.A_NETWORK_NAME)
    if value:
        net_name = struct.unpack('%ds' % len(value), value)[0].decode()

    return dua, eid, rloc16, elapsed, net_name
Example #3
0
 async def request(self, addr, port, path, mtype, payload=''):
     '''Client request'''
     if self.context is None:
         self.context = await aiocoap.Context.create_client_context()
     req = aiocoap.Message(code=Code.POST, mtype=mtype, payload=payload)
     uri = 'coap://[%s]:%u%s' % (addr, port, path)
     req.set_request_uri(uri=uri, set_uri_host=False)
     logging.debug('tx: %s %s' % (uri, ThreadTLV.sub_tlvs_str(payload)))
     try:
         # Workaround for not waiting a response to a non-confirmable request
         if mtype == aiocoap.NON:
             try:
                 await asyncio.wait_for(self.context.request(req).response,
                                        timeout=0.001)
             except asyncio.TimeoutError:
                 return
         else:
             response = await self.context.request(req).response
     except:
         logging.warn('No response from %s', addr)
     else:
         logging.debug('rx: %s %s %s' %
                       (addr, response.code,
                        ThreadTLV.sub_tlvs_str(response.payload)))
         return response.payload
Example #4
0
    async def render_post(self, request):
        # Incoming TLVs parsing
        logging.info('in %s qry: %s' %
                     (URI.A_AQ, ThreadTLV.sub_tlvs_str(request.payload)))

        # Message not handled by Secondary BBR
        if not 'primary' in db.get('bbr_status'):
            return COAP_NO_RESPONSE

        # Find sub TLVs
        dua = None
        value = ThreadTLV.get_value(request.payload, TLV.A_TARGET_EID)
        if value:
            dua = ipaddress.IPv6Address(bytes(value))
        if not dua:
            return COAP_NO_RESPONSE

        # Don't process requests for different prefixes than DUA
        dua_prefix = ipaddress.IPv6Address(db.get('prefix').split('/')[0])
        if dua.packed[:8] != dua_prefix.packed[:8]:
            return COAP_NO_RESPONSE

        # Obtain the RLOC16 from the source's RLOC
        rloc16 = ipaddress.IPv6Address(request.remote.sockaddr[0]).packed[-2:]

        # TODO: mantain a cache
        # Propagate Address Query to the Backbone
        await DUA_HNDLR.send_bb_query(DUA_HNDLR.coap_client, dua, rloc16)

        return COAP_NO_RESPONSE
Example #5
0
    def _parse_net_data(self, tlvs):
        is_pbbr = False
        value = ThreadTLV.get_value(tlvs, TLV.D_NETWORK_DATA)
        if value:
            for tlv in ThreadTLV.sub_tlvs(value):
                type_ = tlv.type >> 1
                if type_ is TLV.N_SERVICE:
                    # Detect BBR Dataset encoding
                    if (tlv.value[0] >> 7 and tlv.value[1] is 1
                            and tlv.value[2] is 1):
                        server_tlvs = ThreadTLV.sub_tlvs(tlv.value[3:])
                        '''BBR is primary if there is only one Server TLV in the
                        BBR Dataset and the RLOC16 is the same as ours'''
                        if len(server_tlvs) == 1:
                            node_rloc = ipaddress.IPv6Address(
                                db.get('dongle_rloc')).packed
                            if node_rloc[14:16] == server_tlvs[0].value[0:2]:
                                is_pbbr = True
                elif type_ is TLV.N_PREFIX:
                    if db.get('prefix_dhcp') and not db.get('dhcp_aloc'):
                        # Detect DHCPv6 Agent ALOC
                        length = math.ceil(tlv.value[1] / 8)
                        byt_prefix = tlv.value[2:2 + length] + bytes(length)
                        int_prefix = int.from_bytes(byt_prefix,
                                                    byteorder='big')
                        str_prefix = ipaddress.IPv6Address(
                            int_prefix).compressed
                        str_prefix += '/%s' % tlv.value[1]
                        if str_prefix == db.get('prefix'):
                            # This is the prefix that we announced
                            for subtlv in ThreadTLV.sub_tlvs(
                                    tlv.value[(length + 2):]):
                                # TODO: verify that there is a Border Router TLV
                                # matching our RLOC16 and DHCP flag
                                if subtlv.type >> 1 is TLV.N_6LOWPAN_ID:
                                    cid = subtlv.value[0] & 0x0f
                                    rloc = db.get('dongle_rloc')
                                    aloc = list(
                                        ipaddress.IPv6Address(rloc).packed)
                                    aloc[14] = 0xfc
                                    aloc[15] = cid
                                    aloc = ipaddress.IPv6Address(
                                        bytes(aloc)).compressed
                                    db.set('dhcp_aloc', aloc)
                                    # Listen to the DHCP ALOC which is going to be
                                    # used by BR MTD children
                                    netmap(aloc, rloc)

        if is_pbbr:
            if 'primary' not in db.get('bbr_status'):
                logging.info('Setting this BBR as Primary')
            db.set('bbr_status', 'primary')
        else:
            if 'secondary' not in db.get('bbr_status'):
                logging.info('Setting this BBR as Secondary')
            db.set('bbr_status', 'secondary')
Example #6
0
    async def send_bb_query(self, client, dua, rloc16=None):
        dua_bytes = ipaddress.IPv6Address(dua).packed
        payload = ThreadTLV(t=TLV.A_TARGET_EID, l=16, v=dua_bytes).array()
        if rloc16:
            payload += ThreadTLV(t=TLV.A_RLOC16, l=2, v=rloc16).array()
        dst = '%s%%%s' % (db.get('all_domain_bbrs'), db.get('exterior_ifname'))

        logging.info(
            'out %s qry: %s' % (URI.B_BQ, ThreadTLV.sub_tlvs_str(payload)))

        await client.non_request(dst, DEFS.PORT_BB, URI.B_BQ, payload)
Example #7
0
    async def send_addr_err(self, dst, mtype, dua, eid_iid):
        'Thread 1.2 5.23.3.6.4'
        dua_bytes = ipaddress.IPv6Address(dua).packed
        payload = ThreadTLV(t=TLV.A_TARGET_EID, l=16, v=dua_bytes).array()
        payload += ThreadTLV(t=TLV.A_ML_EID, l=8,
                             v=bytes.fromhex(eid_iid)).array()

        logging.info('out %s ntf: %s' %
                     (URI.A_AE, ThreadTLV.sub_tlvs_str(payload)))

        await self.coap_client.request(dst, DEFS.PORT_MM, URI.A_AE, mtype,
                                       payload)
Example #8
0
    async def render_post(self, request):
        # Incoming TLVs parsing
        logging.info('in %s ntf: %s' %
                     (URI.B_BMR, ThreadTLV.sub_tlvs_str(request.payload)))

        # Primary BBR shouldn't receive this message
        if not 'secondary' in db.get('bbr_status'):
            return COAP_NO_RESPONSE
        '''
        # IPv6 Addresses TLV
        addrs = []
        value = ThreadTLV.get_value(request.payload, TLV.A_IPV6_ADDRESSES)
        if value:
            _, addrs, _ = Res_N_MR.parse_addrs(value)

        # Timeout TLV
        timeout = ThreadTLV.get_value(request.payload, TLV.A_TIMEOUT)

        # Register valid addresses
        if addrs and timeout:
            MCAST_HNDLR.reg_update(addrs, timeout)
        '''
        # TODO: mantain a Backup Multicast Listeners Table

        return COAP_NO_RESPONSE
Example #9
0
    async def send_addr_err(self, dua, eid_iid, dst_iid):
        'Thread 1.2 5.23.3.6.4'
        dua_bytes = ipaddress.IPv6Address(dua).packed
        payload = ThreadTLV(t=TLV.A_TARGET_EID, l=16, v=dua_bytes).array()
        payload += ThreadTLV(
            t=TLV.A_ML_EID, l=8, v=bytes.fromhex(eid_iid)).array()

        prefix_bytes = ipaddress.IPv6Address(
            db.get('dongle_prefix').split('/')[0]).packed
        dst = ipaddress.IPv6Address(prefix_bytes[0:8] + bytes.fromhex(dst_iid))

        logging.info(
            'out %s ntf: %s' % (URI.A_AE, ThreadTLV.sub_tlvs_str(payload)))

        await self.ntf_client.con_request(dst.compressed, DEFS.PORT_MM,
                                          URI.A_AE, payload)
Example #10
0
    async def render_post(self, request):
        # Incoming TLVs parsing
        logging.info('in %s ans: %s' %
                     (URI.B_BA, ThreadTLV.sub_tlvs_str(request.payload)))

        # Message not handled by Secondary BBR
        if not 'primary' in db.get('bbr_status'):
            return COAP_NO_RESPONSE
            # TODO: 9.4.8.2.9 Caching DUAs Advertised on the Backbone Link

        # Check if all required TLVs are present
        dua, eid, rloc16, elapsed, net_name = _get_b_ba_params(request.payload)
        if None in (dua, eid, elapsed, net_name):
            return COAP_NO_RESPONSE

        logging.info(
            'BB.ans: DUA=%s, ML-EID=%s, Time=%d, Net Name=%s, RLOC16=%s' %
            (dua, eid, elapsed, net_name, rloc16))

        # See if we have this DUA in our table
        src_rloc, entry_eid, _, dad = DUA_HNDLR.find_eid(dua)

        # 9.4.8.2.8 Receipt of Backbone Answer BB.ans
        if not rloc16:
            if not entry_eid:
                # Nothing to do for this EID
                return COAP_NO_RESPONSE
            elif dad is True:
                if entry_eid == eid:
                    # This DUA is still registered somewhere else, inform others
                    DUA_HNDLR.duplicated_found(dua, delete=False)
                    # Send PRO_BB.ntf
                    asyncio.ensure_future(DUA_HNDLR.send_pro_bb_ntf(dua))
                else:
                    # Duplication detected during DAD
                    DUA_HNDLR.duplicated_found(dua, delete=True)
                    # Send ADDR_ERR.ntf
                    asyncio.ensure_future(
                        DUA_HNDLR.send_addr_err(src_rloc, aiocoap.CON, dua,
                                                eid))

        else:
            # Send ADDR_NTF.ans
            bbr_rloc16 = ipaddress.IPv6Address(db.get('ncp_rloc')).packed[-2:]
            # If this BBR NCP originated the addr_qry, send addr_ntf to its
            # link local address
            if rloc16 == bbr_rloc16:
                dst = db.get('ncp_ll')
            else:
                dst = THREAD.get_rloc_from_short(db.get('ncp_prefix'), rloc16)
            asyncio.ensure_future(
                DUA_HNDLR.send_addr_ntf_ans(dst,
                                            dua,
                                            eid=eid,
                                            rloc16=bbr_rloc16,
                                            elapsed=elapsed))

        # ACK
        return aiocoap.Message(mtype=Type.ACK, code=Code.CHANGED)
Example #11
0
 def _parse_active_dataset(self, payload):
     # No response to /c/ag
     if payload is None or b'':
         db.set('dongle_secpol', '0')
     # Response present
     else:
         value = ThreadTLV.get_value(payload, TLV.C_CHANNEL)
         if value:
             db.set('dongle_channel', int(value[2]))
         value = ThreadTLV.get_value(payload, TLV.C_PAN_ID)
         if value:
             db.set('dongle_panid',
                    '0x' + ''.join('%02x' % byte for byte in value))
         value = ThreadTLV.get_value(payload, TLV.C_EXTENDED_PAN_ID)
         if value:
             db.set('dongle_xpanid',
                    '0x' + ''.join('%02x' % byte for byte in value))
         value = ThreadTLV.get_value(payload, TLV.C_NETWORK_NAME)
         if value:
             db.set('dongle_netname',
                    ''.join('%c' % byte for byte in value))
         value = ThreadTLV.get_value(payload,
                                     TLV.C_NETWORK_MESH_LOCAL_PREFIX)
         if value:
             prefix_bytes = bytes(value) + bytes(8)
             prefix_addr = ipaddress.IPv6Address(prefix_bytes)
             db.set('dongle_prefix', prefix_addr.compressed + '/64')
         value = ThreadTLV.get_value(payload, TLV.C_ACTIVE_TIMESTAMP)
         value = ThreadTLV.get_value(payload, TLV.C_SECURITY_POLICY)
         if value:
             db.set('dongle_secpol', value.hex())
Example #12
0
def coap_con_request():
    req_str = db.get('coap_req')
    if req_str:
        db.set('coap_req', '')
        req = json.loads(req_str.replace("'", '"'))
        dst = req.get('dst')[0]
        prt = int(req.get('prt')[0])
        uri = req.get('uri')[0]
        pld = bytes.fromhex(req.get('pld')[0])
        logging.info('out %s ntf: %s' % (uri, ThreadTLV.sub_tlvs_str(pld)))
        asyncio.ensure_future(DUA_HNDLR.ntf_client.con_request(dst, prt, uri, pld))
Example #13
0
    async def render_post(self, request):
        req_dua = None
        status = DMStatus.ST_UNSPEC

        # Incoming TLVs parsing
        logging.info('in %s req: %s' %
                     (URI.N_DR, ThreadTLV.sub_tlvs_str(request.payload)))

        # BBR Primary/Secondary status
        if 'primary' not in db.get('bbr_status'):
            status = DMStatus.ST_NOT_PRI
        elif len(DUA_HNDLR.entries) >= DUA_LIMIT:
            status = DMStatus.ST_RES_SHRT
        else:
            dua = None
            eid = None
            elapsed = 0

            # ML-EID TLV
            value = ThreadTLV.get_value(request.payload, TLV.A_ML_EID)
            if value:
                eid = value.hex()

            # Target EID TLV
            value = ThreadTLV.get_value(request.payload, TLV.A_TARGET_EID)
            if value:
                try:
                    req_dua = bytes(value)
                    dua = ipaddress.IPv6Address(req_dua).compressed
                except:
                    status = DMStatus.ST_INV_ADDR

            # Time Since Last Transaction TLV
            value = ThreadTLV.get_value(request.payload,
                                        TLV.A_TIME_SINCE_LAST_TRANSACTION)
            if value:
                elapsed = struct.unpack('!I', value)[0]

            if eid and dua:
                # Thread Harness may force response status
                if db.get('dua_next_status'):
                    status = int(db.get('dua_next_status'))
                    db.set('dua_next_status', '')
                elif DUA_HNDLR.reg_update(eid, dua, elapsed):
                    status = DMStatus.ST_SUCESS
                else:
                    # Duplication detected (resource shortage not contemplated)
                    status = DMStatus.ST_DUP_ADDR

        # Fill and return the response
        payload = ThreadTLV(t=TLV.A_STATUS, l=1, v=[status]).array()
        if req_dua:
            payload += ThreadTLV(t=TLV.A_TARGET_EID, l=16, v=req_dua).array()
        logging.info(
            'out %s rsp: %s' % (URI.N_DR, ThreadTLV.sub_tlvs_str(payload)))
        return aiocoap.Message(code=Code.CHANGED, payload=payload)
Example #14
0
    async def send_ntf_msg(self,
                           dst,
                           port,
                           uri,
                           mode,
                           dua,
                           eid,
                           elapsed,
                           rloc16=None):

        # Fill TLVs
        # Target EID TLV
        payload = ThreadTLV(t=TLV.A_TARGET_EID,
                            l=16,
                            v=ipaddress.IPv6Address(dua).packed).array()
        # ML-EID TLV
        payload += ThreadTLV(t=TLV.A_ML_EID, l=8, v=bytes.fromhex(eid)).array()
        # RLOV16 TLV
        if rloc16:
            payload += ThreadTLV(t=TLV.A_RLOC16, l=2, v=rloc16).array()
        # Time Since Last Transaction TLV
        payload += ThreadTLV(t=TLV.A_TIME_SINCE_LAST_TRANSACTION,
                             l=4,
                             v=struct.pack('!I', elapsed)).array()
        # Network Name TLV
        net_name = db.get('ncp_netname').encode()
        payload += ThreadTLV(t=TLV.A_NETWORK_NAME, l=len(net_name),
                             v=net_name).array()
        logging.info('out %s ans: %s' % (uri, ThreadTLV.sub_tlvs_str(payload)))

        if mode == aiocoap.CON:
            await self.coap_client.con_request(dst, port, uri, payload)
        else:
            await self.coap_client.non_request(dst, port, uri, payload)
Example #15
0
    async def render_post(self, request):
        # Incoming TLVs parsing
        logging.info('in %s qry: %s' %
                     (URI.B_BQ, ThreadTLV.sub_tlvs_str(request.payload)))

        # Message not handled by Secondary BBR
        if not 'primary' in db.get('bbr_status'):
            return COAP_NO_RESPONSE

        dua = None
        value = ThreadTLV.get_value(request.payload, TLV.A_TARGET_EID)
        if value:
            dua = ipaddress.IPv6Address(bytes(value)).compressed
        rloc16 = ThreadTLV.get_value(request.payload, TLV.A_RLOC16)

        if not dua:
            return COAP_NO_RESPONSE

        # Send BB.ans to the requester
        src_addr = request.remote.sockaddr[0]
        await DUA_HNDLR.send_bb_ans(src_addr, dua, rloc16=rloc16)

        return COAP_NO_RESPONSE
Example #16
0
    async def render_post(self, request):
        # Incoming TLVs parsing
        logging.info('in %s ans: %s' %
                     (URI.B_BA, ThreadTLV.sub_tlvs_str(request.payload)))

        # Message not handled by Secondary BBR
        if not 'primary' in db.get('bbr_status'):
            return COAP_NO_RESPONSE
            # TODO: 9.4.8.2.9 Caching DUAs Advertised on the Backbone Link

        # Check if all required TLVs are present
        dua, eid, _, elapsed, net_name = _get_b_ba_params(request.payload)
        if None in (dua, eid, elapsed, net_name):
            return COAP_NO_RESPONSE

        logging.info('PRO_BB.ntf: DUA=%s, ML-EID=%s, Time=%d, Net Name=%s' %
                     (dua, eid, elapsed, net_name))

        # Se if we have this DUA in our table
        _, entry_eid, entry_elapsed, _ = DUA_HNDLR.find_eid(dua)

        # 9.4.8.2.4 Receipt of Proactive Backbone Notification PRO_BB.ntf Multicast
        if not entry_eid:
            # TODO: 9.4.8.2.9 Caching DUAs Advertised on the Backbone Link
            return COAP_NO_RESPONSE
        elif entry_eid == eid:
            # Case 1: ML-EID IID matches
            if entry_elapsed < elapsed:
                # Send PRO_BB.ntf
                asyncio.ensure_future(DUA_HNDLR.send_pro_bb_ntf(dua))
            else:
                # This DUA has been registered somewhere else more recently
                # Remove silently
                DUA_HNDLR.remove_entry(dua=dua)
        else:
            # Case 2: ML-EID IID does not match (that is, duplicate address detected)
            DUA_HNDLR.remove_entry(dua=dua)
            # Send ADDR_ERR.ntf
            # Special KiBRA-KiNOS message that triggers a multicast ADDR_ERR.ntf
            asyncio.ensure_future(
                DUA_HNDLR.send_addr_err(db.get('ncp_rloc'), aiocoap.NON, dua,
                                        eid))

        # No ACK
        return COAP_NO_RESPONSE
Example #17
0
    async def periodic(self):
        # Check internet connection
        '''
        ping = int(
            str(
                bash('ping -c 1 -s 0 -I %s -q 8.8.8.8 > /dev/null ; echo $?' %
                     db.get('exterior_ifname'))))
        self.br_internet_access = 'online' if ping is 0 else 'offline'
        '''
        # Diags
        response = await self.petitioner.con_request(self.br_permanent_addr,
                                                     DEFS.PORT_MM, URI.D_DG,
                                                     PET_DIAGS)
        if not response:
            return

        # Save BR RLOC16
        rloc16 = ThreadTLV.get_value(response, TLV.D_MAC_ADDRESS)
        # TODO: update dongle_rloc and Linux address
        if rloc16:
            self.br_rloc16 = '%02x%02x' % (rloc16[0], rloc16[1])

        # More requests if changes found in the network or if some time has
        # passed
        current_time = _epoch_ms()
        if response != self.last_diags or current_time > (self.last_time +
                                                          NODE_INACTIVE_MS):
            self.last_diags = response
            self.last_time = current_time
            self._parse_diags(response)
            # Network Data get
            response = await self.petitioner.con_request(
                self.br_permanent_addr, DEFS.PORT_MM, URI.D_DG, PET_NET_DATA)
            self._parse_net_data(response)
            # Active Data Set get
            response = await self.petitioner.con_request(
                self.br_permanent_addr, DEFS.PORT_MM, URI.C_AG,
                PET_ACT_DATASET)
            self._parse_active_dataset(response)
            # Update nodes info
            # TODO: this is commented not to generate noise in the test captures
            '''
Example #18
0
    async def periodic(self):
        # Network visualization not needed in the Thread Harness
        if kibra.__harness__:
            return

        # Check internet connection
        access = NETWORK.internet_access()
        self.br_internet_access = 'online' if access else 'offline'

        # Diags
        response = await self.petitioner.con_request(self.br_permanent_addr,
                                                     THREAD.DEFS.PORT_MM,
                                                     THREAD.URI.D_DG,
                                                     PET_DIAGS)
        if not response:
            return

        # Save BR RLOC16
        rloc16 = ThreadTLV.get_value(response, THREAD.TLV.D_MAC_ADDRESS)
        if rloc16:
            self.br_rloc16 = '%02x%02x' % (rloc16[0], rloc16[1])

        # More requests if changes found in the network or if some time has
        # passed
        current_time = _epoch_ms()
        if response != self.last_diags or current_time > (self.last_time +
                                                          NODE_INACTIVE_MS):
            self.last_diags = response
            self.last_time = current_time
            self._parse_diags(response)
            # Update nodes info
            for rloc16 in self.nodes_list:
                if rloc16 == self.br_rloc16:
                    continue
                node_rloc = THREAD.get_rloc_from_short(db.get('ncp_prefix'),
                                                       rloc16)
                response = await self.petitioner.con_request(
                    node_rloc, THREAD.DEFS.PORT_MM, THREAD.URI.D_DG, PET_DIAGS)
                self._parse_diags(response)
                time.sleep(0.2)
            self._mark_old_nodes()
Example #19
0
    def _parse_diags(self, tlvs):
        now = _epoch_ms()
        json_node_info = {}
        json_node_info['roles'] = []
        json_node_info['routes'] = []
        json_node_info['addresses'] = []
        json_node_info['children'] = []
        leader_rloc16 = None

        # Address16 TLV
        value = ThreadTLV.get_value(tlvs, THREAD.TLV.D_MAC_ADDRESS)
        if value:
            json_node_info['rloc16'] = '%02x%02x' % (value[0], value[1])
            if value[1] == 0:
                json_node_info['roles'].append('router')
            else:
                json_node_info['roles'].append('end-device')
        else:
            return

        # Route 64 TLV
        value = ThreadTLV.get_value(tlvs, THREAD.TLV.D_ROUTE64)
        if value:
            router_id_mask = bin(int.from_bytes(value[1:9], byteorder='big'))
            router_ids = [
                63 - i for i, v in enumerate(router_id_mask[:1:-1]) if int(v)
            ][::-1]
            qualities = value[9:]
            for router_id in router_ids:
                if not qualities:
                    break
                router_quality = int(qualities.pop(0))
                q_out = (router_quality & 0xC0) >> 6
                q_in = (router_quality & 0x30) >> 4
                cost = router_quality & 0x0F
                if q_in is not 0 and q_out is not 0:
                    json_router_info = {}
                    json_router_info['id'] = '%u' % router_id
                    json_router_info['target'] = '%04x' % (router_id << 10)
                    json_router_info['inCost'] = '%u' % q_in
                    json_node_info['routes'].append(json_router_info)
                    if json_router_info['target'] not in self.nodes_list:
                        self.nodes_list.append(json_router_info['target'])
                elif q_in is 0 and q_out is 0 and cost is 1:
                    json_node_info['id'] = '%u' % router_id

        # Leader Data TLV
        value = ThreadTLV.get_value(tlvs, THREAD.TLV.D_LEADER_DATA)
        if value:
            leader_rloc16 = '%04x' % (value[7] << 10)

        # IPv6 Address List TLV
        value = ThreadTLV.get_value(tlvs, THREAD.TLV.D_IPV6_ADRESS_LIST)
        if value:
            addresses = [value[i:i + 16] for i in range(0, len(value), 16)]
            for addr in addresses:
                str_addr = ipaddress.IPv6Address(
                    int.from_bytes(addr, byteorder='big')).compressed
                json_node_info['addresses'].append(str_addr)

        # Now process child info, because json_node_info['rloc16'] is needed
        # Child Table TLV
        value = ThreadTLV.get_value(tlvs, THREAD.TLV.D_CHILD_TABLE)
        if value:
            children = [value[i:i + 3] for i in range(0, len(value), 3)]
            for child in children:
                json_child_info = {}
                rloc_high = bytearray.fromhex(json_node_info['rloc16'])[0]
                rloc_high |= child[0] & 0x01
                json_child_info['rloc16'] = '%02x%02x' % (rloc_high, child[1])
                json_child_info['timeout'] = '%u' % (
                    child[0] >> 3)  # TODO: convert to seconds
                json_node_info['children'].append(json_child_info)

        # Update other informations
        if leader_rloc16 and json_node_info['rloc16'] in leader_rloc16:
            json_node_info['roles'].append('leader')
        if json_node_info['rloc16'] in self.br_rloc16:
            json_node_info['roles'].append('border-router')
            json_node_info['internetAccess'] = self.br_internet_access
        json_node_info['active'] = 'yes'
        json_node_info['lastSeen'] = now

        # Add node to database
        self._add_node(json_node_info)

        # Add children to database
        for child in json_node_info['children']:
            independent_child = copy.deepcopy(child)
            independent_child['roles'] = ['end-device']
            independent_child['active'] = 'yes'
            independent_child['lastSeen'] = now
            self._add_node(independent_child)
Example #20
0
    async def render_post(self, request):
        status = DMStatus.ST_UNSPEC
        good_addrs = []
        bad_addrs = []

        # Incoming TLVs parsing
        in_pload = ThreadTLV.sub_tlvs_str(request.payload)
        logging.info('in %s req: %s' % (URI.N_MR, in_pload))

        # Thread Harness may force response status
        mlr_next_status = db.get('mlr_next_status')
        if kibra.__harness__ and mlr_next_status:
            status = int(mlr_next_status)
            db.set('mlr_next_status', '')
            # Include bad addresses for resources shortage status
            if status == DMStatus.ST_NOT_PRI:
                # IPv6 Addresses TLV
                addrs_value = ThreadTLV.get_value(request.payload,
                                                  TLV.A_IPV6_ADDRESSES)
                if addrs_value:
                    _, good, bad = Res_N_MR.parse_addrs(addrs_value)
                    bad_addrs.append(good)
                    bad_addrs.append(bad)
        # BBR Primary/Secondary status
        elif not 'primary' in db.get('bbr_status'):
            status = DMStatus.ST_NOT_PRI
        # Resources shortage
        elif len(MCAST_HNDLR.maddrs) >= MULTICAST_LIMIT:
            status = DMStatus.ST_RES_SHRT
        # Normal registration
        else:
            timeout = None
            comm_sid = None

            # IPv6 Addresses TLV
            addrs_value = ThreadTLV.get_value(request.payload,
                                              TLV.A_IPV6_ADDRESSES)
            if addrs_value:
                status, good_addrs, bad_addrs = Res_N_MR.parse_addrs(
                    addrs_value)

            # Timeout TLV
            timeout = ThreadTLV.get_value(request.payload, TLV.A_TIMEOUT)

            # Commissioner Session ID TLV
            comm_sid = ThreadTLV.get_value(request.payload,
                                           TLV.A_COMMISSIONER_SESSION_ID)

            # Register valid addresses
            if good_addrs:
                if timeout and comm_sid:
                    addr_tout = struct.unpack('!I', timeout)[0]
                else:
                    addr_tout = db.get('mlr_timeout') or DEFS.MIN_MLR_TIMEOUT
                reg_addrs = []
                reg_addrs_bytes = []
                for addr_bytes in good_addrs:
                    reg_addrs.append(
                        ipaddress.IPv6Address(addr_bytes).compressed)
                    reg_addrs_bytes += addr_bytes
                MCAST_HNDLR.reg_update(reg_addrs, addr_tout)

                # Send BMLR.ntf
                ipv6_addressses_tlv = ThreadTLV(t=TLV.A_IPV6_ADDRESSES,
                                                l=16 * len(good_addrs),
                                                v=reg_addrs_bytes)
                timeout_tlv = ThreadTLV(t=TLV.A_TIMEOUT,
                                        l=4,
                                        v=struct.pack('!I', addr_tout))
                net_name = db.get('ncp_netname').encode()
                network_name_tlv = ThreadTLV(t=TLV.A_NETWORK_NAME,
                                             l=len(net_name),
                                             v=net_name)
                payload = (ipv6_addressses_tlv.array() + timeout_tlv.array() +
                           network_name_tlv.array())
                dst = '%s%%%s' % (db.get('all_network_bbrs'),
                                  db.get('exterior_ifname'))
                await MCAST_HNDLR.coap_client.non_request(
                    dst, DEFS.PORT_BB, URI.B_BMR, payload)

        # Fill and return the response
        out_pload = ThreadTLV(t=TLV.A_STATUS, l=1, v=[status]).array()
        addrs_payload = []
        for elem in bad_addrs:
            addrs_payload += elem
        if bad_addrs:
            out_pload += ThreadTLV(t=TLV.A_IPV6_ADDRESSES,
                                   l=16 * len(bad_addrs),
                                   v=bytes(addrs_payload)).array()
        logging.info('out %s rsp: %s' %
                     (URI.N_MR, ThreadTLV.sub_tlvs_str(out_pload)))
        return aiocoap.Message(code=Code.CHANGED, payload=out_pload)
Example #21
0
import kibra.database as db
import kibra.iptables as IPTABLES
import kibra.network as NETWORK
import kibra.thread as THREAD
from kibra.coapclient import CoapClient
from kibra.ktask import Ktask
from kibra.tlv import ThreadTLV

VALUES = [
    THREAD.TLV.D_MAC_ADDRESS,
    THREAD.TLV.D_ROUTE64,
    THREAD.TLV.D_LEADER_DATA,
    THREAD.TLV.D_IPV6_ADRESS_LIST,
    THREAD.TLV.D_CHILD_TABLE,
]
PET_DIAGS = ThreadTLV(t=THREAD.TLV.D_TYPE_LIST, l=len(VALUES),
                      v=VALUES).array()

NODE_INACTIVE_MS = 90000

DIAGS_DB = {}


def _epoch_ms():
    return int(time.mktime(time.localtime()) * 1000)


class DIAGS(Ktask):
    def __init__(self):
        Ktask.__init__(
            self,
            name='diags',
Example #22
0
    async def render_post(self, request):
        req_dua = None
        status = DMStatus.ST_UNSPEC

        # Incoming TLVs parsing
        logging.info('in %s req: %s' %
                     (URI.N_DR, ThreadTLV.sub_tlvs_str(request.payload)))

        # BBR Primary/Secondary status
        if not 'primary' in db.get('bbr_status'):
            status = DMStatus.ST_NOT_PRI
        elif len(DUA_HNDLR.entries) >= DUA_LIMIT:
            status = DMStatus.ST_RES_SHRT
        else:
            dua = None
            eid = None
            elapsed = 0
            # Only used for sending ADDR_ERR.ntf in case of DAD finds duplicate
            src_rloc = request.remote.sockaddr[0]

            # ML-EID TLV
            value = ThreadTLV.get_value(request.payload, TLV.A_ML_EID)
            if value:
                eid = value.hex()

            # Target EID TLV
            value = ThreadTLV.get_value(request.payload, TLV.A_TARGET_EID)
            if value:
                try:
                    req_dua = bytes(value)
                    dua = ipaddress.IPv6Address(req_dua).compressed
                except:
                    status = DMStatus.ST_INV_ADDR

            # Time Since Last Transaction TLV
            value = ThreadTLV.get_value(request.payload,
                                        TLV.A_TIME_SINCE_LAST_TRANSACTION)
            if value:
                elapsed = struct.unpack('!I', value)[0]

            if eid and dua:
                # Thread Harness may force response status
                if kibra.__harness__ and eid == db.get('dua_next_status_eid'):
                    status = int(db.get('dua_next_status'))
                    db.set('dua_next_status_eid', '')
                    db.set('dua_next_status', '')
                    # DUA-TC-17 step 48
                    if status == 500:
                        return aiocoap.Message(code=Code.INTERNAL_SERVER_ERROR)
                elif DUA_HNDLR.reg_update(src_rloc, eid, dua, elapsed):
                    status = DMStatus.ST_SUCESS
                else:
                    # Duplication detected
                    status = DMStatus.ST_DUP_ADDR

        # Fill and return the response
        payload = ThreadTLV(t=TLV.A_STATUS, l=1, v=[status]).array()
        if req_dua:
            payload += ThreadTLV(t=TLV.A_TARGET_EID, l=16, v=req_dua).array()
        logging.info('out %s rsp: %s' %
                     (URI.N_DR, ThreadTLV.sub_tlvs_str(payload)))
        return aiocoap.Message(code=Code.CHANGED, payload=payload)
Example #23
0
    async def render_post(self, request):
        status = DMStatus.ST_UNSPEC
        good_addrs = []
        bad_addrs = []

        # Incoming TLVs parsing
        in_pload = ThreadTLV.sub_tlvs_str(request.payload)
        logging.info('in %s req: %s' % (URI.N_MR, in_pload))

        # BBR Primary/Secondary status
        if not 'primary' in db.get('bbr_status'):
            status = DMStatus.ST_NOT_PRI
        else:
            timeout = None
            comm_sid = None

            # IPv6 Addresses TLV
            addrs_value = ThreadTLV.get_value(request.payload,
                                              TLV.A_IPV6_ADDRESSES)
            if addrs_value:
                status, good_addrs, bad_addrs = Res_N_MR._parse_addrs(
                    addrs_value)

            # Timeout TLV
            timeout = ThreadTLV.get_value(request.payload, TLV.A_TIMEOUT)

            # Commissioner Session ID TLV
            comm_sid = ThreadTLV.get_value(request.payload,
                                           TLV.A_COMMISSIONER_SESSION_ID)

            # Register valid addresses
            if good_addrs:
                if timeout and comm_sid:
                    addr_tout = timeout
                else:
                    addr_tout = db.get('mlr_timeout') or DEFS.MIN_MLR_TIMEOUT
                reg_addrs = []
                reg_addrs_bytes = []
                for addr_bytes in good_addrs:
                    reg_addrs.append(
                        ipaddress.IPv6Address(addr_bytes).compressed)
                    reg_addrs_bytes += addr_bytes
                MCAST_HNDLR.reg_update(reg_addrs, addr_tout)
                # Send BMLR.ntf
                ipv6_addressses_tlv = ThreadTLV(
                    t=TLV.A_IPV6_ADDRESSES,
                    l=16 * len(good_addrs),
                    v=reg_addrs_bytes)
                timeout_tlv = ThreadTLV(
                    t=TLV.A_TIMEOUT, l=4, v=struct.pack('!I', addr_tout))
                payload = ipv6_addressses_tlv.array() + timeout_tlv.array()
                dst = '%s%%%s' % (db.get('all_network_bbrs'),
                                  db.get('exterior_ifname'))
                client = CoapClient()
                await client.non_request(dst, DEFS.PORT_BB, URI.B_BMR, payload)
                client.stop()

        # Fill and return the response
        out_pload = ThreadTLV(t=TLV.A_STATUS, l=1, v=[status]).array()
        addrs_payload = []
        for elem in bad_addrs:
            addrs_payload += elem
        if bad_addrs:
            out_pload += ThreadTLV(
                t=TLV.A_IPV6_ADDRESSES,
                l=16 * len(bad_addrs),
                v=bytes(addrs_payload)).array()
        logging.info(
            'out %s rsp: %s' % (URI.N_MR, ThreadTLV.sub_tlvs_str(out_pload)))
        return aiocoap.Message(code=Code.CHANGED, payload=out_pload)
Example #24
0
    async def render_post(self, request):
        # Incoming TLVs parsing
        logging.info('in %s ans: %s' %
                     (URI.B_BA, ThreadTLV.sub_tlvs_str(request.payload)))

        # Message not handled by Secondary BBR
        if not 'primary' in db.get('bbr_status'):
            return COAP_NO_RESPONSE

        dua = None
        rloc16 = None
        eid = None
        elapsed = None
        net_name = None
        value = ThreadTLV.get_value(request.payload, TLV.A_TARGET_EID)
        if value:
            dua = ipaddress.IPv6Address(bytes(value)).compressed
        value = ThreadTLV.get_value(request.payload, TLV.A_RLOC16)
        if value is not None:
            rloc16 = value.hex()
        value = ThreadTLV.get_value(request.payload, TLV.A_ML_EID)
        if value:
            eid = value.hex()
        value = ThreadTLV.get_value(request.payload,
                                    TLV.A_TIME_SINCE_LAST_TRANSACTION)
        if value:
            elapsed = struct.unpack('!I', value)[0]
        value = ThreadTLV.get_value(request.payload, TLV.A_NETWORK_NAME)
        if value:
            net_name = struct.unpack('%ds' % len(value), value)[0].decode()

        # Check if all required TLVs are present
        if None in (dua, eid, elapsed, net_name):
            return COAP_NO_RESPONSE

        logging.info(
            'BB.ans: DUA=%s, ML-EID=%s, Time=%d, Net Name=%s, RLOC16=%s' %
            (dua, eid, elapsed, net_name, rloc16))

        # See if its response to DAD or ADDR_QRY
        if not rloc16:
            entry_eid, entry_elapsed, dad = DUA_HNDLR.find_eid(dua)
            if not entry_eid:
                # Nothing to do for this EID
                return COAP_NO_RESPONSE
            elif dad is True:
                if entry_elapsed < elapsed:
                    # This DUA is still registered somewhere else
                    DUA_HNDLR.duplicated_found(dua, delete=False)
                    # Send PRO_BB.ntf
                    asyncio.ensure_future(DUA_HNDLR.send_pro_bb_ntf(dua))
                else:
                    # Duplication detected during DAD
                    DUA_HNDLR.duplicated_found(dua, delete=True)
                    # Send ADDR_ERR.ntf
                    asyncio.ensure_future(
                        DUA_HNDLR.send_addr_err(dua, entry_eid, eid))
            else:
                # This DUA has been registered somewhere else more recently
                # Remove silently
                DUA_HNDLR.remove_entry(dua=dua)
        else:
            # Send ADDR_NTF.ans
            bbr_rloc16 = ipaddress.IPv6Address(
                db.get('dongle_rloc')).packed[-2:]
            # If this BBR dongle originated the addr_qry, send addr_ntf to its
            # link local address
            if rloc16 == bbr_rloc16:
                dst = db.get('dongle_ll')
            else:
                dst = NETWORK.get_rloc_from_short(
                    db.get('dongle_prefix'), rloc16)
            asyncio.ensure_future(
                DUA_HNDLR.send_addr_ntf_ans(
                    dst, dua, eid=eid, rloc16=bbr_rloc16, elapsed=elapsed))

        # ACK
        if request.mtype == aiocoap.NON:
            return COAP_NO_RESPONSE
        else:
            return aiocoap.Message(mtype=Type.ACK, code=Code.CHANGED)
Example #25
0
import time

import kibra.database as db
import kibra.network as NETWORK
from kibra.coapclient import CoapClient
from kibra.iptables import netmap
from kibra.ktask import Ktask
from kibra.shell import bash
from kibra.thread import DEFS, TLV, URI
from kibra.tlv import ThreadTLV

VALUES = [
    TLV.D_MAC_ADDRESS, TLV.D_ROUTE64, TLV.D_LEADER_DATA,
    TLV.D_IPV6_ADRESS_LIST, TLV.D_CHILD_TABLE
]
PET_DIAGS = ThreadTLV(t=TLV.D_TYPE_LIST, l=len(VALUES), v=VALUES).array()

VALUES = [
    TLV.C_CHANNEL, TLV.C_PAN_ID, TLV.C_EXTENDED_PAN_ID, TLV.C_NETWORK_NAME,
    TLV.C_NETWORK_MESH_LOCAL_PREFIX, TLV.C_ACTIVE_TIMESTAMP,
    TLV.C_SECURITY_POLICY
]
PET_ACT_DATASET = ThreadTLV(t=TLV.C_GET, l=len(VALUES), v=VALUES).array()

PET_NET_DATA = ThreadTLV(t=TLV.D_TYPE_LIST, l=1,
                         v=[TLV.D_NETWORK_DATA]).array()

NODE_INACTIVE_MS = 90000

DIAGS_DB = {}