static void ril_query_call_fwd_cb(struct ril_msg *message, gpointer user_data) { struct cb_data *cbd = user_data; struct forw_data *fd = ofono_call_forwarding_get_data(cbd->user); ofono_call_forwarding_query_cb_t cb = cbd->cb; struct ofono_call_forwarding_condition *list; unsigned int list_size = -1; if (message->error != RIL_E_SUCCESS) { ofono_error("%s: rild error: %s", __func__, ril_error_to_string(message->error)); goto error; } list = g_ril_reply_parse_query_call_fwd(fd->ril, message, &list_size); /* * From atmodem: * * Specification is really unclear about this * generate status=0 for all classes just in case */ if (list_size == 0) { list = g_new0(struct ofono_call_forwarding_condition, 1); list_size = 1; list->status = 0; list->cls = fd->last_cls; } else if (list == NULL) {
static void isi_call_forwarding_remove(struct ofono_call_forwarding *cf) { struct forw_data *data = ofono_call_forwarding_get_data(cf); ofono_call_forwarding_set_data(cf, NULL); if (data == NULL) return; g_isi_client_destroy(data->client); g_free(data); }
static void ril_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 cb_data *cbd = cb_data_new(cb, data); struct parcel rilp; int ret = 0; parcel_init(&rilp); parcel_w_int32(&rilp, CF_ACTION_ERASURE); parcel_w_int32(&rilp, type); /* Modem seems to respond with error to all queries * or settings made with bearer class * BEARER_CLASS_DEFAULT. Design decision: If given * class is BEARER_CLASS_DEFAULT let's map it to * SERVICE_CLASS_VOICE effectively making it the * default bearer. This in line with API which is * contains only voice anyways. TODO: Checkout * the behaviour with final modem */ if (cls == BEARER_CLASS_DEFAULT) cls = BEARER_CLASS_VOICE; parcel_w_int32(&rilp, cls); /* Service class */ /* Following 3 values have no real meaning in erasure * but apparently RIL expects them so fields need to * be filled. Otherwise there is no response * */ parcel_w_int32(&rilp, 0x81); /* TOA unknown */ parcel_w_string(&rilp, "1234567890"); parcel_w_int32(&rilp, 60); ret = g_ril_send(fd->ril, RIL_REQUEST_SET_CALL_FORWARD, rilp.data, rilp.size, ril_set_forward_cb, cbd, g_free); parcel_free(&rilp); /* 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 ril_send_forward_cmd(struct ofono_call_forwarding *cf, int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data, int action) { struct forw_data *fd = ofono_call_forwarding_get_data(cf); struct cb_data *cbd = cb_data_new(cb, data); struct parcel rilp; int ret = 0; parcel_init(&rilp); parcel_w_int32(&rilp, action); parcel_w_int32(&rilp, type); /* * Modem seems to respond with error to all queries * or settings made with bearer class * BEARER_CLASS_DEFAULT. Design decision: If given * class is BEARER_CLASS_DEFAULT let's map it to * SERVICE_CLASS_NONE as with it e.g. ./send-ussd '*21*<phone_number>#' * returns cls:53 i.e. 1+4+16+32 as service class. */ if (cls == BEARER_CLASS_DEFAULT) cls = SERVICE_CLASS_NONE; parcel_w_int32(&rilp, cls); /* Service class */ /* Following 3 values have no real meaning in erasure * but apparently RIL expects them so fields need to * be filled. Otherwise there is no response * */ parcel_w_int32(&rilp, 0x81); /* TOA unknown */ parcel_w_string(&rilp, "1234567890"); parcel_w_int32(&rilp, 60); ret = g_ril_send(fd->ril, RIL_REQUEST_SET_CALL_FORWARD, rilp.data, rilp.size, ril_set_forward_cb, cbd, g_free); parcel_free(&rilp); /* In case of error free cbd and return the cb with failure */ if (ret <= 0) { ofono_error("CF action failed"); g_free(cbd); CALLBACK_WITH_FAILURE(cb, data); } }
static void ril_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 cb_data *cbd = cb_data_new(cb, data); struct parcel rilp; int ret = 0; ofono_info("cf registration"); parcel_init(&rilp); parcel_w_int32(&rilp, CF_ACTION_REGISTRATION); parcel_w_int32(&rilp, type); /* * Modem seems to respond with error to all queries * or settings made with bearer class * BEARER_CLASS_DEFAULT. Design decision: If given * class is BEARER_CLASS_DEFAULT let's map it to * SERVICE_CLASS_NONE as with it e.g. ./send-ussd '*21*<phone_number>#' * returns cls:53 i.e. 1+4+16+32 as service class. */ if (cls == BEARER_CLASS_DEFAULT) cls = SERVICE_CLASS_NONE; parcel_w_int32(&rilp, cls); parcel_w_int32(&rilp, number->type); parcel_w_string(&rilp, (char *) number->number); parcel_w_int32(&rilp, time); ret = g_ril_send(fd->ril, RIL_REQUEST_SET_CALL_FORWARD, rilp.data, rilp.size, ril_set_forward_cb, cbd, g_free); /* In case of error free cbd and return the cb with failure */ if (ret <= 0) { ofono_error("CF registration failed"); g_free(cbd); CALLBACK_WITH_FAILURE(cb, data); } }
static void ril_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 cb_data *cbd = cb_data_new(cb, data); struct parcel rilp; int ret = 0; parcel_init(&rilp); parcel_w_int32(&rilp, CF_ACTION_REGISTRATION); parcel_w_int32(&rilp, type); /* Modem seems to respond with error to all queries * or settings made with bearer class * BEARER_CLASS_DEFAULT. Design decision: If given * class is BEARER_CLASS_DEFAULT let's map it to * SERVICE_CLASS_VOICE effectively making it the * default bearer. This in line with API which is * contains only voice anyways. TODO: Checkout * the behaviour with final modem */ if (cls == BEARER_CLASS_DEFAULT) cls = BEARER_CLASS_VOICE; parcel_w_int32(&rilp, cls); parcel_w_int32(&rilp, number->type); parcel_w_string(&rilp, (char *) number->number); parcel_w_int32(&rilp, time); ret = g_ril_send(fd->ril, RIL_REQUEST_SET_CALL_FORWARD, rilp.data, rilp.size, ril_set_forward_cb, cbd, g_free); /* 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 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; }