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 cgev_notify(GAtResult *result, gpointer user_data) { struct ofono_gprs_context *gc = user_data; struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); const char *event; int cid; GAtResultIter iter; g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, "+CGEV:")) return; if (!g_at_result_iter_next_unquoted_string(&iter, &event)) return; if (g_str_has_prefix(event, "NW DEACT") == FALSE) return; if (!g_at_result_iter_skip_next(&iter)) return; if (!g_at_result_iter_next_number(&iter, &cid)) return; DBG("cid %d", cid); if ((unsigned int) cid != gcd->active_context) return; if (gcd->state != STATE_IDLE && gcd->ppp) g_at_ppp_shutdown(gcd->ppp); }
static void at_cmgr_notify(GAtResult *result, gpointer user_data) { struct ofono_sms *sms = user_data; struct sms_data *data = ofono_sms_get_data(sms); GAtResultIter iter; const char *hexpdu; unsigned char pdu[176]; long pdu_len; int tpdu_len; DBG(""); g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, "+CMGR:")) goto err; if (!g_at_result_iter_skip_next(&iter)) goto err; if (!g_at_result_iter_skip_next(&iter)) goto err; if (!g_at_result_iter_next_number(&iter, &tpdu_len)) goto err; hexpdu = g_at_result_pdu(result); if (strlen(hexpdu) > sizeof(pdu) * 2) goto err; DBG("Got PDU: %s, with len: %d", hexpdu, tpdu_len); decode_hex_own_buf(hexpdu, -1, &pdu_len, 0, pdu); if (data->expect_sr) ofono_sms_status_notify(sms, pdu, pdu_len, tpdu_len); else ofono_sms_deliver_notify(sms, pdu, pdu_len, tpdu_len); return; err: ofono_error("Unable to parse CMGR response"); }
static void at_cmgl_notify(GAtResult *result, gpointer user_data) { struct ofono_sms *sms = user_data; struct sms_data *data = ofono_sms_get_data(sms); GAtResultIter iter; const char *hexpdu; unsigned char pdu[176]; long pdu_len; int tpdu_len; int index; int status; char buf[16]; DBG(""); g_at_result_iter_init(&iter, result); while (g_at_result_iter_next(&iter, "+CMGL:")) { if (!g_at_result_iter_next_number(&iter, &index)) goto err; if (!g_at_result_iter_next_number(&iter, &status)) goto err; if (!g_at_result_iter_skip_next(&iter)) goto err; if (!g_at_result_iter_next_number(&iter, &tpdu_len)) goto err; /* Only MT messages */ if (status != 0 && status != 1) continue; hexpdu = g_at_result_pdu(result); DBG("Found an old SMS PDU: %s, with len: %d", hexpdu, tpdu_len); if (strlen(hexpdu) > sizeof(pdu) * 2) continue; decode_hex_own_buf(hexpdu, -1, &pdu_len, 0, pdu); ofono_sms_deliver_notify(sms, pdu, pdu_len, tpdu_len); /* We don't buffer SMS on the SIM/ME, send along a CMGD */ snprintf(buf, sizeof(buf), "AT+CMGD=%d", index); g_at_chat_send(data->chat, buf, none_prefix, at_cmgd_cb, NULL, NULL); } return; err: ofono_error("Unable to parse CMGL response"); }
static void at_cgdcont_test_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct ofono_gprs *gprs = user_data; struct gprs_data *gd = ofono_gprs_get_data(gprs); GAtResultIter iter; int min, max; const char *pdp_type; gboolean found = FALSE; if (!ok) goto error; g_at_result_iter_init(&iter, result); while (!found && g_at_result_iter_next(&iter, "+CGDCONT:")) { gboolean in_list = FALSE; if (!g_at_result_iter_open_list(&iter)) continue; if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE) continue; if (!g_at_result_iter_skip_next(&iter)) continue; if (g_at_result_iter_open_list(&iter)) in_list = TRUE; if (!g_at_result_iter_next_string(&iter, &pdp_type)) continue; if (in_list && !g_at_result_iter_close_list(&iter)) continue; /* We look for IP PDPs */ if (g_str_equal(pdp_type, "IP")) found = TRUE; } if (found == FALSE) goto error; ofono_gprs_set_cid_range(gprs, min, max); g_at_chat_send(gd->chat, "AT+CGREG=?", cgreg_prefix, at_cgreg_test_cb, gprs, NULL); return; error: ofono_info("GPRS not supported on this device"); ofono_gprs_remove(gprs); }
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 at_csms_status_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct ofono_sms *sms = user_data; struct sms_data *data = ofono_sms_get_data(sms); gboolean supported = FALSE; if (ok) { GAtResultIter iter; int service; int mt; int mo; g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, "+CSMS:")) goto out; switch (data->vendor) { case OFONO_VENDOR_HUAWEI: case OFONO_VENDOR_NOVATEL: g_at_result_iter_skip_next(&iter); service = 0; break; default: if (!g_at_result_iter_next_number(&iter, &service)) goto out; break; } if (!g_at_result_iter_next_number(&iter, &mt)) goto out; if (!g_at_result_iter_next_number(&iter, &mo)) goto out; if (service == 1) data->cnma_enabled = TRUE; if (mt == 1 && mo == 1) supported = TRUE; } out: if (!supported) return at_sms_not_supported(sms); /* Now query supported text format */ g_at_chat_send(data->chat, "AT+CMGF=?", cmgf_prefix, at_cmgf_query_cb, sms, NULL); }
static void uipaddr_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct ofono_gprs_context *gc = user_data; struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); GAtResultIter iter; const char *gw = NULL; const char *netmask = NULL; DBG("ok %d", ok); if (!ok) { CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data); return; } g_at_result_iter_init(&iter, result); while (g_at_result_iter_next(&iter, "+UIPADDR:")) { g_at_result_iter_skip_next(&iter); g_at_result_iter_skip_next(&iter); if (!g_at_result_iter_next_string(&iter, &gw)) break; if (!g_at_result_iter_next_string(&iter, &netmask)) break; } if (gw) ofono_gprs_context_set_ipv4_gateway(gc, gw); if (netmask) ofono_gprs_context_set_ipv4_netmask(gc, netmask); CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data); }
static void cops_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; ofono_netreg_operator_cb_t cb = cbd->cb; struct ofono_network_operator op; GAtResultIter iter; int format; const char *name; struct ofono_error error; decode_at_error(&error, g_at_result_final_response(result)); if (!ok) { cb(&error, NULL, cbd->data); return; } 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; strncpy(op.name, name, HFP_MAX_OPERATOR_NAME_LENGTH); op.name[HFP_MAX_OPERATOR_NAME_LENGTH] = '\0'; op.mcc[0] = '\0'; op.mnc[0] = '\0'; op.status = 2; op.tech = -1; cb(&error, &op, cbd->data); return; error: CALLBACK_WITH_FAILURE(cb, NULL, cbd->data); }
static gboolean at_parse_pdu_common(GAtResult *result, const char *prefix, const char **pdu, int *pdulen) { GAtResultIter iter; g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, prefix)) return FALSE; if (!strcmp(prefix, "+CMT:") && !g_at_result_iter_skip_next(&iter)) return FALSE; if (!g_at_result_iter_next_number(&iter, pdulen)) return FALSE; *pdu = g_at_result_pdu(result); return TRUE; }
static void at_cgdcont_read_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct ofono_gprs *gprs = user_data; struct gprs_data *gd = ofono_gprs_get_data(gprs); int activated_cid = gd->last_auto_context_id; const char *apn = NULL; GAtResultIter iter; DBG("ok %d", ok); if (!ok) { ofono_warn("Can't read CGDCONT contexts."); return; } g_at_result_iter_init(&iter, result); while (g_at_result_iter_next(&iter, "+CGDCONT:")) { int read_cid; if (!g_at_result_iter_next_number(&iter, &read_cid)) break; if (read_cid != activated_cid) continue; /* ignore protocol */ g_at_result_iter_skip_next(&iter); g_at_result_iter_next_string(&iter, &apn); break; } if (apn) ofono_gprs_cid_activated(gprs, activated_cid, apn); else ofono_warn("cid %u: Received activated but no apn present", activated_cid); }
static void cssu_notify(GAtResult *result, gpointer user_data) { struct ofono_ssn *ssn = user_data; GAtResultIter iter; int code2; int index = -1; const char *num; struct ofono_phone_number ph; ph.number[0] = '\0'; ph.type = 129; g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, "+CSSU:")) return; if (!g_at_result_iter_next_number(&iter, &code2)) return; /* This field is optional, if we can't read it, try to skip it */ if (!g_at_result_iter_next_number(&iter, &index) && !g_at_result_iter_skip_next(&iter)) goto out; if (!g_at_result_iter_next_string(&iter, &num)) goto out; strncpy(ph.number, num, OFONO_MAX_PHONE_NUMBER_LENGTH); if (!g_at_result_iter_next_number(&iter, &ph.type)) return; out: ofono_ssn_cssu_notify(ssn, code2, index, &ph); }
static void cind_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; ofono_netreg_strength_cb_t cb = cbd->cb; struct netreg_data *nd = cbd->user; int index; int strength; GAtResultIter iter; struct ofono_error error; decode_at_error(&error, g_at_result_final_response(result)); if (!ok) { cb(&error, -1, cbd->data); return; } g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, "+CIND:")) { CALLBACK_WITH_FAILURE(cb, -1, cbd->data); return; } for (index = 1; index < nd->signal_index; index++) g_at_result_iter_skip_next(&iter); g_at_result_iter_next_number(&iter, &strength); if (strength == nd->signal_invalid) strength = -1; else strength = (strength * 100) / (nd->signal_max - nd->signal_min); cb(&error, strength, cbd->data); }
static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct ofono_gprs_context *gc = user_data; struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); GAtResultIter iter; const char *laddrnetmask = NULL; const char *gw = NULL; const char *dns[3] = { NULL, NULL, NULL }; char buf[64]; DBG("ok %d", ok); if (!ok) { struct ofono_error error; decode_at_error(&error, g_at_result_final_response(result)); gcd->cb(&error, gcd->cb_data); return; } g_at_result_iter_init(&iter, result); while (g_at_result_iter_next(&iter, "+CGCONTRDP:")) { /* skip cid, bearer_id, apn */ g_at_result_iter_skip_next(&iter); g_at_result_iter_skip_next(&iter); g_at_result_iter_skip_next(&iter); if (!g_at_result_iter_next_string(&iter, &laddrnetmask)) break; if (!g_at_result_iter_next_string(&iter, &gw)) break; if (!g_at_result_iter_next_string(&iter, &dns[0])) break; if (!g_at_result_iter_next_string(&iter, &dns[1])) break; } set_gprs_context_interface(gc); if (!laddrnetmask || set_address_and_netmask(gc, laddrnetmask) < 0) { CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data); return; } if (gw) ofono_gprs_context_set_ipv4_gateway(gc, gw); if (dns[0]) ofono_gprs_context_set_ipv4_dns_servers(gc, dns); /* * Some older versions of Toby L2 need to issue AT+UIPADDR to get the * the correct gateway and netmask. The newer version will return an * empty ok reply. */ snprintf(buf, sizeof(buf), "AT+UIPADDR=%u", gcd->active_context); if (g_at_chat_send(gcd->chat, buf, uipaddr_prefix, uipaddr_cb, gc, NULL) > 0) return; /* Even if UIPADDR failed, we still have enough data. */ CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data); }
static void mux_query_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct mux_setup_data *msd = user_data; struct mux_setup_data *nmsd; GAtResultIter iter; int min, max; int speed; char buf[64]; /* CMUX query not supported, abort */ if (!ok) goto error; g_at_result_iter_init(&iter, result); if (!g_at_result_iter_next(&iter, "+CMUX:")) goto error; /* Mode */ if (!g_at_result_iter_open_list(&iter)) goto error; if (!g_at_result_iter_next_range(&iter, &min, &max)) goto error; if (!g_at_result_iter_close_list(&iter)) goto error; if (min <= 1 && 1 <= max) msd->mode = 1; else if (min <= 0 && 0 <= max) msd->mode = 0; else goto error; /* Subset */ if (!g_at_result_iter_open_list(&iter)) goto error; if (!g_at_result_iter_next_range(&iter, &min, &max)) goto error; if (!g_at_result_iter_close_list(&iter)) goto error; if (min > 0) goto error; /* Speed, pick highest */ if (g_at_result_iter_open_list(&iter)) { if (!g_at_result_iter_next_range(&iter, &min, &max)) goto error; if (!g_at_result_iter_close_list(&iter)) goto error; speed = max; } else { if (!g_at_result_iter_skip_next(&iter)) goto error; /* not available/used */ speed = -1; } /* Frame size, pick defaults */ if (!g_at_result_iter_open_list(&iter)) goto error; if (!g_at_result_iter_next_range(&iter, &min, &max)) goto error; if (!g_at_result_iter_close_list(&iter)) goto error; if (msd->mode == 0) { if (min > 31 || max < 31) goto error; msd->frame_size = 31; } else if (msd->mode == 1) { if (min > 64 || max < 64) goto error; msd->frame_size = 64; } else goto error; nmsd = g_memdup(msd, sizeof(struct mux_setup_data)); g_at_chat_ref(nmsd->chat); if (speed < 0) sprintf(buf, "AT+CMUX=%u,0,,%u", msd->mode, msd->frame_size); else sprintf(buf, "AT+CMUX=%u,0,%u,%u", msd->mode, speed, msd->frame_size); if (g_at_chat_send(msd->chat, buf, none_prefix, mux_setup_cb, nmsd, msd_free) > 0) return; msd_free(nmsd); error: msd->func(NULL, msd->user); if (msd->destroy) msd->destroy(msd->user); }
static void cops_list_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; ofono_netreg_operator_list_cb_t cb = cbd->cb; struct ofono_network_operator *list; GAtResultIter iter; int num = 0; struct ofono_error error; decode_at_error(&error, g_at_result_final_response(result)); if (!ok) { cb(&error, 0, NULL, cbd->data); return; } g_at_result_iter_init(&iter, result); while (g_at_result_iter_next(&iter, "+COPS:")) { while (g_at_result_iter_skip_next(&iter)) num += 1; } DBG("Got %d elements", num); list = g_try_new0(struct ofono_network_operator, num); if (list == NULL) { CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data); return; } num = 0; g_at_result_iter_init(&iter, result); while (g_at_result_iter_next(&iter, "+COPS:")) { int status, tech, plmn; const char *l, *s, *n; gboolean have_long = FALSE; while (1) { if (!g_at_result_iter_open_list(&iter)) break; if (!g_at_result_iter_next_number(&iter, &status)) break; list[num].status = status; if (!g_at_result_iter_next_string(&iter, &l)) break; if (strlen(l) > 0) { have_long = TRUE; strncpy(list[num].name, l, OFONO_MAX_OPERATOR_NAME_LENGTH); } if (!g_at_result_iter_next_string(&iter, &s)) break; if (strlen(s) > 0 && !have_long) strncpy(list[num].name, s, OFONO_MAX_OPERATOR_NAME_LENGTH); list[num].name[OFONO_MAX_OPERATOR_NAME_LENGTH] = '\0'; if (!g_at_result_iter_next_string(&iter, &n)) break; extract_mcc_mnc(n, list[num].mcc, list[num].mnc); if (!g_at_result_iter_next_number(&iter, &tech)) tech = ACCESS_TECHNOLOGY_GSM; list[num].tech = tech; if (!g_at_result_iter_next_number(&iter, &plmn)) plmn = 0; if (!g_at_result_iter_close_list(&iter)) break; num += 1; } } DBG("Got %d operators", num); { int i = 0; for (; i < num; i++) { DBG("Operator: %s, %s, %s, status: %d, %d", list[i].name, list[i].mcc, list[i].mnc, list[i].status, list[i].tech); } } cb(&error, num, list, cbd->data); g_free(list); }