-/* //device/system/htcgeneric-ril/htcgeneric-ril.c
+/*
**
** Copyright 2006, The Android Open Source Project
** Copyright 2012 Eduardo Jos[e Tagle <ejtagle@tutopia.com>
** limitations under the License.
*/
-/*
-AT^CURC=0
-ATQ0V1
-
-^MODE:
-^RSSI:
-^SRVST:
-+CCCM:
-^CONN:
-^CEND:
-+CDSI:
-^SMMEMFULL:
-+CSSU:
-^DCONN
-^DEND
-^SIMST ¡
-+CRING:
-AT^SYSCFG=2,3,%s,1,2
-^RSSI
-^SMMEMFULL
-*/
-
-/*
-AT^SYSCFG=2,1,3FFFFFFF,1,2 for GPRS/EDGE Preferred
-AT^SYSCFG=2,2,3FFFFFFF,1,2 for 3G Preferred
-AT^SYSCFG=13,1,3FFFFFFF,1,2 for GPRS/EDGE Only
-AT^SYSCFG=14,2,3FFFFFFF,1,2 for 3G Only
-
-The third parameter, 0x3FFFFFFF tells the card to use all bands. A value of 0x400380 here means GSM900/1800/WCDMA2100 only and a value of 0x200000 here means GSM1900 only.
+//#define BYPASS_AUDIO_CHECK 1
-I don't know what the final "1,2" parameter is for. But for some it has to be "2,4" instead for some reason.
+/*
The status updates from the second port are prefixed with a caret and are of these forms:
^MODE:3,2 indicates GPRS
Maybe it's better to first type AT^U2DIAG=0 and then AT^U2DIAG=5 ...
Regards, Phil.
+
+
+-----
+1)with unaccepted sim
+-> AT^CARDLOCK?
+<-^CARDLOCK: 1,10,0 ............ locked
+<-^CARDLOCK: 2,10,0 ............ unlocked
+Quote:
+Originally Posted by sergeymkl
+4. second number of reply to CARDLOCK inquiry.
+<-^CARDLOCK: 1,10,0 ............ locked
+<-^CARDLOCK: 2,10,0 ............ unlocked
+<-^CARDLOCK: A,B,C ............
+A = is to verify if locked or unlocked
+B = attempts left? or total given attempts?
+C = is for?
+
*/
#define LOG_NDEBUG 0
#include "atchannel.h"
#include "at_tok.h"
#include "misc.h"
+#include "net-utils.h"
#include "gsm.h"
#include "requestdatahandler.h"
#include "fcp_parser.h"
#include <cutils/sockets.h>
#include <termios.h>
#include <cutils/properties.h>
+#include <log/logger.h>
#include <stdbool.h>
+#include <stddef.h>
-#define D ALOGD
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <linux/route.h>
+#include <linux/wireless.h>
-#define RIL_VERSION_STRING "Huawei-ril 1.0.0.0"
+#define D ALOGI
+
+#define RIL_VERSION_STRING "Huawei-ril 1.0.0.8 (Built on " __DATE__" " __TIME__ ")"
#define timespec_cmp(a, b, op) \
((a).tv_sec == (b).tv_sec \
#define TIMEOUT_EMRDY 10 /* Module should respond at least within 10s */
#define MAX_BUF 1024
-/* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
-#define PPP_TTY_PATH "ppp0"
-
-
/** declarations */
static const char *getVersion();
static void signalCloseQueues(void);
static void freeCardStatus(RIL_CardStatus_v6 *p_card_status);
static void onDataCallListChanged(void *param);
static int killConn(const char * cid);
-static int wait_for_property(const char *name, const char *desired_value, int maxwait);
+static int wait_for_property(const char *name, const char *desired_value, int maxwait, int allowempty);
static void checkMessageStorageReady(void *p);
+static int pppSupported(void);
static void onSIMReady(void *p);
static void pollSIMState(void *param);
static void checkMessageStorageReady(void *p);
getVersion
};
+static char* rndis_iface_dev = "/dev/ttyUSB0";
+static char* ppp_iface_dev = "/dev/ttyUSB0";
+static int using_rndis = 0;
+
+/* Last call index status */
+static int lastCallIdx = 0;
+
+/* Last call fail cause */
+static int lastCallFailCause = CALL_FAIL_NORMAL;
+
+#define RNDIS_IFACE "rmnet0"
+#define PPP_IFACE "ppp0"
+
static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
static const struct timespec TIMEVAL_SIMPOLL = {1,0};
};
/* The Audio channel */
-static struct GsmAudioTunnel sAudioChannel = GSM_AUDIO_CHANNEL_STATIC_INIT;
+static struct GsmAudioTunnel sAudioChannel;
static char sAudioDevice[64] = {0};
+static int audioTunnelMuted = 0; // If audio tunnel is muted
+
/* Starts the audio tunnel channel */
-static void startAudioTunnel(void)
+static void startAudioTunnel(void* param)
{
+ ALOGD("call startAudioTunnel");
#if 0
ATResponse *atResponse = NULL;
int err;
int voice_disabled = 0, sampling_rate = 8000,
bits_per_sample = 16, framesize_ms = 20;
- if (sAudioChannel.running)
+ if (gsm_audio_tunnel_running(&sAudioChannel))
return;
- // Enable voice function
+ // Enable voice function - Some firmwares fail this command, but
+ // nevertheless, it works. Leave validation for the next one.
err = at_send_command("AT^CVOICE=0");
- if (err != AT_NOERROR)
- goto error;
- // Check status.
- err = at_send_command_singleline("AT^CVOICE=?", "^CVOICE:", &atResponse);
+#ifndef BYPASS_AUDIO_CHECK
+ // Check status - This is the check that matters!
+ err = at_send_command_singleline("AT^CVOICE?", "^CVOICE:", &atResponse);
if (err != AT_NOERROR)
goto error;
err = at_tok_nextint(&line, &voice_disabled);
if (err < 0) goto error;
+ // Check if voice was really enabled
+ if (voice_disabled != 0) goto error;
+
err = at_tok_nextint(&line, &sampling_rate);
if (err < 0) goto error;
err = at_tok_nextint(&line, &framesize_ms);
if (err < 0) goto error;
+#else
+ sampling_rate = 8000;
+ bits_per_sample = 16;
+ framesize_ms = 20;
+#endif
- /* Switch to audio from USB1 */
- err = at_send_command("AT^DDSETEX=2");
- if (err != AT_NOERROR)
- goto error;
+ /* Increase volume to maximum. Some modems do not set the volume if not
+ actually changing values.... And some of them do not understand the
+ command at all. Try to switch volume to maximum - DerArtem */
+ err = at_send_command("AT+CLVL=1"); /* Lo volume */
+ err = at_send_command("AT+CLVL=5"); /* Maximum volume */
/* Start the audio channel */
err = gsm_audio_tunnel_start(&sAudioChannel,sAudioDevice,
if (err)
goto error;
- ALOGE("Audio Tunnel enabled");
+ // Mute/Ummute audioTunnel as requested
+ gsm_audio_tunnel_mute(&sAudioChannel,audioTunnelMuted);
+
+ ALOGD("Audio Tunnel enabled");
at_response_free(atResponse);
return;
ALOGE("Failed to start audio tunnel");
at_response_free(atResponse);
- return;
#endif
+ return;
}
/* Stops the audio tunnel channel */
-static void stopAudioTunnel(void)
+static void stopAudioTunnel(void* param)
{
#if 0
- if (!sAudioChannel.running)
+ if (!gsm_audio_tunnel_running(&sAudioChannel))
return;
// Stop the audio tunnel
gsm_audio_tunnel_stop(&sAudioChannel);
+#endif
+
+ ALOGD("Audio Tunnel disabled");
+}
+
+static void muteAudioTunnel(int muteit)
+{
+ ALOGD("call muteAudioTunnel");
+#if 0
+ audioTunnelMuted = muteit;
- D("Audio Tunnel disabled");
+ ALOGD("Audio Tunnel %smuted",muteit?"":"un");
+
+ if (!gsm_audio_tunnel_running(&sAudioChannel))
+ return;
+
+ // Mute/Ummute audioTunnel if requested
+ gsm_audio_tunnel_mute(&sAudioChannel,audioTunnelMuted);
#endif
}
char done = 0;
RequestQueue *q = NULL;
- RILEvent *e = (RILEvent *) malloc(sizeof(RILEvent));
- memset(e, 0, sizeof(RILEvent));
+ RILEvent *e = (RILEvent *) calloc(1, sizeof(RILEvent));
e->eventCallback = callback;
e->param = param;
if (relativeTime == NULL) {
relativeTime = (const struct timespec *) alloca(sizeof(struct timespec));
- memset((struct timespec *) relativeTime, 0, sizeof(struct timespec));
+ memset((void *) relativeTime, 0, sizeof(struct timespec));
}
clock_gettime(CLOCK_MONOTONIC, &ts);
}
+
/** returns 1 if on, 0 if off, and -1 on error */
static int isRadioOn()
{
ATResponse *atResponse = NULL;
- int err,ison;
+ int err;
char *line;
- char ret1,ret2;
-
- err = at_send_command_singleline("AT^RFSWITCH?", "^RFSWITCH:", &atResponse);
+ char ret1;
+ err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &atResponse);
if (err != AT_NOERROR) {
// assume radio is off
goto error;
err = at_tok_nextbool(&line, &ret1);
if (err < 0) goto error;
- err = at_tok_nextbool(&line, &ret2);
- if (err < 0) goto error;
-
at_response_free(atResponse);
- /* 1 is ON, 0 is OFF */
- ison = (ret1 == 1 && ret2 == 1);
+ ALOGD("Radio is %s", (ret1 == 1) ? "On" : "Off");
- ALOGD("Radio is %s", ison ? "On" : "Off");
-
- return ison;
+ /* 1=means online, all the others, mean offline */
+ return (ret1 == 1) ? 1 : 0;
error:
-
at_response_free(atResponse);
return -1;
}
const char *state;
switch (radioState) {
- case RADIO_STATE_OFF:
- state = "RADIO_STATE_OFF";
- break;
- case RADIO_STATE_UNAVAILABLE:
- state = "RADIO_STATE_UNAVAILABLE";
- break;
- case RADIO_STATE_SIM_NOT_READY:
- state = "RADIO_STATE_SIM_NOT_READY";
- break;
- case RADIO_STATE_SIM_LOCKED_OR_ABSENT:
- state = "RADIO_STATE_SIM_LOCKED_OR_ABSENT";
- break;
- case RADIO_STATE_SIM_READY:
- state = "RADIO_STATE_SIM_READY";
- break;
- case RADIO_STATE_RUIM_NOT_READY:
- state = "RADIO_STATE_RUIM_NOT_READY";
- break;
- case RADIO_STATE_RUIM_READY:
- state = "RADIO_STATE_RUIM_READY";
- break;
- case RADIO_STATE_RUIM_LOCKED_OR_ABSENT:
- state = "RADIO_STATE_RUIM_READY";
- break;
- case RADIO_STATE_NV_NOT_READY:
- state = "RADIO_STATE_NV_NOT_READY";
- break;
- case RADIO_STATE_NV_READY:
- state = "RADIO_STATE_NV_READY";
- break;
- default:
- state = "RADIO_STATE_<> Unknown!";
- break;
+ case RADIO_STATE_OFF:
+ state = "RADIO_STATE_OFF";
+ break;
+ case RADIO_STATE_UNAVAILABLE:
+ state = "RADIO_STATE_UNAVAILABLE";
+ break;
+ case RADIO_STATE_SIM_NOT_READY:
+ state = "RADIO_STATE_SIM_NOT_READY";
+ break;
+ case RADIO_STATE_SIM_LOCKED_OR_ABSENT:
+ state = "RADIO_STATE_SIM_LOCKED_OR_ABSENT";
+ break;
+ case RADIO_STATE_SIM_READY:
+ state = "RADIO_STATE_SIM_READY";
+ break;
+ case RADIO_STATE_RUIM_NOT_READY:
+ state = "RADIO_STATE_RUIM_NOT_READY";
+ break;
+ case RADIO_STATE_RUIM_READY:
+ state = "RADIO_STATE_RUIM_READY";
+ break;
+ case RADIO_STATE_RUIM_LOCKED_OR_ABSENT:
+ state = "RADIO_STATE_RUIM_READY";
+ break;
+ case RADIO_STATE_NV_NOT_READY:
+ state = "RADIO_STATE_NV_NOT_READY";
+ break;
+ case RADIO_STATE_NV_READY:
+ state = "RADIO_STATE_NV_READY";
+ break;
+ default:
+ state = "RADIO_STATE_<> Unknown!";
+ break;
}
return state;
return sState;
}
-
static void setRadioState(RIL_RadioState newState)
{
RIL_RadioState oldState;
oldState = sState;
ALOGI("%s() oldState=%s newState=%s", __func__, radioStateToString(oldState),
- radioStateToString(newState));
+ radioStateToString(newState));
sState = newState;
/* Do these outside of the mutex. */
if (sState != oldState || sState == RADIO_STATE_SIM_LOCKED_OR_ABSENT) {
RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
- NULL, 0);
+ NULL, 0);
if (sState == RADIO_STATE_SIM_READY) {
enqueueRILEvent(checkMessageStorageReady, NULL, NULL);
enqueueRILEvent(onSIMReady, NULL, NULL);
- } else if (sState == RADIO_STATE_SIM_NOT_READY)
+ } else if (sState == RADIO_STATE_SIM_NOT_READY) {
enqueueRILEvent(pollSIMState, NULL, NULL);
+ }
+ }
+}
+
+/*
+-> AT^CARDLOCK?
+<-^CARDLOCK: 1,10,0 ............ locked to an operator: Can be unlocked by code
+<-^CARDLOCK: 2,10,0 ............ unlocked
+<-^CARDLOCK: 3,10,0 ............ locked: Datacard is locked forever to an operator
+<-^CARDLOCK: A,B,C ............
+A = is to verify if locked or unlocked
+B = attempts left? or total given attempts?
+C = is for?
+*/
+
+static int getSimLockStatus(int* status, int* times)
+{
+ ATResponse *atResponse = NULL;
+ int err;
+ char *line;
+
+ err = at_send_command_singleline("AT^CARDLOCK?", "^CARDLOCK:", &atResponse);
+
+ if (err != AT_NOERROR) {
+ // assume locked
+ goto error;
}
+
+ line = atResponse->p_intermediates->line;
+
+ err = at_tok_start(&line);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, status);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, times);
+ if (err < 0) goto error;
+
+ at_response_free(atResponse);
+
+ ALOGD("Card %s, times: %d", *status == 1 ? "Locked" : "Unlocked" , *times);
+ return 0;
+
+error:
+ at_response_free(atResponse);
+ return -1;
}
+
typedef enum {
SIM_ABSENT = 0, /* SIM card is not inserted */
SIM_NOT_READY = 1, /* SIM card is not ready */
UICC_TYPE_UIM,
} UICC_Type;
+
+
/** Returns one of SIM_*. Returns SIM_NOT_READY on error. */
static SIM_Status getSIMStatus(void)
{
SIM_Status ret = SIM_ABSENT;
char *cpinLine;
char *cpinResult;
+ int status, times;
if (getRadioState() == RADIO_STATE_OFF ||
getRadioState() == RADIO_STATE_UNAVAILABLE) {
}
switch (at_get_cme_error(err)) {
- case CME_SIM_NOT_INSERTED:
- ret = SIM_ABSENT;
- break;
- case CME_SIM_PIN_REQUIRED:
- ret = SIM_PIN;
- break;
- case CME_SIM_PUK_REQUIRED:
- ret = SIM_PUK;
- break;
- case CME_SIM_PIN2_REQUIRED:
- ret = SIM_PIN2;
- break;
- case CME_SIM_PUK2_REQUIRED:
- ret = SIM_PUK2;
- break;
- case CME_NETWORK_PERSONALIZATION_PIN_REQUIRED:
- ret = SIM_NETWORK_PERSO;
- break;
- case CME_NETWORK_PERSONALIZATION_PUK_REQUIRED:
- ret = SIM_NETWORK_PERSO_PUK;
- break;
- case CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED:
- ret = SIM_NETWORK_SUBSET_PERSO;
- break;
- case CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED:
- ret = SIM_NETWORK_SUBSET_PERSO_PUK;
- break;
- case CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED:
- ret = SIM_SERVICE_PROVIDER_PERSO;
- break;
- case CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED:
- ret = SIM_SERVICE_PROVIDER_PERSO_PUK;
- break;
- case CME_PH_SIMLOCK_PIN_REQUIRED: /* PUK not in use by modem */
- ret = SIM_SIM_PERSO;
- break;
- case CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED:
- ret = SIM_CORPORATE_PERSO;
- break;
- case CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED:
- ret = SIM_CORPORATE_PERSO_PUK;
- break;
- default:
- ret = SIM_NOT_READY;
- break;
+ case CME_SIM_NOT_INSERTED:
+ ret = SIM_ABSENT;
+ break;
+ case CME_SIM_PIN_REQUIRED:
+ ret = SIM_PIN;
+ break;
+ case CME_SIM_PUK_REQUIRED:
+ ret = SIM_PUK;
+ break;
+ case CME_SIM_PIN2_REQUIRED:
+ ret = SIM_PIN2;
+ break;
+ case CME_SIM_PUK2_REQUIRED:
+ ret = SIM_PUK2;
+ break;
+ case CME_NETWORK_PERSONALIZATION_PIN_REQUIRED:
+ ret = SIM_NETWORK_PERSO;
+ break;
+ case CME_NETWORK_PERSONALIZATION_PUK_REQUIRED:
+ ret = SIM_NETWORK_PERSO_PUK;
+ break;
+ case CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED:
+ ret = SIM_NETWORK_SUBSET_PERSO;
+ break;
+ case CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED:
+ ret = SIM_NETWORK_SUBSET_PERSO_PUK;
+ break;
+ case CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED:
+ ret = SIM_SERVICE_PROVIDER_PERSO;
+ break;
+ case CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED:
+ ret = SIM_SERVICE_PROVIDER_PERSO_PUK;
+ break;
+ case CME_PH_SIMLOCK_PIN_REQUIRED: /* PUK not in use by modem */
+ ret = SIM_SIM_PERSO;
+ break;
+ case CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED:
+ ret = SIM_CORPORATE_PERSO;
+ break;
+ case CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED:
+ ret = SIM_CORPORATE_PERSO_PUK;
+ break;
+ default:
+ ret = SIM_NOT_READY;
+ break;
}
return ret;
}
if (0 == strcmp(cpinResult, "READY")) {
ret = SIM_READY;
+ if (getSimLockStatus(&status,×) < 0)
+ goto done;
+ if (status == 1 || status == 3) {
+ ret = SIM_NETWORK_PERSO;
+ }
} else if (0 == strcmp(cpinResult, "SIM PIN")) {
ret = SIM_PIN;
} else if (0 == strcmp(cpinResult, "SIM PUK")) {
return;
switch (getSIMStatus()) {
- case SIM_NOT_READY:
- ALOGI("SIM_NOT_READY, poll for sim state.");
- enqueueRILEvent(pollSIMState, NULL, &TIMEVAL_SIMPOLL);
- return;
+ case SIM_NOT_READY:
+ ALOGI("SIM_NOT_READY, poll for sim state.");
+ enqueueRILEvent(pollSIMState, NULL, &TIMEVAL_SIMPOLL);
+ return;
- case SIM_PIN2:
- case SIM_PUK2:
- case SIM_PUK2_PERM_BLOCKED:
- case SIM_READY:
- setRadioState(RADIO_STATE_SIM_READY);
- return;
- case SIM_ABSENT:
- 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);
- return;
+ case SIM_PIN2:
+ case SIM_PUK2:
+ case SIM_PUK2_PERM_BLOCKED:
+ case SIM_READY:
+ setRadioState(RADIO_STATE_SIM_READY);
+ return;
+ case SIM_ABSENT:
+ 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);
+ return;
}
}
-
-
static void sendCallStateChanged(void *param)
{
RIL_onUnsolicitedResponse (
static int clccStateToRILState(int state, RIL_CallState *p_state)
-
{
- switch(state) {
+ switch (state) {
case 0: *p_state = RIL_CALL_ACTIVE; return 0;
case 1: *p_state = RIL_CALL_HOLDING; return 0;
case 2: *p_state = RIL_CALL_DIALING; return 0;
ALOGI("Calls=%d,Valid=%d", countCalls, countValidCalls);
- /* If some voice calls are active, enable audio tunnel */
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
+ countValidCalls * sizeof (RIL_Call *));
+
+ /* Start/stop audio tunnel if a valid voice call is detected -
+ This will restart the audiotunnel when we preventively shut it
+ down after user hangs call (but should be restarted if in conference
+ Stopping should be handled by the connection end notification, but,
+ just in case, we also handle it here*/
if (countValidCalls) {
- startAudioTunnel();
+ startAudioTunnel(NULL);
} else {
- stopAudioTunnel();
+ stopAudioTunnel(NULL);
}
- RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
- countValidCalls * sizeof (RIL_Call *));
-
at_response_free(atResponse);
if (needRepoll) {
/* wait for a propertyvalue change */
-static int wait_for_property(const char *name, const char *desired_value, int maxwait)
+static int wait_for_property(const char *name, const char *desired_value, int maxwait, int allowempty)
{
char value[PROPERTY_VALUE_MAX] = {'\0'};
- int maxnaps = maxwait / 1;
+ int maxnaps = maxwait;
if (maxnaps < 1) {
maxnaps = 1;
}
while (maxnaps-- > 0) {
- usleep(1000000);
if (property_get(name, value, NULL)) {
- if (desired_value == NULL ||
- strcmp(value, desired_value) == 0) {
- return 0;
+ if (allowempty || (!allowempty && value[0]!=0)) {
+ if (desired_value == NULL ||
+ strcmp(value, desired_value) == 0) {
+ return 0;
+ }
}
}
+ sleep(1);
}
return -1; /* failure */
}
-static int killConn(const char * cid)
+/* Write an string to the modem */
+static int dial_at_modem(const char* cmd, int skipanswerwait)
{
- int err;
- int fd;
- int i=0;
+ int i, n, ret;
+ int fd = -1;
+ char buf[64+1];
+
+ ALOGD("dial_at_modem: opening modem %s", ppp_iface_dev);
+ do {
+ fd = open( ppp_iface_dev, O_RDWR | O_NOCTTY | O_NDELAY); /* nonblocking */
+ } while (fd < 0 && errno == EINTR);
+
+ if (fd < 0) {
+ ALOGE("could not open modem %s: %s", ppp_iface_dev, strerror(errno) );
+ return -1;
+ }
+
+ // disable echo on serial lines and set a 10 second timeout
+ if ( isatty( fd ) ) {
+ struct termios ios;
+ tcgetattr( fd, &ios );
+ ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
+ ios.c_oflag &= (~ONLCR); /* Stop \n -> \r\n translation on output */
+ ios.c_iflag &= (~(ICRNL | INLCR)); /* Stop \r -> \n & \n -> \r translation on input */
+ ios.c_iflag |= (IGNCR | IXOFF); /* Ignore \r & XON/XOFF on input */
+ ios.c_cc[VTIME] = 10; /* Timeout in 1/10 of a second */
+ ios.c_cc[VMIN] = 0; /* Minimum number of chars returned: 0*/
+ tcsetattr( fd, TCSANOW, &ios );
+ }
+
+ // Discard all pending data */
+ tcflush(fd, TCIOFLUSH);
+
+ // If hangup sequence, wait a bit...
+ if (!strcmp(cmd,"+++")) {
+ sleep(1);
+ }
+
+ // Write command to modem
+ ALOGD("dial_at_modem: writing command: %s", cmd);
+ i = strlen(cmd);
+ n = 0;
+ do {
+ ret = write(fd, cmd + n, i - n);
+ if (ret < 0 && errno == EINTR)
+ continue;
+ if (ret < 0) {
+ ALOGE("Error writing to modem: %s", strerror(errno) );
+ close(fd);
+ return -1;
+ }
+ n += ret;
+ } while (n < i);
- D("killConn");
+ // Force all the data to be transmitted
+ tcdrain(fd);
+
+ // If hangup sequence, wait a bit... and we are done. Modem won't answer it
+ if (!strcmp(cmd,"+++")) {
+ sleep(1);
+
+ // Leave line ready */
+ write(fd, "\r\n", 2);
+ tcdrain(fd);
-#if 0
- while ((fd = open("/sys/class/net/ppp0/ifindex",O_RDONLY)) > 0)
- {
- if(i%5 == 0)
- system("killall pppd");
- if(i>25)
- goto error;
- i++;
close(fd);
- sleep(2);
- }
-#elif 0
- // Requires root access...
- property_set("ctl.stop", "pppd_gprs");
- if (wait_for_property("init.svc.pppd_gprs", "stopped", 10) < 0) {
- goto error;
+ return 0;
}
-#endif
- D("killall pppd finished");
+ // If we must skip waiting for an answer
+ if (skipanswerwait) {
+ close(fd);
+ return 0;
+ }
- err = at_send_command("AT+CGACT=0,%s", cid);
- if (err != AT_NOERROR)
- goto error;
+ // Read answer with timeout
+ ALOGD("dial_at_modem: waiting for response");
+ do {
- at_send_command("ATH");
- return 0;
+ /* Receive a line with timeout */
+ int waitc = 5;
+ n = 0;
+ do {
+ ret = read(fd, &buf[n], 1);
+ if (ret < 0 && (errno == EINTR || errno == EAGAIN))
+ continue;
-error:
- return -1;
-}
+ if (ret < 0) {
+ ALOGE("dial_at_modem: Error reading from serial port: %d",errno);
+ close(fd);
+ return -1;
+ }
+ if (ret == 0) {
+ waitc --;
+ if (waitc <= 0) {
+ ALOGE("dial_at_modem: No answer from modem");
+ close(fd);
+ return -1;
+ }
-//static char userPassStatic[512] = "preload";
+ // not timed out yet, sleep a second
+ sleep(1);
+ } else {
+ /* Something received, restart timeout */
+ waitc = 5;
+ }
-static void requestSetupDefaultPDP(void *data, size_t datalen, RIL_Token t)
-{
- const char *apn;
- const char *user = NULL;
- const char *pass = NULL;
- char pppdcmd[512] = "/system/bin/pppd ";
- int err;
- int fd, pppstatus,i;
- FILE *pppconfig;
- size_t cur = 0;
- ssize_t written, rlen;
- char status[32] = {0};
- char *buffer;
- long buffSize, len;
- int retry = 10;
-
- int n = 1;
- RIL_Data_Call_Response_v6 responses;
- char ppp_dnses[(PROPERTY_VALUE_MAX * 2) + 3] = {'\0'};
- char ppp_local_ip[PROPERTY_VALUE_MAX] = {'\0'};
- char ppp_dns1[PROPERTY_VALUE_MAX] = {'\0'};
- char ppp_dns2[PROPERTY_VALUE_MAX] = {'\0'};
- char ppp_gw[PROPERTY_VALUE_MAX] = {'\0'};
+ // Count of read chars
+ n += ret;
+ } while (n < 64 && buf[n-1] != '\n');
- apn = ((const char **)data)[2];
- user = ((char **)data)[3];
- if (user == NULL || strlen(user) < 2) {
- user = "dummy";
- }
+ /*buf[n] = 0; ALOGD("dial_at_modem: read %d bytes ['%s']",n,&buf[0]);*/
- pass = ((char **)data)[4];
- if (pass == NULL || strlen(pass) < 2) {
- pass = "dummy";
- }
+ // Remove the trailing spaces
+ while (n > 0 && buf[n-1] <= ' ' && buf[n-1] != 0)
+ n--;
+ buf[n] = 0;
- D("requesting data connection to APN '%s'", apn);
+ // Remove the leading spaces
+ n = 0;
+ while (buf[n]<= ' ' && buf[n] != 0)
+ n++;
- // Make sure there is no existing connection or pppd instance running
- if (killConn("1") < 0) {
- ALOGE("killConn Error!");
- goto error;
- }
+ } while (buf[0] == 0); // Ignore blank lines
- /* Switch radio ON */
- err = at_send_command("AT^RFSWITCH=1");
- err = at_send_command("AT+CFUN=1");
+ close(fd);
- /* Define the PDP context */
- err = at_send_command("AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn);
+ ALOGD("dial_at_modem: got answer : '%s'",&buf[n]);
+ if (strstr(&buf[n],"OK")) return 0;
+ if (strstr(&buf[n],"CONNECT")) return 0;
- /* Set required QoS params to default */
- err = at_send_command("AT+CGQREQ=1");
+ return -1;
+}
- /* Set minimum QoS params to default */
- err = at_send_command("AT+CGQMIN=1");
+static int killConn(const char* cididx)
+{
+ /* Leave NDIS mode */
+ if (!pppSupported())
+ at_send_command("AT^NDISDUP=%s,0",cididx);
- /* packet-domain event reporting */
- err = at_send_command("AT+CGEREP=1,0");
+ /* Leave Data context mode */
+ at_send_command("AT+CGACT=0,%s", cididx);
- /* Hangup anything that's happening there now */
- err = at_send_command("AT+CGACT=0,1");
+ /* Hang up */
+ at_send_command("ATH");
- /* Start data on PDP context 1 */
- err = at_send_command("ATD*99***1#");
-// if (err != AT_NOERROR) {
-// goto error;
-// }
- sleep(2); //Wait for the modem to finish
+ /* Kill pppd daemon (just in case)*/
+ system("killall pppd");
- // set up the pap/chap secrets file
-// sprintf(userpass, "%s * %s", user, pass);
+ /* Hang up modem, if needed */
+ //dial_at_modem("+++",1);
+ dial_at_modem("ATH\r\n",1);
- /* start the gprs pppd */
-#if 1
- property_get("rild.ppp.tty", pppdcmd + strlen(pppdcmd), "/dev/ttyUSB0");
- strcat(pppdcmd, " call gprs");
- system(pppdcmd);
-#else
- // Requires root access...
- property_set("ctl.start", "ppp");
- if (wait_for_property("init.svc.ppp", "running", 10) < 0) {
- ALOGE("Timeout waiting init.svc.ppp - giving up!");
- goto error;
+ /* Bring down all interfaces */
+ if (ifc_init() == 0) {
+ ifc_down(RNDIS_IFACE);
+ ifc_down(PPP_IFACE);
+ ifc_close();
}
-#endif
- sleep(10); // Allow time for ip-up to complete
+ return 0;
+}
- if (wait_for_property("net.ppp0.local-ip", NULL, 10) < 0) {
- ALOGE("Timeout waiting net.ppp0.local-ip - giving up!");
- goto error;
- }
+#define LOG_FILE_DIR "/dev/log/"
- property_get("net.ppp0.local-ip", ppp_local_ip, NULL);
- property_get("net.dns1", ppp_dns1, NULL);
- property_get("net.dns2", ppp_dns2, NULL);
- property_get("net.ppp0.gw", ppp_gw, NULL);
- sprintf(ppp_dnses, "%s %s", ppp_dns1, ppp_dns2);
+struct lc_entry {
+ union {
+ unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
+ struct logger_entry entry __attribute__((aligned(4)));
+ };
+};
- ALOGI("Got net.ppp0.local-ip: %s", ppp_local_ip);
+/* Get the connection data used by pppd from the android logcat */
+int get_pppd_info(struct timeval* from, char* local_ip, char* dns1, char* dns2, char* gw)
+{
+ struct lc_entry* lce;
- responses.status = 0;
- responses.suggestedRetryTime = -1;
- responses.cid = 1;
- responses.active = 2;
- responses.type = (char*)"PPP";
- responses.ifname = (char*)PPP_TTY_PATH;
- responses.addresses = ppp_local_ip;
- responses.dnses = ppp_dnses;
- responses.gateways = ppp_gw;
+ const char mainlog[] = LOG_FILE_DIR "main";
+ const char pppd_str[] = "pppd";
+ const char local_ip_str[] = "local IP address ";
+ const char remote_ip_str[] = "remote IP address ";
+ const char primary_dns_str[] = "primary DNS address ";
+ const char secondary_dns_str[] = "secondary DNS address ";
- RIL_onRequestComplete(t, RIL_E_SUCCESS, &responses, sizeof(RIL_Data_Call_Response_v6));
- return;
+ int fd;
+ int result;
+ fd_set readset;
+ int search_tmout = 500; //
-error:
- ALOGE("Unable to setup PDP");
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ local_ip[0] = 0;
+ dns1[0] = 0;
+ dns2[0] = 0;
+ gw[0] = 0;
-}
+ lce = malloc(sizeof(struct lc_entry));
+ if (!lce) {
+ ALOGE("Failed to allocate logcat entry buffer");
+ return -1;
+ }
-/* CHECK There are several error cases if PDP deactivation fails
- * 24.008: 8, 25, 36, 38, 39, 112
- */
-static void requestDeactivateDefaultPDP(void *data, size_t datalen, RIL_Token t)
-{
- char * cid;
+ fd = open(mainlog, O_RDONLY);
+ if (fd < 0) {
+ ALOGE("Unable to open log device '%s': %s", mainlog, strerror(errno));
+ free(lce);
+ return -1;
+ }
- D("requestDeactivateDefaultPDP()");
+ /*ALOGD("filter: sec:%d, usec:%d", from->tv_sec, from->tv_usec);*/
- cid = ((char **)data)[0];
- if (killConn(cid) < 0)
- goto error;
+ while (1) {
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ do {
+ struct timeval timeout = { 0, 10000 /* 10ms */ };
+ FD_ZERO(&readset);
+ FD_SET(fd, &readset);
+ result = select(fd + 1, &readset, NULL, NULL, &timeout);
+ } while (result < 0 && errno == EINTR);
+
+ // Wait until we find something...
+ if (result == 0) {
+ if (search_tmout > 0) {
+ search_tmout --;
+ continue;
+ } else
+ break;
+ }
+
+ if (result > 0 && FD_ISSET(fd, &readset)) {
+
+ /* NOTE: driver guarantees we read exactly one full entry */
+ int ret = read(fd, lce, LOGGER_ENTRY_MAX_LEN);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ if (errno == EAGAIN) {
+ continue;
+ }
+ ALOGE("logcat read");
+ continue;
+ }
+ else if (!ret) {
+ ALOGE("read: Unexpected EOF!");
+ continue;
+ }
+ else if (lce->entry.len != ret - sizeof(struct logger_entry)) {
+ ALOGE("read: unexpected length. Expected %d, got %d",
+ lce->entry.len, ret - sizeof(struct logger_entry));
+ continue;
+ }
+
+ lce->entry.msg[lce->entry.len] = '\0';
+
+ /*
+ * format: <priority:1><tag:N>\0<message:N>\0
+ *
+ * tag str
+ * starts at buf->msg+1
+ * msg
+ * starts at buf->msg+1+len(tag)+1
+ *
+ * The message may have been truncated by the kernel log driver.
+ * When that happens, we must null-terminate the message ourselves.
+ */
+
+ /*ALOGD("entry: tag:%d[%c], sec:%d, usec:%d, n:%s, m:%s", lce->entry.msg[0], lce->entry.msg[0], lce->entry.sec, lce->entry.nsec/1000, &lce->entry.msg[1],(&lce->entry.msg[1])+strlen(&lce->entry.msg[1])+1); */
+
+ // We are interested in pppd entries with I priority newer than specified
+ if ((lce->entry.msg[0] == 'i' || lce->entry.msg[0] == 'I' || lce->entry.msg[0] == 4) &&
+ (lce->entry.sec > from->tv_sec ||
+ (lce->entry.sec == from->tv_sec && (lce->entry.nsec/1000) >= from->tv_usec)) &&
+ !strcmp(&lce->entry.msg[1],pppd_str)) {
+ char * pos = NULL;
+
+ // Dealing with PPPD entries in logcat - Get a pointer to the message
+ char * msg = (&lce->entry.msg[1]) + strlen(&lce->entry.msg[1]) + 1;
+
+ // Strip leading spaces
+ while (*msg != 0 && *msg <= ' ') msg++;
+
+ // And also strip trailing spaces...
+ pos = msg + strlen(msg);
+ while (pos != msg && pos[-1] <= ' ') pos--;
+ *pos = 0;
+
+ // An entry we are interested in ?
+ if ((pos = strstr(msg,local_ip_str)) != NULL) {
+ strcpy(local_ip,msg + sizeof(local_ip_str) - 1);
+ strcpy(gw,msg + sizeof(local_ip_str) - 1);
+ } else
+ if ((pos = strstr(msg,remote_ip_str)) != NULL) {
+ // We found the remote_ip address ... Give no more than 3 seconds for the next entry to appear
+ // (those entries are not mandatory)
+ search_tmout = 300;
+ } else
+ if ((pos = strstr(msg,primary_dns_str)) != NULL) {
+ strcpy(dns1,msg + sizeof(primary_dns_str) - 1);
+ } else
+ if ((pos = strstr(msg,secondary_dns_str)) != NULL) {
+ strcpy(dns2,msg + sizeof(secondary_dns_str) - 1);
+ }
+ }
+
+ // If we have all required data, break now!
+ if (local_ip[0] && gw[0] && dns1[0] && dns2[0]) {
+ break;
+ }
+ }
+ }
+
+ close(fd);
+ free(lce);
+
+ // Return if we succeeded or not
+ return local_ip[0] ? 0 : -1;
+}
+
+
+/* Setup connection using PPP */
+static int setupPPP(RIL_Token t,const char* ctxid,const char* user,const char* pass)
+{
+ int err;
+ char* cmd = NULL;
+ const char* fmt;
+ in_addr_t addr;
+ in_addr_t mask;
+ unsigned flags = 0;
+ int ctr = 10;
+ struct timeval from_tm;
+
+ RIL_Data_Call_Response_v6 responses;
+ char ppp_ifname[PROPERTY_VALUE_MAX] = {'\0'};
+ char ppp_local_ip[PROPERTY_VALUE_MAX] = {'\0'};
+ char ppp_dns1[PROPERTY_VALUE_MAX] = {'\0'};
+ char ppp_dns2[PROPERTY_VALUE_MAX] = {'\0'};
+ char ppp_dnses[(PROPERTY_VALUE_MAX * 2) + 3] = {'\0'};
+ char ppp_gw[PROPERTY_VALUE_MAX] = {'\0'};
+ char pbuf[32] = {'\0'};
+
+
+ ALOGD("Trying to setup PPP connnection...");
+
+#if 1
+ /* PDP context activation */
+ //err = at_send_command("AT+CGACT=0,%s",ctxid);
+ err = at_send_command("ATD*99***%s#", ctxid);
+#else
+ /* Try just with data context activation */
+ asprintf(&cmd,"AT+CGDATA=\"PPP\",%s\r\n",ctxid);
+ err = dial_at_modem(cmd,0);
+ free(cmd);
+ if (err) {
+ /* If failed, retry with dial command */
+ asprintf(&cmd,"ATD*99***%s#\r\n",ctxid);
+ err = dial_at_modem(cmd,0);
+ free(cmd);
+ if (err) {
+ ALOGE("Failed to dial");
+ return -1;
+ }
+ }
+#endif
+
+ /* Wait for the modem to finish */
+ sleep(2);
+
+ /* original options
+ "nodetach debug noauth defaultroute usepeerdns "
+ "connect-delay 1000 "
+ "user NotUsed@nobody.com password NotUsed "
+ "crtscts lcp-echo-failure 0 lcp-echo-interval 0 ipcp-max-configure 30 "
+ "ipcp-max-failure 30 ipcp-max-terminate 10 novj linkname ril";
+ */
+
+#if 0
+ /* start the gprs pppd - pppd must be suid root */
+ if (user == NULL || user[0] == 0 ||
+ pass == NULL || pass[0] == 0 ) {
+
+ fmt = "/system/bin/pppd %s "
+ "115200 "
+ "crtscts modem "
+ "linkname ril%s "
+ "noauth "
+ "user %s password %s "
+ "defaultroute usepeerdns noipdefault "
+ "novj novjccomp nobsdcomp "
+ "ipcp-accept-remote ipcp-accept-local "
+ "dump debug "
+ "lcp-echo-failure 0 lcp-echo-interval 0 ipcp-max-configure 30 "
+ "ipcp-max-failure 30 ipcp-max-terminate 10";
+
+ } else {
+
+ fmt = "/system/bin/pppd %s "
+ "115200 "
+ "crtscts modem "
+ "linkname ril%s "
+ "user %s password %s "
+ "defaultroute usepeerdns noipdefault "
+ "novj novjccomp nobsdcomp "
+ "ipcp-accept-remote ipcp-accept-local "
+ "dump debug "
+ "lcp-echo-failure 0 lcp-echo-interval 0 ipcp-max-configure 30 "
+ "ipcp-max-failure 30 ipcp-max-terminate 10";
+ }
+
+ asprintf(&cmd,fmt,ppp_iface_dev,ctxid, ((user && user[0])? user: "guest"), ((pass && pass[0])? pass: "guest") );
+#else
+ fmt = "/system/bin/pppd %s call gprs";
+ asprintf(&cmd, fmt, ppp_iface_dev);
+#endif
+
+ ALOGD("Starting pppd w/command line: '%s'", cmd);
+
+ // Get current time
+ gettimeofday(&from_tm,NULL);
+
+ // Start PPPD
+ system(cmd);
+ free(cmd);
+
+#if 0
+ /* Try not to depend on ip-up/down scripts ... */
+
+ // Wait until network interface is up and running
+ if (ifc_init() < 0) {
+ ALOGE("Failed initialization of net ifc");
+ return -1;
+ }
+
+ ALOGD("Waiting until net ifc %s is up", PPP_IFACE);
+ ctr = 20;
+ do {
+ sleep(1); // wait one second...
+ flags = 0;
+ ifc_get_info(PPP_IFACE, &addr, &mask, &flags);
+ } while (--ctr > 0 && !(flags & IFF_UP));
+ ifc_close();
+
+ if (ctr <= 0) {
+ ALOGE("Net ifc %s was never upped!", PPP_IFACE);
+ return -1;
+ }
+
+ /* Get PPP information by reading and parsing the PPPD log */
+ if (get_pppd_info(&from_tm, ppp_local_ip, ppp_dns1, ppp_dns2, ppp_gw) < 0) {
+ ALOGE("Unable to get dns/gw");
+ return -1;
+ }
+
+ strcpy(ppp_ifname,PPP_IFACE);
+
+#elif 0
+ // Wait until ppp ip-up script has completely executed...
+ sprintf(pbuf,"net.ril%s.if",ctxid);
+ if (wait_for_property(pbuf, NULL, 20, 0) < 0) {
+ ALOGE("Timeout waiting %s - giving up!", pbuf);
+ return -1;
+ }
+ property_get(pbuf, ppp_ifname, NULL);
+
+ // Get local IP
+ sprintf(pbuf,"net.ril%s.local-ip",ctxid);
+ property_get(pbuf, ppp_local_ip, NULL);
+
+ sprintf(pbuf,"net.ril%s.dns1",ctxid);
+ property_get(pbuf, ppp_dns1, NULL);
+
+ sprintf(pbuf,"net.ril%s.dns2",ctxid);
+ property_get(pbuf, ppp_dns2, NULL);
+
+ sprintf(pbuf,"net.ril%s.gw",ctxid);
+ property_get(pbuf, ppp_gw, NULL);
+
+#else
+ strcpy(ppp_ifname,PPP_IFACE);
+ strcpy(pbuf, "net." PPP_IFACE ".local-ip");
+ if (wait_for_property(pbuf, NULL, 20, 0) < 0) {
+ ALOGE("Timeout waiting %s - giving up!", pbuf);
+ return -1;
+ }
+ property_get("net.ppp0.local-ip", ppp_local_ip, NULL);
+ property_get("net.ppp0.gw", ppp_gw, NULL);
+ property_get("net.dns1", ppp_dns1, NULL);
+ property_get("net.dns2", ppp_dns2, NULL);
+
+#endif
+
+ sprintf(ppp_dnses, "%s %s", ppp_dns1, ppp_dns2);
+
+ ALOGI("Got ifname: %s, local-ip: %s, dns1: %s, dns2: %s, gw: %s",
+ ppp_ifname, ppp_local_ip, ppp_dns1, ppp_dns2, ppp_gw);
+
+ responses.status = 0;
+ responses.suggestedRetryTime = -1;
+ responses.cid = (ctxid[0] - '0');
+ responses.active = 2;
+ responses.type = (char*)"PPP";
+ responses.ifname = ppp_ifname;
+ responses.addresses = ppp_local_ip;
+ responses.dnses = ppp_dnses;
+ responses.gateways = ppp_gw;
+
+ using_rndis = 0;
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &responses, sizeof(RIL_Data_Call_Response_v6));
+ return 0;
+}
+
+/* Converts a hex encoded addr to an std addr */
+static void str2addr(char* addr,const char* str)
+{
+ unsigned int val = (unsigned int) strtoul(str, NULL, 16);
+ sprintf(addr,"%u.%u.%u.%u",
+ (val & 0x000000ffU),
+ (val & 0x0000ff00U) >> 8U,
+ (val & 0x00ff0000U) >> 16U,
+ (val & 0xff000000U) >> 24U);
+}
+
+/* Setup connection using NDIS */
+static int setupNDIS(RIL_Token t,const char* ctxid)
+{
+ ATResponse *atResponse = NULL;
+ RIL_Data_Call_Response_v6 responses;
+ char rndis_dnses[64 + 3] = {'\0'};
+ char rndis_local_ip[32] = {'\0'};
+ char rndis_dns1[32] = {'\0'};
+ char rndis_dns2[32] = {'\0'};
+ char rndis_gw[32] = {'\0'};
+
+ in_addr_t in_addr;
+ in_addr_t in_gateway;
+
+ int err;
+ char *line;
+ char *ip = NULL;
+ char *netmask = NULL;
+ char *gateway = NULL;
+ char *unk = NULL;
+ char *dns1 = NULL;
+ char *dns2 = NULL;
+
+ ALOGD("Trying to setup NDIS connnection...");
+
+ /* Enter data state using context #1 as NDIS */
+ err = at_send_command("AT^NDISDUP=%s,1",ctxid);
+ if (err != AT_NOERROR)
+ return -1;
+
+ /* Leave 10 seconds for startup */
+ sleep(10);
+
+ /* Check DHCP status */
+ err = at_send_command_singleline("AT^DHCP?", "^DHCP:", &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_nextstr(&line, &ip);
+ if (err < 0) goto error;
+
+ err = at_tok_nextstr(&line, &netmask);
+ if (err < 0) goto error;
+
+ err = at_tok_nextstr(&line, &gateway);
+ if (err < 0) goto error;
+
+ err = at_tok_nextstr(&line, &unk);
+ if (err < 0) goto error;
+
+ err = at_tok_nextstr(&line, &dns1);
+ if (err < 0) goto error;
+
+ err = at_tok_nextstr(&line, &dns2);
+ if (err < 0) goto error;
+
+ ALOGD("IP: %s, netmask: %s, gateway: %s, dns1:%s, dns2:%s",ip,netmask,gateway,dns1,dns2);
+
+ str2addr(rndis_local_ip, ip);
+ if (inet_pton(AF_INET, rndis_local_ip, &in_addr) <= 0) {
+ ALOGE("%s() inet_pton() failed for %s!", __func__, rndis_local_ip);
+ goto error;
+ }
+
+ str2addr(rndis_dns1, dns1);
+ str2addr(rndis_dns2, dns2);
+ sprintf(rndis_dnses, "%s %s", rndis_dns1, rndis_dns2);
+
+ str2addr(rndis_gw, gateway);
+ if (inet_pton(AF_INET, rndis_gw, &in_gateway) <= 0) {
+ ALOGE("%s() inet_pton() failed for %s!", __func__, rndis_gw);
+ goto error;
+ }
+
+ at_response_free(atResponse);
+
+ responses.status = 0;
+ responses.suggestedRetryTime = -1;
+ responses.cid = 1;
+ responses.active = 2;
+ responses.type = (char*)"RNDIS";
+ responses.ifname = (char*)RNDIS_IFACE;
+ responses.addresses = rndis_local_ip;
+ responses.dnses = rndis_dnses;
+ responses.gateways = rndis_gw;
+
+ /* Don't use android netutils. We use our own and get the routing correct.
+ * Carl Nordbeck */
+ if (ifc_configure(RNDIS_IFACE, in_addr, in_gateway))
+ ALOGE("%s() Failed to configure the interface %s", __func__, RNDIS_IFACE);
+
+ using_rndis = 1;
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &responses, sizeof(RIL_Data_Call_Response_v6));
+ return 0;
+
+error:
+ ALOGE("Failed to start NDIS mode");
+
+ at_response_free(atResponse);
+ return -1;
+}
+
+/* Query if modem supports PPP. Otherwise, RNDIS will be used */
+static int pppSupported(void)
+{
+ ATResponse *atResponse = NULL;
+
+ int err;
+ int supp_mode = 0; // PPP
+ char *line;
+
+ ALOGD("Identifying modem capabilities...");
+
+ /* Check Modem capabilities */
+ err = at_send_command_singleline("AT^DIALMODE?", "^DIALMODE:", &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, &supp_mode);
+ if (err < 0) goto error;
+
+ ALOGD("Modem mode: %d [0=ppp,1=ndis,2=ppp&ndis]",supp_mode);
+
+ at_response_free(atResponse);
+
+ return supp_mode != 1; // ppp supported
+
+error:
+ ALOGD("Assuming PPP mode");
+ at_response_free(atResponse);
+ return 1;
+}
+
+static void requestSetupDefaultPDP(void *data, size_t datalen, RIL_Token t)
+{
+ const char *apn;
+ const char *user = NULL;
+ const char *pass = NULL;
+ int err;
+ const char* ctxid = "1";
+ int use_ppp;
+
+ apn = ((const char **)data)[2];
+ user = ((char **)data)[3];
+ if (user == NULL || strlen(user) < 2) {
+ user = "dummy";
+ }
+
+ pass = ((char **)data)[4];
+ if (pass == NULL || strlen(pass) < 2) {
+ pass = "dummy";
+ }
+
+ /* Check if PPP is supported */
+ use_ppp = pppSupported();
+
+ D("requesting data connection to APN '%s' use_ppp=%d", apn, use_ppp);
+
+ // Make sure there is no existing connection
+ killConn(ctxid);
+
+
+ /* packet-domain event reporting */
+ err = at_send_command("AT+CGEREP=1,0");
+
+ /* Define the PDP context #1*/
+ err = at_send_command("AT+CGDCONT=%s,\"IP\",\"%s\"",ctxid, apn);
+
+ /* Set required QoS params to default */
+ err = at_send_command("AT+CGQREQ=%s",ctxid);
+
+ /* Set minimum QoS params to default */
+ err = at_send_command("AT+CGQMIN=%s",ctxid);
+
+ /* Attach to GPRS network */
+ err = at_send_command("AT+CGATT=1");
+
+ if (use_ppp) {
+ if (setupPPP(t,ctxid,user,pass) < 0) {
+ goto error;
+ }
+ } else {
+ if (setupNDIS(t,ctxid) < 0) {
+ goto error;
+ }
+ }
+
+ ALOGD("Data connection established!");
+ return;
+
+error:
+ ALOGE("Unable to setup PDP");
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+}
+
+/* CHECK There are several error cases if PDP deactivation fails
+ * 24.008: 8, 25, 36, 38, 39, 112
+ */
+static void requestDeactivateDefaultPDP(void *data, size_t datalen, RIL_Token t)
+{
+ char * cid;
+
+ D("requestDeactivateDefaultPDP()");
+
+ cid = ((char **)data)[0];
+ if (killConn(cid) < 0)
+ goto error;
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
return;
error:
responses[i].cid = -1;
responses[i].active = -1;
responses[i].type = (char*)"";
- responses[i].ifname = (char*)PPP_TTY_PATH;
+ responses[i].ifname = using_rndis ? (char*)RNDIS_IFACE : (char*)PPP_IFACE;
responses[i].addresses = (char*)"";
responses[i].dnses = (char*)"";
responses[i].gateways = (char*)"";
if (err < 0)
goto error;
- responses[i].ifname = (char*)PPP_TTY_PATH;
+ responses[i].ifname = using_rndis ? (char*)RNDIS_IFACE : (char*)PPP_IFACE;
err = at_tok_nextstr(&line, &out);
if (err < 0)
at_response_free(atResponse);
atResponse = NULL;
+ /* Make sure interface is UP and running. If not, invalidate datacall to
+ force Android to reconnect - This will happen when resuming from suspend, as pppd
+ has probably ended as a consequence of the USB bus being suspended and the terminal
+ disappearing. So, that is why we have this check here. Not only the modem has to
+ report an active connection, also linux has to export an active net interface !*/
+ if (ifc_init() >= 0) {
+ in_addr_t addr;
+ in_addr_t mask;
+ unsigned flags = 0;
+ ifc_get_info( responses[i].ifname, &addr, &mask, &flags);
+ if (!(flags & IFF_UP)) {
+ for (i = 0; i < n; i++) {
+ if (responses[i].active) {
+ ALOGD("DataCall cid:%d forced to inactive, as associated interface [%s] is DOWN", responses[i].cid, responses[i].ifname );
+ responses[i].active = 0;
+ }
+ }
+ }
+ ifc_close();
+ }
+
if (t != NULL)
RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
n * sizeof(RIL_Data_Call_Response_v6));
static void enqueue_held_pdu(char type, const char *sms_pdu)
{
- struct held_pdu *hpdu = (struct held_pdu *) malloc(sizeof(*hpdu));
+ struct held_pdu *hpdu = (struct held_pdu *) calloc(1, sizeof(*hpdu));
if (hpdu == NULL) {
ALOGE("%s() failed to allocate memory!", __func__);
return;
}
- memset(hpdu, 0, sizeof(*hpdu));
hpdu->type = type;
hpdu->sms_pdu = strdup(sms_pdu);
if (NULL == hpdu->sms_pdu) {
return;
}
- if (s_held_pdus == NULL)
+ if (s_held_pdus == NULL) {
s_held_pdus = hpdu;
- else {
+ } else {
struct held_pdu *p = s_held_pdus;
while (p->next != NULL)
p = p->next;
* SIM SMS storage area is full, cannot receive
* more messages until memory freed
*/
-void onNewSmsIndication(void)
+static void onNewSmsIndication(void)
{
enqueueRILEvent(isSimSmsStorageFull, NULL, NULL);
}
-void onNewSms(const char *sms_pdu)
+static void onNewSms(const char *sms_pdu)
{
pthread_mutex_lock(&s_held_pdus_mutex);
} else {
s_outstanding_acknowledge = 1;
RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS,
- sms_pdu, strlen(sms_pdu));
+ sms_pdu, strlen(sms_pdu));
}
pthread_mutex_unlock(&s_held_pdus_mutex);
}
-void onNewStatusReport(const char *sms_pdu)
+static void onNewStatusReport(const char *sms_pdu)
{
char *response = NULL;
int err;
} else {
s_outstanding_acknowledge = 1;
RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
- response, strlen(response));
+ response, strlen(response));
}
free(response);
pthread_mutex_unlock(&s_held_pdus_mutex);
}
-void onNewBroadcastSms(const char *pdu)
+static void onNewBroadcastSms(const char *pdu)
{
char *message = NULL;
D("%s() Length : %d", __func__, strlen(pdu));
} else {
s_outstanding_acknowledge = 1;
RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
- message, BSM_LENGTH);
+ message, BSM_LENGTH);
}
pthread_mutex_unlock(&s_held_pdus_mutex);
return;
}
-void onNewSmsOnSIM(const char *s)
+static void onNewSmsOnSIM(const char *s)
{
char *line;
char *mem;
if (err < 0)
goto error;
+ /* Huawei modems use a 0-based message slot index, but the SIM record is 1-based.
+ We will translate Huawei indices to Record indices, to make the Android RIL
+ able to read SMS stored in SIM using SimIo with the same indices as the Sms
+ delete command and NewSmsOnSim index */
+ index += 1;
+
RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM,
- &index, sizeof(int *));
+ &index, sizeof(int *));
finally:
free(line);
smsc[4+length] = '\0';
}
at_response_free(atResponse);
+ } else {
+ strcpy(smsc, testSmsc);
}
- else
- strcpy(smsc,testSmsc);
asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
asprintf(&cmd2, "%s%s", smsc, pdu);
error:
switch (at_get_cms_error(aterr)) {
- case CMS_NO_NETWORK_SERVICE:
- case CMS_NETWORK_TIMEOUT:
- ret = RIL_E_SMS_SEND_FAIL_RETRY;
- break;
- default:
- ret = RIL_E_GENERIC_FAILURE;
- break;
- }
- RIL_onRequestComplete(t, ret, NULL, 0);
+ case CMS_NO_NETWORK_SERVICE:
+ case CMS_NETWORK_TIMEOUT:
+ ret = RIL_E_SMS_SEND_FAIL_RETRY;
+ break;
+ default:
+ ret = RIL_E_GENERIC_FAILURE;
+ break;
+ }
+ RIL_onRequestComplete(t, ret, NULL, 0);
goto finally;
}
{
int err;
- err = at_send_command("AT+CMGD=%d", ((int *) data)[0]);
+ /* Huawei modems use a 0-based message slot index, but the SIM record is 1-based.
+ We will translate Huawei indices to Record indices, to make the Android RIL
+ able to read SMS stored in SIM using SimIo with the same indices as the Sms
+ delete command and NewSmsOnSim index */
+ int idx = ((int *) data)[0] - 1;
+ if (idx < 0) {
+ ALOGE("DeleteSmsOnSim: Invalid index! (%d)",idx);
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
+
+ err = at_send_command("AT+CMGD=%d", idx);
if (err != AT_NOERROR)
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
else
* 1. memory was full and been cleaned up, inform modem memory is available now.
*/
switch (ack) {
- case 0:
- /* Android will handle this, no need to inform modem. always return success. */
- ALOGI("SMS storage full");
- break;
-
- case 1:
- /* Since we are not using +CNMA command. It's fine to return without informing network */
- ALOGI("Failed to inform network for Message Cleanup. Need cmd : ESMSMEMAVAIL");
- break;
-
- default:
- ALOGE("%s() Invalid parameter", __func__);
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- return;
+ case 0:
+ /* Android will handle this, no need to inform modem. always return success. */
+ ALOGI("SMS storage full");
+ break;
+
+ case 1:
+ /* Since we are not using +CNMA command. It's fine to return without informing network */
+ ALOGI("Failed to inform network for Message Cleanup. Need cmd : ESMSMEMAVAIL");
+ break;
+
+ default:
+ ALOGE("%s() Invalid parameter", __func__);
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
}
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
unsolResponse = RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT;
RIL_onUnsolicitedResponse(unsolResponse, hpdu->sms_pdu,
- strlen(hpdu->sms_pdu));
+ strlen(hpdu->sms_pdu));
free(hpdu->sms_pdu);
free(hpdu);
* This is similar to the TS 27.007 "restricted SIM" operation
* where it assumes all of the EF selection will be done by the
* callee.
+ *
+ * Reverse Engineered from Kuawei generic RIL *
*/
-
-/* All files listed under ADF_USIM in 3GPP TS 31.102 */
-static const int ef_usim_files[] = {
- 0x6F05, 0x6F06, 0x6F07, 0x6F08, 0x6F09,
- 0x6F2C, 0x6F31, 0x6F32, 0x6F37, 0x6F38,
- 0x6F39, 0x6F3B, 0x6F3C, 0x6F3E, 0x6F3F,
- 0x6F40, 0x6F41, 0x6F42, 0x6F43, 0x6F45,
- 0x6F46, 0x6F47, 0x6F48, 0x6F49, 0x6F4B,
- 0x6F4C, 0x6F4D, 0x6F4E, 0x6F4F, 0x6F50,
- 0x6F55, 0x6F56, 0x6F57, 0x6F58, 0x6F5B,
- 0x6F5C, 0x6F60, 0x6F61, 0x6F62, 0x6F73,
- 0x6F78, 0x6F7B, 0x6F7E, 0x6F80, 0x6F81,
- 0x6F82, 0x6F83, 0x6FAD, 0x6FB1, 0x6FB2,
- 0x6FB3, 0x6FB4, 0x6FB5, 0x6FB6, 0x6FB7,
- 0x6FC3, 0x6FC4, 0x6FC5, 0x6FC6, 0x6FC7,
- 0x6FC8, 0x6FC9, 0x6FCA, 0x6FCB, 0x6FCC,
- 0x6FCD, 0x6FCE, 0x6FCF, 0x6FD0, 0x6FD1,
- 0x6FD2, 0x6FD3, 0x6FD4, 0x6FD5, 0x6FD6,
- 0x6FD7, 0x6FD8, 0x6FD9, 0x6FDA, 0x6FDB,
+typedef struct _tagSW1SW2{
+ unsigned char mask[2];
+ unsigned char sw[2];
+ char *text;
+} SW1SW2;
+
+static const SW1SW2 sim_answ[]=
+{
+ /* Response to commands which are correctly executed */
+ { { 0xff, 0xff }, { 0x90, 0x00 } , "Ok" },
+ { { 0xff, 0x00 }, { 0x9f, 0x00 } , "%d response bytes available" },
+ /* Memory management */
+ { { 0xff, 0x00 }, { 0x92, 0x00 } , "Update successful but after using an internal retry of %d times" },
+ { { 0xff, 0xff }, { 0x92, 0x40 } , "memory problem" },
+ /* Referencing management */
+ { { 0xff, 0xff }, { 0x94, 0x00 } , "no EF selected" },
+ { { 0xff, 0xff }, { 0x94, 0x02 } , "out of range (invalid address)" },
+ { { 0xff, 0xff }, { 0x94, 0x04 } , "file ID or pattern not found" },
+ { { 0xff, 0xff }, { 0x94, 0x08 } , "file is inconsistent with the command" },
+ /* Security management */
+ { { 0xff, 0xff }, { 0x98, 0x02 } , "no CHV initialised" },
+ { { 0xff, 0xff }, { 0x98, 0x04 } , "access condition not fulfilled,authentication failed at least one attempt left" },
+ { { 0xff, 0xff }, { 0x98, 0x08 } , "in contradiction with CHV status" },
+ { { 0xff, 0xff }, { 0x98, 0x10 } , "in contradiction with invalidation stats" },
+ { { 0xff, 0xff }, { 0x98, 0x40 } , "unsuccessful CHV verification,no attempt left. CHV blocked" },
+ { { 0xff, 0xff }, { 0x98, 0x50 } , "increase cannot be performed,Max value reached" },
+
+ { { 0xff, 0x00 }, { 0x61, 0x00 } , "%d response bytes available" },
+
+ { { 0xff, 0xff }, { 0x62, 0x81 } , "returned data may be corrupt" },
+ { { 0xff, 0xff }, { 0x62, 0x82 } , "EOF reached prematurely" },
+ { { 0xff, 0xff }, { 0x62, 0x83 } , "selected file invalid" },
+ { { 0xff, 0xff }, { 0x62, 0x84 } , "FCI not formated" },
+ { { 0xff, 0x00 }, { 0x62, 0x00 } , "nvmem unchanged" },
+
+ { { 0xff, 0x00 }, { 0x63, 0x00 } , "nvmem changed" },
+ { { 0xff, 0x00 }, { 0x63, 0x81 } , "file filled up by last write" },
+ { { 0xff, 0xf0 }, { 0x63, 0xc0 } , "Counter=%1.1X" },
+
+ { { 0xff, 0xff }, { 0x64, 0x00 } , "nvmem unchanged" },
+ { { 0xff, 0x00 }, { 0x64, 0x00 } , "nvmem unchanged - RFU" },
+
+ { { 0xff, 0xff }, { 0x65, 0x00 } , "nvmem changed" },
+ { { 0xff, 0xff }, { 0x65, 0x81 } , "nvmem changed - memory failure" },
+ { { 0xff, 0x00 }, { 0x65, 0x00 } , "nvmem changed - unknown?" },
+
+ { { 0xff, 0x00 }, { 0x66, 0x00 } , "security related %d" },
+
+ { { 0xff, 0xff }, { 0x67, 0x00 } , "wrong length" },
+ { { 0xff, 0x00 }, { 0x67, 0x00 } , "wrong length - %d expected" },
+
+ { { 0xff, 0xff }, { 0x68, 0x81 } , "wrong cla - logical channel not supported" },
+ { { 0xff, 0xff }, { 0x68, 0x82 } , "wrong cla - secure messaging not supported" },
+ { { 0xff, 0x00 }, { 0x68, 0x00 } , "cla not supported" },
+
+ { { 0xff, 0xff }, { 0x69, 0x81 } , "command incompatible with file structure" },
+ { { 0xff, 0xff }, { 0x69, 0x82 } , "security status not satisfied" },
+ { { 0xff, 0xff }, { 0x69, 0x83 } , "authentication method blocked" },
+ { { 0xff, 0xff }, { 0x69, 0x84 } , "referenced data invalid" },
+ { { 0xff, 0xff }, { 0x69, 0x85 } , "conditions of use not satisfied" },
+ { { 0xff, 0xff }, { 0x69, 0x86 } , "command not allowed - no current EF" },
+ { { 0xff, 0xff }, { 0x69, 0x87 } , "expected SM data objects missing" },
+ { { 0xff, 0xff }, { 0x69, 0x88 } , "SM data objects incorrect" },
+ { { 0xff, 0x00 }, { 0x69, 0x00 } , "command not allowed" },
+
+ { { 0xff, 0xff }, { 0x6a, 0x80 } , "P1-P2: incorrect parameters in data field" },
+ { { 0xff, 0xff }, { 0x6a, 0x81 } , "P1-P2: function not supported" },
+ { { 0xff, 0xff }, { 0x6a, 0x82 } , "P1-P2: file not found" },
+ { { 0xff, 0xff }, { 0x6a, 0x83 } , "P1-P2: record not found" },
+ { { 0xff, 0xff }, { 0x6a, 0x84 } , "P1-P2: not enough memory space in file" },
+ { { 0xff, 0xff }, { 0x6a, 0x85 } , "P1-P2: Lc inconsistent with TLV" },
+ { { 0xff, 0xff }, { 0x6a, 0x86 } , "P1-P2 incorrect" },
+ { { 0xff, 0xff }, { 0x6a, 0x87 } , "P1-P2 inconsistent with Lc" },
+ { { 0xff, 0xff }, { 0x6a, 0x88 } , "Referenced data not found" },
+ { { 0xff, 0x00 }, { 0x6a, 0x00 } , "P1-P2 invalid" },
+
+ { { 0xff, 0x00 }, { 0x6b, 0x00 } , "P1-P2 invalid" },
+
+ { { 0xff, 0x00 }, { 0x6c, 0x00 } , "wrong length - %d expected" },
+
+ { { 0xff, 0x00 }, { 0x6d, 0x00 } , "INS code not supported or invalid" },
+
+ { { 0xff, 0x00 }, { 0x6e, 0x00 } , "CLA %02X not supported" },
+
+ { { 0xff, 0x00 }, { 0x6f, 0x00 } , "no precise diagnosis" },
+
+ { { 0x00, 0x00 }, { 0x00, 0x00 } , "Unknown response" }
};
-static const int ef_telecom_files[] = {
- 0x6F3A, 0x6F3D, 0x6F44, 0x6F4A, 0x6F54,
-};
+/* Interpret and print SIM_IO command result */
+static void print_simansw(unsigned char sw1, unsigned char sw2)
+{
+ unsigned j;
+
+ ALOGD("sw1: 0x%02x, sw2: 0x%02x", sw1, sw2);
+ for (j = 0; j < sizeof(sim_answ)/sizeof(sim_answ[0]); j++) {
+ if ((sw1 & sim_answ[j].mask[0]) == sim_answ[j].sw[0] &&
+ (sw2 & sim_answ[j].mask[1]) == sim_answ[j].sw[1]) {
+ ALOGD(sim_answ[j].text, sw2);
+ return;
+ }
+ }
+
+ ALOGD("Unknown error");
+}
-#define PATH_ADF_USIM_DIRECTORY "3F007FFF"
-#define PATH_ADF_TELECOM_DIRECTORY "3F007F10"
+static unsigned int hex2int(char dig)
+{
+ if (dig >= '0' && dig <= '9')
+ return dig - '0';
+ if (dig >= 'a' && dig <= 'f')
+ return dig - 'a' + 10;
+ if (dig >= 'A' && dig <= 'F')
+ return dig - 'A' + 10;
+ return 0;
+}
-/* RID: A000000087 = 3GPP, PIX: 1002 = 3GPP USIM */
-#define USIM_APPLICATION_ID "A0000000871002"
+static void hexStringToBytes(unsigned char* b, const char* str)
+{
+ int len = strlen(str);
+ len >>= 1;
+ while (len--) {
+ *b++ = (hex2int(str[0]) << 4) | hex2int(str[1]);
+ str += 2;
+ };
+}
-static int sendSimIOCmdICC(const RIL_SIM_IO_v6 *ioargs, ATResponse **atResponse, RIL_SIM_IO_Response *sr)
+static void requestSIM_IO(void *data, size_t datalen, RIL_Token t)
{
+ ATResponse *atResponse = NULL;
+ RIL_SIM_IO_Response sr;
int err;
- char *fmt;
- char *arg6;
- char *arg7;
+ RIL_SIM_IO_v6 *p_args;
char *line;
+ char *fmt;
+
+ /* FIXME handle pin2 */
+ memset(&sr, 0, sizeof(sr));
- /* FIXME Handle pin2. */
- memset(sr, 0, sizeof(*sr));
+ p_args = (RIL_SIM_IO_v6 *)data;
- arg6 = ioargs->data;
- arg7 = ioargs->path;
+ if (!p_args)
+ goto error;
+
+ if (p_args->path != NULL && (strlen(p_args->path) & 3) != 0)
+ goto error;
- if (arg7 && arg6) {
- fmt = "AT+CRSM=%d,%d,%d,%d,%d,\"%s\",\"%s\"";
- } else if (arg7) {
- fmt = "AT+CRSM=%d,%d,%d,%d,%d,,\"%s\"";
- arg6 = arg7;
- } else if (arg6) {
- fmt = "AT+CRSM=%d,%d,%d,%d,%d,\"%s\"";
+ if (p_args->fileid == 0x4F30) {
+ if (!p_args->data) {
+ fmt = "AT+CRSM=%d,%d,%d,%d,%d,,\"3F007F105F3A\"";
+ } else {
+ fmt = "AT+CRSM=%d,%d,%d,%d,%d,%s,\"3F007F105F3A\"";
+ }
} else {
- fmt = "AT+CRSM=%d,%d,%d,%d,%d";
+ if (!p_args->data) {
+ fmt = "AT+CRSM=%d,%d,%d,%d,%d";
+ } else {
+ fmt = "AT+CRSM=%d,%d,%d,%d,%d,%s";
+ }
}
- err = at_send_command_singleline(fmt, "+CRSM:", atResponse,ioargs->command,
- ioargs->fileid, ioargs->p1,
- ioargs->p2, ioargs->p3,
- arg6, arg7);
+ err = at_send_command_singleline(fmt, "+CRSM:", &atResponse,
+ p_args->command,
+ p_args->fileid, p_args->p1,
+ p_args->p2, p_args->p3,
+ p_args->data);
if (err != AT_NOERROR)
- return err;
+ goto error;
- line = (*atResponse)->p_intermediates->line;
+ line = atResponse->p_intermediates->line;
err = at_tok_start(&line);
- if (err < 0)
- goto finally;
+ if (err < 0) goto error;
- err = at_tok_nextint(&line, &(sr->sw1));
- if (err < 0)
- goto finally;
+ err = at_tok_nextint(&line, &(sr.sw1));
+ if (err < 0) goto error;
- err = at_tok_nextint(&line, &(sr->sw2));
- if (err < 0)
- goto finally;
+ err = at_tok_nextint(&line, &(sr.sw2));
+ if (err < 0) goto error;
if (at_tok_hasmore(&line)) {
- err = at_tok_nextstr(&line, &(sr->simResponse));
- if (err < 0)
- goto finally;
- }
-
-finally:
- return err;
-}
-
-static int convertSimIoFcp(RIL_SIM_IO_Response *sr, char **cvt)
-{
- int err;
- /* size_t pos; */
- size_t fcplen;
- struct ts_51011_921_resp resp;
- void *cvt_buf = NULL;
-
- if (!sr->simResponse || !cvt) {
- err = -EINVAL;
- goto error;
- }
-
- fcplen = strlen(sr->simResponse);
- if ((fcplen == 0) || (fcplen & 1)) {
- err = -EINVAL;
- goto error;
- }
-
- err = fcp_to_ts_51011(sr->simResponse, fcplen, &resp);
- if (err < 0)
- goto error;
-
- cvt_buf = malloc(sizeof(resp) * 2 + 1);
- if (!cvt_buf) {
- err = -ENOMEM;
- goto error;
+ err = at_tok_nextstr(&line, &(sr.simResponse));
+ if (err < 0) goto error;
}
- err = binaryToString((unsigned char*)(&resp),
- sizeof(resp), cvt_buf);
- if (err < 0)
- goto error;
-
- /* cvt_buf ownership is moved to the caller */
- *cvt = cvt_buf;
- cvt_buf = NULL;
-
-finally:
- return err;
-
-error:
- free(cvt_buf);
- goto finally;
-}
+ /* Interpret and print results as a debugging aid */
+ print_simansw(sr.sw1,sr.sw2);
-/**
- * RIL_REQUEST_SIM_IO
- *
- * Request SIM I/O operation.
- * This is similar to the TS 27.007 "restricted SIM" operation
- * where it assumes all of the EF selection will be done by the
- * callee.
- */
-static void requestSIM_IO(void *data, size_t datalen, RIL_Token t)
-{
- (void) datalen;
- ATResponse *atResponse = NULL;
- RIL_SIM_IO_Response sr;
- int cvt_done = 0;
- int err;
- UICC_Type UiccType = getUICCType();
+ /* If dealing with a USIM card ... */
+ if (p_args->command == 0xC0 &&
+ sr.simResponse[0] == '6' &&
+ sr.simResponse[1] == '2' &&
+ sr.simResponse[6] == '0' &&
+ sr.simResponse[7] == '5' &&
+ strlen(sr.simResponse) <= 30 &&
+ getUICCType() != UICC_TYPE_SIM) {
- int pathReplaced = 0;
- RIL_SIM_IO_v6 ioargsDup;
+ /* Convert it to a format Android understands */
- /*
- * Android telephony framework does not support USIM cards properly,
- * send GSM filepath where as active cardtype is USIM.
- * Android RIL needs to change the file path of files listed under ADF-USIM
- * if current active cardtype is USIM
- */
- memcpy(&ioargsDup, data, sizeof(RIL_SIM_IO_v6));
- if (UICC_TYPE_USIM == UiccType) {
- unsigned int i;
- int err;
- unsigned int count = sizeof(ef_usim_files) / sizeof(int);
-
- for (i = 0; i < count; i++) {
- if (ef_usim_files[i] == ioargsDup.fileid) {
- err = asprintf(&ioargsDup.path, PATH_ADF_USIM_DIRECTORY);
- if (err < 0)
- goto error;
- pathReplaced = 1;
- ALOGD("%s() Path replaced for USIM: %d", __func__, ioargsDup.fileid);
- break;
- }
- }
- if(!pathReplaced){
- unsigned int count2 = sizeof(ef_telecom_files) / sizeof(int);
- for (i = 0; i < count2; i++) {
- if (ef_telecom_files[i] == ioargsDup.fileid) {
- err = asprintf(&ioargsDup.path, PATH_ADF_TELECOM_DIRECTORY);
- if (err < 0)
- goto error;
- pathReplaced = 1;
- ALOGD("%s() Path replaced for telecom: %d", __func__, ioargsDup.fileid);
- break;
- }
- }
- }
- }
+ unsigned char buf[15];
+ unsigned int val;
- memset(&sr, 0, sizeof(sr));
+ // Convert to bytes...
+ hexStringToBytes(buf,sr.simResponse);
- err = sendSimIOCmdICC(&ioargsDup, &atResponse, &sr);
+ // Reformat response...
+ sr.simResponse[0x00] = '0';
+ sr.simResponse[0x01] = '0';
+ sr.simResponse[0x02] = '0';
+ sr.simResponse[0x03] = '0';
- if (err < 0)
- goto error;
+ val = buf[8] * (buf[7] + (buf[6]<<8U));
+ sprintf(&sr.simResponse[0x04],"%04x",val & 0xFFFFU);
- /*
- * In case the command is GET_RESPONSE and cardtype is 3G SIM
- * convert to 2G FCP
- */
- if (ioargsDup.command == 0xC0 && UiccType != UICC_TYPE_SIM) {
- err = convertSimIoFcp(&sr, &sr.simResponse);
- if (err < 0)
- goto error;
- cvt_done = 1; /* sr.simResponse needs to be freed */
+ sr.simResponse[0x08] = sr.simResponse[0x16];
+ sr.simResponse[0x09] = sr.simResponse[0x17];
+ sr.simResponse[0x0A] = sr.simResponse[0x18];
+ sr.simResponse[0x0B] = sr.simResponse[0x19];
+ sr.simResponse[0x0D] = '4';
+ sr.simResponse[0x1A] = '0';
+ sr.simResponse[0x1B] = '1';
+ sr.simResponse[0x1C] = sr.simResponse[0x0E];
+ sr.simResponse[0x1D] = sr.simResponse[0x0F];
+ sr.simResponse[0x1E] = 0;
}
RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
-
-finally:
at_response_free(atResponse);
- if (cvt_done)
- free(sr.simResponse);
-
- if (pathReplaced)
- free(ioargsDup.path);
return;
error:
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- goto finally;
+ at_response_free(atResponse);
}
-
/*
* The following list contains values for the structure "RIL_AppStatus" to be
* sent to Android on a given SIM state. It is indexed by the SIM_Status above.
char *facility_string = NULL;
char *facility_password = NULL;
char *facility_class = NULL;
+ const char *fmt;
(void) datalen;
facility_password = ((char **) data)[1];
facility_class = ((char **) data)[2];
- err = at_send_command_singleline("AT+CLCK=\"%s\",2,%s,%s", "+CLCK:", &atResponse,
+ if (facility_password != NULL && facility_password[0] != 0) {
+ if (facility_class != NULL && facility_class[0] != 0) {
+ fmt = "AT+CLCK=\"%s\",2,%s,%s";
+ } else {
+ fmt = "AT+CLCK=\"%s\",2,%s";
+ }
+ } else {
+ fmt = "AT+CLCK=\"%s\",2";
+ }
+ err = at_send_command_singleline(fmt, "+CLCK:", &atResponse,
facility_string, facility_password, facility_class);
if (err != AT_NOERROR)
goto error;
* printing NULL with %s will give string "(null)".
*/
err = at_send_command("AT+CLCK=\"%s\",%d,\"%s\",%s", facility_string,
- facility_mode, facility_password, facility_class);
+ facility_mode, facility_password ? facility_password : "", facility_class);
if (at_get_error_type(err) == AT_ERROR)
goto exit;
if (err != AT_NOERROR) {
switch (at_get_cme_error(err)) {
- /* CME ERROR 11: "SIM PIN required" happens when PIN is wrong */
- case CME_SIM_PIN_REQUIRED:
- ALOGI("Wrong PIN");
- errorril = RIL_E_PASSWORD_INCORRECT;
- break;
- /*
- * CME ERROR 12: "SIM PUK required" happens when wrong PIN is used
- * 3 times in a row
- */
- case CME_SIM_PUK_REQUIRED:
- ALOGI("PIN locked, change PIN with PUK");
- num_retries = 0;/* PUK required */
- errorril = RIL_E_PASSWORD_INCORRECT;
- break;
- /* CME ERROR 16: "Incorrect password" happens when PIN is wrong */
- case CME_INCORRECT_PASSWORD:
- ALOGI("Incorrect password, Facility: %s", facility_string);
- errorril = RIL_E_PASSWORD_INCORRECT;
- break;
- /* CME ERROR 17: "SIM PIN2 required" happens when PIN2 is wrong */
- case CME_SIM_PIN2_REQUIRED:
- ALOGI("Wrong PIN2");
- errorril = RIL_E_PASSWORD_INCORRECT;
- break;
- /*
- * CME ERROR 18: "SIM PUK2 required" happens when wrong PIN2 is used
- * 3 times in a row
- */
- case CME_SIM_PUK2_REQUIRED:
- ALOGI("PIN2 locked, change PIN2 with PUK2");
- num_retries = 0;/* PUK2 required */
- errorril = RIL_E_SIM_PUK2;
- break;
- default: /* some other error */
- num_retries = -1;
- break;
+ /* CME ERROR 11: "SIM PIN required" happens when PIN is wrong */
+ case CME_SIM_PIN_REQUIRED:
+ ALOGI("Wrong PIN");
+ errorril = RIL_E_PASSWORD_INCORRECT;
+ break;
+ /*
+ * CME ERROR 12: "SIM PUK required" happens when wrong PIN is used
+ * 3 times in a row
+ */
+ case CME_SIM_PUK_REQUIRED:
+ ALOGI("PIN locked, change PIN with PUK");
+ num_retries = 0;/* PUK required */
+ errorril = RIL_E_PASSWORD_INCORRECT;
+ break;
+ /* CME ERROR 16: "Incorrect password" happens when PIN is wrong */
+ case CME_INCORRECT_PASSWORD:
+ ALOGI("Incorrect password, Facility: %s", facility_string);
+ errorril = RIL_E_PASSWORD_INCORRECT;
+ break;
+ /* CME ERROR 17: "SIM PIN2 required" happens when PIN2 is wrong */
+ case CME_SIM_PIN2_REQUIRED:
+ ALOGI("Wrong PIN2");
+ errorril = RIL_E_PASSWORD_INCORRECT;
+ break;
+ /*
+ * CME ERROR 18: "SIM PUK2 required" happens when wrong PIN2 is used
+ * 3 times in a row
+ */
+ case CME_SIM_PUK2_REQUIRED:
+ ALOGI("PIN2 locked, change PIN2 with PUK2");
+ num_retries = 0;/* PUK2 required */
+ errorril = RIL_E_SIM_PUK2;
+ break;
+ default: /* some other error */
+ num_retries = -1;
+ break;
}
goto finally;
}
err = at_send_command("AT+CPIN=\"%s\",\"%s\"", strings[0], strings[1]);
}
} else if (datalen == 3 * sizeof(char *)) {
- err = at_send_command("AT+CPIN=\"%s\",\"%s\"", strings[0], strings[1]);
+ err = at_send_command("AT+CPIN=\"%s\",\"%s\"", strings[0], strings[1]);
} else {
goto error;
}
if (cme_err != CME_ERROR_NON_CME && err != AT_NOERROR) {
switch (cme_err) {
- case CME_SIM_PIN_REQUIRED:
- case CME_SIM_PUK_REQUIRED:
- case CME_INCORRECT_PASSWORD:
- case CME_SIM_PIN2_REQUIRED:
- case CME_SIM_PUK2_REQUIRED:
- num_retries = 1;
- RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, &num_retries, sizeof(int *));
- break;
- default:
- goto error;
+ case CME_SIM_PIN_REQUIRED:
+ case CME_SIM_PUK_REQUIRED:
+ case CME_INCORRECT_PASSWORD:
+ case CME_SIM_PIN2_REQUIRED:
+ case CME_SIM_PUK2_REQUIRED:
+ num_retries = 1;
+ RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, &num_retries, sizeof(int *));
+ break;
+ default:
+ goto error;
}
} else {
- /*
- * Got OK, return success and wait for *EPEV to trigger poll
- * of SIM state.
- */
+ /* Got OK, return success. */
num_retries = 1;
RIL_onRequestComplete(t, RIL_E_SUCCESS, &num_retries, sizeof(int *));
+
+ /* Make sure we get notifications for network registeration
+ of both voice and data now */
+ at_send_command("AT+CREG=2");
+ at_send_command("AT+CGREG=2");
+
+ /* Notify that SIM is ready */
+ setRadioState(RADIO_STATE_SIM_READY);
}
return;
error:
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(pollOperatorSelected,
- poll_params, &TIMEVAL_OPERATOR_SELECT_POLL);
+ 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(pollOperatorSelected,
+ poll_params, &TIMEVAL_OPERATOR_SELECT_POLL);
}
} else {
/* We got operator, throw a success! */
goto finally;
}
+/**
+ * RIL_REQUEST_SET_BAND_MODE
+ *
+ * Assign a specified band for RF configuration.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is == 0 for "unspecified" (selected by baseband automatically)
+ * ((int *)data)[0] is == 1 for "EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
+ * ((int *)data)[0] is == 2 for "US band" (GSM-850 / PCS-1900 / WCDMA-850 / WCDMA-PCS-1900)
+ * ((int *)data)[0] is == 3 for "JPN band" (WCDMA-800 / WCDMA-IMT-2000)
+ * ((int *)data)[0] is == 4 for "AUS band" (GSM-900 / DCS-1800 / WCDMA-850 / WCDMA-IMT-2000)
+ * ((int *)data)[0] is == 5 for "AUS band 2" (GSM-900 / DCS-1800 / WCDMA-850)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE
+ * GENERIC_FAILURE
+ */
+static void requestSetBandMode(void *data, size_t datalen, RIL_Token t)
+{
+ int band,err;
+ const char* strband;
+
+ assert (datalen >= sizeof(int *));
+ band = ((int *)data)[0];
+
+ switch (band) {
+ case 0:
+ default:
+ strband = "3FFFFFFF";
+ break;
+ case 1:
+ strband = "2000000400380";
+ break;
+ case 2:
+ strband = "4A80000";
+ break;
+ }
+
+ /* Set allowed bands */
+ err = at_send_command("AT^SYSCFG=16,3,%s,1,2", strband );
+ if (err != AT_NOERROR)
+ goto error;
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, sizeof(int));
+ return;
+
+error:
+ ALOGE("ERROR: requestSetBandMode() failed");
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+}
+
+/**
+ * RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE
+ *
+ * Query the list of band mode supported by RF.
+ *
+ * "data" is NULL
+ *
+ * "response" is int *
+ * "response" points to an array of int's, the int[0] is the size of array, reset is one for
+ * each available band mode.
+ *
+ * 0 for "unspecified" (selected by baseband automatically)
+ * 1 for "EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
+ * 2 for "US band" (GSM-850 / PCS-1900 / WCDMA-850 / WCDMA-PCS-1900)
+ * 3 for "JPN band" (WCDMA-800 / WCDMA-IMT-2000)
+ * 4 for "AUS band" (GSM-900 / DCS-1800 / WCDMA-850 / WCDMA-IMT-2000)
+ * 5 for "AUS band 2" (GSM-900 / DCS-1800 / WCDMA-850)
+ *
+ * Valid errors:
+ * SUCCESS
+ * RADIO_NOT_AVAILABLE
+ * GENERIC_FAILURE
+ *
+ * See also: RIL_REQUEST_SET_BAND_MODE
+ */
+static void requestQueryAvailableBandMode(void *data, size_t datalen, RIL_Token t)
+{
+ int err = 0;
+ char *line;
+ ATResponse *atResponse = NULL;
+ char *strband;
+ int mode, acqorder, band;
+
+ err = at_send_command_singleline("AT^SYSCFG?", "^SYSCFG:", &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, &mode);
+ if (err < 0)
+ goto error;
+
+ err = at_tok_nextint(&line, &acqorder);
+ if (err < 0)
+ goto error;
+
+ err = at_tok_nextstr(&line, &strband);
+ if (err < 0)
+ goto error;
+
+ if (strcmp(strband, "2000000400380") == 0)
+ band = 1;
+ else if (strcmp(strband, "4A80000") == 0)
+ band = 2;
+ else
+ band = 0;
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &band, sizeof(int));
+
+finally:
+ at_response_free(atResponse);
+ return;
+
+error:
+ ALOGE("%s() Failed to get current band mode", __func__);
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ goto finally;
+}
+
/**
* RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
assert (datalen >= sizeof(int *));
rat = ((int *)data)[0];
- /* Huawei specific
- AT^SYSCFG=2,1,3FFFFFFF,2,4 for GPRS/EDGE Preferred
- AT^SYSCFG=2,2,3FFFFFFF,2,4 for 3G Preferred
- AT^SYSCFG=13,1,3FFFFFFF,2,4 for GPRS/EDGE Only
- AT^SYSCFG=14,2,3FFFFFFF,2,4 for 3G Only
-
- The third parameter, 0x3FFFFFFF tells the card to use all bands.
- A value of 0x400380 here means GSM900/1800/WCDMA2100 only and a
- value of 0x200000 here means GSM1900 only.
-
- */
-
switch (rat) {
- case PREF_NET_TYPE_GSM_ONLY: /* GSM only */
- cmd = "AT^SYSCFG=13,1,3FFFFFFF,2,4"; /* for GPRS/EDGE Only */
+ case PREF_NET_TYPE_GSM_ONLY: /* GSM only */
+ cmd = "AT^SYSCFG=13,1,40000000,2,4"; /* GSM only */
break;
- case PREF_NET_TYPE_GSM_WCDMA: /* WCDMA only */
- cmd = "AT^SYSCFG=14,2,3FFFFFFF,2,4"; /* for 3G Only */
+ case PREF_NET_TYPE_WCDMA: /* WCDMA only */
+ cmd = "AT^SYSCFG=14,2,40000000,2,4"; /* WCDMA only */
break;
- case PREF_NET_TYPE_GSM_WCDMA_AUTO:
+ case PREF_NET_TYPE_GSM_WCDMA: /* GSM/WCDMA (WCDMA preferred) */
+ cmd = "AT^SYSCFG=2,2,40000000,2,4"; /* Automatic, prefer WCDMA */
+ break;
+ case PREF_NET_TYPE_GSM_WCDMA_AUTO: /* GSM/WCDMA (auto mode, according to PRL) */
default: /* Dual Mode - WCDMA preferred*/
- cmd = "AT^SYSCFG=2,2,3FFFFFFF,2,4"; /* for 3G Preferred */
+ cmd = "AT^SYSCFG=2,0,40000000,2,4"; /* for 3G Preferred */
break;
}
*/
static void requestGetPreferredNetworkType(RIL_Token t)
{
- /*
- AT^SYSCFG=2,1,3FFFFFFF,1,2 for GPRS/EDGE Preferred
- AT^SYSCFG=2,2,3FFFFFFF,1,2 for 3G Preferred
- AT^SYSCFG=13,1,3FFFFFFF,1,2 for GPRS/EDGE Only
- AT^SYSCFG=14,2,3FFFFFFF,1,2 for 3G Only
- */
-
ATResponse *atResponse = NULL;
int err;
char *line;
if (err < 0) goto error;
/* Based on reported syscfg */
- if (ret1 == 13) {
+ if (ret1 == 13 && ret2 == 1) {
response = PREF_NET_TYPE_GSM_ONLY; /* GSM only */
- } else if (ret1 == 14) {
- response = PREF_NET_TYPE_GSM_WCDMA; /* WCDMA only */
+ } else if (ret1 == 14 && ret2 == 2) {
+ response = PREF_NET_TYPE_WCDMA; /* WCDMA only */
+ } else if (ret1 == 2 && ret2 == 2) {
+ response = PREF_NET_TYPE_GSM_WCDMA; /* GSM or WCDMA */
} else {
- response = PREF_NET_TYPE_GSM_WCDMA_AUTO; /* for 3G Preferred */
+ response = PREF_NET_TYPE_GSM_WCDMA_AUTO; /* Auto */
}
D("requestGetPreferredNetworkType() mode:%d", response);
*
* Request current registration state.
*/
-static void requestRegistrationState(RIL_Token t)
+static void requestRegistrationState(RIL_Token t, int data)
{
- int err = 0;
- const char resp_size = 15;
- int response[15];
- char *responseStr[15] = {0};
+ const int resp_size = 15;
+ int response[resp_size];
+ char *responseStr[resp_size];
ATResponse *cgreg_resp = NULL;
char *line;
int commas = 0;
int skip, cs_status = 0;
int i;
+ int err;
+ const char *cmd;
+ const char *prefix;
/* Setting default values in case values are not returned by AT command */
- for (i = 0; i < resp_size; i++)
- responseStr[i] = NULL;
-
+ memset(responseStr, 0, sizeof(responseStr));
memset(response, 0, sizeof(response));
- err = at_send_command_singleline("AT+CREG?", "+CREG:", &cgreg_resp);
+ if (data == 0) {
+ cmd = "AT+CREG?";
+ prefix = "+CREG:";
+ } else {
+ cmd = "AT+CGREG?";
+ prefix = "+CGREG:";
+ }
+
+ err = at_send_command_singleline(cmd, prefix, &cgreg_resp);
if (err != AT_NOERROR)
goto error;
goto error;
switch (commas) {
- case 0: /* +CREG: <stat> */
- err = at_tok_nextint(&line, &response[0]);
- if (err < 0)
- goto error;
+ case 0: /* +CREG: <stat> */
+ err = at_tok_nextint(&line, &response[0]);
+ if (err < 0)
+ goto error;
- response[1] = -1;
- response[2] = -1;
- break;
+ response[1] = -1;
+ response[2] = -1;
+ break;
- case 1: /* +CREG: <n>, <stat> */
- err = at_tok_nextint(&line, &skip);
- if (err < 0)
- goto error;
+ case 1: /* +CREG: <n>, <stat> */
+ err = at_tok_nextint(&line, &skip);
+ if (err < 0)
+ goto error;
- err = at_tok_nextint(&line, &response[0]);
- if (err < 0)
- goto error;
+ err = at_tok_nextint(&line, &response[0]);
+ if (err < 0)
+ goto error;
- response[1] = -1;
- response[2] = -1;
- if (err < 0)
- goto error;
- break;
- case 2: /* +CREG: <stat>, <lac>, <cid> */
- err = at_tok_nextint(&line, &response[0]);
- if (err < 0)
- goto error;
+ response[1] = -1;
+ response[2] = -1;
+ if (err < 0)
+ goto error;
+ break;
+ case 2: /* +CREG: <stat>, <lac>, <cid> */
+ err = at_tok_nextint(&line, &response[0]);
+ if (err < 0)
+ goto error;
- err = at_tok_nexthexint(&line, &response[1]);
- if (err < 0)
- goto error;
+ err = at_tok_nexthexint(&line, &response[1]);
+ if (err < 0)
+ goto error;
- err = at_tok_nexthexint(&line, &response[2]);
- if (err < 0)
- goto error;
- break;
- case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
- case 4: /* +CREG: <n>, <stat>, <lac>, <cid>, <?> */
- err = at_tok_nextint(&line, &skip);
- if (err < 0)
- goto error;
+ err = at_tok_nexthexint(&line, &response[2]);
+ if (err < 0)
+ goto error;
+ break;
+ case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
+ case 4: /* +CREG: <n>, <stat>, <lac>, <cid>, <?> */
+ err = at_tok_nextint(&line, &skip);
+ if (err < 0)
+ goto error;
- err = at_tok_nextint(&line, &response[0]);
- if (err < 0)
- goto error;
+ err = at_tok_nextint(&line, &response[0]);
+ if (err < 0)
+ goto error;
- err = at_tok_nexthexint(&line, &response[1]);
- if (err < 0)
- goto error;
+ err = at_tok_nexthexint(&line, &response[1]);
+ if (err < 0)
+ goto error;
- err = at_tok_nexthexint(&line, &response[2]);
- if (err < 0)
+ err = at_tok_nexthexint(&line, &response[2]);
+
+ /* Hack for broken +CGREG responses which don't return the network type */
+ ATResponse *p_response_op = NULL;
+ err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response_op);
+ /* We need to get the 4th return param */
+ int commas_op;
+ commas_op = 0;
+ char *p_op, *line_op;
+ line_op = p_response_op->p_intermediates->line;
+
+ for (p_op = line_op ; *p_op != '\0' ;p_op++) {
+ if (*p_op == ',') commas_op++;
+ }
+
+ if (commas_op == 3) {
+ err = at_tok_start(&line_op);
+ err = at_tok_nextint(&line_op, &skip);
+ if (err < 0) goto error;
+ err = at_tok_nextint(&line_op, &skip);
+ if (err < 0) goto error;
+ err = at_tok_nextint(&line_op, &skip);
+ if (err < 0) goto error;
+ err = at_tok_nextint(&line_op, &response[3]);
+ if (err < 0) goto error;
+ /* Now translate to 'Broken Android Speak' - can't follow the GSM spec */
+ switch (response[3]) {
+ /* GSM/GSM Compact - aka GRPS */
+ case 0:
+ case 1:
+ response[3] = 1;
+ break;
+
+ /* EGPRS - aka EDGE */
+ case 3:
+ response[3] = 2;
+ break;
+
+ /* UTRAN - UMTS aka 3G */
+ case 2:
+ case 7:
+ response[3] = 3;
+ break;
+
+ /* UTRAN with HSDPA and/or HSUPA aka Turbo-3G*/
+ case 4:
+ case 5:
+ case 6:
+ response[3] = 9;
+ break;
+ }
+ }
+
+ at_response_free(p_response_op);
+ /* End hack */
+
+ if (err < 0)
+ goto error;
+ break;
+ default:
goto error;
- break;
- default:
- goto error;
}
asprintf(&responseStr[1], "%04x", response[1]);
if (response[2] > 0)
asprintf(&responseStr[2], "%08x", response[2]);
+ if (response[3] > 0)
+ asprintf(&responseStr[3], "%d", response[3]);
- if (response[0] == CGREG_STAT_REG_HOME_NET ||
- response[0] == CGREG_STAT_ROAMING)
- responseStr[3] = (0);
+ if (data == 1)
+ responseStr[5] = (char*) "1";
RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr,
resp_size * sizeof(char *));
goto finally;
}
-
-/**
- * RIL_REQUEST_DATA_REGISTRATION_STATE
- *
- * Request current GPRS registration state.
- */
-static void requestGprsRegistrationState(RIL_Token t)
-{
- int err = 0;
- const char resp_size = 6;
- int response[resp_size];
- char *responseStr[resp_size];
- ATResponse *atResponse = NULL;
- char *line, *p;
- int commas = 0;
- int skip, tmp;
- int count = 3;
-
- memset(responseStr, 0, sizeof(responseStr));
- memset(response, 0, sizeof(response));
- response[1] = -1;
- response[2] = -1;
-
- 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;
- /*
- * The solicited version of the +CGREG response is
- * +CGREG: n, stat, [lac, cid [,<AcT>]]
- * and the unsolicited version is
- * +CGREG: stat, [lac, cid [,<AcT>]]
- * The <n> parameter is basically "is unsolicited creg on?"
- * which it should always be.
- *
- * Now we should normally get the solicited version here,
- * but the unsolicited version could have snuck in
- * so we have to handle both.
- *
- * Also since the LAC, CID and AcT are only reported when registered,
- * we can have 1, 2, 3, 4 or 5 arguments here.
- */
- /* Count number of commas */
- p = line;
- err = at_tok_charcounter(line, ',', &commas);
- if (err < 0) {
- ALOGE("%s() at_tok_charcounter failed", __func__);
- goto error;
- }
-
- switch (commas) {
- case 0: /* +CGREG: <stat> */
- err = at_tok_nextint(&line, &response[0]);
- if (err < 0) goto error;
- break;
-
- case 1: /* +CGREG: <n>, <stat> */
- err = at_tok_nextint(&line, &skip);
- if (err < 0) goto error;
- err = at_tok_nextint(&line, &response[0]);
- if (err < 0) goto error;
- break;
-
- case 2: /* +CGREG: <stat>, <lac>, <cid> */
- err = at_tok_nextint(&line, &response[0]);
- if (err < 0) goto error;
- err = at_tok_nexthexint(&line, &response[1]);
- if (err < 0) goto error;
- err = at_tok_nexthexint(&line, &response[2]);
- if (err < 0) goto error;
- break;
-
- case 3: /* +CGREG: <n>, <stat>, <lac>, <cid> */
- /* +CGREG: <stat>, <lac>, <cid>, <AcT> */
- err = at_tok_nextint(&line, &tmp);
- if (err < 0) goto error;
-
- /* We need to check if the second parameter is <lac> */
- if (*(line) == '"') {
- response[0] = tmp; /* <stat> */
- err = at_tok_nexthexint(&line, &response[1]); /* <lac> */
- if (err < 0) goto error;
- err = at_tok_nexthexint(&line, &response[2]); /* <cid> */
- if (err < 0) goto error;
- err = at_tok_nextint(&line, &response[3]); /* <AcT> */
- if (err < 0) goto error;
- count = 4;
- } else {
- err = at_tok_nextint(&line, &response[0]); /* <stat> */
- if (err < 0) goto error;
- err = at_tok_nexthexint(&line, &response[1]); /* <lac> */
- if (err < 0) goto error;
- err = at_tok_nexthexint(&line, &response[2]); /* <cid> */
- if (err < 0) goto error;
- }
- break;
-
- case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <AcT> */
- err = at_tok_nextint(&line, &skip); /* <n> */
- if (err < 0) goto error;
- err = at_tok_nextint(&line, &response[0]); /* <stat> */
- if (err < 0) goto error;
- err = at_tok_nexthexint(&line, &response[1]); /* <lac> */
- if (err < 0) goto error;
- err = at_tok_nexthexint(&line, &response[2]); /* <cid> */
- if (err < 0) goto error;
- err = at_tok_nextint(&line, &response[3]); /* <AcT> */
- if (err < 0) goto error;
- count = 4;
- break;
-
- default:
- ALOGE("%s() Invalid input", __func__);
- goto error;
- }
-
- /* Converting to stringlist for Android */
-
- asprintf(&responseStr[0], "%d", response[0]); /* state */
-
- if (response[1] >= 0)
- asprintf(&responseStr[1], "%04x", response[1]); /* LAC */
- else
- responseStr[1] = NULL;
-
- if (response[2] >= 0)
- asprintf(&responseStr[2], "%08x", response[2]); /* CID */
- else
- responseStr[2] = NULL;
-
- if (response[0] == CGREG_STAT_REG_HOME_NET ||
- response[0] == CGREG_STAT_ROAMING)
- asprintf(&responseStr[3], "%d",response[3]);
- else
- responseStr[3] = NULL;
-
- responseStr[5] = (char*) "1";
-
- RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, resp_size * sizeof(char *));
-
-finally:
-
- if (responseStr[0])
- free(responseStr[0]);
- if (responseStr[1])
- free(responseStr[1]);
- if (responseStr[2])
- free(responseStr[2]);
- if (responseStr[3])
- free(responseStr[3]);
-
- at_response_free(atResponse);
- return;
-
-error:
- ALOGE("%s Must never return an error when radio is on", __func__);
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- goto finally;
-}
-
-
/**
* RIL_REQUEST_OEM_HOOK_RAW
*
{
int err;
char * response = NULL;
- char * line = NULL;
- char * p = NULL;
+ char * dt = NULL;
+ char * tm = NULL;
char * tz = NULL; /* Timezone */
static char sNITZtime[64] = {0};
- line = strdup(s);
+ char * line = strdup(s);
/* Higher layers expect a NITZ string in this format:
* 08/10/28,19:08:37-20,1 (yy/mm/dd,hh:mm:ss(+/-)tz,dst)
*/
+ if (strStartsWith(s,"^NWTIME:")) {
+ /* Network time, as reported by Huawei modems:
+ ^NWTIME: 12/09/22,08:33:59+8,01 */
+
+ /* We got the network time, now assemble the response and send to upper layers */
+ at_tok_start(&line);
+
+ err = at_tok_nextstr(&line, &dt);
+ if (err < 0) goto error;
+
+ err = at_tok_nextstr(&line, &tm);
+ if (err < 0) goto error;
+
+ err = at_tok_nextstr(&line, &tz);
+ if (err < 0) goto error;
+
+ asprintf(&response, "%s,%s,%s", dt ,tm ,tz);
+ RIL_onUnsolicitedResponse(RIL_UNSOL_NITZ_TIME_RECEIVED, response, strlen(response));
+ free(response);
+
+ free(line);
+ return;
+ } else
if (strStartsWith(s,"+CTZV:")){
/* Get Time and Timezone data and store in static variable.
error:
ALOGE("Invalid NITZ line %s", s);
+ free(line);
+}
+
+/* Unsolicited call start status */
+static void unsolicitedCONN(const char * s)
+{
+ int err;
+ int call_id;
+ int type;
+ char * line = strdup(s);
+
+ err = at_tok_start(&line);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &call_id);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &type);
+ if (err < 0) goto error;
+
+ ALOGD("Call started: ID:%d, type:%d", call_id, type);
+
+ /* Store last call index */
+ lastCallIdx = call_id;
+
+ free(line);
+ return;
+
+error:
+ ALOGI("Error getting Call Start status");
+ free(line);
+ return;
+}
+
+/* Unsolicited call start status */
+static void unsolicitedORIG(const char * s)
+{
+ int err;
+ int call_id;
+ int type;
+ char * line = strdup(s);
+
+ err = at_tok_start(&line);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &call_id);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &type);
+ if (err < 0) goto error;
+
+ ALOGD("Call originated: ID:%d, type:%d", call_id, type);
+
+ /* Store last call index */
+ lastCallIdx = call_id;
+
+ free(line);
+ return;
+
+error:
+ ALOGI("Error getting Call Originated status");
+ free(line);
+ return;
+}
+
+/* Unsolicited call conference status */
+static void unsolicitedCONF(const char * s)
+{
+ int err;
+ int call_id;
+ char * line = strdup(s);
+
+ err = at_tok_start(&line);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &call_id);
+ if (err < 0) goto error;
+
+ ALOGD("Call conference started: ID:%d", call_id);
+
+ /* Store last call index */
+ lastCallIdx = call_id;
+
+ free(line);
+ return;
+
+error:
+ ALOGI("Error getting Call Conference Start status");
+ free(line);
+ return;
+}
+
+/* Unsolicited call end status */
+static void unsolicitedCEND(const char * s)
+{
+ int err;
+ int call_id;
+ int duration;
+ int end_status;
+ int cc_cause = CALL_FAIL_NORMAL;
+ char * line = strdup(s);
+
+ err = at_tok_start(&line);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &call_id);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &duration);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &end_status);
+ if (err < 0) goto error;
+
+ if (at_tok_hasmore(&line)) { /* not present if error */
+ err = at_tok_nextint(&line, &cc_cause);
+ if (err < 0) goto error;
+ }
+
+ ALOGD("Call ended: ID:%d, duration:%ds status:%d, cccause:%d", call_id, duration, end_status, cc_cause);
+
+ /* Store last call error */
+ lastCallFailCause = cc_cause;
+
+ free(line);
+ return;
+
+error:
+ ALOGI("Error getting Call End status");
+ lastCallFailCause = CALL_FAIL_NORMAL;
+ free(line);
+ return;
+}
+
+
+static void unsolicitedDCONN(const char *s)
+{
+}
+
+static void unsolicitedDEND(const char *s)
+{
}
static void unsolicitedRSSI(const char * s)
int err;
int rssi;
RIL_SignalStrength_v6 signalStrength;
- char * line = NULL;
- line = strdup(s);
+ char * line = strdup(s);
+
+ memset(&signalStrength, 0, sizeof(RIL_SignalStrength_v6));
err = at_tok_start(&line);
if (err < 0) goto error;
err = at_tok_nextint(&line, &rssi);
if (err < 0) goto error;
+ if (rssi == 99) return;
+
signalStrength.GW_SignalStrength.signalStrength = rssi;
signalStrength.GW_SignalStrength.bitErrorRate = 99;
- signalStrength.CDMA_SignalStrength.dbm = 0;
- signalStrength.CDMA_SignalStrength.ecio = 0;
- signalStrength.EVDO_SignalStrength.dbm = 0;
- signalStrength.EVDO_SignalStrength.ecio = 0;
- signalStrength.EVDO_SignalStrength.signalNoiseRatio = 0;
- signalStrength.LTE_SignalStrength.signalStrength = 0;
- signalStrength.LTE_SignalStrength.rsrp = 0;
- signalStrength.LTE_SignalStrength.rsrq = 0;
- signalStrength.LTE_SignalStrength.rssnr = 0;
- signalStrength.LTE_SignalStrength.cqi = 0;
ALOGI("Signal Strength %d", rssi);
- RIL_onUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH, &signalStrength, sizeof(signalStrength));
+ RIL_onUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH, &signalStrength, sizeof(RIL_SignalStrength_v6));
free(line);
return;
return;
}
+/* Get SIM status: 1=valid, all the others are invalid */
+static int getSimState(void)
+{
+ ATResponse *atResponse = NULL;
+ int err;
+ char *line;
+ int status;
+ int srv_status,srv_domain,roam_status,sys_mode,sim_state = -1;
+
+ // Check status.
+ err = at_send_command_singleline("AT^SYSINFO", "^SYSINFO:", &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, &srv_status);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &srv_domain);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &roam_status);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &sys_mode);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &sim_state);
+ if (err < 0) goto error;
+
+
+ ALOGE("Sim State: %d",sim_state);
+ at_response_free(atResponse);
+ return sim_state;
+
+error:
+ ALOGE("Failed to get sim state");
+
+ at_response_free(atResponse);
+ return -1;
+}
+
+static int requestNetworkRegistration()
+{
+ ATResponse *atResponse = NULL;
+ int err;
+ char *line;
+ int srv_status,srv_domain,nr = 0;
+
+ // Check status.
+ err = at_send_command_singleline("AT^SYSINFO", "^SYSINFO:", &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, &srv_status);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &srv_domain);
+ if (err < 0) goto error;
+
+ nr = (srv_status == 2 && (srv_domain == 2 || srv_domain == 3));
+
+ ALOGE("Network registration (PS) : %s", nr ? "Yes" : "No");
+ at_response_free(atResponse);
+ return nr;
+
+error:
+ ALOGE("Failed to get network registration");
+
+ at_response_free(atResponse);
+ return -1;
+}
+
+/* SIM status change */
+static void unsolicitedSimStatus(const char * s)
+{
+ int err;
+ int state;
+ char * line = NULL;
+
+ /*
+ ^SIMST:0 Invalid USIM card state
+ ^SIMST:1 Valid USIM card state
+ ^SIMST:2 Invalid USIM card in case of CS
+ ^SIMST:3 Invalid USIM card in case of PS
+ ^SIMST:4 Invalid USIM card in case of CS or PS
+ ^SIMST:255 Card not present
+ */
+
+ line = strdup(s);
+
+ err = at_tok_start(&line);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &state);
+ if (err < 0) goto error;
+
+ ALOGD("SIM state: %d",state);
+
+ free(line);
+ return;
+
+error:
+ ALOGI("Error getting state");
+ free(line);
+ return;
+}
+
+static void unsolicitedSrvStatus(const char * s)
+{
+ int err;
+ int mode;
+ char * line = NULL;
+
+ /*
+ ^SRVST:0 No service
+ ^SRVST:1 Restricted service
+ ^SRVST:2 Valid service
+ ^SRVST:3 Restricted Regional Service
+ ^SRVST:4 Power saving and deep sleep
+ */
+
+ line = strdup(s);
+
+ err = at_tok_start(&line);
+ if (err < 0) goto error;
+
+ err = at_tok_nextint(&line, &mode);
+ if (err < 0) goto error;
+
+ free(line);
+ return;
+
+error:
+ ALOGI("Error getting mode");
+ free(line);
+ return;
+}
+
+
static void unsolicitedMode(const char * s)
{
int err;
- int mode1;
- int mode2;
+ int android_mode;
+ int sys_mode;
+ int sys_submode;
char * line = NULL;
/*
- ^MODE:3,2 indicates GPRS
- ^MODE:3,3 indicates EDGE
- ^MODE:5,4 indicates 3G
- ^MODE:5,5 indicates HSDPA
+ ^MODE:<sys_mode>,<sys_submode>
+
+ <sys_mode>: System mode. The values are as follows:
+ 0 No service.
+ 1 AMPS mode (not in use currently)
+ 2 CDMA mode (not in use currently)
+ 3 GSM/GPRS mode
+ 4 HDR mode
+ 5 WCDMA mode
+ 6 GPS mode
+ <sys_submode>: System sub mode. The values are as follows:
+ 0 No service.
+ 1 GSM mode
+ 2 GPRS mode
+ 3 EDEG mode
+ 4 WCDMA mode
+ 5 HSDPA mode
+ 6 HSUPA mode
+ 7 HSDPA mode and HSUPA mode
*/
line = strdup(s);
err = at_tok_start(&line);
if (err < 0) goto error;
- err = at_tok_nextint(&line, &mode1);
+ err = at_tok_nextint(&line, &sys_mode);
if (err < 0) goto error;
- err = at_tok_nextint(&line, &mode2);
+ err = at_tok_nextint(&line, &sys_submode);
if (err < 0) goto error;
+ switch (sys_submode)
+ {
+ case 0:
+ android_mode = RADIO_TECH_UNKNOWN;
+ break;
+ case 1:
+ android_mode = RADIO_TECH_GSM;
+ break;
+ case 2:
+ android_mode = RADIO_TECH_GPRS;
+ break;
+ case 3:
+ android_mode = RADIO_TECH_EDGE;
+ break;
+ case 4:
+ android_mode = RADIO_TECH_UMTS;
+ break;
+ case 5:
+ android_mode = RADIO_TECH_HSDPA;
+ break;
+ case 6:
+ android_mode = RADIO_TECH_HSUPA;
+ break;
+ case 7:
+ android_mode = RADIO_TECH_HSPA;
+ break;
+ }
+
free(line);
+
+ RIL_onUnsolicitedResponse(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, &android_mode, sizeof(int *));
return;
error:
memset(&signalStrength, 0, sizeof(RIL_SignalStrength_v6));
- signalStrength.LTE_SignalStrength.signalStrength = 0x7FFFFFFF;
- signalStrength.LTE_SignalStrength.rsrp = 0x7FFFFFFF;
- signalStrength.LTE_SignalStrength.rsrq = 0x7FFFFFFF;
- signalStrength.LTE_SignalStrength.rssnr = 0x7FFFFFFF;
- signalStrength.LTE_SignalStrength.cqi = 0x7FFFFFFF;
-
err = at_send_command_singleline("AT+CSQ", "+CSQ:", &atResponse);
if (err != AT_NOERROR)
goto error;
err = at_tok_start(&line);
if (err < 0) goto error;
- err = at_tok_nextint(&line,&rssi);
+ err = at_tok_nextint(&line, &rssi);
if (err < 0) goto error;
- signalStrength.GW_SignalStrength.signalStrength = rssi;
-
err = at_tok_nextint(&line, &ber);
- if (err < 0)
- goto error;
+ if (err < 0) goto error;
+ signalStrength.GW_SignalStrength.signalStrength = rssi;
signalStrength.GW_SignalStrength.bitErrorRate = ber;
- signalStrength.CDMA_SignalStrength.dbm = 0;
- signalStrength.CDMA_SignalStrength.ecio = 0;
- signalStrength.EVDO_SignalStrength.dbm = 0;
- signalStrength.EVDO_SignalStrength.ecio = 0;
- signalStrength.EVDO_SignalStrength.signalNoiseRatio = 0;
- signalStrength.LTE_SignalStrength.signalStrength = 0;
- signalStrength.LTE_SignalStrength.rsrp = 0;
- signalStrength.LTE_SignalStrength.rsrq = 0;
- signalStrength.LTE_SignalStrength.rssnr = 0;
- signalStrength.LTE_SignalStrength.cqi = 0;
-
ALOGI("SignalStrength %d BER: %d", rssi, ber);
- RIL_onRequestComplete(t, RIL_E_SUCCESS, &signalStrength,
- sizeof(RIL_SignalStrength_v6));
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &signalStrength, sizeof(RIL_SignalStrength_v6));
at_response_free(atResponse);
atResponse = NULL;
memset(response, 0, sizeof(response));
- err = at_send_command_multiline
- ("AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?", "+COPS:",
- &atResponse);
+ err = at_send_command_multiline(
+ "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?", "+COPS:",
+ &atResponse);
if (err != AT_NOERROR)
goto error;
* +COPS: 0,2,"310170"
*/
for (i = 0, cursor = atResponse->p_intermediates;
- cursor != NULL && i < num_resp_lines;
- cursor = cursor->p_next, i++) {
+ cursor != NULL && i < num_resp_lines;
+ cursor = cursor->p_next, i++) {
char *line = cursor->line;
err = at_tok_start(&line);
if (onOff == 0 && getRadioState() != RADIO_STATE_OFF) {
char value[PROPERTY_VALUE_MAX];
- /* Switch RF OFF */
- err = at_send_command("AT^RFSWITCH=0");
+ err = at_send_command("AT+CFUN=0");
if (err != AT_NOERROR)
goto error;
} else if (onOff > 0 && getRadioState() == RADIO_STATE_OFF) {
- /* Switch RF ON */
- err = at_send_command("AT^RFSWITCH=1");
- if (err != AT_NOERROR)
- goto error;
-
+ err = at_send_command("AT+CFUN=1");
if (err != AT_NOERROR) {
+
// Some stacks return an error when there is no SIM,
// but they really turn the RF portion on
// So, if we get an error, let's check to see if it
restricted = RIL_RESTRICTED_STATE_NONE;
RIL_onUnsolicitedResponse(RIL_UNSOL_RESTRICTED_STATE_CHANGED,
- &restricted, sizeof(int *));
+ &restricted, sizeof(int *));
return;
at_response_free(atResponse);
}
+/**
+ * RIL_REQUEST_GET_IMEI
+ *
+ * Get the device IMEI, which should be 15 decimal digits.
+ */
+static void requestGetIMEI(RIL_Token t)
+{
+ ATResponse *atResponse = NULL;
+ int err;
+ /* IMEI */
+ err = at_send_command_numeric("AT+CGSN", &atResponse);
+
+ if (err != AT_NOERROR)
+ goto error;
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, atResponse->p_intermediates->line, sizeof(char *));
+
+ at_response_free(atResponse);
+ return;
+
+error:
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ at_response_free(atResponse);
+}
/**
* RIL_REQUEST_GET_IMEISV
RIL_onRequestComplete(t, RIL_E_SUCCESS, (void*)"01", sizeof(char *));
}
-
-
-/* RIL_REQUEST_DEVICE_IDENTITY
+/**
+ * RIL_REQUEST_DEVICE_IDENTITY
*
* Request the device ESN / MEID / IMEI / IMEISV.
*
at_response_free(atResponse);
}
+/**
+ * RIL_REQUEST_STK_SETUP_CALL
+ *
+ */
+static void requestStkSetupCall(void * data, size_t datalen, RIL_Token t)
+{
+ int onOff;
+ int err;
+
+ if (datalen < sizeof(int *)) {
+ ALOGE("%s() bad data length!", __func__);
+ goto error;
+ }
+
+ onOff = ((int *)data)[0];
+ err = at_send_command("AT^CSTC=%d", (onOff)?1:0 );
+ if (err != AT_NOERROR)
+ goto error;
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ return;
+
+error:
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
/**
* RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE
*/
static void requestStkSendTerminalResponse(void * data, size_t datalen, RIL_Token t)
{
+ int err;
+ const char *ec = (const char *) data;
(void)datalen;
- const char *stkResponse = (const char *) data;
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+
+ err = at_send_command("AT^CSTR=%d,\"%s\"",strlen(ec),ec);
+
+ if (err != AT_NOERROR)
+ goto error;
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL,0 );
+ return;
+
+error:
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+
}
*/
static void requestStkSendEnvelopeCommand(void * data, size_t datalen, RIL_Token t)
{
+ int err;
const char *ec = (const char *) data;
(void)datalen;
- RIL_onRequestComplete(t, RIL_E_SUCCESS, (void*)"ok", sizeof(char *));
+
+ err = at_send_command("AT^CSEN=%d,\"%s\"",strlen(ec),ec);
+
+ if (err != AT_NOERROR)
+ goto error;
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0 );
+ return;
+
+error:
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
}
}
+static void initStackUnsolv()
+{
+ at_send_command("AT^CSMN");
+}
+
/**
* RIL_REQUEST_STK_SET_PROFILE
*
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
}
-
+/**
+ * RIL_REQUEST_DIAL
+ */
static void requestDial(void *data, size_t datalen, RIL_Token t)
{
RIL_Dial *p_dial;
/* Originate call */
ret = at_send_command("ATD%s%s;", p_dial->address, clir);
+ /* Switch to audio from USB1 */
+ at_send_command("AT^DDSETEX=2");
+
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
p_line = (int *)data;
+ /* Just in case, stop the audio tunnel now. We need to stop if before the modem
+ stops streaming audio. If another call is being held, it will be restarted a
+ little bit later by the ccurrent call list callback */
+ stopAudioTunnel(NULL);
+
// 3GPP 22.030 6.5.5
// "Releases a specific active call X"
ret = at_send_command("AT+CHLD=1%d", p_line[0]);
static void requestHangupWaitingOrBackground(RIL_Token t)
{
+ /* Just in case, stop the audio tunnel now. We need to stop if before the modem
+ stops streaming audio. If another call is being hold, it will be restarted a
+ little bit later by the ccurrent call list callback */
+ stopAudioTunnel(NULL);
+
// 3GPP 22.030 6.5.5
// "Releases all held calls or sets User Determined User Busy
// (UDUB) for a waiting call."
static void requestHangupForegroundResumeBackground(RIL_Token t)
{
+ /* Just in case, stop the audio tunnel now. We need to stop if before the modem
+ stops streaming audio. If another call is being hold, it will be restarted a
+ little bit later */
+ stopAudioTunnel(NULL);
+
// 3GPP 22.030 6.5.5
// "Releases all active calls (if any exist) and accepts
// the other (held or waiting) call."
static void requestSwitchWaitingOrHoldingAndActive(RIL_Token t)
{
+ /* Just in case, stop the audio tunnel now. We need to stop if before the modem
+ stops streaming audio. If another call is being hold, it will be restarted a
+ little bit later */
+ stopAudioTunnel(NULL);
+
// 3GPP 22.030 6.5.5
// "Places all active calls (if any exist) on hold and accepts
// the other (held or waiting) call."
static void requestAnswer(RIL_Token t)
{
+ /* Answer call */
at_send_command("ATA");
+ /* Switch to audio from USB1 */
+ at_send_command("AT^DDSETEX=2");
+
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
}
}
-
+static int wasMuted = 0;
static void requestSetMute(void *data, size_t datalen, RIL_Token t)
{
int err;
assert (datalen >= sizeof(int *));
+ int mute = ((int*)data)[0];
- /* mute */
- err = at_send_command("AT+CMUT=%d", ((int*)data)[0]);
- if (err != AT_NOERROR)
- goto error;
+ /* Store mute status */
+ wasMuted = mute;
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- return;
+ /* mute - Don't consider it an error if it fails, as we are using a Software loopback for audio data */
+ err = at_send_command("AT+CMUT=%d", mute);
-error:
- ALOGE("ERROR: requestSetMute failed");
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ /* Update the audio tunnel mute status */
+ muteAudioTunnel(wasMuted);
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ return;
}
int response[1];
char *line;
+ /* If we fail, return a cached version of it */
err = at_send_command_singleline("AT+CMUT?", "+CMUT:", &atResponse);
-
if (err != AT_NOERROR)
goto error;
return;
error:
- ALOGE("ERROR: requestGetMute failed");
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ ALOGE("ERROR: requestGetMute failed - Returned cached result");
+
+ response[0] = wasMuted;
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(char*));
at_response_free(atResponse);
}
int err = 0;
char c = ((char *)data)[0];
- err = at_send_command("AT+VTS=%c", (int)c);
+ /* Start DTMF generation for 250ms */
+ err = at_send_command("AT^DTMF=%d,%c", lastCallIdx, (int)c); /* 1=call idx */
+
+ /* If failed, try the older method */
+ if (err != AT_NOERROR) {
+ err = at_send_command("AT+VTS=%c", (int)c);
+ }
+
if (err != AT_NOERROR) {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
} else {
}
-
static void requestDtmfStart(void *data, size_t datalen, RIL_Token t)
{
int err;
c = ((char *)data)[0];
- /* Start DTMF generation fro 250ms */
- err = at_send_command("AT^DTMF=0,%c", (int)c);
+ /* Start DTMF generation for 250ms */
+ err = at_send_command("AT^DTMF=%d,%c", lastCallIdx, (int)c); /* 1=call idx */
+
+ /* If failed, try the older method */
+ if (err != AT_NOERROR) {
+ err = at_send_command("AT+VTS=%c", (int)c);
+ }
+
if (err != AT_NOERROR)
goto error;
}
+/* decodes USSDs. Sometimes, they arrive as GSM8, sometimes they arrive as HEX encoded GSM7... */
+static bytes_t decodeUSSD(const char* message)
+{
+ bytes_t utf8 = NULL;
+
+ /* Could be in Hex or in GSM8 ... - Check it - Some modems return HEX
+ encoded GSM7, others return GSM8... */
+ int pos = 0;
+ int ishex = 1;
+ while (1) {
+ unsigned char c = message[pos];
+ if (!c) break;
+ if (!((c >= '0' && c <= '9') || ( c >= 'A' && c <= 'F' ))) {
+ ishex = 0;
+ break;
+ }
+ pos++;
+ };
+
+ /* Not hex encoded. Just convert to UTF-8 from GSM8 */
+ if (!ishex) {
+
+ /* Convert GSM8 to UTF8 */
+ int gsmbytes = strlen(message);
+ int utf8bytes = utf8_from_gsm8((cbytes_t)message,gsmbytes,NULL);
+ utf8 = malloc( utf8bytes + 1);
+ utf8_from_gsm8((cbytes_t)message,gsmbytes,utf8);
+ utf8[utf8bytes]= '\0';
+
+ } else {
+
+ int gsmseptets;
+ int utf8bytes;
+
+ /* Convert HEX to GSM7 */
+ int hexlen = strlen(message);
+ int binlen = (hexlen + 1) >> 1;
+ bytes_t bytes = malloc(binlen + 1);
+ gsm_hex_to_bytes((cbytes_t)message,hexlen,bytes);
+ bytes[binlen] = 0;
+
+ /* And then, GSM7 to UTF8 */
+ gsmseptets = (binlen * 8) / 7; // Round DOWN
+ utf8bytes = utf8_from_gsm7(bytes, 0, gsmseptets, NULL);
+ utf8 = malloc(utf8bytes + 1);
+ utf8_from_gsm7(bytes, 0, gsmseptets, utf8);
+ utf8[utf8bytes] = 0;
+ free(bytes);
+ }
+
+ return utf8;
+}
+
static void unsolicitedUSSD(const char *s)
{
char *line, *linestart;
- int typeCode, count, err, len;
+ int typeCode, count, err;
char *message;
- char *outputmessage;
char *responseStr[2] = {0,0};
D("unsolicitedUSSD %s", s);
- linestart=line=strdup(s);
+ linestart = line = strdup(s);
+
err = at_tok_start(&line);
if (err < 0) goto error;
err = at_tok_nextint(&line, &typeCode);
if (err < 0) goto error;
+ if (typeCode < 0 || typeCode > 5) goto error;
+
if (at_tok_hasmore(&line)) {
+
err = at_tok_nextstr(&line, &message);
if(err < 0) goto error;
- outputmessage = (char*) malloc(strlen(message)*2+1);
- gsm_hex_to_bytes((cbytes_t)message,strlen(message),(bytes_t)outputmessage);
-
- responseStr[1] = (char*) malloc(strlen(outputmessage)*2+1);
-
- len = utf8_from_gsm8((cbytes_t)outputmessage,strlen(outputmessage),(bytes_t)responseStr[1]);
-
- responseStr[1][strlen(message)/2]='\0';
- free(outputmessage);
+ /* Decode message */
+ responseStr[1] = (char*) decodeUSSD(message);
count = 2;
+
} else {
- responseStr[1]=NULL;
+
+ responseStr[1] = NULL;
count = 1;
}
- free(linestart);
+
asprintf(&responseStr[0], "%d", typeCode);
- RIL_onUnsolicitedResponse (RIL_UNSOL_ON_USSD, responseStr, count*sizeof(char*));
+ RIL_onUnsolicitedResponse(RIL_UNSOL_ON_USSD, responseStr, count*sizeof(char*));
+
+ free(linestart);
if (responseStr[0])
free(responseStr[0]);
if (responseStr[1])
static void requestSendUSSD(void *data, size_t datalen, RIL_Token t)
{
int err = 0;
- int len;
- cbytes_t ussdRequest;
- bytes_t temp;
- char *newUSSDRequest;
- ussdRequest = (cbytes_t)(data);
-
- temp = (bytes_t) malloc(strlen((char *)ussdRequest)*sizeof(char)+1);
- len = utf8_to_gsm8(ussdRequest,strlen((char *)ussdRequest),temp);
- newUSSDRequest = (char*) malloc(2*len*sizeof(char)+1);
- gsm_hex_from_bytes(newUSSDRequest,temp, len);
- newUSSDRequest[2*len]='\0';
- free(temp);
-
- err = at_send_command("AT+CUSD=1,\"%s\",15", newUSSDRequest);
- free(newUSSDRequest);
- if (err != AT_NOERROR)
- goto error;
+ cbytes_t ussdRequest = (cbytes_t)(data);
+
+ /*
+ * ussdRequest should be checked for invalid characters that can be used to
+ * send invalid AT commands. However Android have complete check of
+ * ussd strings before they are sent to the RIL.
+ *
+ * AT+CUSD=[<n>[,<str>[,<dcs>]]]
+ * <n> = 0,1,2 Dissable, Enable, Cancel
+ * <str> = CUSD string in UTF8
+ * <dcs> = Cell Brodcast Data Coding Scheme:
+ * 0000 German
+ * 0001 English
+ * 0010 Italian
+ * 0011 French
+ * 0100 Spanish
+ * 0101 Dutch
+ * 0110 Swedish
+ * 0111 Danish
+ * 1000 Portuguese
+ * 1001 Finnish
+ * 1010 Norwegian
+ * 1011 Greek
+ * 1100 Turkish
+ * 1101..1110 Reserved for European languages
+ * 1111 Language unspecified
+ *
+ * According to Android ril.h , CUSD messages are always sent as utf8,
+ * but the dcs field does not have an entry for this.
+ * The nearest "most correct" would be 15 = unspecified,
+ * not adding the dcs would result in the default "0" meaning German,
+ * and some networks are not happy with this.
+ *
+ * Huawei modems, depending on firmware version, seem to accept GSM8 or
+ * a HEX encoded GSM7 request. Try GSM8; if it fails, try GSM7 encoded in HEX
+ */
+
+ /* Convert to GSM8 from UTF8 */
+ int utf8len = strlen((const char*)ussdRequest);
+ int gsmbytes = utf8_to_gsm8(ussdRequest, utf8len, NULL);
+ bytes_t gsm8 = malloc(gsmbytes + 1);
+ utf8_to_gsm8(ussdRequest, utf8len, gsm8);
+ gsm8[gsmbytes] = 0;
+
+ /* Try to send it as GSM8 */
+ err = at_send_command("AT+CUSD=1,%s,15", gsm8);
+
+ /* Some modems like the string to be between quotes ... Retry if error */
+ if (err != AT_NOERROR) {
+ err = at_send_command("AT+CUSD=1,\"%s\",15", gsm8);
+ }
+ free(gsm8);
+
+ /* If modem did not accept the USSD, retry it but using HEX encoded GSM7 */
+ if (err != AT_NOERROR) {
+ char* hex = NULL;
+
+ /* Convert to GSM7 */
+ int gsmseptets = utf8_to_gsm7(ussdRequest, utf8len, NULL, 0);
+ int gsmbytes = ((gsmseptets * 7) + 7) / 8; // Round UP, to be able to transmit incomplete septets
+ bytes_t gsm7 = malloc(gsmbytes + 1);
+ utf8_to_gsm7(ussdRequest, utf8len, gsm7, 0);
+ gsm7[gsmbytes] = 0;
+
+ /* And then encode to HEX */
+ hex = malloc(2*gsmbytes+1);
+ gsm_hex_from_bytes(hex, gsm7, gsmbytes);
+ hex[2*gsmbytes]='\0';
+
+ /* Retry to send the command */
+ ALOGD("utf8len: %d, gsmseptets: %d, gsmbytes:%d", utf8len, gsmseptets, gsmbytes);
+ err = at_send_command("AT+CUSD=1,\"%s\",15", hex);
+ free(gsm7);
+ free(hex);
+
+ if (err != AT_NOERROR)
+ goto error;
+ }
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
return;
/* Reset MS */
err = at_send_command("AT+CFUN=6");
- if (err != AT_NOERROR)
- goto error;
/* Go online */
- err = at_send_command("AT^RFSWITCH=1");
+ err = at_send_command("AT^RFSWITCH=1"); /* ignore error. If unsupported, the next line will enable RF */
err = at_send_command("AT+CFUN=1");
if (err != AT_NOERROR)
goto error;
{
int err = 0;
int updates = 0;
- ATResponse *atResponse = NULL;
updates = ((int *)data)[0] == 1? 2 : 1;
- err = at_send_command_singleline("AT+CREG=%d","+CLIP:",&atResponse, updates);
+ err = at_send_command("AT+CREG=%d", updates);
if (err != AT_NOERROR)
goto error;
- at_response_free(atResponse);
-
- //Always return success for CDMA (for now)
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
return;
error:
- at_response_free(atResponse);
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
}
if(err != AT_NOERROR)
goto error;
+ /*
+ CALL_FAIL_NORMAL = 16,
+ CALL_FAIL_BUSY = 17,
+ CALL_FAIL_CONGESTION = 34,
+ CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
+ CALL_FAIL_CALL_BARRED = 240,
+ CALL_FAIL_FDN_BLOCKED = 241,
+ CALL_FAIL_ERROR_UNSPECIFIED = 0xffff
+ */
+
line = atResponse->p_intermediates->line;
err = at_tok_start(&line);
if(err < 0) goto error;
err = at_tok_nextstr(&line, &tmp);
if(err < 0) goto error;
- err = at_tok_nextint(&line, &response);
- if(err < 0) goto error;
+ if (at_tok_hasmore(&line)) {
+ err = at_tok_nextint(&line, &response);
+ if(err < 0) goto error;
+ }
- RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
- at_response_free(atResponse);
- return;
+ ALOGD("Textual last call fail cause: %s [%d]", tmp, response);
error:
- at_response_free(atResponse);
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ /* Send the last call fail cause */
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &lastCallFailCause, sizeof(int));
+ at_response_free(atResponse);
+ return;
}
/*
/* Check if ME is ready to set preferred message storage */
checkMessageStorageReady(NULL);
- /* Select message service */
- at_send_command("AT+CSMS=0");
-
- /*
- * Always send SMS messages directly to the TE
- *
- * mode = 1 // discard when link is reserved (link should never be
- * reserved)
- * mt = 2 // most messages routed to TE
- * bm = 2 // new cell BM's routed to TE
- * ds = 1 // Status reports routed to TE
- * bfr = 1 // flush buffer
- */
- at_send_command("AT+CNMI=1,2,2,1,1");
-
- /* Select cell broadcast messages: Do not accept messages */
- at_send_command("AT+CSCB=1");
-
- /* Enable automatic timezone update */
- at_send_command("AT+CTZU=1");
-
- /* Enable timezone change reporting */
- at_send_command("AT+CTZR=1");
-
/* Subscribe to network registration events.
* n = 2 - Enable network registration and location information
* unsolicited result code +CREG: <stat>[,<lac>,<ci>]
at_send_command("AT+CREG=1");
}
+ /* Enable proactive network registration notifications */
+ at_send_command("AT+CGREG=2");
+
+ /* Extended Cellular result codes enabled */
+ at_send_command("AT+CRC=1");
+
+ /* Calling line identification enabled */
+ at_send_command("AT+CLIP=1");
+
+ /* Call waiting enabled */
+ at_send_command("AT+CCWA=1");
+
+ /* Alternating voice/data off */
+ at_send_command("AT+CMOD=0");
+
+ /* +CSSU unsolicited supp service notifications */
+ at_send_command("AT+CSSN=0,1");
+
+ /* Connected line identification On*/
+ at_send_command("AT+COLP=1");
+
+ /*
+ * Ensure that the modem is using GSM character set and not IRA,
+ * otherwise weirdness with umlauts and other non-ASCII characters
+ * can result
+ */
+ at_send_command("AT+CSCS=\"GSM\"");
+
+ /* USSD unsolicited */
+ at_send_command("AT+CUSD=1");
+
/* Configure Short Message (SMS) Format
* mode = 0 - PDU mode.
*/
at_send_command("AT+CMGF=0");
- /* Enable unsolicited RSSI reporting */
- at_send_command("AT^CURC=1");
-
- /* Enable GPRS reporting */
- at_send_command("AT+CGEREP=1,0");
+ /* Disable boot messages */
+ at_send_command("AT^BOOT=0,0");
+ /* And flow messages */
+ at_send_command("AT^DSFLOWRPT=0");
/* Select SMS type */
- at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
-}
+ at_send_command_singleline("AT+CSMS=0", "+CSMS:", NULL);
+
+ /* Always send SMS messages directly to the TE */
+ at_send_command("AT+CNMI=2,1,2,2,0");
+ /* Enable unsolicited RSSI reporting */
+ at_send_command("AT^CURC=1");
+}
static void requestNotSupported(RIL_Token t, int request)
{
* GENERIC_FAILURE if we're not in SIM_STATE_READY.
*/
RIL_RadioState radio_state = getRadioState();
-D("%s() %s", __func__, radioStateToString(radio_state));
if (radio_state != RADIO_STATE_SIM_READY &&
(request == RIL_REQUEST_WRITE_SMS_TO_SIM ||
/* Trigger a rehash of network values, just to be sure. */
if (((int *)data)[0] == 1)
RIL_onUnsolicitedResponse(
- RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
- NULL, 0);
+ RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
+ NULL, 0);
break;
- /* Data Call Requests */
+ /* Data Call Requests */
case RIL_REQUEST_SETUP_DATA_CALL:
requestSetupDefaultPDP(data, datalen, t);
break;
requestPDPContextList(t);
break;
- /* SMS Requests */
+ /* SMS Requests */
case RIL_REQUEST_SEND_SMS:
requestSendSMS(data, datalen, t);
break;
requestGSMSMSBroadcastActivation(data, datalen, t);
break;
- /* SIM Handling Requests */
+ /* SIM Handling Requests */
case RIL_REQUEST_SIM_IO:
requestSIM_IO(data, datalen, t);
break;
requestSetFacilityLock(data, datalen, t);
break;
- /* Network Requests */
+ /* Network Requests */
case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
requestEnterSimPin(data, datalen, t, request);
break;
case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
requestGetPreferredNetworkType(t);
break;
- case RIL_REQUEST_VOICE_REGISTRATION_STATE:
- requestRegistrationState(t);
- break;
case RIL_REQUEST_DATA_REGISTRATION_STATE:
- requestGprsRegistrationState(t);
+ requestRegistrationState(t, 1);
+ break;
+ case RIL_REQUEST_VOICE_REGISTRATION_STATE:
+ requestRegistrationState(t, 0);
break;
- /* OEM */
+ /* OEM */
case RIL_REQUEST_OEM_HOOK_RAW:
// echo back data
requestOEMHookRaw(data, datalen, t);
requestOEMHookStrings(data, datalen, t);
break;
- /* Misc */
+ /* Misc */
case RIL_REQUEST_SIGNAL_STRENGTH:
requestSignalStrength(t);
break;
requestGetIMSI(t);
break;
case RIL_REQUEST_GET_IMEI:
- requestGetIMEISV(t);
+ requestGetIMEI(t);
break;
case RIL_REQUEST_GET_IMEISV:
requestGetIMEISV(t);
requestBasebandVersion(t);
break;
- /* SIM Application Toolkit */
+ /* Band control */
+ case RIL_REQUEST_SET_BAND_MODE:
+ requestSetBandMode(data, datalen, t);
+ break;
+ case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
+ requestQueryAvailableBandMode(data, datalen, t);
+ break;
+
+ /* SIM Application Toolkit */
case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE:
requestStkSendTerminalResponse(data, datalen, t);
break;
requestReportStkServiceIsRunning(t);
break;
- /* Misc ops */
+ /* Misc ops */
case RIL_REQUEST_DIAL:
requestDial(data, datalen, t);
break;
default:
ALOGW("FIXME: Unsupported request logged: %s",
- requestToString(request));
+ requestToString(request));
requestNotSupported(t, request);
break;
}
RequestQueue *q = &s_requestQueue;
int err;
- r = (RILRequest *) malloc(sizeof(RILRequest));
- memset(r, 0, sizeof(RILRequest));
+ r = (RILRequest *) calloc(1, sizeof(RILRequest));
/* Formulate a RILRequest and put it in the queue. */
r->request = request;
at_send_command("AT+CCLK=\"%s%c%02d\"", str, tz[0], tzi);
}
-
+/**
+ * Initialize everything
+ */
static char initializeCommon(void)
{
int err = 0;
unsigned int i;
static const char* const initcmd[] = {
- /* Reset the MS*/
- "AT+CFUN=6",
-
- /* atchannel is tolerant of echo but it must */
- /* reset and have verbose result codes */
- "ATZV1",
-
/* echo off */
"ATE0",
- /* No auto-answer */
- "ATS0=0",
+ /* Send verbose results */
+ "ATQ0V1",
/* No auto-answer */
- "AT%AUTOANSWER=0",
-
- /* send results */
- "ATQ0",
-
- /* check for busy, don't check for dialone */
- "ATX3",
-
- /* set DCD depending on service */
- "AT&C1",
-
- /* set DTR according to service */
- "AT&D1",
+ "ATS0=0",
/* Extended errors without textual decriptions */
"AT+CMEE=1",
- /* detailed rings, unknown */
- "AT+CRC=1;+CR=1",
-
- /* caller id = yes */
- "AT+CLIP=1",
-
- /* don't hide outgoing callerID */
- "AT+CLIR=0",
-
- /* Call Waiting notifications */
- "AT+CCWA=1",
-
- /* No connected line identification */
- "AT+COLP=0",
-
- /* USSD unsolicited */
- "AT+CUSD=1",
-
- /* SMS PDU mode */
- "AT+CMGF=0",
-
- //"AT+GTKC=2",
-
- /* +CSSU unsolicited supp service notifications */
- "AT+CSSN=0,1",
-
- /* HEX character set */
- //"AT+CSCS=\"HEX\"",
- "AT+CSCS=\"IRA\"",
-
- /* Modem mode */
- "AT+FCLASS=0",
-
- "AT+CNMI=1,2,2,2,0",
- //"AT+CPPP=1",
+ /* Enable RF */
+ "AT^RFSWITCH=1"
+ };
+ D("%s()", __func__);
- "AT"
- };
+ setRadioState(RADIO_STATE_OFF);
if (at_handshake() < 0) {
LOG_FATAL("Handshake failed!");
return 1;
}
-
for (i=0; i < sizeof(initcmd) / sizeof(initcmd[0]); i++) {
err = at_send_command(initcmd[i]);
if (err != AT_NOERROR) {
}
}
- /* Send the current time of the OS to the module */
- sendTime(NULL);
-
- return 0;
-}
-
-/**
- * Initialize everything
- */
-static char initializeChannel(void)
-{
- int err = 0;
- unsigned int i;
- static const char* const initcmd[] = {
-
- /* Configure Packet Domain Network Registration Status events
- * 2 = Enable network registration and location information
- * unsolicited result code
- */
-
- /* Alternating voice/data off */
- "AT+CMOD=0",
+ /* TE-MS handshake function */
+ //"AT^HS=0,0",
- /* Not muted */
- "AT+CMUT=0",
-
- /* Network registration events */
- "AT+CREG=2",
-
- /* GPRS registration events */
- "AT+CGREG=2",
-
- "AT+CGEQREQ=1,4,0,0,0,0,2,0,\"0E0\",\"0E0\",3,0,0",
-
- /* Enable unsolicited reports */
- "AT^CURC=1",
-
- /* Enable GPRS reporting */
- "AT+CGEREP=1,0",
-
- /* for 3G Preferred */
- "AT^SYSCFG=2,2,3FFFFFFF,1,2",
-
- /* Disable RF */
- "AT^RFSWITCH=0"
- };
-
- D("%s()", __func__);
-
- setRadioState(RADIO_STATE_OFF);
-
- for (i=0; i < sizeof(initcmd) / sizeof(initcmd[0]); i++) {
- err = at_send_command(initcmd[i]);
- if (err != AT_NOERROR) {
- ALOGE("Failed sending command '%s'",initcmd[i]);
- }
- }
/* Assume radio is off on error. */
if (isRadioOn() > 0)
if (getRadioState() == RADIO_STATE_UNAVAILABLE)
return;
+ /* Timezone */
if (strStartsWith(s, "%CTZV:")
|| strStartsWith(s,"+CTZV:")
|| strStartsWith(s,"+CTZDST:")
- || strStartsWith(s,"+HTCCTZV:")) {
+ || strStartsWith(s,"+HTCCTZV:")
+ || strStartsWith(s,"^NWTIME:")
+ ) {
unsolicitedNitzTime(s);
+
+ /* Call status/start/end indicator */
} else if (strStartsWith(s,"+CRING:")
|| strStartsWith(s,"RING")
+ || strStartsWith(s,"+CLIP")
|| strStartsWith(s,"NO CARRIER")
|| strStartsWith(s,"+CCWA")
+ || strStartsWith(s,"^ORIG:")
+ || strStartsWith(s,"^CONF:")
+ || strStartsWith(s,"^CONN:")
+ || strStartsWith(s,"^CEND:")
) {
- RIL_onUnsolicitedResponse (
+
+ /* Start/stop audio tunnel if needed when a successful connection is done */
+ if ( strStartsWith(s,"^ORIG:")) {
+ enqueueRILEvent(startAudioTunnel, NULL, NULL);
+ unsolicitedORIG(s);
+ } else
+ if ( strStartsWith(s,"^CONF:")) {
+ enqueueRILEvent(startAudioTunnel, NULL, NULL);
+ unsolicitedCONF(s);
+ } else
+ if ( strStartsWith(s,"^CONN:")) {
+ enqueueRILEvent(startAudioTunnel, NULL, NULL);
+ unsolicitedCONN(s);
+ } else
+ if (strStartsWith(s,"^CEND:")) {
+ /* This is the only fast way to detect when call was hang by the callee */
+ enqueueRILEvent(stopAudioTunnel, NULL, NULL);
+ unsolicitedCEND(s);
+ }
+
+ RIL_onUnsolicitedResponse(
+ RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
+ NULL, 0);
+ enqueueRILEvent(onDataCallListChanged, NULL, NULL);
+
+ /* Data call status/start/end */
+ } else if (strStartsWith(s,"^DCONN:")
+ || strStartsWith(s,"^DEND:")) {
+
+ RIL_onUnsolicitedResponse(
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
NULL, 0);
enqueueRILEvent(onDataCallListChanged, NULL, NULL);
- } else if (strStartsWith(s,"^RSSI:") ||
- strStartsWith(s,"%RSSI:")) {
+
+ } else if (strStartsWith(s,"^COMM:")) {
+
+
+ } else if (strStartsWith(s,"^RSSI:")
+ || strStartsWith(s,"%RSSI:")) {
unsolicitedRSSI(s);
} else if (strStartsWith(s,"^MODE:")) {
unsolicitedMode(s);
+ } else if (strStartsWith(s,"^SRVST:")) {
+ unsolicitedSrvStatus(s);
+ } else if (strStartsWith(s,"^SIMST:")) {
+ unsolicitedSimStatus(s);
} else if (strStartsWith(s,"+CREG:")
|| strStartsWith(s,"+CGREG:")) {
- RIL_onUnsolicitedResponse (
+ RIL_onUnsolicitedResponse(
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
NULL, 0);
enqueueRILEvent(onDataCallListChanged, NULL, NULL);
onNewSms(sms_pdu);
} else if (strStartsWith(s, "+CBM:")) {
onNewBroadcastSms(sms_pdu);
- } else if (strStartsWith(s, "+CMTI:")) {
+ } else if (strStartsWith(s, "+CMTI:")
+ || strStartsWith(s, "+CDSI:")) {
onNewSmsOnSIM(s);
} else if (strStartsWith(s, "+CDS:")) {
onNewStatusReport(sms_pdu);
enqueueRILEvent(onDataCallListChanged, NULL, NULL);
} else if (strStartsWith(s, "+CUSD:")) {
unsolicitedUSSD(s);
- } else if (strStartsWith(s, "+CIEV: 7") ||
- strStartsWith(s, "Received SMS:")) {
+ } else if (strStartsWith(s, "+CIEV: 7")
+ || strStartsWith(s, "Received SMS:")
+ || strStartsWith(s, "^SMMEMFULL") ) {
onNewSmsIndication();
}
}
RequestQueue *q = s_requestQueues[i];
if ((err = pthread_mutex_lock(&q->queueMutex)) != 0)
ALOGE("%s() failed to take queue mutex: %s",
- __func__, strerror(err));
+ __func__, strerror(err));
q->closed = 1;
if ((err = pthread_cond_signal(&q->cond)) != 0)
ALOGE("%s() failed to broadcast queue update: %s",
- __func__, strerror(err));
+ __func__, strerror(err));
if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
ALOGE("%s() failed to take queue mutex: %s", __func__,
- strerror(err));
+ strerror(err));
}
}
static void usage(char *s)
{
#ifdef RIL_SHLIB
- fprintf(stderr, "htcgeneric-ril requires: -p <tcp port> or -d /dev/tty_device\n");
+ fprintf(stderr, "generic-ril requires: -p <tcp port> or -d /dev/tty_device\n");
#else
fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device] [-v /dev/tty_device]\n", s);
exit(-1);
if (fd < 0) {
ALOGE("%s() Failed to open AT channel %s (%s), retrying in %d.",
- __func__, queueArgs->device_path,
- strerror(errno), TIMEOUT_SEARCH_FOR_TTY);
+ __func__, queueArgs->device_path,
+ strerror(errno), TIMEOUT_SEARCH_FOR_TTY);
sleep(TIMEOUT_SEARCH_FOR_TTY);
/* Never returns. */
}
q = &s_requestQueue;
if (initializeCommon()) {
- ALOGE("%s() Failed to initialize channel!", __func__);
+ ALOGE("%s() Failed to initialize common", __func__);
at_close();
continue;
}
q->closed = 0;
- if (initializeChannel()) {
- ALOGE("%s() Failed to initialize channel!", __func__);
- at_close();
- continue;
- }
-
at_make_default_channel();
ALOGE("%s() Looping the requestQueue!", __func__);
memset(&ts, 0, sizeof(ts));
- if ((err = pthread_mutex_lock(&q->queueMutex)) != 0)
- ALOGE("%s() failed to take queue mutex: %s!",
- __func__, strerror(err));
+ if ((err = pthread_mutex_lock(&q->queueMutex)) != 0)
+ ALOGE("%s() failed to take queue mutex: %s!",
+ __func__, strerror(err));
if (q->closed != 0) {
ALOGW("%s() AT Channel error, attempting to recover..", __func__);
}
while (q->closed == 0 && q->requestList == NULL &&
- q->eventList == NULL) {
+ q->eventList == NULL) {
if ((err = pthread_cond_wait(&q->cond, &q->queueMutex)) != 0)
ALOGE("%s() failed broadcast queue cond: %s!",
- __func__, strerror(err));
+ __func__, strerror(err));
}
/* eventList is prioritized, smallest abstime first. */
err = pthread_cond_timedwait(&q->cond, &q->queueMutex, &q->eventList->abstime);
if (err && err != ETIMEDOUT)
ALOGE("%s() timedwait returned unexpected error: %s",
- __func__, strerror(err));
+ __func__, strerror(err));
}
if (q->closed != 0) {
if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
ALOGE("%s(): Failed to release queue mutex: %s!",
- __func__, strerror(err));
+ __func__, strerror(err));
continue; /* Catch the closed bit at the top of the loop. */
}
clock_gettime(CLOCK_MONOTONIC, &ts);
if (q->eventList != NULL &&
- timespec_cmp(q->eventList->abstime, ts, < )) {
+ timespec_cmp(q->eventList->abstime, ts, < )) {
e = q->eventList;
q->eventList = e->next;
}
if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
ALOGE("%s(): Failed to release queue mutex: %s!",
- __func__, strerror(err));
+ __func__, strerror(err));
if (e) {
e->eventCallback(e->param);
int opt;
int port = -1;
char *loophost = NULL;
- const char *device_path = NULL;
+ const char *ctrl_path = NULL;
struct queueArgs *queueArgs;
pthread_attr_t attr;
+#if 0
+ /* Logcat test */
+ char local_ip[64];
+ char dns1[64];
+ char dns2[64];
+ char gw[64];
+ struct timeval from;
+ int rr;
+ gettimeofday(&from,NULL);
+ rr = get_pppd_info(&from,local_ip, dns1, dns2, gw);
+ ALOGD("result: %d",rr);
+#endif
+
+#if 0
+ char * m = decodeUSSD("D9775D0E6286E7749050FEBECFD3EE33685A9ECFD36F37283D07BDCD201868297449CBED70DA9D769F414679B90C2287E96190FDCDAEB7CBA0F41C849BCD60B41C68297401");
+ ALOGD("Decoded msg: '%s'",m);
+ free(m);
+#endif
+
+ memset(&sAudioChannel, 0, sizeof(sAudioChannel));
+
s_rilenv = env;
/* By default, use USB1 as audio channel */
D("%s() entering...", __func__);
- while (-1 != (opt = getopt(argc, argv, "z:p:d:v:"))) {
+ while (-1 != (opt = getopt(argc, argv, "z:n:i:p:d:v:"))) {
switch (opt) {
case 'z':
loophost = optarg;
break;
case 'd':
- device_path = optarg;
- D("%s() Opening tty device %s", __func__, device_path);
+ ctrl_path = optarg;
+ D("%s() Opening tty device %s", __func__, ctrl_path);
break;
case 'v':
D("%s() Opening voice tty device %s", __func__, sAudioDevice);
break;
+ case 'n':
+ rndis_iface_dev = optarg;
+ D("%s() Using network interface %s as primary data channel.", __func__, rndis_iface_dev);
+ break;
+
+ case 'i':
+ ppp_iface_dev = optarg;
+ D("%s() Using ppp interface %s as primary data channel.", __func__, ppp_iface_dev);
+ break;
+
default:
usage(argv[0]);
return NULL;
}
}
- if (port < 0 && device_path == NULL) {
+ if (port < 0 && ctrl_path == NULL) {
usage(argv[0]);
return NULL;
}
- queueArgs = (struct queueArgs*) malloc(sizeof(struct queueArgs));
- memset(queueArgs, 0, sizeof(struct queueArgs));
+ queueArgs = (struct queueArgs*) calloc(1, sizeof(struct queueArgs));
- queueArgs->device_path = device_path;
+ queueArgs->device_path = ctrl_path;
queueArgs->port = port;
queueArgs->loophost = loophost;
int opt;
int port = -1;
char *loophost = NULL;
- const char *device_path = NULL;
+ const char *ctrl_path = NULL;
struct queueArgs *queueArgs;
+ memset(&sAudioChannel, 0, sizeof(sAudioChannel));
+
/* By default, use USB1 as audio channel */
strcpy(sAudioDevice,"/dev/ttyUSB1");
D("%s() entering...", __func__);
- while (-1 != (opt = getopt(argc, argv, "z:p:d:v:"))) {
+ while (-1 != (opt = getopt(argc, argv, "z:n:i:p:d:v:"))) {
switch (opt) {
case 'z':
loophost = optarg;
break;
case 'd':
- device_path = optarg;
- D("%s() Opening tty device %s", __func__, device_path);
+ ctrl_path = optarg;
+ D("%s() Opening tty device %s", __func__, ctrl_path);
break;
case 'v':
D("%s() Opening voice tty device %s", __func__, sAudioDevice);
break;
+ case 'n':
+ rndis_iface_dev = optarg;
+ D("%s() Using network interface %s as primary data channel.", __func__, rndis_iface_dev);
+ break;
+
+ case 'i':
+ ppp_iface_dev = optarg;
+ D("%s() Using ppp interface %s as primary data channel.", __func__, ppp_iface_dev);
+ break;
+
default:
usage(argv[0]);
return 0;
}
}
- if (port < 0 && device_path == NULL) {
+ if (port < 0 && ctrl_path == NULL) {
usage(argv[0]);
return 0;
}
- queueArgs = (struct queueArgs*) malloc(sizeof(struct queueArgs));
- memset(queueArgs, 0, sizeof(struct queueArgs));
+ queueArgs = (struct queueArgs*) calloc(1, sizeof(struct queueArgs));
- queueArgs->device_path = device_path;
+ queueArgs->device_path = ctrl_path;
queueArgs->port = port;
queueArgs->loophost = loophost;