def print_alert(alert):
    try: 
        alert_type = AlertType.find_one_by_code(alert.type)
        message= alert_type.code + '-' + alert_type.message
        dict_parameters= json.loads(alert.parameters)
        for param_name, param_value in dict_parameters.items():
            message= message.replace('{'+param_name+'}', str(param_value))
        message= message.replace('{'+'packet_id'+'}', str(alert.packet_id))
        message= message.replace('{'+'created_at'+'}', alert.created_at.strftime('%Y-%m-%d %H:%M'))
        collector= DataCollector.get(alert.data_collector_id)
        if collector:
            message= message.replace('{'+'collector.name'+'}', collector.name+' (ID '+str(collector.id)+')')
        logging.debug(message)
    except Exception as e:
        logging.error('Error printing alert: {0}'.format(e))
    def gateway_resource_usage(self, gateway, packet, policy_manager):
        gateway.npackets_up += 1 if packet.uplink else 0
        gateway.npackets_down += 1 if not packet.uplink else 0
        gateway.last_activity = packet.date

        # If gateway is reconnecting, then resolve every "not transmitting"
        # issue for this gateway, with reason_id 0 (problem solved automatically)
        if not gateway.connected:
            res_comment = "The gateway has transmitted again"
            issue_solved = Issue.solve(
                resolution_reason=res_comment,
                date=packet.date,
                issue_type="LAF-403",
                gateway_id=gateway.id,
            )
            if issue_solved:
                emit_alert(
                    "LAF-600",
                    packet,
                    gateway=gateway,
                    alert_solved_type="LAF-403",
                    alert_solved=AlertType.find_one_by_code("LAF-403").name,
                    resolution_reason=res_comment)

        gateway.connected = True

        # Update activity_freq (which is the time between packets)
        time_diff = (packet.date -
                     self.gateway_stats[gateway.id]["last_date"]).seconds
        if gateway.activity_freq:
            maw = policy_manager.get_parameters(
                "LAF-102")["moving_average_weight"]
            gateway.activity_freq = maw * gateway.activity_freq + (
                1 - maw) * time_diff
        else:
            gateway.activity_freq = time_diff
