static void isi_registration(struct ofono_call_forwarding *cf, int type, int cls, const struct ofono_phone_number *number, int time, ofono_call_forwarding_set_cb_t cb, void *data) { struct forw_data *fd = ofono_call_forwarding_get_data(cf); struct isi_cb_data *cbd = isi_cb_data_new(cf, cb, data); int ss_code = forw_type_to_isi_code(type); char *ucs2 = NULL; size_t numlen = strlen(number->number); size_t sb_len = ALIGN4(6 + 2 * numlen); size_t pad_len = sb_len - (6 + 2 * numlen); uint8_t msg[7 + 6 + 28 * 2 + 3] = { SS_SERVICE_REQ, SS_REGISTRATION, SS_GSM_TELEPHONY, ss_code >> 8, ss_code & 0xFF, SS_SEND_ADDITIONAL_INFO, 1, /* Subblock count */ SS_FORWARDING, sb_len, number->type, ss_code == SS_GSM_FORW_NO_REPLY ? time : SS_UNDEFINED_TIME, numlen, 0, /* Sub address length */ /* * Followed by number in UCS-2 (no NULL termination), * zero sub address bytes, and 0 to 3 bytes of filler */ }; size_t msg_len = 7 + 6 + numlen * 2 + pad_len; if (cbd == NULL || fd == NULL || numlen > 28) goto error; DBG("forwarding type %d class %d number %s", type, cls, number->number); if (ss_code < 0) goto error; ucs2 = g_convert(number->number, numlen, "UCS-2BE", "UTF-8//TRANSLIT", NULL, NULL, NULL); if (ucs2 == NULL) goto error; memcpy(msg + 13, ucs2, numlen * 2); g_free(ucs2); if (g_isi_client_send(fd->client, msg, msg_len, registration_resp_cb, cbd, g_free)) return; error: CALLBACK_WITH_FAILURE(cb, data); g_free(cbd); } static void erasure_resp_cb(const GIsiMessage *msg, void *data) { struct isi_cb_data *cbd = data; ofono_call_forwarding_set_cb_t cb = cbd->cb; GIsiSubBlockIter iter; uint8_t status; if (!check_resp(msg, SS_SERVICE_COMPLETED_RESP, SS_ERASURE)) goto error; for (g_isi_sb_iter_init(&iter, msg, 6); g_isi_sb_iter_is_valid(&iter); g_isi_sb_iter_next(&iter)) { if (g_isi_sb_iter_get_id(&iter) != SS_GSM_FORWARDING_INFO) continue; if (!decode_gsm_forwarding_info(&iter, &status, NULL, NULL, NULL)) goto error; if (status & (SS_GSM_ACTIVE | SS_GSM_REGISTERED)) goto error; } CALLBACK_WITH_SUCCESS(cb, cbd->data); return; error: CALLBACK_WITH_FAILURE(cb, cbd->data); } static void isi_erasure(struct ofono_call_forwarding *cf, int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data) { struct forw_data *fd = ofono_call_forwarding_get_data(cf); struct isi_cb_data *cbd = isi_cb_data_new(cf, cb, data); int ss_code = forw_type_to_isi_code(type); const uint8_t msg[] = { SS_SERVICE_REQ, SS_ERASURE, SS_GSM_TELEPHONY, ss_code >> 8, ss_code & 0xFF, SS_SEND_ADDITIONAL_INFO, 0, /* Subblock count */ }; DBG("forwarding type %d class %d", type, cls); if (cbd == NULL || fd == NULL || ss_code < 0) goto error; if (g_isi_client_send(fd->client, msg, sizeof(msg), erasure_resp_cb, cbd, g_free)) return; error: CALLBACK_WITH_FAILURE(cb, data); g_free(cbd); } static void query_resp_cb(const GIsiMessage *msg, void *data) { struct isi_cb_data *cbd = data; ofono_call_forwarding_query_cb_t cb = cbd->cb; GIsiSubBlockIter iter; struct ofono_call_forwarding_condition list = { .status = 0, .cls = 7, .time = 0, .phone_number = { .number[0] = '\0', .type = 0, }, }; uint8_t status; uint8_t ton; uint8_t noreply; char *number = NULL; if (!check_resp(msg, SS_SERVICE_COMPLETED_RESP, SS_INTERROGATION)) goto error; for (g_isi_sb_iter_init(&iter, msg, 6); g_isi_sb_iter_is_valid(&iter); g_isi_sb_iter_next(&iter)) { DBG("Got %s", ss_subblock_name(g_isi_sb_iter_get_id(&iter))); if (g_isi_sb_iter_get_id(&iter) != SS_GSM_FORWARDING_INFO) continue; if (!decode_gsm_forwarding_info(&iter, &status, &ton, &noreply, &number)) goto error; list.status = status & (SS_GSM_ACTIVE | SS_GSM_REGISTERED | SS_GSM_PROVISIONED); list.time = noreply; list.phone_number.type = ton | 0x80; DBG("Number <%s>", number); strncpy(list.phone_number.number, number, OFONO_MAX_PHONE_NUMBER_LENGTH); list.phone_number.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0'; g_free(number); DBG("forwarding query: %d, %d, %s(%d) - %d sec", list.status, list.cls, list.phone_number.number, list.phone_number.type, list.time); } CALLBACK_WITH_SUCCESS(cb, 1, &list, cbd->data); return; error: CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data); } static void isi_query(struct ofono_call_forwarding *cf, int type, int cls, ofono_call_forwarding_query_cb_t cb, void *data) { struct forw_data *fd = ofono_call_forwarding_get_data(cf); struct isi_cb_data *cbd = isi_cb_data_new(cf, cb, data); int ss_code = forw_type_to_isi_code(type); const uint8_t msg[] = { SS_SERVICE_REQ, SS_INTERROGATION, SS_GSM_TELEPHONY, ss_code >> 8, ss_code & 0xFF, SS_SEND_ADDITIONAL_INFO, 0, /* Subblock count */ }; DBG("forwarding type %d class %d", type, cls); if (cbd == NULL || fd == NULL || cls != 7 || ss_code < 0) goto error; if (g_isi_client_send(fd->client, msg, sizeof(msg), query_resp_cb, cbd, g_free)) return; error: CALLBACK_WITH_FAILURE(cb, 0, NULL, data); g_free(cbd); } static void reachable_cb(const GIsiMessage *msg, void *data) { struct ofono_call_forwarding *cf = data; if (g_isi_msg_error(msg) < 0) { ofono_call_forwarding_remove(cf); return; } ISI_RESOURCE_DBG(msg); ofono_call_forwarding_register(cf); } static int isi_call_forwarding_probe(struct ofono_call_forwarding *cf, unsigned int vendor, void *user) { GIsiModem *modem = user; struct forw_data *fd; fd = g_try_new0(struct forw_data, 1); if (fd == NULL) return -ENOMEM; fd->client = g_isi_client_create(modem, PN_SS); if (fd->client == NULL) { g_free(fd); return -ENOMEM; } ofono_call_forwarding_set_data(cf, fd); g_isi_client_verify(fd->client, reachable_cb, cf, NULL); return 0; }
/* * sim_state_watch listens to SIM state changes and creates/removes atoms * accordingly. This is needed because we cannot rely on the modem core code, * which handles modem state transitions, to do this due to the SIM not being * accessible in the offline state for mtk modems. This causes a mismatch * between what the core thinks it can do in some states and what the mtk modem * can really do in those. This is a workaround to solve that. */ static void sim_state_watch(enum ofono_sim_state new_state, void *data) { struct ofono_modem *modem = data; struct mtk_data *md = ofono_modem_get_data(modem); if (new_state == OFONO_SIM_STATE_READY) { struct ofono_gprs_context *gc; struct ril_gprs_driver_data gprs_data = { md->ril, modem }; struct ril_gprs_context_data inet_ctx = { md->ril, OFONO_GPRS_CONTEXT_TYPE_INTERNET }; struct ril_gprs_context_data mms_ctx = { md->ril, OFONO_GPRS_CONTEXT_TYPE_MMS }; DBG("SIM ready, creating more atoms"); /* * TODO: this function should setup: * - stk ( SIM toolkit ) */ md->sms = ofono_sms_create(modem, OFONO_RIL_VENDOR_MTK, RILMODEM, md->ril); /* netreg needs access to the SIM (SPN, SPDI) */ md->netreg = ofono_netreg_create(modem, OFONO_RIL_VENDOR_MTK, RILMODEM, md->ril); md->ussd = ofono_ussd_create(modem, OFONO_RIL_VENDOR_MTK, RILMODEM, md->ril); md->call_settings = ofono_call_settings_create(modem, OFONO_RIL_VENDOR_MTK, RILMODEM, md->ril); md->call_forwarding = ofono_call_forwarding_create(modem, OFONO_RIL_VENDOR_MTK, RILMODEM, md->ril); md->call_barring = ofono_call_barring_create(modem, OFONO_RIL_VENDOR_MTK, RILMODEM, md->ril); md->phonebook = ofono_phonebook_create(modem, OFONO_RIL_VENDOR_MTK, RILMODEM, modem); md->gprs = ofono_gprs_create(modem, OFONO_RIL_VENDOR_MTK, MTKMODEM, &gprs_data); gc = ofono_gprs_context_create(modem, OFONO_RIL_VENDOR_MTK, RILMODEM, &inet_ctx); if (gc) { ofono_gprs_context_set_type(gc, OFONO_GPRS_CONTEXT_TYPE_INTERNET); ofono_gprs_add_context(md->gprs, gc); } gc = ofono_gprs_context_create(modem, OFONO_RIL_VENDOR_MTK, RILMODEM, &mms_ctx); if (gc) { ofono_gprs_context_set_type(gc, OFONO_GPRS_CONTEXT_TYPE_MMS); ofono_gprs_add_context(md->gprs, gc); } md->message_waiting = ofono_message_waiting_create(modem); if (md->message_waiting) ofono_message_waiting_register(md->message_waiting); /* * Now that we can access IMSI, see if a FW change is needed. */ md->sim_plmn_type = get_plmn_type(ofono_sim_get_imsi(md->sim)); check_modem_fw(modem); } else if (new_state == OFONO_SIM_STATE_LOCKED_OUT) { DBG("SIM locked, removing atoms"); if (md->message_waiting) { ofono_message_waiting_remove(md->message_waiting); md->message_waiting = NULL; } if (md->gprs) { ofono_gprs_remove(md->gprs); md->gprs = NULL; } if (md->phonebook) { ofono_phonebook_remove(md->phonebook); md->phonebook = NULL; } if (md->call_barring) { ofono_call_barring_remove(md->call_barring); md->call_barring = NULL; } if (md->call_forwarding) { ofono_call_forwarding_remove(md->call_forwarding); md->call_forwarding = NULL; } if (md->call_settings) { ofono_call_settings_remove(md->call_settings); md->call_settings = NULL; } if (md->ussd) { ofono_ussd_remove(md->ussd); md->ussd = NULL; } if (md->netreg) { ofono_netreg_remove(md->netreg); md->netreg = NULL; } if (md->sms) { ofono_sms_remove(md->sms); md->sms = NULL; } } }