Exemplo n.º 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
Exemplo n.º 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
Exemplo n.º 3
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)
Exemplo n.º 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
Exemplo n.º 5
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())
Exemplo n.º 6
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')
Exemplo n.º 7
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
Exemplo n.º 8
0
    async def render_post(self, request):
        # Incoming TLVs parsing
        logging.info('in %s req: %s' %
                     (URI.B_BMR, ThreadTLV.sub_tlvs_str(request.payload)))

        # Primary BBR shouldn't receive this message
        if not 'primary' 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)

        return COAP_NO_RESPONSE
Exemplo n.º 9
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
            '''
Exemplo n.º 10
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()
Exemplo n.º 11
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)
Exemplo n.º 12
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)
Exemplo n.º 13
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)
Exemplo n.º 14
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)
Exemplo n.º 15
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)