def process_packet(packet, policy):
    result = ""
    key_tested = False
    global device_auth_obj
    global dontGenerateKeys
    global keys
    global hours_betweeen_bruteforce_trials
    device_auth_obj = None

    if packet.m_type not in ("JoinRequest", "JoinAccept"): return
    if not policy.is_enabled("LAF-009"): return
    if packet.dev_eui is None: return

    if packet.m_type == "JoinRequest":

        # device_obj = ObjectInstantiator.get_or_error_device(packet)
        device_obj = Device.find_with(
            dev_eui=packet.dev_eui, data_collector_id=packet.data_collector_id)
        if not device_obj: return

        # Before cracking with many different keys, try with a PotentialAppKey previously found. In case this key is valid, we are pretty sure that is the correct AppKey
        device_auth_obj = DeviceAuthData.find_one_by_device_id(device_obj.id)
        if device_auth_obj and extractMIC(
                device_auth_obj.join_request) != packet.mic:
            pot_app_keys = [
                pk.app_key_hex for pk in
                PotentialAppKey.find_all_by_device_auth_id(device_auth_obj.id)
            ]

            if len(pot_app_keys) > 0:
                correct_app_keys = LorawanWrapper.testAppKeysWithJoinRequest(
                    keys=[bytes(pk, encoding='utf-8') for pk in pot_app_keys],
                    data=packet.data,
                    dontGenerateKeys=True).split()
                correct_app_keys = [
                    ak.upper().rstrip() for ak in correct_app_keys
                ]
                key_tested = True

                pk_to_remove = [
                    pk for pk in pot_app_keys if pk not in correct_app_keys
                ]
                PotentialAppKey.delete_keys(
                    device_auth_data_id=device_auth_obj.id, keys=pk_to_remove)

                if len(correct_app_keys) > 1:
                    logging.warning(
                        f"Found more than one possible keys for the device {packet.dev_eui}."
                        +
                        f" One of them should be the correct. Check it manually. Keys: {correct_app_keys}"
                    )
                elif len(correct_app_keys) == 1:
                    # AppKey found!!
                    device_auth_obj.second_join_request_packet_id = packet.id
                    device_auth_obj.second_join_request = packet.data
                    device_auth_obj.app_key_hex = correct_app_keys[0]

                    emit_alert(
                        "LAF-009",
                        packet,
                        device=device_obj,
                        device_auth_id=device_auth_obj.id,
                        app_key=correct_app_keys[0],
                        packet_id_1=device_auth_obj.join_request_packet_id,
                        packet_type_1="JoinRequest",
                        packet_type_2="JoinRequest")
                    return

        # Check if the DeviceAuthData wasn't already generated
        never_bruteforced = False

        if device_auth_obj is None:
            never_bruteforced = True
            try:
                device_auth_obj = DeviceAuthData(
                    device_id=device_obj.id,
                    data_collector_id=packet.data_collector_id,
                    organization_id=packet.organization_id,
                    join_request=packet.data,
                    created_at=packet.date,
                    join_request_packet_id=packet.id)
                device_auth_obj.save()
            except Exception as exc:
                logging.error(
                    "Error trying to save DeviceAuthData at JoinRequest: {0}".
                    format(exc))

        # Check when was the last time it was bruteforced and
        # Try checking with the keys dictionary, the keys generated on the fly
        # and the keys uploaded by the corresponding organization
        elapsed = packet.date - device_auth_obj.created_at  # Time in seconds

        if elapsed > datetime.timedelta(hours=hours_betweeen_bruteforce_trials
                                        ) or never_bruteforced or True:

            result = LorawanWrapper.testAppKeysWithJoinRequest(
                keys, packet.data, dontGenerateKeys)
            organization_keys = [
                bytes(app_key.key.upper(), encoding='utf-8')
                for app_key in AppKey.get_with(
                    organization_id=packet.organization_id)
            ]
            result_org_keys = LorawanWrapper.testAppKeysWithJoinRequest(
                organization_keys, packet.data, dontGenerateKeys=True)
            if result_org_keys != "":
                result += " " + result_org_keys

            key_tested = True

            # Update the last time it was bruteforced
            device_auth_obj.created_at = packet.date

            # If potential keys found...
            if result != "":

                device_auth_obj.join_request_packet_id = packet.id
                device_auth_obj.join_request = packet.data

                # Split string possibly containing keys separated by spaces
                candidate_keys_array = set(result.split())

                for hex_key in candidate_keys_array:
                    try:
                        # Save the potential app key if it does not exists already in the DB
                        potential_key_obj = PotentialAppKey.get_by_device_auth_data_and_hex_app_key(
                            device_auth_data_id=device_auth_obj.id,
                            app_key_hex=hex_key.upper())
                        if not potential_key_obj:
                            potential_key_obj = PotentialAppKey(
                                app_key_hex=hex_key.upper(),
                                organization_id=packet.organization_id,
                                last_seen=packet.date,
                                packet_id=packet.id,
                                device_auth_data_id=device_auth_obj.id)
                            potential_key_obj.save()
                    except Exception as exc:
                        logging.error(
                            "Error trying to save PotentialAppKey at JoinRequest: {0}"
                            .format(exc))

    elif packet.m_type == "JoinAccept" and packet.data is not None:

        last_seconds_date = packet.date - datetime.timedelta(seconds=5)

        try:
            organization_keys = PotentialAppKey.find_all_by_organization_id_after_datetime(
                packet.organization_id, last_seconds_date)

            # Return if no JR keys were found
            if len(organization_keys) != 0:
                keys_array = list()
                for pk in organization_keys:
                    # Fetch keys in byte format. Needed by ctypes
                    keys_array.append(
                        bytes(pk.app_key_hex.rstrip().upper(),
                              encoding='utf-8'))

                # Remove possible duplicates in array
                keys_array = list(dict.fromkeys(keys_array))

                result = LorawanWrapper.testAppKeysWithJoinAccept(
                    keys_array, packet.data, True)
                key_tested = True
        except Exception as es:
            logging.error(f"Error trying to bforce JA: {es}")

        if result != "":

            # Clean the key string
            result = result.rstrip().upper()

            for potential_key_obj in organization_keys:
                if potential_key_obj.app_key_hex.upper() == result:
                    device_auth_obj = DeviceAuthData.find_one_by_id(
                        potential_key_obj.device_auth_data_id)
                    break

            if device_auth_obj:
                #Add missing data
                device_auth_obj.join_accept = packet.data
                device_auth_obj.join_accept_packet_id = packet.id
                device_auth_obj.app_key_hex = result

                # Add session keys
                device_auth_obj = deriveSessionKeys(device_auth_obj, result)

                # Get the device to get dev_eui
                device_obj = Device.get(device_auth_obj.device_id)

                # Get DevAddr from JA packet
                dev_addr = LorawanWrapper.getDevAddr(result, packet.data)

                emit_alert("LAF-009",
                           packet,
                           device=device_obj,
                           device_auth_id=device_auth_obj.id,
                           app_key=result,
                           dev_addr=dev_addr,
                           packet_id_1=device_auth_obj.join_request_packet_id,
                           packet_type_1="JoinRequest",
                           packet_type_2="JoinAccept")
            else:
                logging.error(
                    "Cracked a JoinAccept but no device_auth object found")

    if key_tested and len(result) == 0:
        res_comment = "The AppKey was modified"
        issue_solved = Issue.solve(
            resolution_reason=res_comment,
            date=packet.date,
            issue_type="LAF-009",
            device_id=device_obj.id,
        )
        if issue_solved:
            emit_alert("LAF-600",
                       packet,
                       device=device_obj,
                       alert_solved_type="LAF-009",
                       alert_solved=AlertType.find_one_by_code("LAF-009").name,
                       resolution_reason=res_comment)
