Ejemplo n.º 1
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
Ejemplo n.º 2
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)
Ejemplo n.º 3
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
Ejemplo n.º 4
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)
Ejemplo n.º 5
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
Ejemplo n.º 6
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
Ejemplo n.º 7
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)
Ejemplo n.º 8
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)
Ejemplo n.º 9
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))
Ejemplo n.º 10
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)
Ejemplo n.º 11
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)
Ejemplo 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
            # 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
Ejemplo n.º 13
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
Ejemplo n.º 14
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)
Ejemplo n.º 15
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)
Ejemplo n.º 16
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)
Ejemplo n.º 17
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)