def basic_check(self, received_testscript_msg_bytes): """ Basic check for all the LoRaWAN test steps. It verifies the MIC of the message and sets a flag if the received message if of a CONFIRMED_UP type (so an ACK could be sent to the DUT). """ super().basic_check( received_testscript_msg_bytes=received_testscript_msg_bytes) self.received_testscript_msg = flora_messages.GatewayMessage( json_ttm_str=received_testscript_msg_bytes.decode()) lorawan_msg = self.received_testscript_msg.parse_lorawan_message() mtype_str = lorawan_msg.mhdr.mtype_str # Register in flag if the received message needs Acknowdlegment knowdlege if mtype_str in ('CONFIRMED_UP', ): self.ctx_test_manager.device_under_test.message_to_ack = True else: self.ctx_test_manager.device_under_test.message_to_ack = False network_key = self.ctx_test_manager.device_under_test.loramac_params.nwkskey if mtype_str in ('JOIN_REQUEST', ): network_key = self.ctx_test_manager.device_under_test.appkey logger.info( f"Checking MIC using key {utils.bytes_to_text(network_key)}.") calculated_mic = lorawan_msg.calculate_mic(key=network_key) if not lorawan_msg.mic_bytes == calculated_mic: description_template = "Wrong MIC.\nKey: {key}\nMIC: {received_mic}\nCalculated: {calc}" raise lorawan_errors.MICError( description=description_template.format( key=utils.bytes_to_text(network_key), received_mic=utils.bytes_to_text(lorawan_msg.mic_bytes), calc=utils.bytes_to_text(calculated_mic)), test_case=self.ctx_test_manager.tc_name, step_name=self.name, last_message=self.received_testscript_msg.get_printable_str())
def raise_unexpected_response_error(self, last_message_bytes): self.received_testscript_msg = flora_messages.GatewayMessage( json_ttm_str=last_message_bytes.decode()) exeption_raised = test_errors.UnexpectedResponseError( description="Unexpected msg.", test_case=self.ctx_test_manager.tc_name, step_name=self.name, last_message=str(self.received_testscript_msg)) logger.debug(str(exeption_raised)) raise exeption_raised
def step_handler(self, ch, method, properties, body): """ Accepts a join request if it has the correct format and is not a replay (devnonce not previously used). """ if not self.received_testscript_msg: self.received_testscript_msg = flora_messages.GatewayMessage( json_ttm_str=body.decode()) lw_joinrequest = self.received_testscript_msg.parse_lorawan_message() if lw_joinrequest.mhdr.mtype_str == "JOIN_REQUEST": self.process_join_request(body_bytes=body) else: raise test_errors.UnexpectedResponseError( description="A Join Request message was expected.", step_name=self.name, last_message=self.received_testscript_msg.get_printable_str(), test_case=self.ctx_test_manager.tc_name)
def step_handler(self, ch, method, properties, body): if not self.received_testscript_msg: self.received_testscript_msg = flora_messages.GatewayMessage( json_ttm_str=body.decode()) frmpayload_response = tests_parameters.FRMPAYLOAD.TEST_DEACTIVATE end_device = self.ctx_test_manager.device_under_test lw_response = end_device.prepare_lorawan_data( frmpayload=frmpayload_response, fport=224) if self.default_rx1_window: json_nwk_response = self.received_testscript_msg.create_nwk_response_str( phypayload=lw_response, delay=end_device.loramac_params.rx1_delay, datr_offset=end_device.loramac_params.rx1_dr_offset) else: json_nwk_response = self.received_testscript_msg.create_nwk_response_str( phypayload=lw_response, delay=end_device.loramac_params.rx2_delay, data_rate=end_device.loramac_params.rx2_dr, frequency=end_device.loramac_params.rx2_frequency) self.send_downlink(routing_key=message_broker.routing_keys.toAgent + '.gw1', msg=json_nwk_response) received_lorawan = self.received_testscript_msg.parse_lorawan_message( ignore_format_errors=True) step_report = ui_reports.InputFormBody( title="{TC}: Print message".format( TC=self.ctx_test_manager.tc_name.upper()), tag_key=self.ctx_test_manager.tc_name, tag_value=" ") step_report.add_field( ui_reports.ParagraphField(name="Received in Step: {}".format( self.name), value=str(received_lorawan))) step_report.add_field( ui_reports.ParagraphField( name="Sent in Step: {}".format(self.name), value=str(lorawan_parser.LoRaWANMessage(lw_response)))) ui_publisher.display_on_gui( msg_str=str(step_report), key_prefix=message_broker.service_names.test_session_coordinator) self.print_step_info( sending=tests_parameters.FRMPAYLOAD.TEST_DEACTIVATE)
def step_handler(self, ch, method, properties, body): """ Pong message handler.""" if not self.received_testscript_msg: self.received_testscript_msg = flora_messages.GatewayMessage( json_ttm_str=body.decode()) received_lorawan = self.received_testscript_msg.parse_lorawan_message() appskey = self.ctx_test_manager.device_under_test.loramac_params.appskey received_frmpayload = received_lorawan.get_frmpayload_plaintext( key=appskey) mtype_str = received_lorawan.mhdr.mtype_str if mtype_str in ('UNCONFIRMED_UP', 'UNCONFIRMED_DOWN', 'CONFIRMED_UP', 'CONFIRMED_DOWN'): if (received_lorawan.macpayload.fport_int == 224 and received_frmpayload[0:1] == lorawan.lorawan_parameters.testing.TEST_CODE.PINGPONG): if not received_frmpayload == self.expected_bytes: raise lorawan_errors.EchoError( description="PONG {0} received when expecting {1}.". format(utils.bytes_to_text(received_frmpayload), utils.bytes_to_text(self.expected_bytes)), step_name=self.name, test_case=self.ctx_test_manager.tc_name, last_message=self.received_testscript_msg. get_printable_str(encryption_key=appskey)) else: # If it's a data message, but not a PONG, the FRMPayload is decrypted and showed in the GUI. raise test_errors.UnexpectedResponseError( description="Waiting for a PONG response.", step_name=self.name, last_message=self.received_testscript_msg. get_printable_str(encryption_key=appskey), test_case=self.ctx_test_manager.tc_name) else: raise test_errors.UnexpectedResponseError( description="Waiting for a PONG response.", step_name=self.name, last_message=self.received_testscript_msg.get_printable_str(), test_case=self.ctx_test_manager.tc_name)
def step_handler(self, ch, method, properties, body): """ Actions performed in this step of the test. """ if not self.received_testscript_msg: self.received_testscript_msg = flora_messages.GatewayMessage( json_ttm_str=body.decode()) frmpayload_response = tests_parameters.FRMPAYLOAD.TEST_ACT lw_received = self.received_testscript_msg.parse_lorawan_message() mtype_str = lw_received.mhdr.mtype_str if mtype_str == "JOIN_REQUEST": self.process_join_request(body_bytes=body) # If it's a TESTING MESSAGE (LoRaWAN data using port 224): elif (mtype_str in ('UNCONFIRMED_UP', 'CONFIRMED_UP') and not lw_received.macpayload.fport_int == 224): end_device = self.ctx_test_manager.device_under_test lw_response = end_device.prepare_lorawan_data( frmpayload=frmpayload_response, fport=224) if self.default_rx1_window: json_nwk_response = self.received_testscript_msg.create_nwk_response_str( phypayload=lw_response, delay=end_device.loramac_params.rx1_delay, datr_offset=end_device.loramac_params.rx1_dr_offset) else: json_nwk_response = self.received_testscript_msg.create_nwk_response_str( phypayload=lw_response, delay=end_device.loramac_params.rx2_delay, data_rate=end_device.loramac_params.rx2_dr, frequency=end_device.loramac_params.rx2_frequency) self.send_downlink( routing_key=message_broker.routing_keys.toAgent + '.gw1', msg=json_nwk_response) self.ctx_test_manager.ctx_test_session_coordinator.downlink_counter = 0 self.print_step_info(sending=frmpayload_response) else: raise test_errors.UnexpectedResponseError( description="Waiting for a data message (any port but 224).", step_name=self.name, last_message=self.received_testscript_msg.get_printable_str(), test_case=self.ctx_test_manager.tc_name)
def process_join_request(self, body_bytes): """ Process a Join Request message and sends the Join Accept in the default RX1 with the configured parameters. :param body_bytes: byte sequence of the Join Request. :return: None. """ if not self.received_testscript_msg: self.received_testscript_msg = flora_messages.GatewayMessage( json_ttm_str=body_bytes.decode()) lw_joinrequest = self.received_testscript_msg.parse_lorawan_message() devnonce = lw_joinrequest.macpayload.devnonce_bytes end_device = self.ctx_test_manager.device_under_test previous_rx1_dr = end_device.loramac_params.rx1_dr_offset previous_rx2_dr = end_device.loramac_params.rx2_dr jaccept_phypayload = self.ctx_test_manager.device_under_test.accept_join( devnonce=devnonce, dlsettings=self.accept_dlsettings, rxdelay=self.accept_rxdelay, cflist=self.accept_cflist) if self.default_rx1_window: json_nwk_response = self.received_testscript_msg.create_nwk_response_str( phypayload=jaccept_phypayload, delay=end_device.loramac_params.joinaccept_delay1, datr_offset=previous_rx1_dr) else: json_nwk_response = self.received_testscript_msg.create_nwk_response_str( phypayload=jaccept_phypayload, delay=end_device.loramac_params.joinaccept_delay2, data_rate=previous_rx2_dr, frequency=end_device.loramac_params.rx2_frequency) self.send_downlink(routing_key=message_broker.routing_keys.toAgent + '.gw1', msg=json_nwk_response) self.print_step_info( received_str=self.received_testscript_msg.get_printable_str(), sending=jaccept_phypayload, additional_message="Session Updated.\n" + str(self.ctx_test_manager.device_under_test))
def step_handler(self, ch, method, properties, body): """ Checks the downlink counter of an Activation Ok message.""" if not self.received_testscript_msg: self.received_testscript_msg = flora_messages.GatewayMessage( json_ttm_str=body.decode()) lw_message = self.received_testscript_msg.parse_lorawan_message() appskey = self.ctx_test_manager.device_under_test.loramac_params.appskey received_frmpayload = lw_message.get_frmpayload_plaintext(key=appskey) mtype_str = lw_message.mhdr.mtype_str if (mtype_str in ('UNCONFIRMED_UP', 'CONFIRMED_UP') and lw_message.macpayload.fport_int == 224 and len(received_frmpayload) == 2 and received_frmpayload[0:1] != lorawan.lorawan_parameters.testing.TEST_CODE.PINGPONG): self.check_act_ok(received_frmpayload=received_frmpayload) else: raise test_errors.UnexpectedResponseError( description="Waiting for an ACT OK with downlink counter.", step_name=self.name, last_message=self.received_testscript_msg.get_printable_str(), test_case=self.ctx_test_manager.tc_name)
def up_message_handler(self, body_str): received_testscript_msg = flora_messages.GatewayMessage( json_ttm_str=body_str) lorawan_msg = received_testscript_msg.parse_lorawan_message() logger.info("--------------------------------------------------------\n") logger.info(f"Received Uplink: {str(lorawan_msg)}") mtype_int = lorawan_msg.mhdr.mtype_int if lorawan_msg.mhdr.mhdr_bytes == lorawan_parameters.MHDR.JOIN_REQUEST: try: devnonce = lorawan_msg.macpayload.devnonce_bytes deveui_hex = utils.bytes_to_text(lorawan_msg.macpayload.deveui_bytes).upper() appeui_hex = utils.bytes_to_text(lorawan_msg.macpayload.appeui_bytes).upper() if not self.sessions_handler.is_registered(dev_eui_hex=deveui_hex, app_eui_hex=appeui_hex): logger.info(f"Device Not Registered: {deveui_hex}") return self.sessions_handler.process_otta_join( deveui_hex=deveui_hex, devnonce=devnonce, dlsettings=self.accept_dlsettings, rxdelay=self.accept_rxdelay, cflist=self.accept_cflist) jaccept_phypayload = self.sessions_handler.get_joinaccept_bytes( deveui_hex=deveui_hex) json_nwk_response = received_testscript_msg.create_nwk_response_str( phypayload=jaccept_phypayload, delay=lorawan_parameters.TIMING.JOIN_ACCEPT_DELAY1, datr_offset=lorawan_parameters.DR_OFFSET.RX1_DEFAULT) logger.info(f"Sending Join Accept: {str(json_nwk_response)}") self.downlink_mq_interface.send(routing_key=routing_keys.fromSchedulerToAgent, data=json_nwk_response) except scheduler_errors.DuplicatedNonce as dne: logger.info(f"Ignoring Duplicated nonce {devnonce}") elif lorawan_msg.mhdr.mhdr_bytes == lorawan_parameters.MHDR.UNCONFIRMED_UP: devaddrhex = utils.bytes_to_text(lorawan_msg.macpayload.fhdr.devaddr_bytes).upper() network_key_hex = self.sessions_handler.get_nwk_s_key_hex(dev_addr_hex=devaddrhex) if network_key_hex is None: logger.info(f"No active session for device: {devaddrhex}") return network_key = bytes.fromhex(network_key_hex) calculated_mic = lorawan_msg.calculate_mic(key=network_key) dev_eui_hex = self.sessions_handler.get_dev_eui_hex(dev_addr_hex=devaddrhex) if not lorawan_msg.mic_bytes == calculated_mic: logger.info( f"Wrong MIC. Expecting {calculated_mic}, Device {dev_eui_hex} ({devaddrhex}).") logger.info(f"MIC OK (NwkSKey: {utils.bytes_to_text(network_key)}, dev {dev_eui_hex})") frmpayload_command = bytes.fromhex( self.sessions_handler.get_command_hex(dev_addr_hex=devaddrhex)) lw_response = self.sessions_handler.prepare_lorawan_data(dev_eui_hex=dev_eui_hex, frmpayload=frmpayload_command) json_nwk_response = received_testscript_msg.create_nwk_response_str( phypayload=lw_response, delay=lorawan_parameters.TIMING.RECEIVE_DELAY1, datr_offset=lorawan_parameters.DR_OFFSET.RX1_DEFAULT) logger.info(f"Sending Downlink Data: {str(json_nwk_response)}") self.downlink_mq_interface.send(routing_key=routing_keys.fromSchedulerToAgent, data=json_nwk_response)