Exemple #4
0
    def __call__(self, packet, device_session, device, gateway, policy):
        if self.last_gc is None: self.last_gc = packet.date
        if (packet.date - self.last_gc).seconds > 3600:
            self.garbage_collection(today=packet.date)

        if (device is None or gateway is None or packet.f_count is None
                or not device.is_otaa):
            return  # Can't be done anything without these data or with an ABP device

        # Used to identify a "connection" to check. Here for connection we are
        # talking about the flow of packets between a gateway and a device
        # in the context of a stablished device_session.
        lpacket_uid = (device.id, gateway.id)
        if lpacket_uid not in self.last_packet:  # first packet for this device
            self.last_packet[lpacket_uid] = {
                'f_count': packet.f_count,
                'dev_addr': packet.dev_addr,
                'has_joined': packet.m_type in ["JoinRequest", "JoinAccept"],
                'date': packet.date
            }
            return

        if (  # The device has regenerated the session
                packet.m_type in ["JoinRequest", "JoinAccept"] or
            (packet.dev_addr is not None and
             self.last_packet[lpacket_uid]["dev_addr"] != packet.dev_addr)):
            res_comment = "The device has regenerated the session"
            issue_solved = Issue.solve(
                resolution_reason=res_comment,
                date=packet.date,
                issue_type="LAF-011",
                device_id=device.id,
            )
            if issue_solved:
                emit_alert(
                    "LAF-600",
                    packet,
                    device=device,
                    alert_solved_type="LAF-011",
                    alert_solved=AlertType.find_one_by_code("LAF-011").name,
                    resolution_reason=res_comment)
            self.last_packet[lpacket_uid]["has_joined"] = True
            return

        if (packet.m_type not in ["UnconfirmedDataUp", "ConfirmedDataUp"]
                or packet.dev_addr is None):
            return  # The packet is not important for the rest of this check

        if (  # The counter has restarted
                lpacket_uid in self.last_packet and packet.f_count == 0
                and self.last_packet[lpacket_uid]["f_count"] > 65500):
            if (  # It hasn't regenerated the session
                    not self.last_packet[lpacket_uid]["has_joined"]
                    and policy.is_enabled("LAF-011")):
                emit_alert("LAF-011",
                           packet,
                           device=device,
                           device_session=device_session,
                           gateway=gateway,
                           counter=device_session.up_link_counter,
                           new_counter=packet.f_count,
                           prev_packet_id=device_session.last_packet_id)
            # After the restart the join request was "used", for another restart
            # we need another JR. Therefore, the flag is set to false.
            self.last_packet[lpacket_uid]["has_joined"] = False

        self.last_packet[lpacket_uid]['f_count'] = packet.f_count
        self.last_packet[lpacket_uid]['dev_addr'] = packet.dev_addr
        self.last_packet[lpacket_uid]['date'] = packet.date
    def device_resource_usage(self, device, packet, policy_manager):
        if packet.uplink and packet.f_count == self.device_stats[
                device.id]["last_fcount"]:
            if (
                packet.gateway in self.device_stats[device.id]['last_fcount_gtw'] and \
                packet.f_count == self.device_stats[device.id]['last_fcount_gtw'][packet.gateway]
            ):
                packet.is_retransmission = True
            else:
                # Same packet came from another gateway. Not adding it to last_fcount_gtw
                # in order to count retransmissions of this packet only in one gateway
                packet.is_repeated = True
            return  # Repeated or retransmitted uplink packet

        if not packet.uplink and packet.f_count == self.device_stats[
                device.id]["last_fcount_down"]:
            packet.is_repeated = True
            return  # Repeated downlink packet

        device.npackets_up += 1 if packet.uplink else 0
        device.npackets_down += 1 if not packet.uplink else 0

        if packet.uplink and self.device_stats[device.id]["last_fcount"]:
            device.last_activity = packet.date

            # If device is reconnecting, then resolve every "not transmitting"
            # issue for this device, with reason_id 0 (problem solved automatically)
            if not device.connected:
                res_comment = "The device has transmitted again"
                issue_solved = Issue.solve(
                    resolution_reason=res_comment,
                    date=packet.date,
                    issue_type="LAF-401",
                    device_id=device.id,
                )
                if issue_solved:
                    emit_alert(
                        "LAF-600",
                        packet,
                        device=device,
                        alert_solved_type="LAF-401",
                        alert_solved=AlertType.find_one_by_code(
                            "LAF-401").name,
                        resolution_reason="The device has transmitted again")

            device.connected = True

            last_fcount = self.device_stats[device.id]["last_fcount"]
            count_diff = int(packet.f_count - last_fcount) % (2**16)

            # The counter changed a lot, probably the session was restarted
            if count_diff > 64 or count_diff < 1:
                del self.device_stats[device.id]
                return False

            # Update activity_freq (which is the time between packets) and activity_freq_variance
            most_recent_date = (
                max(self.device_stats[device.id]["last_date"].values())
            ) if self.device_stats[device.id].get("last_date") else packet.date
            time_diff = (packet.date - most_recent_date).seconds / count_diff
            if device.activity_freq:
                freq_diff = time_diff - device.activity_freq
                maw = policy_manager.get_parameters(
                    "LAF-401")["moving_average_weight"]
                device.activity_freq = device.activity_freq + (1 -
                                                               maw) * freq_diff
                device.activity_freq_variance = maw * device.activity_freq_variance + (
                    1 - maw) * (freq_diff**2)
            else:
                device.activity_freq = time_diff
                device.activity_freq_variance = 0

            # Update the number of packets lost
            packet.npackets_lost_found = count_diff - 1

            # TODO: this stat update should be removed, after remove it form the back end
            if device.npackets_lost:
                maw = 0.9
                device.npackets_lost = maw * device.npackets_lost + (
                    1 - maw) * (count_diff - 1)
            else:
                device.npackets_lost = count_diff - 1

            # Update the max (from all the gateways) rssi of the device
            if packet.rssi is not None:
                if packet.gateway in self.device_stats[device.id]["rssi"]:
                    maw = policy_manager.get_parameters(
                        "LAF-100")["moving_average_weight"]
                    self.device_stats[device.id]["rssi"][packet.gateway] = \
                        maw *  self.device_stats[device.id]["rssi"][packet.gateway] + \
                        (1 - maw) * packet.rssi
                else:
                    self.device_stats[device.id]["rssi"][
                        packet.gateway] = packet.rssi

            try:
                device.max_rssi = max(
                    self.device_stats[device.id]["rssi"].values())
            except:
                pass

            # Update the max lsnr value of the device, considering all the gateways
            if packet.lsnr is not None:
                if packet.gateway in self.device_stats[device.id]["lsnr"]:
                    maw = policy_manager.get_parameters(
                        "LAF-102")["moving_average_weight"]
                    self.device_stats[device.id]["lsnr"][packet.gateway] = \
                        maw *  self.device_stats[device.id]["lsnr"][packet.gateway] + \
                        (1 - maw) * packet.lsnr
                else:
                    self.device_stats[device.id]["lsnr"][
                        packet.gateway] = packet.lsnr

            try:
                device.max_lsnr = max(
                    self.device_stats[device.id]["lsnr"].values())
            except:
                pass

            # Update size of payload. The payload size is in bytes.
            device.payload_size = self.get_len_bytes_base_64(packet.data)
        return True
