1 /* //device/system/reference-ril/reference-ril.c
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include <telephony/ril_cdma_sms.h>
19 #include <telephony/librilutils.h>
20 #include <stdio.h>
21 #include <assert.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <sys/cdefs.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <inttypes.h>
29 #include <fcntl.h>
30 #include <pthread.h>
31 #include <alloca.h>
32 #include "atchannel.h"
33 #include "at_tok.h"
34 #include "misc.h"
35 #include <getopt.h>
36 #include <sys/socket.h>
37 #include <cutils/properties.h>
38 #include <cutils/sockets.h>
39 #include <termios.h>
40 #include <sys/wait.h>
41 #include <stdbool.h>
42 #include <net/if.h>
43 #include <netinet/in.h>
44
45 #include "ril.h"
46
47 #define LOG_TAG "RIL"
48 #include <utils/Log.h>
49
noopRemoveWarning(void * a)50 static void *noopRemoveWarning( void *a ) { return a; }
51 #define RIL_UNUSED_PARM(a) noopRemoveWarning((void *)&(a));
52
53 #define MAX_AT_RESPONSE 0x1000
54
55 /* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
56 // This is used if Wifi is not supported, plain old eth0
57 #define PPP_TTY_PATH_ETH0 "eth0"
58 // This is used if Wifi is supported to separate radio and wifi interface
59 #define PPP_TTY_PATH_RADIO0 "radio0"
60
61 // Default MTU value
62 #define DEFAULT_MTU 1500
63
64 #ifdef USE_TI_COMMANDS
65
66 // Enable a workaround
67 // 1) Make incoming call, do not answer
68 // 2) Hangup remote end
69 // Expected: call should disappear from CLCC line
70 // Actual: Call shows as "ACTIVE" before disappearing
71 #define WORKAROUND_ERRONEOUS_ANSWER 1
72
73 // Some varients of the TI stack do not support the +CGEV unsolicited
74 // response. However, they seem to send an unsolicited +CME ERROR: 150
75 #define WORKAROUND_FAKE_CGEV 1
76 #endif
77
78 /* Modem Technology bits */
79 #define MDM_GSM 0x01
80 #define MDM_WCDMA 0x02
81 #define MDM_CDMA 0x04
82 #define MDM_EVDO 0x08
83 #define MDM_LTE 0x10
84
85 typedef struct {
86 int supportedTechs; // Bitmask of supported Modem Technology bits
87 int currentTech; // Technology the modem is currently using (in the format used by modem)
88 int isMultimode;
89
90 // Preferred mode bitmask. This is actually 4 byte-sized bitmasks with different priority values,
91 // in which the byte number from LSB to MSB give the priority.
92 //
93 // |MSB| | |LSB
94 // value: |00 |00 |00 |00
95 // byte #: |3 |2 |1 |0
96 //
97 // Higher byte order give higher priority. Thus, a value of 0x0000000f represents
98 // a preferred mode of GSM, WCDMA, CDMA, and EvDo in which all are equally preferrable, whereas
99 // 0x00000201 represents a mode with GSM and WCDMA, in which WCDMA is preferred over GSM
100 int32_t preferredNetworkMode;
101 int subscription_source;
102
103 } ModemInfo;
104
105 static ModemInfo *sMdmInfo;
106 // TECH returns the current technology in the format used by the modem.
107 // It can be used as an l-value
108 #define TECH(mdminfo) ((mdminfo)->currentTech)
109 // TECH_BIT returns the bitmask equivalent of the current tech
110 #define TECH_BIT(mdminfo) (1 << ((mdminfo)->currentTech))
111 #define IS_MULTIMODE(mdminfo) ((mdminfo)->isMultimode)
112 #define TECH_SUPPORTED(mdminfo, tech) ((mdminfo)->supportedTechs & (tech))
113 #define PREFERRED_NETWORK(mdminfo) ((mdminfo)->preferredNetworkMode)
114 // CDMA Subscription Source
115 #define SSOURCE(mdminfo) ((mdminfo)->subscription_source)
116
117 static int net2modem[] = {
118 MDM_GSM | MDM_WCDMA, // 0 - GSM / WCDMA Pref
119 MDM_GSM, // 1 - GSM only
120 MDM_WCDMA, // 2 - WCDMA only
121 MDM_GSM | MDM_WCDMA, // 3 - GSM / WCDMA Auto
122 MDM_CDMA | MDM_EVDO, // 4 - CDMA / EvDo Auto
123 MDM_CDMA, // 5 - CDMA only
124 MDM_EVDO, // 6 - EvDo only
125 MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO, // 7 - GSM/WCDMA, CDMA, EvDo
126 MDM_LTE | MDM_CDMA | MDM_EVDO, // 8 - LTE, CDMA and EvDo
127 MDM_LTE | MDM_GSM | MDM_WCDMA, // 9 - LTE, GSM/WCDMA
128 MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA, // 10 - LTE, CDMA, EvDo, GSM/WCDMA
129 MDM_LTE, // 11 - LTE only
130 };
131
132 static int32_t net2pmask[] = {
133 MDM_GSM | (MDM_WCDMA << 8), // 0 - GSM / WCDMA Pref
134 MDM_GSM, // 1 - GSM only
135 MDM_WCDMA, // 2 - WCDMA only
136 MDM_GSM | MDM_WCDMA, // 3 - GSM / WCDMA Auto
137 MDM_CDMA | MDM_EVDO, // 4 - CDMA / EvDo Auto
138 MDM_CDMA, // 5 - CDMA only
139 MDM_EVDO, // 6 - EvDo only
140 MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO, // 7 - GSM/WCDMA, CDMA, EvDo
141 MDM_LTE | MDM_CDMA | MDM_EVDO, // 8 - LTE, CDMA and EvDo
142 MDM_LTE | MDM_GSM | MDM_WCDMA, // 9 - LTE, GSM/WCDMA
143 MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA, // 10 - LTE, CDMA, EvDo, GSM/WCDMA
144 MDM_LTE, // 11 - LTE only
145 };
146
is3gpp2(int radioTech)147 static int is3gpp2(int radioTech) {
148 switch (radioTech) {
149 case RADIO_TECH_IS95A:
150 case RADIO_TECH_IS95B:
151 case RADIO_TECH_1xRTT:
152 case RADIO_TECH_EVDO_0:
153 case RADIO_TECH_EVDO_A:
154 case RADIO_TECH_EVDO_B:
155 case RADIO_TECH_EHRPD:
156 return 1;
157 default:
158 return 0;
159 }
160 }
161
162 typedef enum {
163 SIM_ABSENT = 0,
164 SIM_NOT_READY = 1,
165 SIM_READY = 2,
166 SIM_PIN = 3,
167 SIM_PUK = 4,
168 SIM_NETWORK_PERSONALIZATION = 5,
169 RUIM_ABSENT = 6,
170 RUIM_NOT_READY = 7,
171 RUIM_READY = 8,
172 RUIM_PIN = 9,
173 RUIM_PUK = 10,
174 RUIM_NETWORK_PERSONALIZATION = 11,
175 ISIM_ABSENT = 12,
176 ISIM_NOT_READY = 13,
177 ISIM_READY = 14,
178 ISIM_PIN = 15,
179 ISIM_PUK = 16,
180 ISIM_NETWORK_PERSONALIZATION = 17,
181 } SIM_Status;
182
183 static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
184 static RIL_RadioState currentState();
185 static int onSupports (int requestCode);
186 static void onCancel (RIL_Token t);
187 static const char *getVersion();
188 static int isRadioOn();
189 static SIM_Status getSIMStatus();
190 static int getCardStatus(RIL_CardStatus_v6 **pp_card_status);
191 static void freeCardStatus(RIL_CardStatus_v6 *p_card_status);
192 static void onDataCallListChanged(void *param);
193
194 extern const char * requestToString(int request);
195
196 /*** Static Variables ***/
197 static const RIL_RadioFunctions s_callbacks = {
198 RIL_VERSION,
199 onRequest,
200 currentState,
201 onSupports,
202 onCancel,
203 getVersion
204 };
205
206 #ifdef RIL_SHLIB
207 static const struct RIL_Env *s_rilenv;
208
209 #define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
210 #define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
211 #define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
212 #endif
213
214 static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
215
216 static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
217 static pthread_cond_t s_state_cond = PTHREAD_COND_INITIALIZER;
218
219 static int s_port = -1;
220 static const char * s_device_path = NULL;
221 static int s_device_socket = 0;
222
223 /* trigger change to this with s_state_cond */
224 static int s_closed = 0;
225
226 static int sFD; /* file desc of AT channel */
227 static char sATBuffer[MAX_AT_RESPONSE+1];
228 static char *sATBufferCur = NULL;
229
230 static const struct timeval TIMEVAL_SIMPOLL = {1,0};
231 static const struct timeval TIMEVAL_CALLSTATEPOLL = {0,500000};
232 static const struct timeval TIMEVAL_0 = {0,0};
233
234 static int s_ims_registered = 0; // 0==unregistered
235 static int s_ims_services = 1; // & 0x1 == sms over ims supported
236 static int s_ims_format = 1; // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
237 static int s_ims_cause_retry = 0; // 1==causes sms over ims to temp fail
238 static int s_ims_cause_perm_failure = 0; // 1==causes sms over ims to permanent fail
239 static int s_ims_gsm_retry = 0; // 1==causes sms over gsm to temp fail
240 static int s_ims_gsm_fail = 0; // 1==causes sms over gsm to permanent fail
241
242 #ifdef WORKAROUND_ERRONEOUS_ANSWER
243 // Max number of times we'll try to repoll when we think
244 // we have a AT+CLCC race condition
245 #define REPOLL_CALLS_COUNT_MAX 4
246
247 // Line index that was incoming or waiting at last poll, or -1 for none
248 static int s_incomingOrWaitingLine = -1;
249 // Number of times we've asked for a repoll of AT+CLCC
250 static int s_repollCallsCount = 0;
251 // Should we expect a call to be answered in the next CLCC?
252 static int s_expectAnswer = 0;
253 #endif /* WORKAROUND_ERRONEOUS_ANSWER */
254
255
256 static int s_cell_info_rate_ms = INT_MAX;
257 static int s_mcc = 0;
258 static int s_mnc = 0;
259 static int s_lac = 0;
260 static int s_cid = 0;
261
262 static void pollSIMState (void *param);
263 static void setRadioState(RIL_RadioState newState);
264 static void setRadioTechnology(ModemInfo *mdm, int newtech);
265 static int query_ctec(ModemInfo *mdm, int *current, int32_t *preferred);
266 static int parse_technology_response(const char *response, int *current, int32_t *preferred);
267 static int techFromModemType(int mdmtype);
268
clccStateToRILState(int state,RIL_CallState * p_state)269 static int clccStateToRILState(int state, RIL_CallState *p_state)
270
271 {
272 switch(state) {
273 case 0: *p_state = RIL_CALL_ACTIVE; return 0;
274 case 1: *p_state = RIL_CALL_HOLDING; return 0;
275 case 2: *p_state = RIL_CALL_DIALING; return 0;
276 case 3: *p_state = RIL_CALL_ALERTING; return 0;
277 case 4: *p_state = RIL_CALL_INCOMING; return 0;
278 case 5: *p_state = RIL_CALL_WAITING; return 0;
279 default: return -1;
280 }
281 }
282
283 /**
284 * Note: directly modified line and has *p_call point directly into
285 * modified line
286 */
callFromCLCCLine(char * line,RIL_Call * p_call)287 static int callFromCLCCLine(char *line, RIL_Call *p_call)
288 {
289 //+CLCC: 1,0,2,0,0,\"+18005551212\",145
290 // index,isMT,state,mode,isMpty(,number,TOA)?
291
292 int err;
293 int state;
294 int mode;
295
296 err = at_tok_start(&line);
297 if (err < 0) goto error;
298
299 err = at_tok_nextint(&line, &(p_call->index));
300 if (err < 0) goto error;
301
302 err = at_tok_nextbool(&line, &(p_call->isMT));
303 if (err < 0) goto error;
304
305 err = at_tok_nextint(&line, &state);
306 if (err < 0) goto error;
307
308 err = clccStateToRILState(state, &(p_call->state));
309 if (err < 0) goto error;
310
311 err = at_tok_nextint(&line, &mode);
312 if (err < 0) goto error;
313
314 p_call->isVoice = (mode == 0);
315
316 err = at_tok_nextbool(&line, &(p_call->isMpty));
317 if (err < 0) goto error;
318
319 if (at_tok_hasmore(&line)) {
320 err = at_tok_nextstr(&line, &(p_call->number));
321
322 /* tolerate null here */
323 if (err < 0) return 0;
324
325 // Some lame implementations return strings
326 // like "NOT AVAILABLE" in the CLCC line
327 if (p_call->number != NULL
328 && 0 == strspn(p_call->number, "+0123456789")
329 ) {
330 p_call->number = NULL;
331 }
332
333 err = at_tok_nextint(&line, &p_call->toa);
334 if (err < 0) goto error;
335 }
336
337 p_call->uusInfo = NULL;
338
339 return 0;
340
341 error:
342 RLOGE("invalid CLCC line\n");
343 return -1;
344 }
345
parseSimResponseLine(char * line,RIL_SIM_IO_Response * response)346 static int parseSimResponseLine(char* line, RIL_SIM_IO_Response* response) {
347 int err;
348
349 err = at_tok_start(&line);
350 if (err < 0) return err;
351 err = at_tok_nextint(&line, &response->sw1);
352 if (err < 0) return err;
353 err = at_tok_nextint(&line, &response->sw2);
354 if (err < 0) return err;
355
356 if (at_tok_hasmore(&line)) {
357 err = at_tok_nextstr(&line, &response->simResponse);
358 if (err < 0) return err;
359 }
360 return 0;
361 }
362
363 enum InterfaceState {
364 kInterfaceUp,
365 kInterfaceDown,
366 };
367
setInterfaceState(const char * interfaceName,enum InterfaceState state)368 static RIL_Errno setInterfaceState(const char* interfaceName,
369 enum InterfaceState state) {
370 struct ifreq request;
371 int status = 0;
372 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
373 if (sock == -1) {
374 RLOGE("Failed to open interface socket: %s (%d)",
375 strerror(errno), errno);
376 return RIL_E_GENERIC_FAILURE;
377 }
378
379 memset(&request, 0, sizeof(request));
380 strncpy(request.ifr_name, interfaceName, sizeof(request.ifr_name));
381 request.ifr_name[sizeof(request.ifr_name) - 1] = '\0';
382 status = ioctl(sock, SIOCGIFFLAGS, &request);
383 if (status != 0) {
384 RLOGE("Failed to get interface flags for %s: %s (%d)",
385 interfaceName, strerror(errno), errno);
386 close(sock);
387 return RIL_E_RADIO_NOT_AVAILABLE;
388 }
389
390 bool isUp = (request.ifr_flags & IFF_UP);
391 if ((state == kInterfaceUp && isUp) || (state == kInterfaceDown && !isUp)) {
392 // Interface already in desired state
393 close(sock);
394 return RIL_E_SUCCESS;
395 }
396
397 // Simply toggle the flag since we know it's the opposite of what we want
398 request.ifr_flags ^= IFF_UP;
399
400 status = ioctl(sock, SIOCSIFFLAGS, &request);
401 if (status != 0) {
402 RLOGE("Failed to set interface flags for %s: %s (%d)",
403 interfaceName, strerror(errno), errno);
404 close(sock);
405 return RIL_E_GENERIC_FAILURE;
406 }
407
408 close(sock);
409 return RIL_E_SUCCESS;
410 }
411
412 /** do post-AT+CFUN=1 initialization */
onRadioPowerOn()413 static void onRadioPowerOn()
414 {
415 #ifdef USE_TI_COMMANDS
416 /* Must be after CFUN=1 */
417 /* TI specific -- notifications for CPHS things such */
418 /* as CPHS message waiting indicator */
419
420 at_send_command("AT%CPHS=1", NULL);
421
422 /* TI specific -- enable NITZ unsol notifs */
423 at_send_command("AT%CTZV=1", NULL);
424 #endif
425
426 pollSIMState(NULL);
427 }
428
429 /** do post- SIM ready initialization */
onSIMReady()430 static void onSIMReady()
431 {
432 at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
433 /*
434 * Always send SMS messages directly to the TE
435 *
436 * mode = 1 // discard when link is reserved (link should never be
437 * reserved)
438 * mt = 2 // most messages routed to TE
439 * bm = 2 // new cell BM's routed to TE
440 * ds = 1 // Status reports routed to TE
441 * bfr = 1 // flush buffer
442 */
443 at_send_command("AT+CNMI=1,2,2,1,1", NULL);
444 }
445
requestRadioPower(void * data,size_t datalen __unused,RIL_Token t)446 static void requestRadioPower(void *data, size_t datalen __unused, RIL_Token t)
447 {
448 int onOff;
449
450 int err;
451 ATResponse *p_response = NULL;
452
453 assert (datalen >= sizeof(int *));
454 onOff = ((int *)data)[0];
455
456 if (onOff == 0 && sState != RADIO_STATE_OFF) {
457 err = at_send_command("AT+CFUN=0", &p_response);
458 if (err < 0 || p_response->success == 0) goto error;
459 setRadioState(RADIO_STATE_OFF);
460 } else if (onOff > 0 && sState == RADIO_STATE_OFF) {
461 err = at_send_command("AT+CFUN=1", &p_response);
462 if (err < 0|| p_response->success == 0) {
463 // Some stacks return an error when there is no SIM,
464 // but they really turn the RF portion on
465 // So, if we get an error, let's check to see if it
466 // turned on anyway
467
468 if (isRadioOn() != 1) {
469 goto error;
470 }
471 }
472 setRadioState(RADIO_STATE_ON);
473 }
474
475 at_response_free(p_response);
476 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
477 return;
478 error:
479 at_response_free(p_response);
480 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
481 }
482
requestShutdown(RIL_Token t)483 static void requestShutdown(RIL_Token t)
484 {
485 int onOff;
486
487 int err;
488 ATResponse *p_response = NULL;
489
490 if (sState != RADIO_STATE_OFF) {
491 err = at_send_command("AT+CFUN=0", &p_response);
492 setRadioState(RADIO_STATE_UNAVAILABLE);
493 }
494
495 at_response_free(p_response);
496 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
497 return;
498 }
499
500 static void requestOrSendDataCallList(RIL_Token *t);
501
onDataCallListChanged(void * param __unused)502 static void onDataCallListChanged(void *param __unused)
503 {
504 requestOrSendDataCallList(NULL);
505 }
506
requestDataCallList(void * data __unused,size_t datalen __unused,RIL_Token t)507 static void requestDataCallList(void *data __unused, size_t datalen __unused, RIL_Token t)
508 {
509 requestOrSendDataCallList(&t);
510 }
511
512 // Hang up, reject, conference, call waiting
requestCallSelection(void * data __unused,size_t datalen __unused,RIL_Token t,int request)513 static void requestCallSelection(
514 void *data __unused, size_t datalen __unused, RIL_Token t, int request)
515 {
516 // 3GPP 22.030 6.5.5
517 static char hangupWaiting[] = "AT+CHLD=0";
518 static char hangupForeground[] = "AT+CHLD=1";
519 static char switchWaiting[] = "AT+CHLD=2";
520 static char conference[] = "AT+CHLD=3";
521 static char reject[] = "ATH";
522
523 char* atCommand;
524
525 if (getSIMStatus() == SIM_ABSENT) {
526 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
527 return;
528 }
529
530 switch(request) {
531 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
532 // "Releases all held calls or sets User Determined User Busy
533 // (UDUB) for a waiting call."
534 atCommand = hangupWaiting;
535 break;
536 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
537 // "Releases all active calls (if any exist) and accepts
538 // the other (held or waiting) call."
539 atCommand = hangupForeground;
540 break;
541 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
542 // "Places all active calls (if any exist) on hold and accepts
543 // the other (held or waiting) call."
544 atCommand = switchWaiting;
545 #ifdef WORKAROUND_ERRONEOUS_ANSWER
546 s_expectAnswer = 1;
547 #endif /* WORKAROUND_ERRONEOUS_ANSWER */
548 break;
549 case RIL_REQUEST_CONFERENCE:
550 // "Adds a held call to the conversation"
551 atCommand = conference;
552 break;
553 case RIL_REQUEST_UDUB:
554 // User determined user busy (reject)
555 atCommand = reject;
556 break;
557 default:
558 assert(0);
559 }
560 at_send_command(atCommand, NULL);
561 // Success or failure is ignored by the upper layer here.
562 // It will call GET_CURRENT_CALLS and determine success that way.
563 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
564 }
565
hasWifiCapability()566 static bool hasWifiCapability()
567 {
568 char propValue[PROP_VALUE_MAX];
569 return property_get("ro.boot.qemu.wifi", propValue, "") > 0 &&
570 strcmp("1", propValue) == 0;
571 }
572
getRadioInterfaceName(bool hasWifi)573 static const char* getRadioInterfaceName(bool hasWifi)
574 {
575 return hasWifi ? PPP_TTY_PATH_RADIO0 : PPP_TTY_PATH_ETH0;
576 }
577
requestOrSendDataCallList(RIL_Token * t)578 static void requestOrSendDataCallList(RIL_Token *t)
579 {
580 ATResponse *p_response;
581 ATLine *p_cur;
582 int err;
583 int n = 0;
584 char *out;
585 char propValue[PROP_VALUE_MAX];
586 bool hasWifi = hasWifiCapability();
587 const char* radioInterfaceName = getRadioInterfaceName(hasWifi);
588
589 err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &p_response);
590 if (err != 0 || p_response->success == 0) {
591 if (t != NULL)
592 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
593 else
594 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
595 NULL, 0);
596 return;
597 }
598
599 for (p_cur = p_response->p_intermediates; p_cur != NULL;
600 p_cur = p_cur->p_next)
601 n++;
602
603 RIL_Data_Call_Response_v11 *responses =
604 alloca(n * sizeof(RIL_Data_Call_Response_v11));
605
606 int i;
607 for (i = 0; i < n; i++) {
608 responses[i].status = -1;
609 responses[i].suggestedRetryTime = -1;
610 responses[i].cid = -1;
611 responses[i].active = -1;
612 responses[i].type = "";
613 responses[i].ifname = "";
614 responses[i].addresses = "";
615 responses[i].dnses = "";
616 responses[i].gateways = "";
617 responses[i].pcscf = "";
618 responses[i].mtu = 0;
619 }
620
621 RIL_Data_Call_Response_v11 *response = responses;
622 for (p_cur = p_response->p_intermediates; p_cur != NULL;
623 p_cur = p_cur->p_next) {
624 char *line = p_cur->line;
625
626 err = at_tok_start(&line);
627 if (err < 0)
628 goto error;
629
630 err = at_tok_nextint(&line, &response->cid);
631 if (err < 0)
632 goto error;
633
634 err = at_tok_nextint(&line, &response->active);
635 if (err < 0)
636 goto error;
637
638 response++;
639 }
640
641 at_response_free(p_response);
642
643 err = at_send_command_multiline ("AT+CGDCONT?", "+CGDCONT:", &p_response);
644 if (err != 0 || p_response->success == 0) {
645 if (t != NULL)
646 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
647 else
648 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
649 NULL, 0);
650 return;
651 }
652
653 for (p_cur = p_response->p_intermediates; p_cur != NULL;
654 p_cur = p_cur->p_next) {
655 char *line = p_cur->line;
656 int cid;
657
658 err = at_tok_start(&line);
659 if (err < 0)
660 goto error;
661
662 err = at_tok_nextint(&line, &cid);
663 if (err < 0)
664 goto error;
665
666 for (i = 0; i < n; i++) {
667 if (responses[i].cid == cid)
668 break;
669 }
670
671 if (i >= n) {
672 /* details for a context we didn't hear about in the last request */
673 continue;
674 }
675
676 // Assume no error
677 responses[i].status = 0;
678
679 // type
680 err = at_tok_nextstr(&line, &out);
681 if (err < 0)
682 goto error;
683
684 int type_size = strlen(out) + 1;
685 responses[i].type = alloca(type_size);
686 strlcpy(responses[i].type, out, type_size);
687
688 // APN ignored for v5
689 err = at_tok_nextstr(&line, &out);
690 if (err < 0)
691 goto error;
692
693 int ifname_size = strlen(radioInterfaceName) + 1;
694 responses[i].ifname = alloca(ifname_size);
695 strlcpy(responses[i].ifname, radioInterfaceName, ifname_size);
696
697 err = at_tok_nextstr(&line, &out);
698 if (err < 0)
699 goto error;
700
701 int addresses_size = strlen(out) + 1;
702 responses[i].addresses = alloca(addresses_size);
703 strlcpy(responses[i].addresses, out, addresses_size);
704
705 /* I don't know where we are, so use the public Google DNS
706 * servers by default and no gateway.
707 */
708 responses[i].dnses = "8.8.8.8 8.8.4.4";
709 responses[i].gateways = "";
710 }
711
712 at_response_free(p_response);
713
714 if (t != NULL)
715 RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
716 n * sizeof(RIL_Data_Call_Response_v11));
717 else
718 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
719 responses,
720 n * sizeof(RIL_Data_Call_Response_v11));
721
722 return;
723
724 error:
725 if (t != NULL)
726 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
727 else
728 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
729 NULL, 0);
730
731 at_response_free(p_response);
732 }
733
requestQueryNetworkSelectionMode(void * data __unused,size_t datalen __unused,RIL_Token t)734 static void requestQueryNetworkSelectionMode(
735 void *data __unused, size_t datalen __unused, RIL_Token t)
736 {
737 int err;
738 ATResponse *p_response = NULL;
739 int response = 0;
740 char *line;
741
742 err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response);
743
744 if (err < 0 || p_response->success == 0) {
745 goto error;
746 }
747
748 line = p_response->p_intermediates->line;
749
750 err = at_tok_start(&line);
751
752 if (err < 0) {
753 goto error;
754 }
755
756 err = at_tok_nextint(&line, &response);
757
758 if (err < 0) {
759 goto error;
760 }
761
762 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
763 at_response_free(p_response);
764 return;
765 error:
766 at_response_free(p_response);
767 RLOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
768 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
769 }
770
sendCallStateChanged(void * param __unused)771 static void sendCallStateChanged(void *param __unused)
772 {
773 RIL_onUnsolicitedResponse (
774 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
775 NULL, 0);
776 }
777
requestGetCurrentCalls(void * data __unused,size_t datalen __unused,RIL_Token t)778 static void requestGetCurrentCalls(void *data __unused, size_t datalen __unused, RIL_Token t)
779 {
780 int err;
781 ATResponse *p_response;
782 ATLine *p_cur;
783 int countCalls;
784 int countValidCalls;
785 RIL_Call *p_calls;
786 RIL_Call **pp_calls;
787 int i;
788 int needRepoll = 0;
789
790 #ifdef WORKAROUND_ERRONEOUS_ANSWER
791 int prevIncomingOrWaitingLine;
792
793 prevIncomingOrWaitingLine = s_incomingOrWaitingLine;
794 s_incomingOrWaitingLine = -1;
795 #endif /*WORKAROUND_ERRONEOUS_ANSWER*/
796
797 err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
798
799 if (err != 0 || p_response->success == 0) {
800 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
801 return;
802 }
803
804 /* count the calls */
805 for (countCalls = 0, p_cur = p_response->p_intermediates
806 ; p_cur != NULL
807 ; p_cur = p_cur->p_next
808 ) {
809 countCalls++;
810 }
811
812 /* yes, there's an array of pointers and then an array of structures */
813
814 pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
815 p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
816 memset (p_calls, 0, countCalls * sizeof(RIL_Call));
817
818 /* init the pointer array */
819 for(i = 0; i < countCalls ; i++) {
820 pp_calls[i] = &(p_calls[i]);
821 }
822
823 for (countValidCalls = 0, p_cur = p_response->p_intermediates
824 ; p_cur != NULL
825 ; p_cur = p_cur->p_next
826 ) {
827 err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
828
829 if (err != 0) {
830 continue;
831 }
832
833 #ifdef WORKAROUND_ERRONEOUS_ANSWER
834 if (p_calls[countValidCalls].state == RIL_CALL_INCOMING
835 || p_calls[countValidCalls].state == RIL_CALL_WAITING
836 ) {
837 s_incomingOrWaitingLine = p_calls[countValidCalls].index;
838 }
839 #endif /*WORKAROUND_ERRONEOUS_ANSWER*/
840
841 if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
842 && p_calls[countValidCalls].state != RIL_CALL_HOLDING
843 ) {
844 needRepoll = 1;
845 }
846
847 countValidCalls++;
848 }
849
850 #ifdef WORKAROUND_ERRONEOUS_ANSWER
851 // Basically:
852 // A call was incoming or waiting
853 // Now it's marked as active
854 // But we never answered it
855 //
856 // This is probably a bug, and the call will probably
857 // disappear from the call list in the next poll
858 if (prevIncomingOrWaitingLine >= 0
859 && s_incomingOrWaitingLine < 0
860 && s_expectAnswer == 0
861 ) {
862 for (i = 0; i < countValidCalls ; i++) {
863
864 if (p_calls[i].index == prevIncomingOrWaitingLine
865 && p_calls[i].state == RIL_CALL_ACTIVE
866 && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX
867 ) {
868 RLOGI(
869 "Hit WORKAROUND_ERRONOUS_ANSWER case."
870 " Repoll count: %d\n", s_repollCallsCount);
871 s_repollCallsCount++;
872 goto error;
873 }
874 }
875 }
876
877 s_expectAnswer = 0;
878 s_repollCallsCount = 0;
879 #endif /*WORKAROUND_ERRONEOUS_ANSWER*/
880
881 RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
882 countValidCalls * sizeof (RIL_Call *));
883
884 at_response_free(p_response);
885
886 #ifdef POLL_CALL_STATE
887 if (countValidCalls) { // We don't seem to get a "NO CARRIER" message from
888 // smd, so we're forced to poll until the call ends.
889 #else
890 if (needRepoll) {
891 #endif
892 RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
893 }
894
895 return;
896 #ifdef WORKAROUND_ERRONEOUS_ANSWER
897 error:
898 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
899 at_response_free(p_response);
900 #endif
901 }
902
903 static void requestDial(void *data, size_t datalen __unused, RIL_Token t)
904 {
905 RIL_Dial *p_dial;
906 char *cmd;
907 const char *clir;
908 int ret;
909
910 p_dial = (RIL_Dial *)data;
911
912 switch (p_dial->clir) {
913 case 1: clir = "I"; break; /*invocation*/
914 case 2: clir = "i"; break; /*suppression*/
915 default:
916 case 0: clir = ""; break; /*subscription default*/
917 }
918
919 asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
920
921 ret = at_send_command(cmd, NULL);
922
923 free(cmd);
924
925 /* success or failure is ignored by the upper layer here.
926 it will call GET_CURRENT_CALLS and determine success that way */
927 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
928 }
929
930 static void requestWriteSmsToSim(void *data, size_t datalen __unused, RIL_Token t)
931 {
932 RIL_SMS_WriteArgs *p_args;
933 char *cmd;
934 int length;
935 int err;
936 ATResponse *p_response = NULL;
937
938 if (getSIMStatus() == SIM_ABSENT) {
939 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
940 return;
941 }
942
943 p_args = (RIL_SMS_WriteArgs *)data;
944
945 length = strlen(p_args->pdu)/2;
946 asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
947
948 err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response);
949
950 if (err != 0 || p_response->success == 0) goto error;
951
952 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
953 at_response_free(p_response);
954
955 return;
956 error:
957 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
958 at_response_free(p_response);
959 }
960
961 static void requestHangup(void *data, size_t datalen __unused, RIL_Token t)
962 {
963 int *p_line;
964
965 int ret;
966 char *cmd;
967
968 if (getSIMStatus() == SIM_ABSENT) {
969 RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
970 return;
971 }
972 p_line = (int *)data;
973
974 // 3GPP 22.030 6.5.5
975 // "Releases a specific active call X"
976 asprintf(&cmd, "AT+CHLD=1%d", p_line[0]);
977
978 ret = at_send_command(cmd, NULL);
979
980 free(cmd);
981
982 /* success or failure is ignored by the upper layer here.
983 it will call GET_CURRENT_CALLS and determine success that way */
984 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
985 }
986
987 static void requestSignalStrength(void *data __unused, size_t datalen __unused, RIL_Token t)
988 {
989 ATResponse *p_response = NULL;
990 int err;
991 char *line;
992 int count = 0;
993 // Accept a response that is at least v6, and up to v10
994 int minNumOfElements=sizeof(RIL_SignalStrength_v6)/sizeof(int);
995 int maxNumOfElements=sizeof(RIL_SignalStrength_v10)/sizeof(int);
996 int response[maxNumOfElements];
997
998 memset(response, 0, sizeof(response));
999
1000 err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response);
1001
1002 if (err < 0 || p_response->success == 0) {
1003 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1004 goto error;
1005 }
1006
1007 line = p_response->p_intermediates->line;
1008
1009 err = at_tok_start(&line);
1010 if (err < 0) goto error;
1011
1012 for (count = 0; count < maxNumOfElements; count++) {
1013 err = at_tok_nextint(&line, &(response[count]));
1014 if (err < 0 && count < minNumOfElements) goto error;
1015 }
1016
1017 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
1018
1019 at_response_free(p_response);
1020 return;
1021
1022 error:
1023 RLOGE("requestSignalStrength must never return an error when radio is on");
1024 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1025 at_response_free(p_response);
1026 }
1027
1028 /**
1029 * networkModePossible. Decides whether the network mode is appropriate for the
1030 * specified modem
1031 */
1032 static int networkModePossible(ModemInfo *mdm, int nm)
1033 {
1034 if ((net2modem[nm] & mdm->supportedTechs) == net2modem[nm]) {
1035 return 1;
1036 }
1037 return 0;
1038 }
1039 static void requestSetPreferredNetworkType( int request __unused, void *data,
1040 size_t datalen __unused, RIL_Token t )
1041 {
1042 ATResponse *p_response = NULL;
1043 char *cmd = NULL;
1044 int value = *(int *)data;
1045 int current, old;
1046 int err;
1047 int32_t preferred = net2pmask[value];
1048
1049 RLOGD("requestSetPreferredNetworkType: current: %x. New: %x", PREFERRED_NETWORK(sMdmInfo), preferred);
1050 if (!networkModePossible(sMdmInfo, value)) {
1051 RIL_onRequestComplete(t, RIL_E_MODE_NOT_SUPPORTED, NULL, 0);
1052 return;
1053 }
1054 if (query_ctec(sMdmInfo, ¤t, NULL) < 0) {
1055 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1056 return;
1057 }
1058 old = PREFERRED_NETWORK(sMdmInfo);
1059 RLOGD("old != preferred: %d", old != preferred);
1060 if (old != preferred) {
1061 asprintf(&cmd, "AT+CTEC=%d,\"%x\"", current, preferred);
1062 RLOGD("Sending command: <%s>", cmd);
1063 err = at_send_command_singleline(cmd, "+CTEC:", &p_response);
1064 free(cmd);
1065 if (err || !p_response->success) {
1066 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1067 return;
1068 }
1069 PREFERRED_NETWORK(sMdmInfo) = value;
1070 if (!strstr( p_response->p_intermediates->line, "DONE") ) {
1071 int current;
1072 int res = parse_technology_response(p_response->p_intermediates->line, ¤t, NULL);
1073 switch (res) {
1074 case -1: // Error or unable to parse
1075 break;
1076 case 1: // Only able to parse current
1077 case 0: // Both current and preferred were parsed
1078 setRadioTechnology(sMdmInfo, current);
1079 break;
1080 }
1081 }
1082 }
1083 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1084 }
1085
1086 static void requestGetPreferredNetworkType(int request __unused, void *data __unused,
1087 size_t datalen __unused, RIL_Token t)
1088 {
1089 int preferred;
1090 unsigned i;
1091
1092 switch ( query_ctec(sMdmInfo, NULL, &preferred) ) {
1093 case -1: // Error or unable to parse
1094 case 1: // Only able to parse current
1095 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1096 break;
1097 case 0: // Both current and preferred were parsed
1098 for ( i = 0 ; i < sizeof(net2pmask) / sizeof(int32_t) ; i++ ) {
1099 if (preferred == net2pmask[i]) {
1100 RIL_onRequestComplete(t, RIL_E_SUCCESS, &i, sizeof(int));
1101 return;
1102 }
1103 }
1104 RLOGE("Unknown preferred mode received from modem: %d", preferred);
1105 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1106 break;
1107 }
1108
1109 }
1110
1111 static void requestCdmaPrlVersion(int request __unused, void *data __unused,
1112 size_t datalen __unused, RIL_Token t)
1113 {
1114 int err;
1115 char * responseStr;
1116 ATResponse *p_response = NULL;
1117 const char *cmd;
1118 char *line;
1119
1120 err = at_send_command_singleline("AT+WPRL?", "+WPRL:", &p_response);
1121 if (err < 0 || !p_response->success) goto error;
1122 line = p_response->p_intermediates->line;
1123 err = at_tok_start(&line);
1124 if (err < 0) goto error;
1125 err = at_tok_nextstr(&line, &responseStr);
1126 if (err < 0 || !responseStr) goto error;
1127 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, strlen(responseStr));
1128 at_response_free(p_response);
1129 return;
1130 error:
1131 at_response_free(p_response);
1132 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1133 }
1134
1135 static void requestCdmaBaseBandVersion(int request __unused, void *data __unused,
1136 size_t datalen __unused, RIL_Token t)
1137 {
1138 int err;
1139 char * responseStr;
1140 ATResponse *p_response = NULL;
1141 const char *cmd;
1142 const char *prefix;
1143 char *line, *p;
1144 int commas;
1145 int skip;
1146 int count = 4;
1147
1148 // Fixed values. TODO: query modem
1149 responseStr = strdup("1.0.0.0");
1150 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, sizeof(responseStr));
1151 free(responseStr);
1152 }
1153
1154 static void requestDeviceIdentity(int request __unused, void *data __unused,
1155 size_t datalen __unused, RIL_Token t)
1156 {
1157 int err;
1158 int response[4];
1159 char * responseStr[4];
1160 ATResponse *p_response = NULL;
1161 const char *cmd;
1162 const char *prefix;
1163 char *line, *p;
1164 int commas;
1165 int skip;
1166 int count = 4;
1167
1168 // Fixed values. TODO: Query modem
1169 responseStr[0] = "----";
1170 responseStr[1] = "----";
1171 responseStr[2] = "77777777";
1172 responseStr[3] = ""; // default empty for non-CDMA
1173
1174 err = at_send_command_numeric("AT+CGSN", &p_response);
1175 if (err < 0 || p_response->success == 0) {
1176 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1177 return;
1178 } else {
1179 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
1180 responseStr[3] = p_response->p_intermediates->line;
1181 } else {
1182 responseStr[0] = p_response->p_intermediates->line;
1183 }
1184 }
1185
1186 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
1187 at_response_free(p_response);
1188 }
1189
1190 static void requestCdmaGetSubscriptionSource(int request __unused, void *data,
1191 size_t datalen __unused, RIL_Token t)
1192 {
1193 int err;
1194 int *ss = (int *)data;
1195 ATResponse *p_response = NULL;
1196 char *cmd = NULL;
1197 char *line = NULL;
1198 int response;
1199
1200 asprintf(&cmd, "AT+CCSS?");
1201 if (!cmd) goto error;
1202
1203 err = at_send_command_singleline(cmd, "+CCSS:", &p_response);
1204 if (err < 0 || !p_response->success)
1205 goto error;
1206
1207 line = p_response->p_intermediates->line;
1208 err = at_tok_start(&line);
1209 if (err < 0) goto error;
1210
1211 err = at_tok_nextint(&line, &response);
1212 free(cmd);
1213 cmd = NULL;
1214
1215 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1216
1217 return;
1218 error:
1219 free(cmd);
1220 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1221 }
1222
1223 static void requestCdmaSetSubscriptionSource(int request __unused, void *data,
1224 size_t datalen, RIL_Token t)
1225 {
1226 int err;
1227 int *ss = (int *)data;
1228 ATResponse *p_response = NULL;
1229 char *cmd = NULL;
1230
1231 if (!ss || !datalen) {
1232 RLOGE("RIL_REQUEST_CDMA_SET_SUBSCRIPTION without data!");
1233 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1234 return;
1235 }
1236 asprintf(&cmd, "AT+CCSS=%d", ss[0]);
1237 if (!cmd) goto error;
1238
1239 err = at_send_command(cmd, &p_response);
1240 if (err < 0 || !p_response->success)
1241 goto error;
1242 free(cmd);
1243 cmd = NULL;
1244
1245 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1246
1247 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, ss, sizeof(ss[0]));
1248
1249 return;
1250 error:
1251 free(cmd);
1252 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1253 }
1254
1255 static void requestCdmaSubscription(int request __unused, void *data __unused,
1256 size_t datalen __unused, RIL_Token t)
1257 {
1258 int err;
1259 int response[5];
1260 char * responseStr[5];
1261 ATResponse *p_response = NULL;
1262 const char *cmd;
1263 const char *prefix;
1264 char *line, *p;
1265 int commas;
1266 int skip;
1267 int count = 5;
1268
1269 // Fixed values. TODO: Query modem
1270 responseStr[0] = "8587777777"; // MDN
1271 responseStr[1] = "1"; // SID
1272 responseStr[2] = "1"; // NID
1273 responseStr[3] = "8587777777"; // MIN
1274 responseStr[4] = "1"; // PRL Version
1275 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
1276 }
1277
1278 static void requestCdmaGetRoamingPreference(int request __unused, void *data __unused,
1279 size_t datalen __unused, RIL_Token t)
1280 {
1281 int roaming_pref = -1;
1282 ATResponse *p_response = NULL;
1283 char *line;
1284 int res;
1285
1286 res = at_send_command_singleline("AT+WRMP?", "+WRMP:", &p_response);
1287 if (res < 0 || !p_response->success) {
1288 goto error;
1289 }
1290 line = p_response->p_intermediates->line;
1291
1292 res = at_tok_start(&line);
1293 if (res < 0) goto error;
1294
1295 res = at_tok_nextint(&line, &roaming_pref);
1296 if (res < 0) goto error;
1297
1298 RIL_onRequestComplete(t, RIL_E_SUCCESS, &roaming_pref, sizeof(roaming_pref));
1299 return;
1300 error:
1301 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1302 }
1303
1304 static void requestCdmaSetRoamingPreference(int request __unused, void *data,
1305 size_t datalen __unused, RIL_Token t)
1306 {
1307 int *pref = (int *)data;
1308 ATResponse *p_response = NULL;
1309 char *line;
1310 int res;
1311 char *cmd = NULL;
1312
1313 asprintf(&cmd, "AT+WRMP=%d", *pref);
1314 if (cmd == NULL) goto error;
1315
1316 res = at_send_command(cmd, &p_response);
1317 if (res < 0 || !p_response->success)
1318 goto error;
1319
1320 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1321 free(cmd);
1322 return;
1323 error:
1324 free(cmd);
1325 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1326 }
1327
1328 static int parseRegistrationState(char *str, int *type, int *items, int **response)
1329 {
1330 int err;
1331 char *line = str, *p;
1332 int *resp = NULL;
1333 int skip;
1334 int count = 3;
1335 int commas;
1336
1337 RLOGD("parseRegistrationState. Parsing: %s",str);
1338 err = at_tok_start(&line);
1339 if (err < 0) goto error;
1340
1341 /* Ok you have to be careful here
1342 * The solicited version of the CREG response is
1343 * +CREG: n, stat, [lac, cid]
1344 * and the unsolicited version is
1345 * +CREG: stat, [lac, cid]
1346 * The <n> parameter is basically "is unsolicited creg on?"
1347 * which it should always be
1348 *
1349 * Now we should normally get the solicited version here,
1350 * but the unsolicited version could have snuck in
1351 * so we have to handle both
1352 *
1353 * Also since the LAC and CID are only reported when registered,
1354 * we can have 1, 2, 3, or 4 arguments here
1355 *
1356 * finally, a +CGREG: answer may have a fifth value that corresponds
1357 * to the network type, as in;
1358 *
1359 * +CGREG: n, stat [,lac, cid [,networkType]]
1360 */
1361
1362 /* count number of commas */
1363 commas = 0;
1364 for (p = line ; *p != '\0' ;p++) {
1365 if (*p == ',') commas++;
1366 }
1367
1368 resp = (int *)calloc(commas + 1, sizeof(int));
1369 if (!resp) goto error;
1370 switch (commas) {
1371 case 0: /* +CREG: <stat> */
1372 err = at_tok_nextint(&line, &resp[0]);
1373 if (err < 0) goto error;
1374 resp[1] = -1;
1375 resp[2] = -1;
1376 break;
1377
1378 case 1: /* +CREG: <n>, <stat> */
1379 err = at_tok_nextint(&line, &skip);
1380 if (err < 0) goto error;
1381 err = at_tok_nextint(&line, &resp[0]);
1382 if (err < 0) goto error;
1383 resp[1] = -1;
1384 resp[2] = -1;
1385 if (err < 0) goto error;
1386 break;
1387
1388 case 2: /* +CREG: <stat>, <lac>, <cid> */
1389 err = at_tok_nextint(&line, &resp[0]);
1390 if (err < 0) goto error;
1391 err = at_tok_nexthexint(&line, &resp[1]);
1392 if (err < 0) goto error;
1393 err = at_tok_nexthexint(&line, &resp[2]);
1394 if (err < 0) goto error;
1395 break;
1396 case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
1397 err = at_tok_nextint(&line, &skip);
1398 if (err < 0) goto error;
1399 err = at_tok_nextint(&line, &resp[0]);
1400 if (err < 0) goto error;
1401 err = at_tok_nexthexint(&line, &resp[1]);
1402 if (err < 0) goto error;
1403 err = at_tok_nexthexint(&line, &resp[2]);
1404 if (err < 0) goto error;
1405 break;
1406 /* special case for CGREG, there is a fourth parameter
1407 * that is the network type (unknown/gprs/edge/umts)
1408 */
1409 case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
1410 err = at_tok_nextint(&line, &skip);
1411 if (err < 0) goto error;
1412 err = at_tok_nextint(&line, &resp[0]);
1413 if (err < 0) goto error;
1414 err = at_tok_nexthexint(&line, &resp[1]);
1415 if (err < 0) goto error;
1416 err = at_tok_nexthexint(&line, &resp[2]);
1417 if (err < 0) goto error;
1418 err = at_tok_nexthexint(&line, &resp[3]);
1419 if (err < 0) goto error;
1420 count = 4;
1421 break;
1422 default:
1423 goto error;
1424 }
1425 s_lac = resp[1];
1426 s_cid = resp[2];
1427 if (response)
1428 *response = resp;
1429 if (items)
1430 *items = commas + 1;
1431 if (type)
1432 *type = techFromModemType(TECH(sMdmInfo));
1433 return 0;
1434 error:
1435 free(resp);
1436 return -1;
1437 }
1438
1439 #define REG_STATE_LEN 15
1440 #define REG_DATA_STATE_LEN 6
1441 static void requestRegistrationState(int request, void *data __unused,
1442 size_t datalen __unused, RIL_Token t)
1443 {
1444 int err;
1445 int *registration;
1446 char **responseStr = NULL;
1447 ATResponse *p_response = NULL;
1448 const char *cmd;
1449 const char *prefix;
1450 char *line;
1451 int i = 0, j, numElements = 0;
1452 int count = 3;
1453 int type, startfrom;
1454
1455 RLOGD("requestRegistrationState");
1456 if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
1457 cmd = "AT+CREG?";
1458 prefix = "+CREG:";
1459 numElements = REG_STATE_LEN;
1460 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1461 cmd = "AT+CGREG?";
1462 prefix = "+CGREG:";
1463 numElements = REG_DATA_STATE_LEN;
1464 } else {
1465 assert(0);
1466 goto error;
1467 }
1468
1469 err = at_send_command_singleline(cmd, prefix, &p_response);
1470
1471 if (err != 0) goto error;
1472
1473 line = p_response->p_intermediates->line;
1474
1475 if (parseRegistrationState(line, &type, &count, ®istration)) goto error;
1476
1477 responseStr = malloc(numElements * sizeof(char *));
1478 if (!responseStr) goto error;
1479 memset(responseStr, 0, numElements * sizeof(char *));
1480 /**
1481 * The first '4' bytes for both registration states remain the same.
1482 * But if the request is 'DATA_REGISTRATION_STATE',
1483 * the 5th and 6th byte(s) are optional.
1484 */
1485 if (is3gpp2(type) == 1) {
1486 RLOGD("registration state type: 3GPP2");
1487 // TODO: Query modem
1488 startfrom = 3;
1489 if(request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
1490 asprintf(&responseStr[3], "8"); // EvDo revA
1491 asprintf(&responseStr[4], "1"); // BSID
1492 asprintf(&responseStr[5], "123"); // Latitude
1493 asprintf(&responseStr[6], "222"); // Longitude
1494 asprintf(&responseStr[7], "0"); // CSS Indicator
1495 asprintf(&responseStr[8], "4"); // SID
1496 asprintf(&responseStr[9], "65535"); // NID
1497 asprintf(&responseStr[10], "0"); // Roaming indicator
1498 asprintf(&responseStr[11], "1"); // System is in PRL
1499 asprintf(&responseStr[12], "0"); // Default Roaming indicator
1500 asprintf(&responseStr[13], "0"); // Reason for denial
1501 asprintf(&responseStr[14], "0"); // Primary Scrambling Code of Current cell
1502 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1503 asprintf(&responseStr[3], "8"); // Available data radio technology
1504 }
1505 } else { // type == RADIO_TECH_3GPP
1506 RLOGD("registration state type: 3GPP");
1507 startfrom = 0;
1508 asprintf(&responseStr[1], "%x", registration[1]);
1509 asprintf(&responseStr[2], "%x", registration[2]);
1510 if (count > 3)
1511 asprintf(&responseStr[3], "%d", registration[3]);
1512 }
1513 asprintf(&responseStr[0], "%d", registration[0]);
1514
1515 /**
1516 * Optional bytes for DATA_REGISTRATION_STATE request
1517 * 4th byte : Registration denial code
1518 * 5th byte : The max. number of simultaneous Data Calls
1519 */
1520 if(request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1521 // asprintf(&responseStr[4], "3");
1522 // asprintf(&responseStr[5], "1");
1523 }
1524
1525 for (j = startfrom; j < numElements; j++) {
1526 if (!responseStr[i]) goto error;
1527 }
1528 free(registration);
1529 registration = NULL;
1530
1531 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, numElements*sizeof(responseStr));
1532 for (j = 0; j < numElements; j++ ) {
1533 free(responseStr[j]);
1534 responseStr[j] = NULL;
1535 }
1536 free(responseStr);
1537 responseStr = NULL;
1538 at_response_free(p_response);
1539
1540 return;
1541 error:
1542 if (responseStr) {
1543 for (j = 0; j < numElements; j++) {
1544 free(responseStr[j]);
1545 responseStr[j] = NULL;
1546 }
1547 free(responseStr);
1548 responseStr = NULL;
1549 }
1550 RLOGE("requestRegistrationState must never return an error when radio is on");
1551 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1552 at_response_free(p_response);
1553 }
1554
1555 static void requestOperator(void *data __unused, size_t datalen __unused, RIL_Token t)
1556 {
1557 int err;
1558 int i;
1559 int skip;
1560 ATLine *p_cur;
1561 char *response[3];
1562
1563 memset(response, 0, sizeof(response));
1564
1565 ATResponse *p_response = NULL;
1566
1567 err = at_send_command_multiline(
1568 "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
1569 "+COPS:", &p_response);
1570
1571 /* we expect 3 lines here:
1572 * +COPS: 0,0,"T - Mobile"
1573 * +COPS: 0,1,"TMO"
1574 * +COPS: 0,2,"310170"
1575 */
1576
1577 if (err != 0) goto error;
1578
1579 for (i = 0, p_cur = p_response->p_intermediates
1580 ; p_cur != NULL
1581 ; p_cur = p_cur->p_next, i++
1582 ) {
1583 char *line = p_cur->line;
1584
1585 err = at_tok_start(&line);
1586 if (err < 0) goto error;
1587
1588 err = at_tok_nextint(&line, &skip);
1589 if (err < 0) goto error;
1590
1591 // If we're unregistered, we may just get
1592 // a "+COPS: 0" response
1593 if (!at_tok_hasmore(&line)) {
1594 response[i] = NULL;
1595 continue;
1596 }
1597
1598 err = at_tok_nextint(&line, &skip);
1599 if (err < 0) goto error;
1600
1601 // a "+COPS: 0, n" response is also possible
1602 if (!at_tok_hasmore(&line)) {
1603 response[i] = NULL;
1604 continue;
1605 }
1606
1607 err = at_tok_nextstr(&line, &(response[i]));
1608 if (err < 0) goto error;
1609 // Simple assumption that mcc and mnc are 3 digits each
1610 if (strlen(response[i]) == 6) {
1611 if (sscanf(response[i], "%3d%3d", &s_mcc, &s_mnc) != 2) {
1612 RLOGE("requestOperator expected mccmnc to be 6 decimal digits");
1613 }
1614 }
1615 }
1616
1617 if (i != 3) {
1618 /* expect 3 lines exactly */
1619 goto error;
1620 }
1621
1622 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
1623 at_response_free(p_response);
1624
1625 return;
1626 error:
1627 RLOGE("requestOperator must not return error when radio is on");
1628 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1629 at_response_free(p_response);
1630 }
1631
1632 static void requestCdmaSendSMS(void *data, size_t datalen, RIL_Token t)
1633 {
1634 int err = 1; // Set to go to error:
1635 RIL_SMS_Response response;
1636 RIL_CDMA_SMS_Message* rcsm;
1637
1638 if (getSIMStatus() == SIM_ABSENT) {
1639 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
1640 return;
1641 }
1642
1643 RLOGD("requestCdmaSendSMS datalen=%zu, sizeof(RIL_CDMA_SMS_Message)=%zu",
1644 datalen, sizeof(RIL_CDMA_SMS_Message));
1645
1646 // verify data content to test marshalling/unmarshalling:
1647 rcsm = (RIL_CDMA_SMS_Message*)data;
1648 RLOGD("TeleserviceID=%d, bIsServicePresent=%d, \
1649 uServicecategory=%d, sAddress.digit_mode=%d, \
1650 sAddress.Number_mode=%d, sAddress.number_type=%d, ",
1651 rcsm->uTeleserviceID, rcsm->bIsServicePresent,
1652 rcsm->uServicecategory,rcsm->sAddress.digit_mode,
1653 rcsm->sAddress.number_mode,rcsm->sAddress.number_type);
1654
1655 if (err != 0) goto error;
1656
1657 // Cdma Send SMS implementation will go here:
1658 // But it is not implemented yet.
1659
1660 memset(&response, 0, sizeof(response));
1661 response.messageRef = 1;
1662 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1663 return;
1664
1665 error:
1666 // Cdma Send SMS will always cause send retry error.
1667 response.messageRef = -1;
1668 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
1669 }
1670
1671 static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
1672 {
1673 int err;
1674 const char *smsc;
1675 const char *pdu;
1676 int tpLayerLength;
1677 char *cmd1, *cmd2;
1678 RIL_SMS_Response response;
1679 ATResponse *p_response = NULL;
1680
1681 if (getSIMStatus() == SIM_ABSENT) {
1682 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
1683 return;
1684 }
1685
1686 memset(&response, 0, sizeof(response));
1687 RLOGD("requestSendSMS datalen =%zu", datalen);
1688
1689 if (s_ims_gsm_fail != 0) goto error;
1690 if (s_ims_gsm_retry != 0) goto error2;
1691
1692 smsc = ((const char **)data)[0];
1693 pdu = ((const char **)data)[1];
1694
1695 tpLayerLength = strlen(pdu)/2;
1696
1697 // "NULL for default SMSC"
1698 if (smsc == NULL) {
1699 smsc= "00";
1700 }
1701
1702 asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
1703 asprintf(&cmd2, "%s%s", smsc, pdu);
1704
1705 err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response);
1706
1707 free(cmd1);
1708 free(cmd2);
1709
1710 if (err != 0 || p_response->success == 0) goto error;
1711
1712 /* FIXME fill in messageRef and ackPDU */
1713 response.messageRef = 1;
1714 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1715 at_response_free(p_response);
1716
1717 return;
1718 error:
1719 response.messageRef = -2;
1720 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
1721 at_response_free(p_response);
1722 return;
1723 error2:
1724 // send retry error.
1725 response.messageRef = -1;
1726 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
1727 at_response_free(p_response);
1728 return;
1729 }
1730
1731 static void requestImsSendSMS(void *data, size_t datalen, RIL_Token t)
1732 {
1733 RIL_IMS_SMS_Message *p_args;
1734 RIL_SMS_Response response;
1735
1736 memset(&response, 0, sizeof(response));
1737
1738 RLOGD("requestImsSendSMS: datalen=%zu, "
1739 "registered=%d, service=%d, format=%d, ims_perm_fail=%d, "
1740 "ims_retry=%d, gsm_fail=%d, gsm_retry=%d",
1741 datalen, s_ims_registered, s_ims_services, s_ims_format,
1742 s_ims_cause_perm_failure, s_ims_cause_retry, s_ims_gsm_fail,
1743 s_ims_gsm_retry);
1744
1745 // figure out if this is gsm/cdma format
1746 // then route it to requestSendSMS vs requestCdmaSendSMS respectively
1747 p_args = (RIL_IMS_SMS_Message *)data;
1748
1749 if (0 != s_ims_cause_perm_failure ) goto error;
1750
1751 // want to fail over ims and this is first request over ims
1752 if (0 != s_ims_cause_retry && 0 == p_args->retry) goto error2;
1753
1754 if (RADIO_TECH_3GPP == p_args->tech) {
1755 return requestSendSMS(p_args->message.gsmMessage,
1756 datalen - sizeof(RIL_RadioTechnologyFamily),
1757 t);
1758 } else if (RADIO_TECH_3GPP2 == p_args->tech) {
1759 return requestCdmaSendSMS(p_args->message.cdmaMessage,
1760 datalen - sizeof(RIL_RadioTechnologyFamily),
1761 t);
1762 } else {
1763 RLOGE("requestImsSendSMS invalid format value =%d", p_args->tech);
1764 }
1765
1766 error:
1767 response.messageRef = -2;
1768 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
1769 return;
1770
1771 error2:
1772 response.messageRef = -1;
1773 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
1774 }
1775
1776 static void requestSimOpenChannel(void *data, size_t datalen, RIL_Token t)
1777 {
1778 ATResponse *p_response = NULL;
1779 int32_t session_id;
1780 int err;
1781 char cmd[32];
1782 char dummy;
1783 char *line;
1784
1785 // Max length is 16 bytes according to 3GPP spec 27.007 section 8.45
1786 if (data == NULL || datalen == 0 || datalen > 16) {
1787 ALOGE("Invalid data passed to requestSimOpenChannel");
1788 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1789 return;
1790 }
1791
1792 snprintf(cmd, sizeof(cmd), "AT+CCHO=%s", (char*) data);
1793
1794 err = at_send_command_numeric(cmd, &p_response);
1795 if (err < 0 || p_response == NULL || p_response->success == 0) {
1796 ALOGE("Error %d opening logical channel: %d",
1797 err, p_response ? p_response->success : 0);
1798 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1799 at_response_free(p_response);
1800 return;
1801 }
1802
1803 // Ensure integer only by scanning for an extra char but expect one result
1804 line = p_response->p_intermediates->line;
1805 if (sscanf(line, "%" SCNd32 "%c", &session_id, &dummy) != 1) {
1806 ALOGE("Invalid AT response, expected integer, was '%s'", line);
1807 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1808 return;
1809 }
1810
1811 RIL_onRequestComplete(t, RIL_E_SUCCESS, &session_id, sizeof(&session_id));
1812 at_response_free(p_response);
1813 }
1814
1815 static void requestSimCloseChannel(void *data, size_t datalen, RIL_Token t)
1816 {
1817 ATResponse *p_response = NULL;
1818 int32_t session_id;
1819 int err;
1820 char cmd[32];
1821
1822 if (data == NULL || datalen != sizeof(session_id)) {
1823 ALOGE("Invalid data passed to requestSimCloseChannel");
1824 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1825 return;
1826 }
1827 session_id = ((int32_t *)data)[0];
1828 snprintf(cmd, sizeof(cmd), "AT+CCHC=%" PRId32, session_id);
1829 err = at_send_command_singleline(cmd, "+CCHC", &p_response);
1830
1831 if (err < 0 || p_response == NULL || p_response->success == 0) {
1832 ALOGE("Error %d closing logical channel %d: %d",
1833 err, session_id, p_response ? p_response->success : 0);
1834 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1835 at_response_free(p_response);
1836 return;
1837 }
1838
1839 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1840
1841 at_response_free(p_response);
1842 }
1843
1844 static void requestSimTransmitApduChannel(void *data,
1845 size_t datalen,
1846 RIL_Token t)
1847 {
1848 ATResponse *p_response = NULL;
1849 int err;
1850 char *cmd;
1851 char *line;
1852 size_t cmd_size;
1853 RIL_SIM_IO_Response sim_response;
1854 RIL_SIM_APDU *apdu = (RIL_SIM_APDU *)data;
1855
1856 if (apdu == NULL || datalen != sizeof(RIL_SIM_APDU)) {
1857 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1858 return;
1859 }
1860
1861 cmd_size = 10 + (apdu->data ? strlen(apdu->data) : 0);
1862 asprintf(&cmd, "AT+CGLA=%d,%zu,%02x%02x%02x%02x%02x%s",
1863 apdu->sessionid, cmd_size, apdu->cla, apdu->instruction,
1864 apdu->p1, apdu->p2, apdu->p3, apdu->data ? apdu->data : "");
1865
1866 err = at_send_command_singleline(cmd, "+CGLA", &p_response);
1867 free(cmd);
1868 if (err < 0 || p_response == NULL || p_response->success == 0) {
1869 ALOGE("Error %d transmitting APDU: %d",
1870 err, p_response ? p_response->success : 0);
1871 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1872 at_response_free(p_response);
1873 return;
1874 }
1875
1876 line = p_response->p_intermediates->line;
1877 err = parseSimResponseLine(line, &sim_response);
1878
1879 if (err == 0) {
1880 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1881 &sim_response, sizeof(sim_response));
1882 } else {
1883 ALOGE("Error %d parsing SIM response line: %s", err, line);
1884 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1885 }
1886 at_response_free(p_response);
1887 }
1888
1889 static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
1890 {
1891 const char *apn;
1892 char *cmd;
1893 int err;
1894 ATResponse *p_response = NULL;
1895
1896 apn = ((const char **)data)[2];
1897
1898 #ifdef USE_TI_COMMANDS
1899 // Config for multislot class 10 (probably default anyway eh?)
1900 err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
1901 NULL);
1902
1903 err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
1904 #endif /* USE_TI_COMMANDS */
1905
1906 int fd, qmistatus;
1907 size_t cur = 0;
1908 size_t len;
1909 ssize_t written, rlen;
1910 char status[32] = {0};
1911 int retry = 10;
1912 const char *pdp_type;
1913
1914 RLOGD("requesting data connection to APN '%s'", apn);
1915
1916 fd = open ("/dev/qmi", O_RDWR);
1917 if (fd >= 0) { /* the device doesn't exist on the emulator */
1918
1919 RLOGD("opened the qmi device\n");
1920 asprintf(&cmd, "up:%s", apn);
1921 len = strlen(cmd);
1922
1923 while (cur < len) {
1924 do {
1925 written = write (fd, cmd + cur, len - cur);
1926 } while (written < 0 && errno == EINTR);
1927
1928 if (written < 0) {
1929 RLOGE("### ERROR writing to /dev/qmi");
1930 close(fd);
1931 goto error;
1932 }
1933
1934 cur += written;
1935 }
1936
1937 // wait for interface to come online
1938
1939 do {
1940 sleep(1);
1941 do {
1942 rlen = read(fd, status, 31);
1943 } while (rlen < 0 && errno == EINTR);
1944
1945 if (rlen < 0) {
1946 RLOGE("### ERROR reading from /dev/qmi");
1947 close(fd);
1948 goto error;
1949 } else {
1950 status[rlen] = '\0';
1951 RLOGD("### status: %s", status);
1952 }
1953 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
1954
1955 close(fd);
1956
1957 if (retry == 0) {
1958 RLOGE("### Failed to get data connection up\n");
1959 goto error;
1960 }
1961
1962 qmistatus = system("netcfg rmnet0 dhcp");
1963
1964 RLOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
1965
1966 if (qmistatus < 0) goto error;
1967
1968 } else {
1969 bool hasWifi = hasWifiCapability();
1970 const char* radioInterfaceName = getRadioInterfaceName(hasWifi);
1971 if (setInterfaceState(radioInterfaceName, kInterfaceUp) != RIL_E_SUCCESS) {
1972 goto error;
1973 }
1974
1975 if (datalen > 6 * sizeof(char *)) {
1976 pdp_type = ((const char **)data)[6];
1977 } else {
1978 pdp_type = "IP";
1979 }
1980
1981 asprintf(&cmd, "AT+CGDCONT=1,\"%s\",\"%s\",,0,0", pdp_type, apn);
1982 //FIXME check for error here
1983 err = at_send_command(cmd, NULL);
1984 free(cmd);
1985
1986 // Set required QoS params to default
1987 err = at_send_command("AT+CGQREQ=1", NULL);
1988
1989 // Set minimum QoS params to default
1990 err = at_send_command("AT+CGQMIN=1", NULL);
1991
1992 // packet-domain event reporting
1993 err = at_send_command("AT+CGEREP=1,0", NULL);
1994
1995 // Hangup anything that's happening there now
1996 err = at_send_command("AT+CGACT=1,0", NULL);
1997
1998 // Start data on PDP context 1
1999 err = at_send_command("ATD*99***1#", &p_response);
2000
2001 if (err < 0 || p_response->success == 0) {
2002 goto error;
2003 }
2004 }
2005
2006 requestOrSendDataCallList(&t);
2007
2008 at_response_free(p_response);
2009
2010 return;
2011 error:
2012 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2013 at_response_free(p_response);
2014
2015 }
2016
2017 static void requestDeactivateDataCall(RIL_Token t)
2018 {
2019 bool hasWifi = hasWifiCapability();
2020 const char* radioInterfaceName = getRadioInterfaceName(hasWifi);
2021 RIL_Errno rilErrno = setInterfaceState(radioInterfaceName, kInterfaceDown);
2022 RIL_onRequestComplete(t, rilErrno, NULL, 0);
2023 }
2024
2025 static void requestSMSAcknowledge(void *data, size_t datalen __unused, RIL_Token t)
2026 {
2027 int ackSuccess;
2028 int err;
2029
2030 if (getSIMStatus() == SIM_ABSENT) {
2031 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2032 return;
2033 }
2034
2035 ackSuccess = ((int *)data)[0];
2036
2037 if (ackSuccess == 1) {
2038 err = at_send_command("AT+CNMA=1", NULL);
2039 } else if (ackSuccess == 0) {
2040 err = at_send_command("AT+CNMA=2", NULL);
2041 } else {
2042 RLOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
2043 goto error;
2044 }
2045
2046 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2047 error:
2048 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2049
2050 }
2051
2052 static void requestSIM_IO(void *data, size_t datalen __unused, RIL_Token t)
2053 {
2054 ATResponse *p_response = NULL;
2055 RIL_SIM_IO_Response sr;
2056 int err;
2057 char *cmd = NULL;
2058 RIL_SIM_IO_v6 *p_args;
2059 char *line;
2060
2061 memset(&sr, 0, sizeof(sr));
2062
2063 p_args = (RIL_SIM_IO_v6 *)data;
2064
2065 /* FIXME handle pin2 */
2066
2067 if (p_args->data == NULL) {
2068 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
2069 p_args->command, p_args->fileid,
2070 p_args->p1, p_args->p2, p_args->p3);
2071 } else {
2072 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
2073 p_args->command, p_args->fileid,
2074 p_args->p1, p_args->p2, p_args->p3, p_args->data);
2075 }
2076
2077 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
2078
2079 if (err < 0 || p_response->success == 0) {
2080 goto error;
2081 }
2082
2083 line = p_response->p_intermediates->line;
2084
2085 err = parseSimResponseLine(line, &sr);
2086 if (err < 0) {
2087 goto error;
2088 }
2089
2090 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
2091 at_response_free(p_response);
2092 free(cmd);
2093
2094 return;
2095 error:
2096 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2097 at_response_free(p_response);
2098 free(cmd);
2099
2100 }
2101
2102 static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
2103 {
2104 ATResponse *p_response = NULL;
2105 int err;
2106 char* cmd = NULL;
2107 const char** strings = (const char**)data;;
2108
2109 if ( datalen == sizeof(char*) ) {
2110 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
2111 } else if ( datalen == 2*sizeof(char*) ) {
2112 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
2113 } else
2114 goto error;
2115
2116 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
2117 free(cmd);
2118
2119 if (err < 0 || p_response->success == 0) {
2120 error:
2121 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
2122 } else {
2123 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2124 }
2125 at_response_free(p_response);
2126 }
2127
2128
2129 static void requestSendUSSD(void *data, size_t datalen __unused, RIL_Token t)
2130 {
2131 const char *ussdRequest;
2132
2133 ussdRequest = (char *)(data);
2134
2135
2136 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2137
2138 // @@@ TODO
2139
2140 }
2141
2142 static void requestExitEmergencyMode(void *data __unused, size_t datalen __unused, RIL_Token t)
2143 {
2144 int err;
2145 ATResponse *p_response = NULL;
2146
2147 err = at_send_command("AT+WSOS=0", &p_response);
2148
2149 if (err < 0 || p_response->success == 0) {
2150 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2151 return;
2152 }
2153
2154 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2155 }
2156
2157 // TODO: Use all radio types
2158 static int techFromModemType(int mdmtype)
2159 {
2160 int ret = -1;
2161 switch (1 << mdmtype) {
2162 case MDM_CDMA:
2163 ret = RADIO_TECH_1xRTT;
2164 break;
2165 case MDM_EVDO:
2166 ret = RADIO_TECH_EVDO_A;
2167 break;
2168 case MDM_GSM:
2169 ret = RADIO_TECH_GPRS;
2170 break;
2171 case MDM_WCDMA:
2172 ret = RADIO_TECH_HSPA;
2173 break;
2174 case MDM_LTE:
2175 ret = RADIO_TECH_LTE;
2176 break;
2177 }
2178 return ret;
2179 }
2180
2181 static void requestGetCellInfoList(void *data __unused, size_t datalen __unused, RIL_Token t)
2182 {
2183 uint64_t curTime = ril_nano_time();
2184 RIL_CellInfo_v12 ci[1] =
2185 {
2186 { // ci[0]
2187 1, // cellInfoType
2188 1, // registered
2189 RIL_TIMESTAMP_TYPE_MODEM,
2190 curTime - 1000, // Fake some time in the past
2191 { // union CellInfo
2192 { // RIL_CellInfoGsm gsm
2193 { // gsm.cellIdneityGsm
2194 s_mcc, // mcc
2195 s_mnc, // mnc
2196 s_lac, // lac
2197 s_cid, // cid
2198 0, //arfcn unknown
2199 0xFF, // bsic unknown
2200 },
2201 { // gsm.signalStrengthGsm
2202 10, // signalStrength
2203 0 // bitErrorRate
2204 , INT_MAX // timingAdvance invalid value
2205 }
2206 }
2207 }
2208 }
2209 };
2210
2211 RIL_onRequestComplete(t, RIL_E_SUCCESS, ci, sizeof(ci));
2212 }
2213
2214
2215 static void requestSetCellInfoListRate(void *data, size_t datalen __unused, RIL_Token t)
2216 {
2217 // For now we'll save the rate but no RIL_UNSOL_CELL_INFO_LIST messages
2218 // will be sent.
2219 assert (datalen == sizeof(int));
2220 s_cell_info_rate_ms = ((int *)data)[0];
2221
2222 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2223 }
2224
2225 static void requestGetHardwareConfig(void *data, size_t datalen, RIL_Token t)
2226 {
2227 // TODO - hook this up with real query/info from radio.
2228
2229 RIL_HardwareConfig hwCfg;
2230
2231 RIL_UNUSED_PARM(data);
2232 RIL_UNUSED_PARM(datalen);
2233
2234 hwCfg.type = -1;
2235
2236 RIL_onRequestComplete(t, RIL_E_SUCCESS, &hwCfg, sizeof(hwCfg));
2237 }
2238
2239 static void requestGetTtyMode(void *data, size_t datalen, RIL_Token t)
2240 {
2241 int ttyModeResponse;
2242
2243 RIL_UNUSED_PARM(data);
2244 RIL_UNUSED_PARM(datalen);
2245
2246 ttyModeResponse = (getSIMStatus() == SIM_READY) ? 1 // TTY Full
2247 : 0; // TTY Off
2248
2249 RIL_onRequestComplete(t, RIL_E_SUCCESS, &ttyModeResponse, sizeof(ttyModeResponse));
2250 }
2251
2252 static void requestGetRadioCapability(void *data, size_t datalen, RIL_Token t)
2253 {
2254 RIL_RadioCapability radioCapability;
2255
2256 RIL_UNUSED_PARM(data);
2257 RIL_UNUSED_PARM(datalen);
2258
2259 radioCapability.version = RIL_RADIO_CAPABILITY_VERSION;
2260 radioCapability.session = 0;
2261 radioCapability.phase = 0;
2262 radioCapability.rat = 0;
2263 radioCapability.logicalModemUuid[0] = '\0';
2264 radioCapability.status = RC_STATUS_SUCCESS;
2265
2266 RIL_onRequestComplete(t, RIL_E_SUCCESS, &radioCapability, sizeof(radioCapability));
2267 }
2268
2269 static void requestGetMute(void *data, size_t datalen, RIL_Token t)
2270 {
2271 int muteResponse;
2272
2273 RIL_UNUSED_PARM(data);
2274 RIL_UNUSED_PARM(datalen);
2275
2276 muteResponse = 0; // Mute disabled
2277
2278 RIL_onRequestComplete(t, RIL_E_SUCCESS, &muteResponse, sizeof(muteResponse));
2279 }
2280
2281 /*** Callback methods from the RIL library to us ***/
2282
2283 /**
2284 * Call from RIL to us to make a RIL_REQUEST
2285 *
2286 * Must be completed with a call to RIL_onRequestComplete()
2287 *
2288 * RIL_onRequestComplete() may be called from any thread, before or after
2289 * this function returns.
2290 *
2291 * Because onRequest function could be called from multiple different thread,
2292 * we must ensure that the underlying at_send_command_* function
2293 * is atomic.
2294 */
2295 static void
2296 onRequest (int request, void *data, size_t datalen, RIL_Token t)
2297 {
2298 ATResponse *p_response;
2299 int err;
2300
2301 RLOGD("onRequest: %s", requestToString(request));
2302
2303 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
2304 * when RADIO_STATE_UNAVAILABLE.
2305 */
2306 if (sState == RADIO_STATE_UNAVAILABLE
2307 && request != RIL_REQUEST_GET_SIM_STATUS
2308 ) {
2309 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2310 return;
2311 }
2312
2313 /* Ignore all non-power requests when RADIO_STATE_OFF
2314 * (except RIL_REQUEST_GET_SIM_STATUS)
2315 */
2316 if (sState == RADIO_STATE_OFF) {
2317 switch(request) {
2318 case RIL_REQUEST_BASEBAND_VERSION:
2319 case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
2320 case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE:
2321 case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
2322 case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
2323 case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
2324 case RIL_REQUEST_CDMA_SUBSCRIPTION:
2325 case RIL_REQUEST_DEVICE_IDENTITY:
2326 case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
2327 case RIL_REQUEST_GET_ACTIVITY_INFO:
2328 case RIL_REQUEST_GET_CARRIER_RESTRICTIONS:
2329 case RIL_REQUEST_GET_CURRENT_CALLS:
2330 case RIL_REQUEST_GET_IMEI:
2331 case RIL_REQUEST_GET_MUTE:
2332 case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
2333 case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
2334 case RIL_REQUEST_GET_RADIO_CAPABILITY:
2335 case RIL_REQUEST_GET_SIM_STATUS:
2336 case RIL_REQUEST_NV_RESET_CONFIG:
2337 case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
2338 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
2339 case RIL_REQUEST_QUERY_TTY_MODE:
2340 case RIL_REQUEST_RADIO_POWER:
2341 case RIL_REQUEST_SET_BAND_MODE:
2342 case RIL_REQUEST_SET_CARRIER_RESTRICTIONS:
2343 case RIL_REQUEST_SET_LOCATION_UPDATES:
2344 case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
2345 case RIL_REQUEST_SET_TTY_MODE:
2346 case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
2347 case RIL_REQUEST_STOP_LCE:
2348 case RIL_REQUEST_VOICE_RADIO_TECH:
2349 // Process all the above, even though the radio is off
2350 break;
2351
2352 default:
2353 // For all others, say NOT_AVAILABLE because the radio is off
2354 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2355 return;
2356 }
2357 }
2358
2359 switch (request) {
2360 case RIL_REQUEST_GET_SIM_STATUS: {
2361 RIL_CardStatus_v6 *p_card_status;
2362 char *p_buffer;
2363 int buffer_size;
2364
2365 int result = getCardStatus(&p_card_status);
2366 if (result == RIL_E_SUCCESS) {
2367 p_buffer = (char *)p_card_status;
2368 buffer_size = sizeof(*p_card_status);
2369 } else {
2370 p_buffer = NULL;
2371 buffer_size = 0;
2372 }
2373 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
2374 freeCardStatus(p_card_status);
2375 break;
2376 }
2377 case RIL_REQUEST_GET_CURRENT_CALLS:
2378 requestGetCurrentCalls(data, datalen, t);
2379 break;
2380 case RIL_REQUEST_DIAL:
2381 requestDial(data, datalen, t);
2382 break;
2383 case RIL_REQUEST_HANGUP:
2384 requestHangup(data, datalen, t);
2385 break;
2386 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
2387 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
2388 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
2389 case RIL_REQUEST_CONFERENCE:
2390 case RIL_REQUEST_UDUB:
2391 requestCallSelection(data, datalen, t, request);
2392 break;
2393 case RIL_REQUEST_ANSWER:
2394 at_send_command("ATA", NULL);
2395
2396 #ifdef WORKAROUND_ERRONEOUS_ANSWER
2397 s_expectAnswer = 1;
2398 #endif /* WORKAROUND_ERRONEOUS_ANSWER */
2399
2400 if (getSIMStatus() != SIM_READY) {
2401 RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
2402 } else {
2403 // Success or failure is ignored by the upper layer here.
2404 // It will call GET_CURRENT_CALLS and determine success that way.
2405 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2406 }
2407 break;
2408
2409 case RIL_REQUEST_SEPARATE_CONNECTION:
2410 {
2411 char cmd[12];
2412 int party = ((int*)data)[0];
2413
2414 if (getSIMStatus() == SIM_ABSENT) {
2415 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2416 return;
2417 }
2418 // Make sure that party is in a valid range.
2419 // (Note: The Telephony middle layer imposes a range of 1 to 7.
2420 // It's sufficient for us to just make sure it's single digit.)
2421 if (party > 0 && party < 10) {
2422 sprintf(cmd, "AT+CHLD=2%d", party);
2423 at_send_command(cmd, NULL);
2424 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2425 } else {
2426 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2427 }
2428 }
2429 break;
2430
2431 case RIL_REQUEST_SIGNAL_STRENGTH:
2432 requestSignalStrength(data, datalen, t);
2433 break;
2434 case RIL_REQUEST_VOICE_REGISTRATION_STATE:
2435 case RIL_REQUEST_DATA_REGISTRATION_STATE:
2436 requestRegistrationState(request, data, datalen, t);
2437 break;
2438 case RIL_REQUEST_OPERATOR:
2439 requestOperator(data, datalen, t);
2440 break;
2441 case RIL_REQUEST_RADIO_POWER:
2442 requestRadioPower(data, datalen, t);
2443 break;
2444 case RIL_REQUEST_DTMF: {
2445 char c = ((char *)data)[0];
2446 char *cmd;
2447 asprintf(&cmd, "AT+VTS=%c", (int)c);
2448 at_send_command(cmd, NULL);
2449 free(cmd);
2450 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2451 break;
2452 }
2453 case RIL_REQUEST_SEND_SMS:
2454 case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
2455 requestSendSMS(data, datalen, t);
2456 break;
2457 case RIL_REQUEST_CDMA_SEND_SMS:
2458 requestCdmaSendSMS(data, datalen, t);
2459 break;
2460 case RIL_REQUEST_IMS_SEND_SMS:
2461 requestImsSendSMS(data, datalen, t);
2462 break;
2463 case RIL_REQUEST_SIM_OPEN_CHANNEL:
2464 requestSimOpenChannel(data, datalen, t);
2465 break;
2466 case RIL_REQUEST_SIM_CLOSE_CHANNEL:
2467 requestSimCloseChannel(data, datalen, t);
2468 break;
2469 case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL:
2470 requestSimTransmitApduChannel(data, datalen, t);
2471 break;
2472 case RIL_REQUEST_SETUP_DATA_CALL:
2473 requestSetupDataCall(data, datalen, t);
2474 break;
2475 case RIL_REQUEST_DEACTIVATE_DATA_CALL:
2476 requestDeactivateDataCall(t);
2477 break;
2478 case RIL_REQUEST_SMS_ACKNOWLEDGE:
2479 requestSMSAcknowledge(data, datalen, t);
2480 break;
2481
2482 case RIL_REQUEST_GET_IMSI:
2483 p_response = NULL;
2484 err = at_send_command_numeric("AT+CIMI", &p_response);
2485
2486 if (err < 0 || p_response->success == 0) {
2487 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2488 } else {
2489 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2490 p_response->p_intermediates->line, sizeof(char *));
2491 }
2492 at_response_free(p_response);
2493 break;
2494
2495 case RIL_REQUEST_GET_IMEI:
2496 p_response = NULL;
2497 err = at_send_command_numeric("AT+CGSN", &p_response);
2498
2499 if (err < 0 || p_response->success == 0) {
2500 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2501 } else {
2502 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2503 p_response->p_intermediates->line, sizeof(char *));
2504 }
2505 at_response_free(p_response);
2506 break;
2507
2508 case RIL_REQUEST_SIM_IO:
2509 requestSIM_IO(data,datalen,t);
2510 break;
2511
2512 case RIL_REQUEST_SEND_USSD:
2513 requestSendUSSD(data, datalen, t);
2514 break;
2515
2516 case RIL_REQUEST_CANCEL_USSD:
2517 if (getSIMStatus() == SIM_ABSENT) {
2518 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2519 return;
2520 }
2521 p_response = NULL;
2522 err = at_send_command_numeric("AT+CUSD=2", &p_response);
2523
2524 if (err < 0 || p_response->success == 0) {
2525 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2526 } else {
2527 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2528 p_response->p_intermediates->line, sizeof(char *));
2529 }
2530 at_response_free(p_response);
2531 break;
2532
2533 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
2534 if (getSIMStatus() == SIM_ABSENT) {
2535 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2536 } else {
2537 at_send_command("AT+COPS=0", NULL);
2538 }
2539 break;
2540
2541 case RIL_REQUEST_DATA_CALL_LIST:
2542 requestDataCallList(data, datalen, t);
2543 break;
2544
2545 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
2546 requestQueryNetworkSelectionMode(data, datalen, t);
2547 break;
2548
2549 case RIL_REQUEST_OEM_HOOK_RAW:
2550 // echo back data
2551 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2552 break;
2553
2554
2555 case RIL_REQUEST_OEM_HOOK_STRINGS: {
2556 int i;
2557 const char ** cur;
2558
2559 RLOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
2560
2561
2562 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
2563 i > 0 ; cur++, i --) {
2564 RLOGD("> '%s'", *cur);
2565 }
2566
2567 // echo back strings
2568 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2569 break;
2570 }
2571
2572 case RIL_REQUEST_WRITE_SMS_TO_SIM:
2573 requestWriteSmsToSim(data, datalen, t);
2574 break;
2575
2576 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
2577 char * cmd;
2578 p_response = NULL;
2579 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
2580 err = at_send_command(cmd, &p_response);
2581 free(cmd);
2582 if (err < 0 || p_response->success == 0) {
2583 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2584 } else {
2585 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2586 }
2587 at_response_free(p_response);
2588 break;
2589 }
2590
2591 case RIL_REQUEST_ENTER_SIM_PIN:
2592 case RIL_REQUEST_ENTER_SIM_PUK:
2593 case RIL_REQUEST_ENTER_SIM_PIN2:
2594 case RIL_REQUEST_ENTER_SIM_PUK2:
2595 case RIL_REQUEST_CHANGE_SIM_PIN:
2596 case RIL_REQUEST_CHANGE_SIM_PIN2:
2597 requestEnterSimPin(data, datalen, t);
2598 break;
2599
2600 case RIL_REQUEST_IMS_REGISTRATION_STATE: {
2601 int reply[2];
2602 //0==unregistered, 1==registered
2603 reply[0] = s_ims_registered;
2604
2605 //to be used when changed to include service supporated info
2606 //reply[1] = s_ims_services;
2607
2608 // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
2609 reply[1] = s_ims_format;
2610
2611 RLOGD("IMS_REGISTRATION=%d, format=%d ",
2612 reply[0], reply[1]);
2613 if (reply[1] != -1) {
2614 RIL_onRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply));
2615 } else {
2616 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2617 }
2618 break;
2619 }
2620
2621 case RIL_REQUEST_VOICE_RADIO_TECH:
2622 {
2623 int tech = techFromModemType(TECH(sMdmInfo));
2624 if (tech < 0 )
2625 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2626 else
2627 RIL_onRequestComplete(t, RIL_E_SUCCESS, &tech, sizeof(tech));
2628 }
2629 break;
2630 case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
2631 requestSetPreferredNetworkType(request, data, datalen, t);
2632 break;
2633
2634 case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
2635 requestGetPreferredNetworkType(request, data, datalen, t);
2636 break;
2637
2638 case RIL_REQUEST_GET_CELL_INFO_LIST:
2639 requestGetCellInfoList(data, datalen, t);
2640 break;
2641
2642 case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
2643 requestSetCellInfoListRate(data, datalen, t);
2644 break;
2645
2646 case RIL_REQUEST_GET_HARDWARE_CONFIG:
2647 requestGetHardwareConfig(data, datalen, t);
2648 break;
2649
2650 case RIL_REQUEST_SHUTDOWN:
2651 requestShutdown(t);
2652 break;
2653
2654 case RIL_REQUEST_QUERY_TTY_MODE:
2655 requestGetTtyMode(data, datalen, t);
2656 break;
2657
2658 case RIL_REQUEST_GET_RADIO_CAPABILITY:
2659 requestGetRadioCapability(data, datalen, t);
2660 break;
2661
2662 case RIL_REQUEST_GET_MUTE:
2663 requestGetMute(data, datalen, t);
2664 break;
2665
2666 case RIL_REQUEST_SET_INITIAL_ATTACH_APN:
2667 case RIL_REQUEST_ALLOW_DATA:
2668 case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
2669 case RIL_REQUEST_SET_CLIR:
2670 case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION:
2671 case RIL_REQUEST_SET_BAND_MODE:
2672 case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
2673 case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
2674 case RIL_REQUEST_SET_LOCATION_UPDATES:
2675 case RIL_REQUEST_SET_TTY_MODE:
2676 case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
2677 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2678 break;
2679
2680 case RIL_REQUEST_BASEBAND_VERSION:
2681 requestCdmaBaseBandVersion(request, data, datalen, t);
2682 break;
2683
2684 case RIL_REQUEST_DEVICE_IDENTITY:
2685 requestDeviceIdentity(request, data, datalen, t);
2686 break;
2687
2688 case RIL_REQUEST_CDMA_SUBSCRIPTION:
2689 requestCdmaSubscription(request, data, datalen, t);
2690 break;
2691
2692 case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
2693 requestCdmaGetSubscriptionSource(request, data, datalen, t);
2694 break;
2695
2696 case RIL_REQUEST_START_LCE:
2697 case RIL_REQUEST_STOP_LCE:
2698 case RIL_REQUEST_PULL_LCEDATA:
2699 if (getSIMStatus() == SIM_ABSENT) {
2700 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
2701 } else {
2702 RIL_onRequestComplete(t, RIL_E_LCE_NOT_SUPPORTED, NULL, 0);
2703 }
2704 break;
2705
2706 case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
2707 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2708 requestCdmaGetRoamingPreference(request, data, datalen, t);
2709 } else {
2710 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2711 }
2712 break;
2713
2714 case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
2715 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2716 requestCdmaSetSubscriptionSource(request, data, datalen, t);
2717 } else {
2718 // VTS tests expect us to silently do nothing
2719 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2720 }
2721 break;
2722
2723 case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
2724 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2725 requestCdmaSetRoamingPreference(request, data, datalen, t);
2726 } else {
2727 // VTS tests expect us to silently do nothing
2728 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2729 }
2730 break;
2731
2732 case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
2733 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2734 requestExitEmergencyMode(data, datalen, t);
2735 } else {
2736 // VTS tests expect us to silently do nothing
2737 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2738 }
2739 break;
2740
2741 default:
2742 RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));
2743 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2744 break;
2745 }
2746 }
2747
2748 /**
2749 * Synchronous call from the RIL to us to return current radio state.
2750 * RADIO_STATE_UNAVAILABLE should be the initial state.
2751 */
2752 static RIL_RadioState
2753 currentState()
2754 {
2755 return sState;
2756 }
2757 /**
2758 * Call from RIL to us to find out whether a specific request code
2759 * is supported by this implementation.
2760 *
2761 * Return 1 for "supported" and 0 for "unsupported"
2762 */
2763
2764 static int
2765 onSupports (int requestCode __unused)
2766 {
2767 //@@@ todo
2768
2769 return 1;
2770 }
2771
2772 static void onCancel (RIL_Token t __unused)
2773 {
2774 //@@@todo
2775
2776 }
2777
2778 static const char * getVersion(void)
2779 {
2780 return "android reference-ril 1.0";
2781 }
2782
2783 static void
2784 setRadioTechnology(ModemInfo *mdm, int newtech)
2785 {
2786 RLOGD("setRadioTechnology(%d)", newtech);
2787
2788 int oldtech = TECH(mdm);
2789
2790 if (newtech != oldtech) {
2791 RLOGD("Tech change (%d => %d)", oldtech, newtech);
2792 TECH(mdm) = newtech;
2793 if (techFromModemType(newtech) != techFromModemType(oldtech)) {
2794 int tech = techFromModemType(TECH(sMdmInfo));
2795 if (tech > 0 ) {
2796 RIL_onUnsolicitedResponse(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED,
2797 &tech, sizeof(tech));
2798 }
2799 }
2800 }
2801 }
2802
2803 static void
2804 setRadioState(RIL_RadioState newState)
2805 {
2806 RLOGD("setRadioState(%d)", newState);
2807 RIL_RadioState oldState;
2808
2809 pthread_mutex_lock(&s_state_mutex);
2810
2811 oldState = sState;
2812
2813 if (s_closed > 0) {
2814 // If we're closed, the only reasonable state is
2815 // RADIO_STATE_UNAVAILABLE
2816 // This is here because things on the main thread
2817 // may attempt to change the radio state after the closed
2818 // event happened in another thread
2819 newState = RADIO_STATE_UNAVAILABLE;
2820 }
2821
2822 if (sState != newState || s_closed > 0) {
2823 sState = newState;
2824
2825 pthread_cond_broadcast (&s_state_cond);
2826 }
2827
2828 pthread_mutex_unlock(&s_state_mutex);
2829
2830
2831 /* do these outside of the mutex */
2832 if (sState != oldState) {
2833 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
2834 NULL, 0);
2835 // Sim state can change as result of radio state change
2836 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
2837 NULL, 0);
2838
2839 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
2840 * from the AT reader thread
2841 * Currently, this doesn't happen, but if that changes then these
2842 * will need to be dispatched on the request thread
2843 */
2844 if (sState == RADIO_STATE_ON) {
2845 onRadioPowerOn();
2846 }
2847 }
2848 }
2849
2850 /** Returns RUIM_NOT_READY on error */
2851 static SIM_Status
2852 getRUIMStatus()
2853 {
2854 ATResponse *p_response = NULL;
2855 int err;
2856 int ret;
2857 char *cpinLine;
2858 char *cpinResult;
2859
2860 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
2861 ret = SIM_NOT_READY;
2862 goto done;
2863 }
2864
2865 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2866
2867 if (err != 0) {
2868 ret = SIM_NOT_READY;
2869 goto done;
2870 }
2871
2872 switch (at_get_cme_error(p_response)) {
2873 case CME_SUCCESS:
2874 break;
2875
2876 case CME_SIM_NOT_INSERTED:
2877 ret = SIM_ABSENT;
2878 goto done;
2879
2880 default:
2881 ret = SIM_NOT_READY;
2882 goto done;
2883 }
2884
2885 /* CPIN? has succeeded, now look at the result */
2886
2887 cpinLine = p_response->p_intermediates->line;
2888 err = at_tok_start (&cpinLine);
2889
2890 if (err < 0) {
2891 ret = SIM_NOT_READY;
2892 goto done;
2893 }
2894
2895 err = at_tok_nextstr(&cpinLine, &cpinResult);
2896
2897 if (err < 0) {
2898 ret = SIM_NOT_READY;
2899 goto done;
2900 }
2901
2902 if (0 == strcmp (cpinResult, "SIM PIN")) {
2903 ret = SIM_PIN;
2904 goto done;
2905 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
2906 ret = SIM_PUK;
2907 goto done;
2908 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
2909 return SIM_NETWORK_PERSONALIZATION;
2910 } else if (0 != strcmp (cpinResult, "READY")) {
2911 /* we're treating unsupported lock types as "sim absent" */
2912 ret = SIM_ABSENT;
2913 goto done;
2914 }
2915
2916 at_response_free(p_response);
2917 p_response = NULL;
2918 cpinResult = NULL;
2919
2920 ret = SIM_READY;
2921
2922 done:
2923 at_response_free(p_response);
2924 return ret;
2925 }
2926
2927 /** Returns SIM_NOT_READY on error */
2928 static SIM_Status
2929 getSIMStatus()
2930 {
2931 ATResponse *p_response = NULL;
2932 int err;
2933 int ret;
2934 char *cpinLine;
2935 char *cpinResult;
2936
2937 RLOGD("getSIMStatus(). sState: %d",sState);
2938 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2939
2940 if (err != 0) {
2941 ret = SIM_NOT_READY;
2942 goto done;
2943 }
2944
2945 switch (at_get_cme_error(p_response)) {
2946 case CME_SUCCESS:
2947 break;
2948
2949 case CME_SIM_NOT_INSERTED:
2950 ret = SIM_ABSENT;
2951 goto done;
2952
2953 default:
2954 ret = SIM_NOT_READY;
2955 goto done;
2956 }
2957
2958 /* CPIN? has succeeded, now look at the result */
2959
2960 cpinLine = p_response->p_intermediates->line;
2961 err = at_tok_start (&cpinLine);
2962
2963 if (err < 0) {
2964 ret = SIM_NOT_READY;
2965 goto done;
2966 }
2967
2968 err = at_tok_nextstr(&cpinLine, &cpinResult);
2969
2970 if (err < 0) {
2971 ret = SIM_NOT_READY;
2972 goto done;
2973 }
2974
2975 if (0 == strcmp (cpinResult, "SIM PIN")) {
2976 ret = SIM_PIN;
2977 goto done;
2978 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
2979 ret = SIM_PUK;
2980 goto done;
2981 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
2982 return SIM_NETWORK_PERSONALIZATION;
2983 } else if (0 != strcmp (cpinResult, "READY")) {
2984 /* we're treating unsupported lock types as "sim absent" */
2985 ret = SIM_ABSENT;
2986 goto done;
2987 }
2988
2989 at_response_free(p_response);
2990 p_response = NULL;
2991 cpinResult = NULL;
2992
2993 ret = (sState == RADIO_STATE_ON) ? SIM_READY : SIM_NOT_READY;
2994
2995 done:
2996 at_response_free(p_response);
2997 return ret;
2998 }
2999
3000
3001 /**
3002 * Get the current card status.
3003 *
3004 * This must be freed using freeCardStatus.
3005 * @return: On success returns RIL_E_SUCCESS
3006 */
3007 static int getCardStatus(RIL_CardStatus_v6 **pp_card_status) {
3008 static RIL_AppStatus app_status_array[] = {
3009 // SIM_ABSENT = 0
3010 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
3011 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3012 // SIM_NOT_READY = 1
3013 { RIL_APPTYPE_USIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
3014 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3015 // SIM_READY = 2
3016 { RIL_APPTYPE_USIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
3017 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3018 // SIM_PIN = 3
3019 { RIL_APPTYPE_USIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
3020 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3021 // SIM_PUK = 4
3022 { RIL_APPTYPE_USIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
3023 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
3024 // SIM_NETWORK_PERSONALIZATION = 5
3025 { RIL_APPTYPE_USIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
3026 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3027 // RUIM_ABSENT = 6
3028 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
3029 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3030 // RUIM_NOT_READY = 7
3031 { RIL_APPTYPE_RUIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
3032 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3033 // RUIM_READY = 8
3034 { RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
3035 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3036 // RUIM_PIN = 9
3037 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
3038 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3039 // RUIM_PUK = 10
3040 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
3041 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
3042 // RUIM_NETWORK_PERSONALIZATION = 11
3043 { RIL_APPTYPE_RUIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
3044 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3045 // ISIM_ABSENT = 12
3046 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
3047 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3048 // ISIM_NOT_READY = 13
3049 { RIL_APPTYPE_ISIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
3050 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3051 // ISIM_READY = 14
3052 { RIL_APPTYPE_ISIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
3053 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3054 // ISIM_PIN = 15
3055 { RIL_APPTYPE_ISIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
3056 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3057 // ISIM_PUK = 16
3058 { RIL_APPTYPE_ISIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
3059 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
3060 // ISIM_NETWORK_PERSONALIZATION = 17
3061 { RIL_APPTYPE_ISIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
3062 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3063
3064 };
3065 RIL_CardState card_state;
3066 int num_apps;
3067
3068 int sim_status = getSIMStatus();
3069 if (sim_status == SIM_ABSENT) {
3070 card_state = RIL_CARDSTATE_ABSENT;
3071 num_apps = 0;
3072 } else {
3073 card_state = RIL_CARDSTATE_PRESENT;
3074 num_apps = 3;
3075 }
3076
3077 // Allocate and initialize base card status.
3078 RIL_CardStatus_v6 *p_card_status = malloc(sizeof(RIL_CardStatus_v6));
3079 p_card_status->card_state = card_state;
3080 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
3081 p_card_status->gsm_umts_subscription_app_index = -1;
3082 p_card_status->cdma_subscription_app_index = -1;
3083 p_card_status->ims_subscription_app_index = -1;
3084 p_card_status->num_applications = num_apps;
3085
3086 // Initialize application status
3087 int i;
3088 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
3089 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
3090 }
3091
3092 // Pickup the appropriate application status
3093 // that reflects sim_status for gsm.
3094 if (num_apps != 0) {
3095 p_card_status->num_applications = 3;
3096 p_card_status->gsm_umts_subscription_app_index = 0;
3097 p_card_status->cdma_subscription_app_index = 1;
3098 p_card_status->ims_subscription_app_index = 2;
3099
3100 // Get the correct app status
3101 p_card_status->applications[0] = app_status_array[sim_status];
3102 p_card_status->applications[1] = app_status_array[sim_status + RUIM_ABSENT];
3103 p_card_status->applications[2] = app_status_array[sim_status + ISIM_ABSENT];
3104 }
3105
3106 *pp_card_status = p_card_status;
3107 return RIL_E_SUCCESS;
3108 }
3109
3110 /**
3111 * Free the card status returned by getCardStatus
3112 */
3113 static void freeCardStatus(RIL_CardStatus_v6 *p_card_status) {
3114 free(p_card_status);
3115 }
3116
3117 /**
3118 * SIM ready means any commands that access the SIM will work, including:
3119 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
3120 * (all SMS-related commands)
3121 */
3122
3123 static void pollSIMState (void *param __unused)
3124 {
3125 ATResponse *p_response;
3126 int ret;
3127
3128 if (sState != RADIO_STATE_UNAVAILABLE) {
3129 // no longer valid to poll
3130 return;
3131 }
3132
3133 switch(getSIMStatus()) {
3134 case SIM_ABSENT:
3135 case SIM_PIN:
3136 case SIM_PUK:
3137 case SIM_NETWORK_PERSONALIZATION:
3138 default:
3139 RLOGI("SIM ABSENT or LOCKED");
3140 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
3141 return;
3142
3143 case SIM_NOT_READY:
3144 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
3145 return;
3146
3147 case SIM_READY:
3148 RLOGI("SIM_READY");
3149 onSIMReady();
3150 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
3151 return;
3152 }
3153 }
3154
3155 /** returns 1 if on, 0 if off, and -1 on error */
3156 static int isRadioOn()
3157 {
3158 ATResponse *p_response = NULL;
3159 int err;
3160 char *line;
3161 char ret;
3162
3163 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
3164
3165 if (err < 0 || p_response->success == 0) {
3166 // assume radio is off
3167 goto error;
3168 }
3169
3170 line = p_response->p_intermediates->line;
3171
3172 err = at_tok_start(&line);
3173 if (err < 0) goto error;
3174
3175 err = at_tok_nextbool(&line, &ret);
3176 if (err < 0) goto error;
3177
3178 at_response_free(p_response);
3179
3180 return (int)ret;
3181
3182 error:
3183
3184 at_response_free(p_response);
3185 return -1;
3186 }
3187
3188 /**
3189 * Parse the response generated by a +CTEC AT command
3190 * The values read from the response are stored in current and preferred.
3191 * Both current and preferred may be null. The corresponding value is ignored in that case.
3192 *
3193 * @return: -1 if some error occurs (or if the modem doesn't understand the +CTEC command)
3194 * 1 if the response includes the current technology only
3195 * 0 if the response includes both current technology and preferred mode
3196 */
3197 int parse_technology_response( const char *response, int *current, int32_t *preferred )
3198 {
3199 int err;
3200 char *line, *p;
3201 int ct;
3202 int32_t pt = 0;
3203 char *str_pt;
3204
3205 line = p = strdup(response);
3206 RLOGD("Response: %s", line);
3207 err = at_tok_start(&p);
3208 if (err || !at_tok_hasmore(&p)) {
3209 RLOGD("err: %d. p: %s", err, p);
3210 free(line);
3211 return -1;
3212 }
3213
3214 err = at_tok_nextint(&p, &ct);
3215 if (err) {
3216 free(line);
3217 return -1;
3218 }
3219 if (current) *current = ct;
3220
3221 RLOGD("line remaining after int: %s", p);
3222
3223 err = at_tok_nexthexint(&p, &pt);
3224 if (err) {
3225 free(line);
3226 return 1;
3227 }
3228 if (preferred) {
3229 *preferred = pt;
3230 }
3231 free(line);
3232
3233 return 0;
3234 }
3235
3236 int query_supported_techs( ModemInfo *mdm __unused, int *supported )
3237 {
3238 ATResponse *p_response;
3239 int err, val, techs = 0;
3240 char *tok;
3241 char *line;
3242
3243 RLOGD("query_supported_techs");
3244 err = at_send_command_singleline("AT+CTEC=?", "+CTEC:", &p_response);
3245 if (err || !p_response->success)
3246 goto error;
3247 line = p_response->p_intermediates->line;
3248 err = at_tok_start(&line);
3249 if (err || !at_tok_hasmore(&line))
3250 goto error;
3251 while (!at_tok_nextint(&line, &val)) {
3252 techs |= ( 1 << val );
3253 }
3254 if (supported) *supported = techs;
3255 return 0;
3256 error:
3257 at_response_free(p_response);
3258 return -1;
3259 }
3260
3261 /**
3262 * query_ctec. Send the +CTEC AT command to the modem to query the current
3263 * and preferred modes. It leaves values in the addresses pointed to by
3264 * current and preferred. If any of those pointers are NULL, the corresponding value
3265 * is ignored, but the return value will still reflect if retreiving and parsing of the
3266 * values suceeded.
3267 *
3268 * @mdm Currently unused
3269 * @current A pointer to store the current mode returned by the modem. May be null.
3270 * @preferred A pointer to store the preferred mode returned by the modem. May be null.
3271 * @return -1 on error (or failure to parse)
3272 * 1 if only the current mode was returned by modem (or failed to parse preferred)
3273 * 0 if both current and preferred were returned correctly
3274 */
3275 int query_ctec(ModemInfo *mdm __unused, int *current, int32_t *preferred)
3276 {
3277 ATResponse *response = NULL;
3278 int err;
3279 int res;
3280
3281 RLOGD("query_ctec. current: %p, preferred: %p", current, preferred);
3282 err = at_send_command_singleline("AT+CTEC?", "+CTEC:", &response);
3283 if (!err && response->success) {
3284 res = parse_technology_response(response->p_intermediates->line, current, preferred);
3285 at_response_free(response);
3286 return res;
3287 }
3288 RLOGE("Error executing command: %d. response: %p. status: %d", err, response, response? response->success : -1);
3289 at_response_free(response);
3290 return -1;
3291 }
3292
3293 int is_multimode_modem(ModemInfo *mdm)
3294 {
3295 ATResponse *response;
3296 int err;
3297 char *line;
3298 int tech;
3299 int32_t preferred;
3300
3301 if (query_ctec(mdm, &tech, &preferred) == 0) {
3302 mdm->currentTech = tech;
3303 mdm->preferredNetworkMode = preferred;
3304 if (query_supported_techs(mdm, &mdm->supportedTechs)) {
3305 return 0;
3306 }
3307 return 1;
3308 }
3309 return 0;
3310 }
3311
3312 /**
3313 * Find out if our modem is GSM, CDMA or both (Multimode)
3314 */
3315 static void probeForModemMode(ModemInfo *info)
3316 {
3317 ATResponse *response;
3318 int err;
3319 assert (info);
3320 // Currently, our only known multimode modem is qemu's android modem,
3321 // which implements the AT+CTEC command to query and set mode.
3322 // Try that first
3323
3324 if (is_multimode_modem(info)) {
3325 RLOGI("Found Multimode Modem. Supported techs mask: %8.8x. Current tech: %d",
3326 info->supportedTechs, info->currentTech);
3327 return;
3328 }
3329
3330 /* Being here means that our modem is not multimode */
3331 info->isMultimode = 0;
3332
3333 /* CDMA Modems implement the AT+WNAM command */
3334 err = at_send_command_singleline("AT+WNAM","+WNAM:", &response);
3335 if (!err && response->success) {
3336 at_response_free(response);
3337 // TODO: find out if we really support EvDo
3338 info->supportedTechs = MDM_CDMA | MDM_EVDO;
3339 info->currentTech = MDM_CDMA;
3340 RLOGI("Found CDMA Modem");
3341 return;
3342 }
3343 if (!err) at_response_free(response);
3344 // TODO: find out if modem really supports WCDMA/LTE
3345 info->supportedTechs = MDM_GSM | MDM_WCDMA | MDM_LTE;
3346 info->currentTech = MDM_GSM;
3347 RLOGI("Found GSM Modem");
3348 }
3349
3350 /**
3351 * Initialize everything that can be configured while we're still in
3352 * AT+CFUN=0
3353 */
3354 static void initializeCallback(void *param __unused)
3355 {
3356 ATResponse *p_response = NULL;
3357 int err;
3358
3359 setRadioState (RADIO_STATE_OFF);
3360
3361 at_handshake();
3362
3363 probeForModemMode(sMdmInfo);
3364 /* note: we don't check errors here. Everything important will
3365 be handled in onATTimeout and onATReaderClosed */
3366
3367 /* atchannel is tolerant of echo but it must */
3368 /* have verbose result codes */
3369 at_send_command("ATE0Q0V1", NULL);
3370
3371 /* No auto-answer */
3372 at_send_command("ATS0=0", NULL);
3373
3374 /* Extended errors */
3375 at_send_command("AT+CMEE=1", NULL);
3376
3377 /* Network registration events */
3378 err = at_send_command("AT+CREG=2", &p_response);
3379
3380 /* some handsets -- in tethered mode -- don't support CREG=2 */
3381 if (err < 0 || p_response->success == 0) {
3382 at_send_command("AT+CREG=1", NULL);
3383 }
3384
3385 at_response_free(p_response);
3386
3387 /* GPRS registration events */
3388 at_send_command("AT+CGREG=1", NULL);
3389
3390 /* Call Waiting notifications */
3391 at_send_command("AT+CCWA=1", NULL);
3392
3393 /* Alternating voice/data off */
3394 at_send_command("AT+CMOD=0", NULL);
3395
3396 /* Not muted */
3397 at_send_command("AT+CMUT=0", NULL);
3398
3399 /* +CSSU unsolicited supp service notifications */
3400 at_send_command("AT+CSSN=0,1", NULL);
3401
3402 /* no connected line identification */
3403 at_send_command("AT+COLP=0", NULL);
3404
3405 /* HEX character set */
3406 at_send_command("AT+CSCS=\"HEX\"", NULL);
3407
3408 /* USSD unsolicited */
3409 at_send_command("AT+CUSD=1", NULL);
3410
3411 /* Enable +CGEV GPRS event notifications, but don't buffer */
3412 at_send_command("AT+CGEREP=1,0", NULL);
3413
3414 /* SMS PDU mode */
3415 at_send_command("AT+CMGF=0", NULL);
3416
3417 #ifdef USE_TI_COMMANDS
3418
3419 at_send_command("AT%CPI=3", NULL);
3420
3421 /* TI specific -- notifications when SMS is ready (currently ignored) */
3422 at_send_command("AT%CSTAT=1", NULL);
3423
3424 #endif /* USE_TI_COMMANDS */
3425
3426
3427 /* assume radio is off on error */
3428 if (isRadioOn() > 0) {
3429 setRadioState (RADIO_STATE_ON);
3430 }
3431 }
3432
3433 static void waitForClose()
3434 {
3435 pthread_mutex_lock(&s_state_mutex);
3436
3437 while (s_closed == 0) {
3438 pthread_cond_wait(&s_state_cond, &s_state_mutex);
3439 }
3440
3441 pthread_mutex_unlock(&s_state_mutex);
3442 }
3443
3444 static void sendUnsolImsNetworkStateChanged()
3445 {
3446 #if 0 // to be used when unsol is changed to return data.
3447 int reply[2];
3448 reply[0] = s_ims_registered;
3449 reply[1] = s_ims_services;
3450 reply[1] = s_ims_format;
3451 #endif
3452 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED,
3453 NULL, 0);
3454 }
3455
3456 /**
3457 * Called by atchannel when an unsolicited line appears
3458 * This is called on atchannel's reader thread. AT commands may
3459 * not be issued here
3460 */
3461 static void onUnsolicited (const char *s, const char *sms_pdu)
3462 {
3463 char *line = NULL, *p;
3464 int err;
3465
3466 /* Ignore unsolicited responses until we're initialized.
3467 * This is OK because the RIL library will poll for initial state
3468 */
3469 if (sState == RADIO_STATE_UNAVAILABLE) {
3470 return;
3471 }
3472
3473 if (strStartsWith(s, "%CTZV:")) {
3474 /* TI specific -- NITZ time */
3475 char *response;
3476
3477 line = p = strdup(s);
3478 at_tok_start(&p);
3479
3480 err = at_tok_nextstr(&p, &response);
3481
3482 if (err != 0) {
3483 RLOGE("invalid NITZ line %s\n", s);
3484 } else {
3485 RIL_onUnsolicitedResponse (
3486 RIL_UNSOL_NITZ_TIME_RECEIVED,
3487 response, strlen(response) + 1);
3488 }
3489 free(line);
3490 } else if (strStartsWith(s,"+CRING:")
3491 || strStartsWith(s,"RING")
3492 || strStartsWith(s,"NO CARRIER")
3493 || strStartsWith(s,"+CCWA")
3494 ) {
3495 RIL_onUnsolicitedResponse (
3496 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
3497 NULL, 0);
3498 #ifdef WORKAROUND_FAKE_CGEV
3499 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
3500 #endif /* WORKAROUND_FAKE_CGEV */
3501 } else if (strStartsWith(s,"+CREG:")
3502 || strStartsWith(s,"+CGREG:")
3503 ) {
3504 RIL_onUnsolicitedResponse (
3505 RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
3506 NULL, 0);
3507 #ifdef WORKAROUND_FAKE_CGEV
3508 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
3509 #endif /* WORKAROUND_FAKE_CGEV */
3510 } else if (strStartsWith(s, "+CMT:")) {
3511 RIL_onUnsolicitedResponse (
3512 RIL_UNSOL_RESPONSE_NEW_SMS,
3513 sms_pdu, strlen(sms_pdu));
3514 } else if (strStartsWith(s, "+CDS:")) {
3515 RIL_onUnsolicitedResponse (
3516 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
3517 sms_pdu, strlen(sms_pdu));
3518 } else if (strStartsWith(s, "+CGEV:")) {
3519 /* Really, we can ignore NW CLASS and ME CLASS events here,
3520 * but right now we don't since extranous
3521 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
3522 */
3523 /* can't issue AT commands here -- call on main thread */
3524 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
3525 #ifdef WORKAROUND_FAKE_CGEV
3526 } else if (strStartsWith(s, "+CME ERROR: 150")) {
3527 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
3528 #endif /* WORKAROUND_FAKE_CGEV */
3529 } else if (strStartsWith(s, "+CTEC: ")) {
3530 int tech, mask;
3531 switch (parse_technology_response(s, &tech, NULL))
3532 {
3533 case -1: // no argument could be parsed.
3534 RLOGE("invalid CTEC line %s\n", s);
3535 break;
3536 case 1: // current mode correctly parsed
3537 case 0: // preferred mode correctly parsed
3538 mask = 1 << tech;
3539 if (mask != MDM_GSM && mask != MDM_CDMA &&
3540 mask != MDM_WCDMA && mask != MDM_LTE) {
3541 RLOGE("Unknown technology %d\n", tech);
3542 } else {
3543 setRadioTechnology(sMdmInfo, tech);
3544 }
3545 break;
3546 }
3547 } else if (strStartsWith(s, "+CCSS: ")) {
3548 int source = 0;
3549 line = p = strdup(s);
3550 if (!line) {
3551 RLOGE("+CCSS: Unable to allocate memory");
3552 return;
3553 }
3554 if (at_tok_start(&p) < 0) {
3555 free(line);
3556 return;
3557 }
3558 if (at_tok_nextint(&p, &source) < 0) {
3559 RLOGE("invalid +CCSS response: %s", line);
3560 free(line);
3561 return;
3562 }
3563 SSOURCE(sMdmInfo) = source;
3564 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,
3565 &source, sizeof(source));
3566 } else if (strStartsWith(s, "+WSOS: ")) {
3567 char state = 0;
3568 int unsol;
3569 line = p = strdup(s);
3570 if (!line) {
3571 RLOGE("+WSOS: Unable to allocate memory");
3572 return;
3573 }
3574 if (at_tok_start(&p) < 0) {
3575 free(line);
3576 return;
3577 }
3578 if (at_tok_nextbool(&p, &state) < 0) {
3579 RLOGE("invalid +WSOS response: %s", line);
3580 free(line);
3581 return;
3582 }
3583 free(line);
3584
3585 unsol = state ?
3586 RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE : RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
3587
3588 RIL_onUnsolicitedResponse(unsol, NULL, 0);
3589
3590 } else if (strStartsWith(s, "+WPRL: ")) {
3591 int version = -1;
3592 line = p = strdup(s);
3593 if (!line) {
3594 RLOGE("+WPRL: Unable to allocate memory");
3595 return;
3596 }
3597 if (at_tok_start(&p) < 0) {
3598 RLOGE("invalid +WPRL response: %s", s);
3599 free(line);
3600 return;
3601 }
3602 if (at_tok_nextint(&p, &version) < 0) {
3603 RLOGE("invalid +WPRL response: %s", s);
3604 free(line);
3605 return;
3606 }
3607 free(line);
3608 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_PRL_CHANGED, &version, sizeof(version));
3609 } else if (strStartsWith(s, "+CFUN: 0")) {
3610 setRadioState(RADIO_STATE_OFF);
3611 }
3612 }
3613
3614 /* Called on command or reader thread */
3615 static void onATReaderClosed()
3616 {
3617 RLOGI("AT channel closed\n");
3618 at_close();
3619 s_closed = 1;
3620
3621 setRadioState (RADIO_STATE_UNAVAILABLE);
3622 }
3623
3624 /* Called on command thread */
3625 static void onATTimeout()
3626 {
3627 RLOGI("AT channel timeout; closing\n");
3628 at_close();
3629
3630 s_closed = 1;
3631
3632 /* FIXME cause a radio reset here */
3633
3634 setRadioState (RADIO_STATE_UNAVAILABLE);
3635 }
3636
3637 /* Called to pass hardware configuration information to telephony
3638 * framework.
3639 */
3640 static void setHardwareConfiguration(int num, RIL_HardwareConfig *cfg)
3641 {
3642 RIL_onUnsolicitedResponse(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, cfg, num*sizeof(*cfg));
3643 }
3644
3645 static void usage(char *s __unused)
3646 {
3647 #ifdef RIL_SHLIB
3648 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
3649 #else
3650 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
3651 exit(-1);
3652 #endif
3653 }
3654
3655 static void *
3656 mainLoop(void *param __unused)
3657 {
3658 int fd;
3659 int ret;
3660
3661 AT_DUMP("== ", "entering mainLoop()", -1 );
3662 at_set_on_reader_closed(onATReaderClosed);
3663 at_set_on_timeout(onATTimeout);
3664
3665 for (;;) {
3666 fd = -1;
3667 while (fd < 0) {
3668 if (s_port > 0) {
3669 fd = socket_network_client("localhost", s_port, SOCK_STREAM);
3670 } else if (s_device_socket) {
3671 fd = socket_local_client(s_device_path,
3672 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
3673 SOCK_STREAM);
3674 } else if (s_device_path != NULL) {
3675 fd = open (s_device_path, O_RDWR);
3676 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
3677 /* disable echo on serial ports */
3678 struct termios ios;
3679 tcgetattr( fd, &ios );
3680 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
3681 tcsetattr( fd, TCSANOW, &ios );
3682 }
3683 }
3684
3685 if (fd < 0) {
3686 perror ("opening AT interface. retrying...");
3687 sleep(10);
3688 /* never returns */
3689 }
3690 }
3691
3692 s_closed = 0;
3693 ret = at_open(fd, onUnsolicited);
3694
3695 if (ret < 0) {
3696 RLOGE ("AT error %d on at_open\n", ret);
3697 return 0;
3698 }
3699
3700 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
3701
3702 // Give initializeCallback a chance to dispatched, since
3703 // we don't presently have a cancellation mechanism
3704 sleep(1);
3705
3706 waitForClose();
3707 RLOGI("Re-opening after close");
3708 }
3709 }
3710
3711 #ifdef RIL_SHLIB
3712
3713 pthread_t s_tid_mainloop;
3714
3715 const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
3716 {
3717 int ret;
3718 int fd = -1;
3719 int opt;
3720 pthread_attr_t attr;
3721
3722 s_rilenv = env;
3723
3724 while ( -1 != (opt = getopt(argc, argv, "p:d:s:c:"))) {
3725 switch (opt) {
3726 case 'p':
3727 s_port = atoi(optarg);
3728 if (s_port == 0) {
3729 usage(argv[0]);
3730 return NULL;
3731 }
3732 RLOGI("Opening loopback port %d\n", s_port);
3733 break;
3734
3735 case 'd':
3736 s_device_path = optarg;
3737 RLOGI("Opening tty device %s\n", s_device_path);
3738 break;
3739
3740 case 's':
3741 s_device_path = optarg;
3742 s_device_socket = 1;
3743 RLOGI("Opening socket %s\n", s_device_path);
3744 break;
3745
3746 case 'c':
3747 RLOGI("Client id received %s\n", optarg);
3748 break;
3749
3750 default:
3751 usage(argv[0]);
3752 return NULL;
3753 }
3754 }
3755
3756 if (s_port < 0 && s_device_path == NULL) {
3757 usage(argv[0]);
3758 return NULL;
3759 }
3760
3761 sMdmInfo = calloc(1, sizeof(ModemInfo));
3762 if (!sMdmInfo) {
3763 RLOGE("Unable to alloc memory for ModemInfo");
3764 return NULL;
3765 }
3766 pthread_attr_init (&attr);
3767 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3768 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
3769
3770 return &s_callbacks;
3771 }
3772 #else /* RIL_SHLIB */
3773 int main (int argc, char **argv)
3774 {
3775 int ret;
3776 int fd = -1;
3777 int opt;
3778
3779 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
3780 switch (opt) {
3781 case 'p':
3782 s_port = atoi(optarg);
3783 if (s_port == 0) {
3784 usage(argv[0]);
3785 }
3786 RLOGI("Opening loopback port %d\n", s_port);
3787 break;
3788
3789 case 'd':
3790 s_device_path = optarg;
3791 RLOGI("Opening tty device %s\n", s_device_path);
3792 break;
3793
3794 case 's':
3795 s_device_path = optarg;
3796 s_device_socket = 1;
3797 RLOGI("Opening socket %s\n", s_device_path);
3798 break;
3799
3800 default:
3801 usage(argv[0]);
3802 }
3803 }
3804
3805 if (s_port < 0 && s_device_path == NULL) {
3806 usage(argv[0]);
3807 }
3808
3809 RIL_register(&s_callbacks);
3810
3811 mainLoop(NULL);
3812
3813 return 0;
3814 }
3815
3816 #endif /* RIL_SHLIB */
3817