/** * Poll +COPS? and return a success, or if the loop counter reaches * REPOLL_OPERATOR_SELECTED, return generic failure. */ static void pollOperatorSelected(void *params) { int err = 0; int response = 0; char *line = NULL; ATResponse *atresponse = NULL; struct operatorPollParams *poll_params; RIL_Token t; assert(params != NULL); poll_params = (struct operatorPollParams *) params; t = poll_params->t; if (poll_params->loopcount >= REPOLL_OPERATOR_SELECTED) goto error; err = at_send_command_singleline("AT+COPS?", "+COPS:", &atresponse); if (err != AT_NOERROR) goto error; line = atresponse->p_intermediates->line; err = at_tok_start(&line); if (err < 0) goto error; err = at_tok_nextint(&line, &response); if (err < 0) goto error; /* If we don't get more than the COPS: {0-4} we are not registered. Loop and try again. */ if (!at_tok_hasmore(&line)) { switch (s_registrationDeniedReason) { case IMSI_UNKNOWN_IN_HLR: /* fall through */ case ILLEGAL_ME: RIL_onRequestComplete(t, RIL_E_ILLEGAL_SIM_OR_ME, NULL, 0); free(poll_params); break; default: poll_params->loopcount++; enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, pollOperatorSelected, poll_params, &TIMEVAL_OPERATOR_SELECT_POLL); } } else { /* We got operator, throw a success! */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); free(poll_params); } at_response_free(atresponse); return; error: RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); free(poll_params); at_response_free(atresponse); return; }
/** * SIM ready means any commands that access the SIM will work, including: * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM * (all SMS-related commands). */ void pollSIMState(void *param) { if (((int) param) != 1 && getRadioState() != RADIO_STATE_SIM_NOT_READY && getRadioState() != RADIO_STATE_SIM_LOCKED_OR_ABSENT) /* No longer valid to poll. */ return; switch (getSIMStatus()) { case SIM_NOT_READY: ALOGI("SIM_NOT_READY, poll for sim state."); enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, pollSIMState, NULL, &TIMEVAL_SIMPOLL); return; case SIM_PIN2: case SIM_PUK2: case SIM_PUK2_PERM_BLOCKED: case SIM_READY: setRadioState(RADIO_STATE_SIM_READY); enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, setPollSIMState, (void *) 1, NULL); return; case SIM_ABSENT: setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT); enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, setPollSIMState, (void *) 0, NULL); return; case SIM_PIN: case SIM_PUK: case SIM_NETWORK_PERSO: case SIM_NETWORK_SUBSET_PERSO: case SIM_SERVICE_PROVIDER_PERSO: case SIM_CORPORATE_PERSO: case SIM_SIM_PERSO: case SIM_STERICSSON_LOCK: case SIM_BLOCKED: case SIM_PERM_BLOCKED: case SIM_NETWORK_PERSO_PUK: case SIM_NETWORK_SUBSET_PERSO_PUK: case SIM_SERVICE_PROVIDER_PERSO_PUK: case SIM_CORPORATE_PERSO_PUK: /* pass through, do not break */ default: setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT); enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, setPollSIMState, (void *) 1, NULL); return; } }
void onSimHotswap(const char *s) { if (strcmp ("*EESIMSWAP:0", s) == 0) { ALOGD("%s() SIM Removed", __func__); s_simRemoved = 1; /* Toggle radio state since Android won't * poll the sim state unless the radio * state has changed from the previous * value */ setRadioState(RADIO_STATE_SIM_NOT_READY); setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT); enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, setPollSIMState, (void *) 0, NULL); } else if (strcmp ("*EESIMSWAP:1", s) == 0) { ALOGD("%s() SIM Inserted", __func__); s_simRemoved = 0; set_pending_hotswap(1); enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, setPollSIMState, (void *) 1, NULL); } else ALOGD("%s() Unknown SIM Hot Swap Event: %s", __func__, s); }
/** * RIL_UNSOL_NITZ_TIME_RECEIVED * * Called when radio has received a NITZ time message. * * "data" is const char * pointing to NITZ time string * */ void onNetworkTimeReceived(const char *s) { /* Special handling of DST for Android framework Module does not include DST correction in NITZ, but Android expects it */ char *line, *tok, *response, *time, *timestamp; int tz, dst; tok = line = strdup(s); if (NULL == tok) { LOGE("%s() Failed to allocate memory", __func__); return; } at_tok_start(&tok); LOGD("%s() Got nitz: %s", __func__, s); if (at_tok_nextint(&tok, &tz) != 0) LOGE("%s() Failed to parse NITZ tz %s", __func__, s); else if (at_tok_nextstr(&tok, &time) != 0) LOGE("%s() Failed to parse NITZ time %s", __func__, s); else if (at_tok_nextstr(&tok, ×tamp) != 0) LOGE("%s() Failed to parse NITZ timestamp %s", __func__, s); else { if (at_tok_nextint(&tok, &dst) != 0) { dst = 0; LOGE("%s() Failed to parse NITZ dst, fallbacking to dst=0 %s", __func__, s); } if (!(asprintf(&response, "%s%+03d,%02d", time + 2, tz + (dst * 4), dst))) { free(line); LOGE("%s() Failed to allocate string", __func__); return; } if (strncmp(response, last_nitz_time, strlen(response)) != 0) { RIL_onUnsolicitedResponse(RIL_UNSOL_NITZ_TIME_RECEIVED, response, sizeof(char *)); strncpy(last_nitz_time, response, strlen(response)); } else LOGD("%s() Discarding NITZ since it hasn't changed since last update", __func__); free(response); enqueueRILEvent(RIL_EVENT_QUEUE_NORMAL, sendTime, NULL, NULL); } free(line); }
void onNetworkStatusChanged(const char *s) { int err; int skip; int cs_status, ps_status; int resp; char *line = NULL, *tok = NULL; cs_status = ps_status = 0; tok = line = strdup(s); if (tok == NULL) goto error; at_tok_start(&tok); err = at_tok_nextint(&tok, &skip); if (err < 0) goto error; err = at_tok_nextint(&tok, &cs_status); if (err < 0) goto error; err = at_tok_nextint(&tok, &ps_status); if (err < 0) goto error; resp = RIL_RESTRICTED_STATE_NONE; if (cs_status == E2REG_ACCESS_CLASS_BARRED) resp |= RIL_RESTRICTED_STATE_CS_ALL; if (ps_status == E2REG_ACCESS_CLASS_BARRED) resp |= RIL_RESTRICTED_STATE_PS_ALL; RIL_onUnsolicitedResponse(RIL_UNSOL_RESTRICTED_STATE_CHANGED, &resp, sizeof(int *)); /* If registered, poll signal strength for faster update of signal bar */ if ((cs_status == E2REG_REGISTERED) || (ps_status == E2REG_REGISTERED)) enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, pollSignalStrength, (void *)-1, NULL); error: free(line); }
/** * RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC * * Specify that the network should be selected automatically. */ void requestSetNetworkSelectionAutomatic(void *data, size_t datalen, RIL_Token t) { (void) data; (void) datalen; int err = 0; ATResponse *atresponse = NULL; int mode = 0; int skip; char *line; char *operator = NULL; struct operatorPollParams *poll_params = NULL; poll_params = malloc(sizeof(struct operatorPollParams)); if (NULL == poll_params) goto error; /* First check if we are already scanning or in manual mode */ err = at_send_command_singleline("AT+COPS=3,2;+COPS?", "+COPS:", &atresponse); if (err != AT_NOERROR) goto error; line = atresponse->p_intermediates->line; err = at_tok_start(&line); if (err < 0) goto error; /* Read network selection mode */ err = at_tok_nextint(&line, &mode); if (err < 0) goto error; /* If we're unregistered, we may just get a "+COPS: 0" response. */ if (!at_tok_hasmore(&line)) { if (mode == 1) { LOGD("%s() Changing manual to automatic network mode", __func__); goto do_auto; } else goto check_reg; } err = at_tok_nextint(&line, &skip); if (err < 0) goto error; /* A "+COPS: 0, n" response is also possible. */ if (!at_tok_hasmore(&line)) { if (mode == 1) { LOGD("%s() Changing manual to automatic network mode", __func__); goto do_auto; } else goto check_reg; } /* Read numeric operator */ err = at_tok_nextstr(&line, &operator); if (err < 0) goto error; /* If operator is found then do a new scan, else let it continue the already pending scan */ if (operator && strlen(operator) == 0) { if (mode == 1) { LOGD("%s() Changing manual to automatic network mode", __func__); goto do_auto; } else goto check_reg; } /* Operator found */ if (mode == 1) { LOGD("%s() Changing manual to automatic network mode", __func__); goto do_auto; } else { LOGD("%s() Already in automatic mode with known operator, trigger a new network scan", __func__); goto do_auto; } /* Check if module is scanning, if not then trigger a rescan */ check_reg: at_response_free(atresponse); atresponse = NULL; /* Check CS domain first */ err = at_send_command_singleline("AT+CREG?", "+CREG:", &atresponse); if (err != AT_NOERROR) goto error; line = atresponse->p_intermediates->line; err = at_tok_start(&line); if (err < 0) goto error; /* Read registration unsolicited mode */ err = at_tok_nextint(&line, &mode); if (err < 0) goto error; /* Read registration status */ err = at_tok_nextint(&line, &mode); if (err < 0) goto error; /* If scanning has stopped, then perform a new scan */ if (mode == 0) { LOGD("%s() Already in automatic mode, but not currently scanning on CS," "trigger a new network scan", __func__); goto do_auto; } /* Now check PS domain */ at_response_free(atresponse); atresponse = NULL; err = at_send_command_singleline("AT+CGREG?", "+CGREG:", &atresponse); if (err != AT_NOERROR) goto error; line = atresponse->p_intermediates->line; err = at_tok_start(&line); if (err < 0) goto error; /* Read registration unsolicited mode */ err = at_tok_nextint(&line, &mode); if (err < 0) goto error; /* Read registration status */ err = at_tok_nextint(&line, &mode); if (err < 0) goto error; /* If scanning has stopped, then perform a new scan */ if (mode == 0) { LOGD("%s() Already in automatic mode, but not currently scanning on PS," "trigger a new network scan", __func__); goto do_auto; } else { LOGD("%s() Already in automatic mode and scanning", __func__); goto finish_scan; } do_auto: at_response_free(atresponse); atresponse = NULL; /* This command does two things, one it sets automatic mode, two it starts a new network scan! */ err = at_send_command("AT+COPS=0"); if (err != AT_NOERROR) goto error; finish_scan: at_response_free(atresponse); atresponse = NULL; poll_params->loopcount = 0; poll_params->t = t; enqueueRILEvent(RIL_EVENT_QUEUE_NORMAL, pollOperatorSelected, poll_params, &TIMEVAL_OPERATOR_SELECT_POLL); return; error: free(poll_params); at_response_free(atresponse); RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); return; }
void onSignalStrengthChanged(const char *s) { (void) s; enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, pollSignalStrength, NULL, NULL); }
/** * RIL_UNSOL_SIM_REFRESH * * Indicate when SIM issue a REFRESH proactive command to applications. */ void onStkSimRefresh(const char *s) { int commas = 0; char *line = NULL; char *tok = NULL; int i, skip; int err = -1; int response[2]; /* *ESIMRF: <cmdnumber>,<type>[[,< fileid>,<pathid>][…]] */ tok = line = strdup(s); err = at_tok_charcounter(tok, ',', &commas); if (err < 0) commas = 0; else commas -= 1; err = at_tok_start(&tok); if (err < 0) goto error; err = at_tok_nextint(&tok, &(s_refeshStatus.cmdNumber)); if (err < 0) goto error; err = at_tok_nextint(&tok, &(s_refeshStatus.cmdQualifier)); if (err < 0) goto error; switch(s_refeshStatus.cmdQualifier) { case SAT_SIM_INITIALIZATION_AND_FULL_FILE_CHANGE_NOTIFICATION: case SAT_SIM_INITIALIZATION_AND_FILE_CHANGE_NOTIFICATION: case SAT_SIM_INITIALIZATION: case SAT_NAA_APPLICATION_RESET: /* SIM initialized. All files should be re-read. */ response[0] = SIM_INIT; s_refeshStatus.Result = 3; /* success, EFs read */ break; case SAT_FILE_CHANGE_NOTIFICATION: /* one or more files on SIM has been updated */ response[0] = SIM_FILE_UPDATE; s_refeshStatus.Result = 3; /* success, EFs read */ break; case SAT_SIM_RESET: /* SIM reset. All files should be re-read. */ response[0] = SIM_RESET; break; case SAT_NAA_SESSION_RESET: /* one or more files on SIM has been updated */ response[0] = SIM_FILE_UPDATE; s_refeshStatus.Result = 3; /* success, EFs read */ break; case SAT_STEERING_OF_ROAMING: /* not set in Terminal Profile for Android, should never happen */ default: goto error; break; } if (response[0] != SIM_FILE_UPDATE) { response[1] = 0; RIL_onUnsolicitedResponse(RIL_UNSOL_SIM_REFRESH, response, sizeof(response)); goto finally; } for (i = 0; i < commas; i += 2) { err = at_tok_nextint(&tok, &(response[1])); if (err < 0) { /* check if response is already sent to Android */ if (i > 0) goto finally; else goto error; } /* <pathid> is not used by Android */ err = at_tok_nextint(&tok, &skip); if (err < 0) { /* check if response is already sent to Android */ if (i > 0) goto finally; else goto error; } RIL_onUnsolicitedResponse(RIL_UNSOL_SIM_REFRESH, response, sizeof(response)); } finally: #ifndef USE_U8500_RIL if (response[0] != SIM_RESET) { // AT commands cannot be sent from the at reader thread enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, sendRefreshTerminalResponse, NULL, NULL); } #endif free(line); return; error: ALOGE("%s: failed to parse %s, default to SIM_INITIALIZATION", __func__, s); if (s_refeshStatus.cmdNumber < 0) s_refeshStatus.cmdNumber = 1; if (s_refeshStatus.cmdQualifier < 0) s_refeshStatus.cmdQualifier = SAT_SIM_INITIALIZATION; if (s_refeshStatus.Result < 0) s_refeshStatus.Result = 2; /* command performed with missing information */ response[0] = SIM_INIT; response[1] = 0; RIL_onUnsolicitedResponse(RIL_UNSOL_SIM_REFRESH, response, sizeof(response)); goto finally; }
void onConnectionStateChanged(const char *s) { int m_state = -1, m_cause = -1, err; int commas; err = at_tok_start((char **) &s); if (err < 0) return; /* Count number of commas */ err = at_tok_charcounter((char *) s, ',', &commas); if (err < 0) return; err = at_tok_nextint((char **) &s, &m_state); if (err < 0 || m_state < E2NAP_ST_DISCONNECTED || m_state > E2NAP_ST_CONNECTED) { m_state = -1; return; } err = at_tok_nextint((char **) &s, &m_cause); /* The <cause> will only be indicated/considered when <state> * is disconnected */ if (err < 0 || m_cause < E2NAP_C_SUCCESS || m_cause > E2NAP_C_MAXIMUM || m_state != E2NAP_ST_DISCONNECTED) m_cause = -1; if (commas == 3) { int m_state2 = -1, m_cause2 = -1; err = at_tok_nextint((char **) &s, &m_state2); if (err < 0 || m_state2 < E2NAP_ST_DISCONNECTED || m_state2 > E2NAP_ST_CONNECTED) { m_state = -1; return; } if (m_state2 == E2NAP_ST_DISCONNECTED) { err = at_tok_nextint((char **) &s, &m_cause2); if (err < 0 || m_cause2 < E2NAP_C_SUCCESS || m_cause2 > E2NAP_C_MAXIMUM) { m_cause2 = -1; } } if ((err = pthread_mutex_lock(&s_e2nap_mutex)) != 0) LOGE("%s() failed to take e2nap mutex: %s", __func__, strerror(err)); if (m_state == E2NAP_ST_CONNECTING || m_state2 == E2NAP_ST_CONNECTING) { s_e2napState = E2NAP_ST_CONNECTING; } else if (m_state == E2NAP_ST_CONNECTED) { s_e2napCause = m_cause2; s_e2napState = E2NAP_ST_CONNECTED; } else if (m_state2 == E2NAP_ST_CONNECTED) { s_e2napCause = m_cause; s_e2napState = E2NAP_ST_CONNECTED; } else { s_e2napCause = m_cause; s_e2napState = E2NAP_ST_DISCONNECTED; } if ((err = pthread_mutex_unlock(&s_e2nap_mutex)) != 0) LOGE("%s() failed to release e2nap mutex: %s", __func__, strerror(err)); } else { if ((err = pthread_mutex_lock(&s_e2nap_mutex)) != 0) LOGE("%s() failed to take e2nap mutex: %s", __func__, strerror(err)); s_e2napState = m_state; s_e2napCause = m_cause; if ((err = pthread_mutex_unlock(&s_e2nap_mutex)) != 0) LOGE("%s() failed to release e2nap mutex: %s", __func__, strerror(err)); } LOGD("%s() %s", e2napStateToString(m_state), __func__); if (m_state != E2NAP_ST_CONNECTING) enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, onPDPContextListChanged, NULL, NULL); /* Make system request network information. This will allow RIL to report any new * technology made available from connection. */ if (E2NAP_ST_CONNECTED == m_state) RIL_onUnsolicitedResponse( RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0); mbm_check_error_cause(); }
void onConnectionStateChanged(const char *s) { int m_state = -1, m_cause = -1, err; int commas; err = at_tok_start((char **) &s); if (err < 0) return; /* Count number of commas */ err = at_tok_charcounter((char *) s, ',', &commas); if (err < 0) return; err = at_tok_nextint((char **) &s, &m_state); if (err < 0 || m_state < E2NAP_STATE_DISCONNECTED || m_state > E2NAP_STATE_CONNECTING) { m_state = -1; return; } err = at_tok_nextint((char **) &s, &m_cause); /* The <cause> will only be indicated/considered when <state> * is disconnected */ if (err < 0 || m_cause < E2NAP_CAUSE_SUCCESS || m_cause > E2NAP_CAUSE_MAXIMUM || m_state != E2NAP_STATE_DISCONNECTED) m_cause = -1; if (commas == 3) { int m_state2 = -1, m_cause2 = -1; err = at_tok_nextint((char **) &s, &m_state2); if (err < 0 || m_state2 < E2NAP_STATE_DISCONNECTED || m_state2 > E2NAP_STATE_CONNECTED) { m_state = -1; return; } if (m_state2 == E2NAP_STATE_DISCONNECTED) { err = at_tok_nextint((char **) &s, &m_cause2); if (err < 0 || m_cause2 < E2NAP_CAUSE_SUCCESS || m_cause2 > E2NAP_CAUSE_MAXIMUM) { m_cause2 = -1; } } if ((err = pthread_mutex_lock(&s_e2nap_mutex)) != 0) ALOGE("%s() failed to take e2nap mutex: %s", __func__, strerror(err)); if (m_state == E2NAP_STATE_CONNECTING || m_state2 == E2NAP_STATE_CONNECTING) { s_e2napState = E2NAP_STATE_CONNECTING; } else if (m_state == E2NAP_STATE_CONNECTED) { s_e2napCause = m_cause2; s_e2napState = E2NAP_STATE_CONNECTED; } else if (m_state2 == E2NAP_STATE_CONNECTED) { s_e2napCause = m_cause; s_e2napState = E2NAP_STATE_CONNECTED; } else { s_e2napCause = m_cause; s_e2napState = E2NAP_STATE_DISCONNECTED; } if ((err = pthread_mutex_unlock(&s_e2nap_mutex)) != 0) ALOGE("%s() failed to release e2nap mutex: %s", __func__, strerror(err)); } else { if ((err = pthread_mutex_lock(&s_e2nap_mutex)) != 0) ALOGE("%s() failed to take e2nap mutex: %s", __func__, strerror(err)); s_e2napState = m_state; s_e2napCause = m_cause; if ((err = pthread_mutex_unlock(&s_e2nap_mutex)) != 0) ALOGE("%s() failed to release e2nap mutex: %s", __func__, strerror(err)); } mbm_check_error_cause(); if (m_state == E2NAP_STATE_DISCONNECTED) { /* Bring down the interface as well. */ if (!(ifc_init())) { ifc_down(ril_iface); ifc_close(); } else ALOGE("%s() Failed to set up ifc!", __func__); } if ((m_state == E2NAP_STATE_DISCONNECTED) && (s_DeactCalled == 0)) { enqueueRILEvent(RIL_EVENT_QUEUE_PRIO, onPDPContextListChanged, NULL, NULL); } s_DeactCalled = 0; }