Exemple #6
0
    def __call__(self, packet, device_session, device, gateway, policy):
        if self.last_gc is None: self.last_gc = packet.date
        if (packet.date - self.last_gc).seconds > 3600:
            self.garbage_collection(today=packet.date)

        if (device is None or gateway is None or packet.f_count is None):
            return  # Can't be done anything without these data.

        if device.is_otaa:
            return  # It's already detected as OTAA, nothing to do.

        # Used to identify a "connection" to check. Here for connection we are
        # talking about the flow of packets between a gateway and a device in
        # in the context of a stablished device_session.
        lpacket_uid = (device.id, gateway.id)

        if (  # This indicates that the device is OTAA
                packet.m_type in ["JoinRequest", "JoinAccept"] or
            (packet.dev_addr is not None and lpacket_uid in self.last_packet
             and
             self.last_packet[lpacket_uid]["dev_addr"] != packet.dev_addr)):
            res_comment = "The device has sent a join request"
            issue_solved = Issue.solve(
                resolution_reason=res_comment,
                date=packet.date,
                issue_type="LAF-006",
                device_id=device.id,
            )
            if issue_solved:
                emit_alert(
                    "LAF-600",
                    packet,
                    device=device,
                    alert_solved_type="LAF-006",
                    alert_solved=AlertType.find_one_by_code("LAF-006").name,
                    resolution_reason=res_comment)
            device.is_otaa = True
            return

        if packet.m_type in ["UnconfirmedDataUp", "ConfirmedDataUp"
                             ] and packet.dev_addr is not None:
            if (  # This indicates that the device is ABP
                    lpacket_uid in self.last_packet
                    and policy.is_enabled("LAF-006") and packet.f_count == 0
                    and self.last_packet[lpacket_uid]["f_count"] > 0
                    and self.last_packet[lpacket_uid]["dev_addr"]
                    == packet.dev_addr):
                emit_alert("LAF-006",
                           packet,
                           device=device,
                           device_session=device_session,
                           gateway=gateway,
                           counter=self.last_packet[lpacket_uid]["f_count"],
                           new_counter=packet.f_count)
                device.is_otaa = False

            # For each "connection" (see definition in previous comment), we save
            # the counter and dev_addr.
            self.last_packet[lpacket_uid] = {
                'f_count': packet.f_count,
                'dev_addr': packet.dev_addr,
                'date': packet.date
            }
