static void at_signal_strength(struct ofono_netreg *netreg, ofono_netreg_strength_cb_t cb, void *data) { struct netreg_data *nd = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, data); cbd->user = nd; /* * If we defaulted to using CIND, then keep using it, * otherwise fall back to CSQ */ if (nd->signal_index > 0) { if (g_at_chat_send(nd->chat, "AT+CIND?", cind_prefix, cind_cb, cbd, g_free) > 0) return; } else { if (g_at_chat_send(nd->chat, "AT+CSQ", csq_prefix, csq_cb, cbd, g_free) > 0) return; } g_free(cbd); CALLBACK_WITH_FAILURE(cb, -1, data); }
static void ril_register_manual(struct ofono_netreg *netreg, const char *mcc, const char *mnc, ofono_netreg_register_cb_t cb, void *data) { struct netreg_data *nd = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, data); char buf[OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1]; struct parcel rilp; int request = RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL; int ret; /* add *netreg_data to callback */ cbd->user = nd; parcel_init(&rilp); /* RIL expects a char * specifying MCCMNC of network to select */ snprintf(buf, sizeof(buf), "%s%s", mcc, mnc); parcel_w_string(&rilp, buf); ret = g_ril_send(nd->ril, request, rilp.data, rilp.size, ril_register_cb, cbd, g_free); parcel_free(&rilp); g_ril_append_print_buf(nd->ril, "(%s)", buf); g_ril_print_request(nd->ril, ret, request); /* In case of error free cbd and return the cb with failure */ if (ret <= 0) { g_free(cbd); CALLBACK_WITH_FAILURE(cb, data); } }
static void cops_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; struct netreg_data *nd = ofono_netreg_get_data(cbd->user); ofono_netreg_operator_cb_t cb = cbd->cb; struct ofono_network_operator op; GAtResultIter iter; int format, tech; const char *name; struct ofono_error error; decode_at_error(&error, g_at_result_final_response(result)); if (!ok) goto error; g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, "+COPS:")) goto error; g_at_result_iter_skip_next(&iter); ok = g_at_result_iter_next_number(&iter, &format); if (ok == FALSE || format != 0) goto error; if (g_at_result_iter_next_string(&iter, &name) == FALSE) goto error; /* Default to GSM */ if (g_at_result_iter_next_number(&iter, &tech) == FALSE) tech = ACCESS_TECHNOLOGY_GSM; strncpy(op.name, name, OFONO_MAX_OPERATOR_NAME_LENGTH); op.name[OFONO_MAX_OPERATOR_NAME_LENGTH] = '\0'; strncpy(op.mcc, nd->mcc, OFONO_MAX_MCC_LENGTH); op.mcc[OFONO_MAX_MCC_LENGTH] = '\0'; strncpy(op.mnc, nd->mnc, OFONO_MAX_MNC_LENGTH); op.mnc[OFONO_MAX_MNC_LENGTH] = '\0'; /* Set to current */ op.status = 2; op.tech = tech; DBG("cops_cb: %s, %s %s %d", name, nd->mcc, nd->mnc, tech); cb(&error, &op, cbd->data); g_free(cbd); return; error: cb(&error, NULL, cbd->data); g_free(cbd); }
static void ril_nitz_notify(struct ril_msg *message, gpointer user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *nd = ofono_netreg_get_data(netreg); int year, mon, mday, hour, min, sec, dst, tzi; char tzs, tz[4]; gchar *nitz; if ((nitz = g_ril_unsol_parse_nitz(nd->ril, message)) == NULL) goto error; sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u", &year, &mon, &mday, &hour, &min, &sec, &tzs, &tzi, &dst); sprintf(tz, "%c%d", tzs, tzi); nd->time.utcoff = atoi(tz) * 15 * 60; nd->time.dst = dst; nd->time.sec = sec; nd->time.min = min; nd->time.hour = hour; nd->time.mday = mday; nd->time.mon = mon; nd->time.year = 2000 + year; ofono_netreg_time_notify(netreg, &nd->time); g_free(nitz); return; error: ofono_error("%s: unable to notify ofono about NITZ", __func__); }
static void qmi_register_manual(struct ofono_netreg *netreg, const char *mcc, const char *mnc, ofono_netreg_register_cb_t cb, void *user_data) { struct netreg_data *data = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, user_data); struct qmi_nas_param_register_manual_info info; struct qmi_param *param; DBG(""); param = qmi_param_new_uint8(QMI_NAS_PARAM_REGISTER_ACTION, QMI_NAS_REGISTER_ACTION_MANUAL); if (!param) goto error; info.mcc = atoi(mcc); info.mnc = atoi(mnc); info.rat = data->current_rat; qmi_param_append(param, QMI_NAS_PARAM_REGISTER_MANUAL_INFO, sizeof(info), &info); if (qmi_service_send(data->nas, QMI_NAS_REGISTER_NET, param, register_net_cb, cbd, g_free) > 0) return; qmi_param_free(param); error: CALLBACK_WITH_FAILURE(cb, cbd->data); g_free(cbd); }
static void event_notify(struct qmi_result *result, void *user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *data = ofono_netreg_get_data(netreg); const struct qmi_nas_signal_strength *ss; const struct qmi_nas_rf_info *rf; uint16_t len; DBG(""); ss = qmi_result_get(result, QMI_NAS_NOTIFY_SIGNAL_STRENGTH, &len); if (ss) { int strength; DBG("signal with %d dBm on %d", ss->dbm, ss->rat); strength = dbm_to_strength(ss->dbm); ofono_netreg_strength_notify(netreg, strength); } rf = qmi_result_get(result, QMI_NAS_NOTIFY_RF_INFO, &len); if (rf) { uint8_t i; for (i = 0; i < rf->count; i++) { DBG("rat %d band %d channel %d", rf->info[i].rat, rf->info[i].band, rf->info[i].channel); } data->current_rat = rf->info[i].rat; } }
static void ril_network_state_change(struct ril_msg *message, gpointer user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *nd = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(ril_creg_notify, netreg); int request = RIL_REQUEST_VOICE_REGISTRATION_STATE; int ret; cbd->user = nd; if (message->req != RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED) goto error; g_ril_print_unsol_no_args(nd->ril, message); ret = g_ril_send(nd->ril, request, NULL, 0, ril_creg_cb, cbd, g_free); /* For operator update ofono will use the current_operator cb * so we don't need to probe ril here */ g_ril_print_request_no_args(nd->ril, ret, request); if (ret > 0) return; error: ofono_error("Unable to request network state changed"); g_free(cbd); }
static void hfp_current_operator(struct ofono_netreg *netreg, ofono_netreg_operator_cb_t cb, void *data) { struct netreg_data *nd = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, data); gboolean ok; if (!cbd) goto error; cbd->user = netreg; ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", NULL, NULL, cbd, NULL); if (ok) ok = g_at_chat_send(nd->chat, "AT+COPS?", cops_prefix, cops_cb, cbd, g_free); if (ok) return; error: CALLBACK_WITH_FAILURE(cb, NULL, data); }
static void qmi_register_auto(struct ofono_netreg *netreg, ofono_netreg_register_cb_t cb, void *user_data) { struct netreg_data *data = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, user_data); struct qmi_param *param; DBG(""); param = qmi_param_new_uint8(QMI_NAS_PARAM_REGISTER_ACTION, QMI_NAS_REGISTER_ACTION_AUTO); if (!param) goto error; if (qmi_service_send(data->nas, QMI_NAS_REGISTER_NET, param, register_net_cb, cbd, g_free) > 0) return; qmi_param_free(param); error: CALLBACK_WITH_FAILURE(cb, cbd->data); g_free(cbd); }
static void ifx_ctzdst_notify(GAtResult *result, gpointer user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *nd = ofono_netreg_get_data(netreg); int dst; GAtResultIter iter; g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, "+CTZDST:")) return; if (!g_at_result_iter_next_number(&iter, &dst)) return; DBG("dst %d", dst); nd->time.dst = dst; if (nd->nitz_timeout > 0) { g_source_remove(nd->nitz_timeout); nd->nitz_timeout = 0; } ofono_netreg_time_notify(netreg, &nd->time); }
static void ciev_notify(GAtResult *result, gpointer user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *nd = ofono_netreg_get_data(netreg); int strength, ind; GAtResultIter iter; g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, "+CIEV:")) return; if (!g_at_result_iter_next_number(&iter, &ind)) return; if (ind != nd->signal_index) return; if (!g_at_result_iter_next_number(&iter, &strength)) return; if (strength == nd->signal_invalid) strength = -1; else strength = (strength * 100) / (nd->signal_max - nd->signal_min); ofono_netreg_strength_notify(netreg, strength); }
static void at_current_operator(struct ofono_netreg *netreg, ofono_netreg_operator_cb_t cb, void *data) { struct netreg_data *nd = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, data); gboolean ok; cbd->user = netreg; /* Nokia modems have a broken return value for the string * returned for the numeric value. It misses a " at the end. * Trying to read this will stall the parser. So skip it. */ if (nd->vendor == OFONO_VENDOR_NOKIA) { ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", none_prefix, NULL, NULL, NULL); if (ok) ok = g_at_chat_send(nd->chat, "AT+COPS?", cops_prefix, cops_cb, cbd, NULL); } else { ok = g_at_chat_send(nd->chat, "AT+COPS=3,2", none_prefix, NULL, NULL, NULL); if (ok) ok = g_at_chat_send(nd->chat, "AT+COPS?", cops_prefix, cops_numeric_cb, cbd, NULL); } if (ok) return; g_free(cbd); CALLBACK_WITH_FAILURE(cb, NULL, data); }
static void hfp_netreg_remove(struct ofono_netreg *netreg) { struct netreg_data *nd = ofono_netreg_get_data(netreg); ofono_netreg_set_data(netreg, NULL); g_free(nd); }
static void cnti_query_tech_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct tech_query *tq = user_data; struct netreg_data *nd = ofono_netreg_get_data(tq->netreg); ofono_netreg_status_notify(tq->netreg, tq->status, tq->lac, tq->ci, nd->tech); }
static void qmi_current_operator(struct ofono_netreg *netreg, ofono_netreg_operator_cb_t cb, void *user_data) { struct netreg_data *data = ofono_netreg_get_data(netreg); DBG(""); CALLBACK_WITH_SUCCESS(cb, &data->operator, user_data); }
static void ril_strength_notify(struct ril_msg *message, gpointer user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *nd = ofono_netreg_get_data(netreg); int strength = g_ril_unsol_parse_signal_strength(nd->ril, message, nd->tech); ofono_netreg_strength_notify(netreg, strength); }
static void ril_network_state_change(struct ril_msg *message, gpointer user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *nd = ofono_netreg_get_data(netreg); g_ril_print_unsol_no_args(nd->ril, message); ril_registration_status(netreg, NULL, NULL); }
static void option_tech_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; struct ofono_netreg *netreg = cbd->data; struct netreg_data *nd = ofono_netreg_get_data(netreg); if (ok) nd->tech = option_parse_tech(result); else nd->tech = -1; }
static void at_registration_status(struct ofono_netreg *netreg, ofono_netreg_status_cb_t cb, void *data) { struct netreg_data *nd = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, data); cbd->user = nd; switch (nd->vendor) { case OFONO_VENDOR_MBM: /* * Send *ERINFO to find out the current tech, it will be * intercepted in mbm_erinfo_notify */ g_at_chat_send(nd->chat, "AT*ERINFO?", none_prefix, NULL, NULL, NULL); break; case OFONO_VENDOR_GOBI: /* * Send *CNTI=0 to find out the current tech, it will be * intercepted in gobi_cnti_notify */ g_at_chat_send(nd->chat, "AT*CNTI=0", none_prefix, NULL, NULL, NULL); break; case OFONO_VENDOR_NOVATEL: /* * Send $CNTI=0 to find out the current tech, it will be * intercepted in nw_cnti_notify */ g_at_chat_send(nd->chat, "AT$CNTI=0", none_prefix, NULL, NULL, NULL); break; case OFONO_VENDOR_OPTION_HSO: /* * Send AT_OCTI?;_OUWCTI? to find out the current tech, * option_tech_cb will call fire CREG? to do the rest. */ if (g_at_chat_send(nd->chat, "AT_OCTI?;_OUWCTI?", option_tech_prefix, option_tech_cb, cbd, NULL) == 0) nd->tech = -1; break; } if (g_at_chat_send(nd->chat, "AT+CREG?", creg_prefix, at_creg_cb, cbd, g_free) > 0) return; g_free(cbd); CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, data); }
static gboolean notify_time(gpointer user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *nd = ofono_netreg_get_data(netreg); nd->nitz_timeout = 0; ofono_netreg_time_notify(netreg, &nd->time); return FALSE; }
static void cops_numeric_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; struct netreg_data *nd = ofono_netreg_get_data(cbd->user); ofono_netreg_operator_cb_t cb = cbd->cb; GAtResultIter iter; const char *str; int format; int len; struct ofono_error error; decode_at_error(&error, g_at_result_final_response(result)); if (!ok) goto error; g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, "+COPS:")) goto error; g_at_result_iter_skip_next(&iter); ok = g_at_result_iter_next_number(&iter, &format); if (ok == FALSE || format != 2) goto error; if (g_at_result_iter_next_string(&iter, &str) == FALSE) goto error; len = strspn(str, "0123456789"); if (len != 5 && len != 6) goto error; extract_mcc_mnc(str, nd->mcc, nd->mnc); DBG("Cops numeric got mcc: %s, mnc: %s", nd->mcc, nd->mnc); ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", none_prefix, NULL, NULL, NULL); if (ok) ok = g_at_chat_send(nd->chat, "AT+COPS?", cops_prefix, cops_cb, cbd, NULL); if (ok) return; error: cb(&error, NULL, cbd->data); g_free(cbd); }
static void ril_netreg_remove(struct ofono_netreg *netreg) { struct netreg_data *nd = ofono_netreg_get_data(netreg); if (nd->nitz_timeout) g_source_remove(nd->nitz_timeout); ofono_netreg_set_data(netreg, NULL); g_ril_unref(nd->ril); g_free(nd); }
static void hfp_netreg_remove(struct ofono_netreg *netreg) { struct netreg_data *nd = ofono_netreg_get_data(netreg); if (nd->register_source != 0) g_source_remove(nd->register_source); ofono_netreg_set_data(netreg, NULL); g_at_chat_unref(nd->chat); g_free(nd); }
static void ril_register_auto(struct ofono_netreg *netreg, ofono_netreg_register_cb_t cb, void *data) { struct netreg_data *nd = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, data, nd); if (g_ril_send(nd->ril, RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, NULL, ril_register_cb, cbd, g_free) == 0) { g_free(cbd); CALLBACK_WITH_FAILURE(cb, data); } }
static void ril_list_operators(struct ofono_netreg *netreg, ofono_netreg_operator_list_cb_t cb, void *data) { struct netreg_data *nd = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, data, nd); if (g_ril_send(nd->ril, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, NULL, ril_cops_list_cb, cbd, g_free) == 0) { g_free(cbd); CALLBACK_WITH_FAILURE(cb, 0, NULL, data); } }
static void ril_current_operator(struct ofono_netreg *netreg, ofono_netreg_operator_cb_t cb, void *data) { struct netreg_data *nd = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, data, nd); if (g_ril_send(nd->ril, RIL_REQUEST_OPERATOR, NULL, ril_cops_cb, cbd, g_free) == 0) { g_free(cbd); CALLBACK_WITH_FAILURE(cb, NULL, data); } }
static void ril_strength_notify(struct ril_msg *message, gpointer user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *nd = ofono_netreg_get_data(netreg); int strength; g_assert(message->req == RIL_UNSOL_SIGNAL_STRENGTH); strength = ril_util_get_signal(nd->ril, message); ofono_netreg_strength_notify(netreg, strength); return; }
static void mbm_erinfo_notify(GAtResult *result, gpointer user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *nd = ofono_netreg_get_data(netreg); GAtResultIter iter; int mode, gsm, umts; g_at_result_iter_init(&iter, result); if (g_at_result_iter_next(&iter, "*ERINFO:") == FALSE) return; if (g_at_result_iter_next_number(&iter, &mode) == FALSE) return; if (g_at_result_iter_next_number(&iter, &gsm) == FALSE) return; /* * According to MBM the ERINFO unsolicited response does not contain * the mode parameter, however at least the MD300 does report it. So * we handle both 2 and 3 argument versions */ if (g_at_result_iter_next_number(&iter, &umts) == FALSE) { gsm = mode; umts = gsm; } ofono_info("network capability: GSM %d UMTS %d", gsm, umts); /* Convert to tech values from 27.007 */ switch (gsm) { case 1: /* GSM */ nd->tech = ACCESS_TECHNOLOGY_GSM; break; case 2: /* EDGE */ nd->tech = ACCESS_TECHNOLOGY_GSM_EGPRS; break; default: nd->tech = -1; } switch (umts) { case 1: /* UMTS */ nd->tech = ACCESS_TECHNOLOGY_UTRAN; break; case 2: /* UMTS + HSDPA */ nd->tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA; break; } }
static void ril_signal_strength(struct ofono_netreg *netreg, ofono_netreg_strength_cb_t cb, void *data) { struct netreg_data *nd = ofono_netreg_get_data(netreg); struct cb_data *cbd = cb_data_new(cb, data, nd); if (g_ril_send(nd->ril, RIL_REQUEST_SIGNAL_STRENGTH, NULL, ril_strength_cb, cbd, g_free) == 0) { ofono_error("Send RIL_REQUEST_SIGNAL_STRENGTH failed."); g_free(cbd); CALLBACK_WITH_FAILURE(cb, -1, data); } }
static void ss_info_notify(struct qmi_result *result, void *user_data) { struct ofono_netreg *netreg = user_data; struct netreg_data *data = ofono_netreg_get_data(netreg); int status, lac, cellid, tech; DBG(""); if (!extract_ss_info(result, &status, &lac, &cellid, &tech, &data->operator)) return; ofono_netreg_status_notify(netreg, status, lac, cellid, tech); }