static bool handle_cops_cme_error(struct ubmodem_s *modem,
                                  const struct at_resp_info_s *info)
{
  /* Ignore CME error 15 and 3, as without network COPS=0 will eventually
   * report error and also give +CREG URC messages with the correct indication
   * of the issue.
   */

  if (info->errorcode == 15 || info->errorcode == 3)
    return false;

  if (info->errorcode == 30)
    {
      /* No network service. */

      __ubmodem_level_transition_failed(modem, "NETWORK: No network service.");
      return true;
    }
  else
    {
      __ubmodem_level_transition_failed(modem, "NETWORK: Could not connect, error %d",
                                        info->errorcode);
      return true;
    }
}
static int network_register_timer_handler(struct ubmodem_s *modem,
                                          const int timer_id, void * const arg)
{
  const char *reason;

  if (timer_id != -1)
    {
      /* One-shot timer, not registered anymore. */

      modem->creg_timer_id = -1;
    }

  /* Could not register in time. Disable RF. */

  if (timer_id == -1)
    reason = "NETWORK: Denied.";
  else
    reason = "NETWORK: Timeout.";

  /* Mark for retry, 'level transition failed' can modify the actual target
   * level. */

  __ubmodem_network_cleanup(modem);
  __ubmodem_retry_current_level(modem, UBMODEM_LEVEL_SIM_ENABLED);

  /* Failed to connect network. */

  __ubmodem_level_transition_failed(modem, "%s", reason);

  return OK;
}
static int network_register_timeout_handler(struct ubmodem_s *modem,
                                            const int timer_id,
                                            void * const arg)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  struct timespec curr_ts;
  const char *reason;
  int ret;

  MODEM_DEBUGASSERT(modem, modem->creg_timer_id == timer_id);

  if (timer_id != -1)
    {
      /* One-shot timer, not registered anymore. */

      modem->creg_timer_id = -1;

      ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_HIGH, false);
    }

  (void)clock_gettime(CLOCK_MONOTONIC, &curr_ts);

  if (curr_ts.tv_sec - sub->net_reg_start_ts.tv_sec <=
      MODEM_CMD_NETWORK_REGISTRATION_TIMEOUT / 10)
    {
      /* Too soon, reregister timer. */

      ret = __ubmodem_set_timer(modem, NETWORK_REGISTRATION_CHECK_SECS * 1000,
                                &network_register_timeout_handler, sub);
      MODEM_DEBUGASSERT(modem, ret != ERROR);

      modem->creg_timer_id = ret;

      ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_HIGH, true);

      return OK;
    }

  /* Could not register in time. Disable RF. */

  if (timer_id == -1)
    reason = "NETWORK: Denied.";
  else
    reason = "NETWORK: Timeout.";

  /* Mark for retry, 'level transition failed' can modify the actual target
   * level. */

  __ubmodem_network_cleanup(modem);
  __ubmodem_retry_current_level(modem, UBMODEM_LEVEL_SIM_ENABLED);

  /* Failed to connect network. */

  __ubmodem_level_transition_failed(modem, "%s", reason);

  return OK;
}
static int reregister_network_failed(struct ubmodem_s *modem, void *priv)
{
  ubdbg("\n");

  /* Mark for retry, 'level transition failed' can modify the actual target
   * level. */

  __ubmodem_network_cleanup(modem);
  __ubmodem_retry_current_level(modem, UBMODEM_LEVEL_SIM_ENABLED);

  /* Could not reregister, shutdown modem. */

  __ubmodem_level_transition_failed(modem, "%s", "NETWORK: Lost connection.");

  /* Return error to tell task starter that task did not start new work on
   * state machine. */

  return ERROR;
}