Exemple #7
0
def process_packet(packet, policy):
    chrono.start("total")

    chrono.start("dev id")
    packet = device_identifier(packet)
    chrono.stop()

    chrono.start("search objs")
    gateway = Gateway.find_with(gw_hex_id=packet.gateway,
                                data_collector_id=packet.data_collector_id)
    device = Device.find_with(dev_eui=packet.dev_eui,
                              data_collector_id=packet.data_collector_id)
    device_session = DeviceSession.find_with(
        dev_addr=packet.dev_addr, data_collector_id=packet.data_collector_id)
    chrono.stop()

    chrono.start("instantiation")
    ## Gateway instantiation
    if gateway is None and packet.gateway:
        gateway = Gateway.create_from_packet(packet)
        gateway.save()
        if policy.is_enabled("LAF-402"):
            emit_alert("LAF-402", packet, gateway=gateway)

    ## Device instantiation
    if device is None and packet.dev_eui:
        device = Device.create_from_packet(packet)
        device.save()

    ## Session instantiation
    if device_session is None and packet.dev_addr:
        device_session = DeviceSession.create_from_packet(packet)
        device_session.save()

        if device:
            issue_solved = Issue.solve(
                resolution_reason="Device connected",
                date=packet.date,
                issue_type="LAF-404",
                device_id=device.id,
            )
            if issue_solved:
                emit_alert(
                    "LAF-600",
                    packet,
                    device=device,
                    alert_solved_type="LAF-404",
                    alert_solved=AlertType.find_one_by_code("LAF-404").name,
                    resolution_reason="Device connected")

    ## Emit new device alert if it is the first data packet
    if device and device_session and device.pending_first_connection:
        device.pending_first_connection = False
        session.commit()
        if policy.is_enabled("LAF-400"):
            emit_alert("LAF-400",
                       packet,
                       device=device,
                       gateway=gateway,
                       device_session=device_session,
                       number_of_devices=DataCollector.number_of_devices(
                           packet.data_collector_id))

    chrono.stop()

    ## Associations
    chrono.start("gw2dev")
    if device and gateway:
        GatewayToDevice.associate(gateway.id, device.id)
    chrono.stop()

    ## Associate device with device_session
    chrono.start("dev2sess")
    if device and device_session:
        if device_session.device_id is not None and device.id != device_session.device_id and policy.is_enabled(
                "LAF-002"):
            conflict_device_obj = Device.get(device_session.device_id)
            emit_alert("LAF-002",
                       packet,
                       device=device,
                       device_session=device_session,
                       gateway=gateway,
                       old_dev_eui=conflict_device_obj.dev_eui,
                       new_dev_eui=device.dev_eui,
                       prev_packet_id=device_session.last_packet_id)
        if device_session.device_id is None or device.id != device_session.device_id:
            device_session.device_id = device.id
            session.commit()
    chrono.stop()

    chrono.start("guesses")
    ## If the packet does not have a gateway, try to guess from the device
    if gateway is None and device:
        possible_gateways = GatewayToDevice.associated_with(device.id)
        if len(possible_gateways) == 1:
            gateway = Gateway.get(possible_gateways[0])

    ## If the packet does not have a dev_eui, try to guess from the device_session
    if device is None and device_session and device_session.device_id:
        device = Device.get(device_session.device_id)
    chrono.stop()

    chrono.start("checks")
    ## Check alert

    ## LAF-404
    # The data_collector and dev_eui is used as UID to count JRs.
    if packet.dev_eui:
        if packet.m_type == 'JoinRequest':
            # If the previos packet was also a JR, then it is considered as failed
            if jr_counters[(packet.data_collector_id, packet.dev_eui)] > 0:
                packet.failed_jr_found = True
            jr_counters[(packet.data_collector_id, packet.dev_eui)] += 1
        else:
            jr_counters[(packet.data_collector_id, packet.dev_eui)] = 0

        if (policy.is_enabled("LAF-404")
                and jr_counters[(packet.data_collector_id, packet.dev_eui)] >
                policy.get_parameters("LAF-404")["max_join_request_fails"]):
            if device:
                emit_alert("LAF-404", packet, device=device, gateway=gateway)
            else:
                log.warning(
                    f"Device not found in DB when LAF-404 detected for device {packet.dev_eui} from data collector {packet.data_collector_id}"
                )

    ## Check alert LAF-010
    if gateway and policy.is_enabled("LAF-010"):
        location_accuracy = policy.get_parameters(
            "LAF-010")["location_accuracy"]
        location_change = gateway.distance_to(packet.latitude,
                                              packet.longitude)
        if location_change > location_accuracy:
            emit_alert("LAF-010",
                       packet,
                       gateway=gateway,
                       old_latitude=gateway.location_latitude,
                       old_longitude=gateway.location_longitude,
                       new_latitude=packet.latitude,
                       new_longitude=packet.longitude)

    if packet.m_type == "JoinRequest" and device:
        # Check if DevNonce is repeated and save it
        prev_packet_id = DevNonce.saveIfNotExists(packet.dev_nonce, device.id,
                                                  packet.id)
        if prev_packet_id and device.has_joined:
            device.repeated_dev_nonce = True

            if policy.is_enabled("LAF-001"):
                emit_alert("LAF-001",
                           packet,
                           device=device,
                           gateway=gateway,
                           dev_nonce=packet.dev_nonce,
                           prev_packet_id=prev_packet_id)
        elif not (prev_packet_id):
            device.has_joined = False

    is_uplink_packet = packet.m_type in [
        "UnconfirmedDataUp", "ConfirmedDataUp"
    ]
    if device_session and is_uplink_packet and packet.f_count is not None:
        # Check counter
        if packet.f_count == 0:
            # Make sure we have processed at least one packet for this device in this run before firing the alarm
            if device_session.id in last_uplink_mic:
                # Skip if received the same counter as previous packet and mics are equal
                if not (packet.f_count == device_session.up_link_counter
                        and last_uplink_mic[device_session.id] == packet.mic):

                    if device and device.has_joined:
                        # The counter = 0  is valid, then change the has_joined flag
                        device.has_joined = False
                    device_session.reset_counter += 1
                    session.commit()
        last_uplink_mic[device_session.id] = packet.mic

    # Check alert LAF-007
    check_duplicated_session(packet=packet,
                             device_session=device_session,
                             device=device,
                             gateway=gateway,
                             policy=policy)
    # CHeck alert LAF-011
    check_session_regeneration(packet=packet,
                               device_session=device_session,
                               device=device,
                               gateway=gateway,
                               policy=policy)
    # Check alert LAF-006
    abp_detector(packet=packet,
                 device_session=device_session,
                 device=device,
                 gateway=gateway,
                 policy=policy)
    # Check alert LAF-103
    check_retransmissions(packet=packet,
                          device_session=device_session,
                          device=device,
                          gateway=gateway,
                          policy_manager=policy)
    # Check alert LAF-101
    check_packets_lost(packet=packet,
                       device_session=device_session,
                       device=device,
                       gateway=gateway,
                       policy_manager=policy)

    chrono.stop()

    chrono.start("update")

    resource_meter(device, packet, policy)
    resource_meter(gateway, packet, policy)
    resource_meter.gc(packet.date)

    if gateway: gateway.update_state(packet)
    if device_session: device_session.update_state(packet)
    if device: device.update_state(packet)

    ## Check alert LAF-100
    if (
        device and device.max_rssi is not None and \
        policy.is_enabled("LAF-100") and \
        device.max_rssi < policy.get_parameters("LAF-100")["minimum_rssi"]
    ):
        emit_alert("LAF-100",
                   packet,
                   device=device,
                   device_session=device_session,
                   gateway=gateway,
                   rssi=device.max_rssi)

    ## Check alert LAF-102
    if(
        device and \
        device.max_lsnr is not None and \
        policy.is_enabled("LAF-102") and \
        device.max_lsnr < policy.get_parameters("LAF-102")["minimum_lsnr"]
    ):
        emit_alert(alert_type="LAF-102",
                   packet=packet,
                   device=device,
                   device_session=device_session,
                   gateway=gateway,
                   lsnr=device.max_lsnr)

    chrono.stop("update")
    chrono.stop("total")
    chrono.lap()