blob: 1a1eb9baebd24a57ab77603acaba86c388e29432 [file] [log] [blame]
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001/* //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
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -070018#include <telephony/ril_cdma_sms.h>
Wink Saville8a9e0212013-04-09 12:11:38 -070019#include <telephony/librilutils.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080020#include <stdio.h>
21#include <assert.h>
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
Mark Salyzynba58c202014-03-12 15:20:22 -070025#include <sys/cdefs.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080026#include <sys/types.h>
27#include <sys/stat.h>
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -070028#include <inttypes.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080029#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/sockets.h>
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +010038#include <sys/system_properties.h>
Weilun Du9f471e22017-02-07 10:47:19 -080039#include <termios.h>
bohuba723ce2017-03-29 12:20:46 -070040#include <qemu_pipe.h>
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -070041#include <sys/wait.h>
42#include <stdbool.h>
43#include <net/if.h>
44#include <netinet/in.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080045
Wink Saville9a9fbd22011-02-15 17:13:10 -080046#include "ril.h"
47
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080048#define LOG_TAG "RIL"
49#include <utils/Log.h>
50
Etan Cohend3652192014-06-20 08:28:44 -070051static void *noopRemoveWarning( void *a ) { return a; }
52#define RIL_UNUSED_PARM(a) noopRemoveWarning((void *)&(a));
53
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080054#define MAX_AT_RESPONSE 0x1000
55
Wink Savillef4c4d362009-04-02 01:37:03 -070056/* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
Bjoern Johanssona8bec892017-02-09 22:55:02 -080057// This is used if Wifi is not supported, plain old eth0
58#define PPP_TTY_PATH_ETH0 "eth0"
59// This is used if Wifi is supported to separate radio and wifi interface
60#define PPP_TTY_PATH_RADIO0 "radio0"
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080061
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -070062// Default MTU value
63#define DEFAULT_MTU 1500
64
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080065#ifdef USE_TI_COMMANDS
66
67// Enable a workaround
68// 1) Make incoming call, do not answer
69// 2) Hangup remote end
70// Expected: call should disappear from CLCC line
71// Actual: Call shows as "ACTIVE" before disappearing
72#define WORKAROUND_ERRONEOUS_ANSWER 1
73
74// Some varients of the TI stack do not support the +CGEV unsolicited
75// response. However, they seem to send an unsolicited +CME ERROR: 150
76#define WORKAROUND_FAKE_CGEV 1
77#endif
78
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -070079/* Modem Technology bits */
80#define MDM_GSM 0x01
81#define MDM_WCDMA 0x02
82#define MDM_CDMA 0x04
83#define MDM_EVDO 0x08
84#define MDM_LTE 0x10
85
86typedef struct {
87 int supportedTechs; // Bitmask of supported Modem Technology bits
88 int currentTech; // Technology the modem is currently using (in the format used by modem)
89 int isMultimode;
90
91 // Preferred mode bitmask. This is actually 4 byte-sized bitmasks with different priority values,
92 // in which the byte number from LSB to MSB give the priority.
93 //
94 // |MSB| | |LSB
95 // value: |00 |00 |00 |00
96 // byte #: |3 |2 |1 |0
97 //
98 // Higher byte order give higher priority. Thus, a value of 0x0000000f represents
99 // a preferred mode of GSM, WCDMA, CDMA, and EvDo in which all are equally preferrable, whereas
100 // 0x00000201 represents a mode with GSM and WCDMA, in which WCDMA is preferred over GSM
101 int32_t preferredNetworkMode;
102 int subscription_source;
103
104} ModemInfo;
105
106static ModemInfo *sMdmInfo;
107// TECH returns the current technology in the format used by the modem.
108// It can be used as an l-value
109#define TECH(mdminfo) ((mdminfo)->currentTech)
110// TECH_BIT returns the bitmask equivalent of the current tech
111#define TECH_BIT(mdminfo) (1 << ((mdminfo)->currentTech))
112#define IS_MULTIMODE(mdminfo) ((mdminfo)->isMultimode)
113#define TECH_SUPPORTED(mdminfo, tech) ((mdminfo)->supportedTechs & (tech))
114#define PREFERRED_NETWORK(mdminfo) ((mdminfo)->preferredNetworkMode)
115// CDMA Subscription Source
116#define SSOURCE(mdminfo) ((mdminfo)->subscription_source)
117
118static int net2modem[] = {
119 MDM_GSM | MDM_WCDMA, // 0 - GSM / WCDMA Pref
120 MDM_GSM, // 1 - GSM only
121 MDM_WCDMA, // 2 - WCDMA only
122 MDM_GSM | MDM_WCDMA, // 3 - GSM / WCDMA Auto
123 MDM_CDMA | MDM_EVDO, // 4 - CDMA / EvDo Auto
124 MDM_CDMA, // 5 - CDMA only
125 MDM_EVDO, // 6 - EvDo only
126 MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO, // 7 - GSM/WCDMA, CDMA, EvDo
127 MDM_LTE | MDM_CDMA | MDM_EVDO, // 8 - LTE, CDMA and EvDo
128 MDM_LTE | MDM_GSM | MDM_WCDMA, // 9 - LTE, GSM/WCDMA
129 MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA, // 10 - LTE, CDMA, EvDo, GSM/WCDMA
130 MDM_LTE, // 11 - LTE only
131};
132
133static int32_t net2pmask[] = {
134 MDM_GSM | (MDM_WCDMA << 8), // 0 - GSM / WCDMA Pref
135 MDM_GSM, // 1 - GSM only
136 MDM_WCDMA, // 2 - WCDMA only
137 MDM_GSM | MDM_WCDMA, // 3 - GSM / WCDMA Auto
138 MDM_CDMA | MDM_EVDO, // 4 - CDMA / EvDo Auto
139 MDM_CDMA, // 5 - CDMA only
140 MDM_EVDO, // 6 - EvDo only
141 MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO, // 7 - GSM/WCDMA, CDMA, EvDo
142 MDM_LTE | MDM_CDMA | MDM_EVDO, // 8 - LTE, CDMA and EvDo
143 MDM_LTE | MDM_GSM | MDM_WCDMA, // 9 - LTE, GSM/WCDMA
144 MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA, // 10 - LTE, CDMA, EvDo, GSM/WCDMA
145 MDM_LTE, // 11 - LTE only
146};
147
148static int is3gpp2(int radioTech) {
149 switch (radioTech) {
150 case RADIO_TECH_IS95A:
151 case RADIO_TECH_IS95B:
152 case RADIO_TECH_1xRTT:
153 case RADIO_TECH_EVDO_0:
154 case RADIO_TECH_EVDO_A:
155 case RADIO_TECH_EVDO_B:
156 case RADIO_TECH_EHRPD:
157 return 1;
158 default:
159 return 0;
160 }
161}
162
John Wang309ac292009-07-30 14:53:23 -0700163typedef enum {
164 SIM_ABSENT = 0,
165 SIM_NOT_READY = 1,
Naveen Kalla2baf7232016-10-11 13:49:20 -0700166 SIM_READY = 2,
John Wang309ac292009-07-30 14:53:23 -0700167 SIM_PIN = 3,
168 SIM_PUK = 4,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700169 SIM_NETWORK_PERSONALIZATION = 5,
170 RUIM_ABSENT = 6,
171 RUIM_NOT_READY = 7,
172 RUIM_READY = 8,
173 RUIM_PIN = 9,
174 RUIM_PUK = 10,
bohu076e6872017-07-02 21:33:28 -0700175 RUIM_NETWORK_PERSONALIZATION = 11,
176 ISIM_ABSENT = 12,
177 ISIM_NOT_READY = 13,
178 ISIM_READY = 14,
179 ISIM_PIN = 15,
180 ISIM_PUK = 16,
181 ISIM_NETWORK_PERSONALIZATION = 17,
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100182} SIM_Status;
John Wang309ac292009-07-30 14:53:23 -0700183
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800184static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
185static RIL_RadioState currentState();
186static int onSupports (int requestCode);
187static void onCancel (RIL_Token t);
188static const char *getVersion();
189static int isRadioOn();
John Wang309ac292009-07-30 14:53:23 -0700190static SIM_Status getSIMStatus();
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700191static int getCardStatus(RIL_CardStatus_v6 **pp_card_status);
192static void freeCardStatus(RIL_CardStatus_v6 *p_card_status);
Wink Savillef4c4d362009-04-02 01:37:03 -0700193static void onDataCallListChanged(void *param);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800194
195extern const char * requestToString(int request);
196
197/*** Static Variables ***/
198static const RIL_RadioFunctions s_callbacks = {
199 RIL_VERSION,
200 onRequest,
201 currentState,
202 onSupports,
203 onCancel,
204 getVersion
205};
206
207#ifdef RIL_SHLIB
208static const struct RIL_Env *s_rilenv;
209
210#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
211#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
212#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
213#endif
214
215static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
216
217static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
218static pthread_cond_t s_state_cond = PTHREAD_COND_INITIALIZER;
219
220static int s_port = -1;
221static const char * s_device_path = NULL;
222static int s_device_socket = 0;
223
224/* trigger change to this with s_state_cond */
225static int s_closed = 0;
226
227static int sFD; /* file desc of AT channel */
228static char sATBuffer[MAX_AT_RESPONSE+1];
229static char *sATBufferCur = NULL;
230
231static const struct timeval TIMEVAL_SIMPOLL = {1,0};
232static const struct timeval TIMEVAL_CALLSTATEPOLL = {0,500000};
233static const struct timeval TIMEVAL_0 = {0,0};
234
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -0700235static int s_ims_registered = 0; // 0==unregistered
236static int s_ims_services = 1; // & 0x1 == sms over ims supported
237static int s_ims_format = 1; // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
238static int s_ims_cause_retry = 0; // 1==causes sms over ims to temp fail
239static int s_ims_cause_perm_failure = 0; // 1==causes sms over ims to permanent fail
240static int s_ims_gsm_retry = 0; // 1==causes sms over gsm to temp fail
241static int s_ims_gsm_fail = 0; // 1==causes sms over gsm to permanent fail
242
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800243#ifdef WORKAROUND_ERRONEOUS_ANSWER
244// Max number of times we'll try to repoll when we think
245// we have a AT+CLCC race condition
246#define REPOLL_CALLS_COUNT_MAX 4
247
248// Line index that was incoming or waiting at last poll, or -1 for none
249static int s_incomingOrWaitingLine = -1;
250// Number of times we've asked for a repoll of AT+CLCC
251static int s_repollCallsCount = 0;
252// Should we expect a call to be answered in the next CLCC?
253static int s_expectAnswer = 0;
254#endif /* WORKAROUND_ERRONEOUS_ANSWER */
255
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200256
Wink Saville8a9e0212013-04-09 12:11:38 -0700257static int s_cell_info_rate_ms = INT_MAX;
258static int s_mcc = 0;
259static int s_mnc = 0;
260static int s_lac = 0;
261static int s_cid = 0;
262
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800263static void pollSIMState (void *param);
264static void setRadioState(RIL_RadioState newState);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700265static void setRadioTechnology(ModemInfo *mdm, int newtech);
266static int query_ctec(ModemInfo *mdm, int *current, int32_t *preferred);
267static int parse_technology_response(const char *response, int *current, int32_t *preferred);
268static int techFromModemType(int mdmtype);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800269
270static int clccStateToRILState(int state, RIL_CallState *p_state)
271
272{
273 switch(state) {
274 case 0: *p_state = RIL_CALL_ACTIVE; return 0;
275 case 1: *p_state = RIL_CALL_HOLDING; return 0;
276 case 2: *p_state = RIL_CALL_DIALING; return 0;
277 case 3: *p_state = RIL_CALL_ALERTING; return 0;
278 case 4: *p_state = RIL_CALL_INCOMING; return 0;
279 case 5: *p_state = RIL_CALL_WAITING; return 0;
280 default: return -1;
281 }
282}
283
284/**
285 * Note: directly modified line and has *p_call point directly into
286 * modified line
287 */
Wink Saville3d54e742009-05-18 18:00:44 -0700288static int callFromCLCCLine(char *line, RIL_Call *p_call)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800289{
290 //+CLCC: 1,0,2,0,0,\"+18005551212\",145
291 // index,isMT,state,mode,isMpty(,number,TOA)?
292
293 int err;
294 int state;
295 int mode;
296
297 err = at_tok_start(&line);
298 if (err < 0) goto error;
299
300 err = at_tok_nextint(&line, &(p_call->index));
301 if (err < 0) goto error;
302
303 err = at_tok_nextbool(&line, &(p_call->isMT));
304 if (err < 0) goto error;
305
306 err = at_tok_nextint(&line, &state);
307 if (err < 0) goto error;
308
309 err = clccStateToRILState(state, &(p_call->state));
310 if (err < 0) goto error;
311
312 err = at_tok_nextint(&line, &mode);
313 if (err < 0) goto error;
314
315 p_call->isVoice = (mode == 0);
316
317 err = at_tok_nextbool(&line, &(p_call->isMpty));
318 if (err < 0) goto error;
319
320 if (at_tok_hasmore(&line)) {
321 err = at_tok_nextstr(&line, &(p_call->number));
322
323 /* tolerate null here */
324 if (err < 0) return 0;
325
326 // Some lame implementations return strings
327 // like "NOT AVAILABLE" in the CLCC line
328 if (p_call->number != NULL
329 && 0 == strspn(p_call->number, "+0123456789")
330 ) {
331 p_call->number = NULL;
332 }
333
334 err = at_tok_nextint(&line, &p_call->toa);
335 if (err < 0) goto error;
336 }
337
Wink Saville74fa3882009-12-22 15:35:41 -0800338 p_call->uusInfo = NULL;
339
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800340 return 0;
341
342error:
Wink Saville4dcab4f2012-11-19 16:05:13 -0800343 RLOGE("invalid CLCC line\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800344 return -1;
345}
346
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -0700347static int parseSimResponseLine(char* line, RIL_SIM_IO_Response* response) {
348 int err;
349
350 err = at_tok_start(&line);
351 if (err < 0) return err;
352 err = at_tok_nextint(&line, &response->sw1);
353 if (err < 0) return err;
354 err = at_tok_nextint(&line, &response->sw2);
355 if (err < 0) return err;
356
357 if (at_tok_hasmore(&line)) {
358 err = at_tok_nextstr(&line, &response->simResponse);
359 if (err < 0) return err;
360 }
361 return 0;
362}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800363
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -0700364enum InterfaceState {
365 kInterfaceUp,
366 kInterfaceDown,
367};
368
369static RIL_Errno setInterfaceState(const char* interfaceName,
370 enum InterfaceState state) {
371 struct ifreq request;
372 int status = 0;
373 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
374 if (sock == -1) {
375 RLOGE("Failed to open interface socket: %s (%d)",
376 strerror(errno), errno);
377 return RIL_E_GENERIC_FAILURE;
378 }
379
380 memset(&request, 0, sizeof(request));
381 strncpy(request.ifr_name, interfaceName, sizeof(request.ifr_name));
382 request.ifr_name[sizeof(request.ifr_name) - 1] = '\0';
383 status = ioctl(sock, SIOCGIFFLAGS, &request);
384 if (status != 0) {
385 RLOGE("Failed to get interface flags for %s: %s (%d)",
386 interfaceName, strerror(errno), errno);
387 close(sock);
388 return RIL_E_RADIO_NOT_AVAILABLE;
389 }
390
391 bool isUp = (request.ifr_flags & IFF_UP);
392 if ((state == kInterfaceUp && isUp) || (state == kInterfaceDown && !isUp)) {
393 // Interface already in desired state
394 close(sock);
395 return RIL_E_SUCCESS;
396 }
397
398 // Simply toggle the flag since we know it's the opposite of what we want
399 request.ifr_flags ^= IFF_UP;
400
401 status = ioctl(sock, SIOCSIFFLAGS, &request);
402 if (status != 0) {
403 RLOGE("Failed to set interface flags for %s: %s (%d)",
404 interfaceName, strerror(errno), errno);
405 close(sock);
406 return RIL_E_GENERIC_FAILURE;
407 }
408
409 close(sock);
410 return RIL_E_SUCCESS;
411}
412
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800413/** do post-AT+CFUN=1 initialization */
414static void onRadioPowerOn()
415{
416#ifdef USE_TI_COMMANDS
417 /* Must be after CFUN=1 */
418 /* TI specific -- notifications for CPHS things such */
419 /* as CPHS message waiting indicator */
420
421 at_send_command("AT%CPHS=1", NULL);
422
423 /* TI specific -- enable NITZ unsol notifs */
424 at_send_command("AT%CTZV=1", NULL);
425#endif
426
427 pollSIMState(NULL);
428}
429
430/** do post- SIM ready initialization */
431static void onSIMReady()
432{
433 at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
434 /*
435 * Always send SMS messages directly to the TE
436 *
437 * mode = 1 // discard when link is reserved (link should never be
438 * reserved)
439 * mt = 2 // most messages routed to TE
440 * bm = 2 // new cell BM's routed to TE
441 * ds = 1 // Status reports routed to TE
442 * bfr = 1 // flush buffer
443 */
444 at_send_command("AT+CNMI=1,2,2,1,1", NULL);
445}
446
Sanket Padawef0c8ca72016-06-30 15:01:08 -0700447static void requestRadioPower(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800448{
449 int onOff;
450
451 int err;
452 ATResponse *p_response = NULL;
453
454 assert (datalen >= sizeof(int *));
455 onOff = ((int *)data)[0];
456
457 if (onOff == 0 && sState != RADIO_STATE_OFF) {
458 err = at_send_command("AT+CFUN=0", &p_response);
Jim Kayeb6f3f7e2017-12-07 14:06:22 -0800459 if (err < 0 || p_response->success == 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800460 setRadioState(RADIO_STATE_OFF);
461 } else if (onOff > 0 && sState == RADIO_STATE_OFF) {
462 err = at_send_command("AT+CFUN=1", &p_response);
463 if (err < 0|| p_response->success == 0) {
464 // Some stacks return an error when there is no SIM,
465 // but they really turn the RF portion on
466 // So, if we get an error, let's check to see if it
467 // turned on anyway
468
469 if (isRadioOn() != 1) {
470 goto error;
471 }
472 }
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700473 setRadioState(RADIO_STATE_ON);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800474 }
475
476 at_response_free(p_response);
477 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
478 return;
479error:
480 at_response_free(p_response);
481 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
482}
483
Naveen Kallaa65a16a2014-07-31 16:48:31 -0700484static void requestShutdown(RIL_Token t)
485{
486 int onOff;
487
488 int err;
489 ATResponse *p_response = NULL;
490
491 if (sState != RADIO_STATE_OFF) {
492 err = at_send_command("AT+CFUN=0", &p_response);
493 setRadioState(RADIO_STATE_UNAVAILABLE);
494 }
495
496 at_response_free(p_response);
497 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
498 return;
499}
500
Wink Savillef4c4d362009-04-02 01:37:03 -0700501static void requestOrSendDataCallList(RIL_Token *t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800502
Mark Salyzynba58c202014-03-12 15:20:22 -0700503static void onDataCallListChanged(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800504{
Wink Savillef4c4d362009-04-02 01:37:03 -0700505 requestOrSendDataCallList(NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800506}
507
Mark Salyzynba58c202014-03-12 15:20:22 -0700508static void requestDataCallList(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800509{
Wink Savillef4c4d362009-04-02 01:37:03 -0700510 requestOrSendDataCallList(&t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800511}
512
Jim Kayeb6f3f7e2017-12-07 14:06:22 -0800513// Hang up, reject, conference, call waiting
514static void requestCallSelection(
515 void *data __unused, size_t datalen __unused, RIL_Token t, int request)
516{
517 // 3GPP 22.030 6.5.5
518 static char hangupWaiting[] = "AT+CHLD=0";
519 static char hangupForeground[] = "AT+CHLD=1";
520 static char switchWaiting[] = "AT+CHLD=2";
521 static char conference[] = "AT+CHLD=3";
522 static char reject[] = "ATH";
523
524 char* atCommand;
525
526 if (getSIMStatus() == SIM_ABSENT) {
527 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
528 return;
529 }
530
531 switch(request) {
532 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
533 // "Releases all held calls or sets User Determined User Busy
534 // (UDUB) for a waiting call."
535 atCommand = hangupWaiting;
536 break;
537 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
538 // "Releases all active calls (if any exist) and accepts
539 // the other (held or waiting) call."
540 atCommand = hangupForeground;
541 break;
542 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
543 // "Places all active calls (if any exist) on hold and accepts
544 // the other (held or waiting) call."
545 atCommand = switchWaiting;
546#ifdef WORKAROUND_ERRONEOUS_ANSWER
547 s_expectAnswer = 1;
548#endif /* WORKAROUND_ERRONEOUS_ANSWER */
549 break;
550 case RIL_REQUEST_CONFERENCE:
551 // "Adds a held call to the conversation"
552 atCommand = conference;
553 break;
554 case RIL_REQUEST_UDUB:
555 // User determined user busy (reject)
556 atCommand = reject;
557 break;
558 default:
559 assert(0);
560 }
561 at_send_command(atCommand, NULL);
562 // Success or failure is ignored by the upper layer here.
563 // It will call GET_CURRENT_CALLS and determine success that way.
564 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
565}
566
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -0700567static bool hasWifiCapability()
Bjoern Johanssona8bec892017-02-09 22:55:02 -0800568{
569 char propValue[PROP_VALUE_MAX];
570 return __system_property_get("ro.kernel.qemu.wifi", propValue) != 0 &&
571 strcmp("1", propValue) == 0;
572}
573
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -0700574static const char* getRadioInterfaceName(bool hasWifi)
575{
576 return hasWifi ? PPP_TTY_PATH_RADIO0 : PPP_TTY_PATH_ETH0;
577}
578
Wink Savillef4c4d362009-04-02 01:37:03 -0700579static void requestOrSendDataCallList(RIL_Token *t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800580{
581 ATResponse *p_response;
582 ATLine *p_cur;
583 int err;
584 int n = 0;
585 char *out;
Bjoern Johanssona8bec892017-02-09 22:55:02 -0800586 char propValue[PROP_VALUE_MAX];
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -0700587 bool hasWifi = hasWifiCapability();
588 const char* radioInterfaceName = getRadioInterfaceName(hasWifi);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800589
590 err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &p_response);
591 if (err != 0 || p_response->success == 0) {
592 if (t != NULL)
593 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
594 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700595 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800596 NULL, 0);
597 return;
598 }
599
600 for (p_cur = p_response->p_intermediates; p_cur != NULL;
601 p_cur = p_cur->p_next)
602 n++;
603
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700604 RIL_Data_Call_Response_v11 *responses =
605 alloca(n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800606
607 int i;
608 for (i = 0; i < n; i++) {
Wink Saville43808972011-01-13 17:39:51 -0800609 responses[i].status = -1;
Wink Saville250eb3c2011-06-22 09:11:34 -0700610 responses[i].suggestedRetryTime = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800611 responses[i].cid = -1;
612 responses[i].active = -1;
613 responses[i].type = "";
Wink Saville43808972011-01-13 17:39:51 -0800614 responses[i].ifname = "";
615 responses[i].addresses = "";
616 responses[i].dnses = "";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700617 responses[i].gateways = "";
Etan Cohend3652192014-06-20 08:28:44 -0700618 responses[i].pcscf = "";
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700619 responses[i].mtu = 0;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800620 }
621
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700622 RIL_Data_Call_Response_v11 *response = responses;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800623 for (p_cur = p_response->p_intermediates; p_cur != NULL;
624 p_cur = p_cur->p_next) {
625 char *line = p_cur->line;
626
627 err = at_tok_start(&line);
628 if (err < 0)
629 goto error;
630
631 err = at_tok_nextint(&line, &response->cid);
632 if (err < 0)
633 goto error;
634
635 err = at_tok_nextint(&line, &response->active);
636 if (err < 0)
637 goto error;
638
639 response++;
640 }
641
642 at_response_free(p_response);
643
644 err = at_send_command_multiline ("AT+CGDCONT?", "+CGDCONT:", &p_response);
645 if (err != 0 || p_response->success == 0) {
646 if (t != NULL)
647 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
648 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700649 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800650 NULL, 0);
651 return;
652 }
653
654 for (p_cur = p_response->p_intermediates; p_cur != NULL;
655 p_cur = p_cur->p_next) {
656 char *line = p_cur->line;
657 int cid;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800658
659 err = at_tok_start(&line);
660 if (err < 0)
661 goto error;
662
663 err = at_tok_nextint(&line, &cid);
664 if (err < 0)
665 goto error;
666
667 for (i = 0; i < n; i++) {
668 if (responses[i].cid == cid)
669 break;
670 }
671
672 if (i >= n) {
673 /* details for a context we didn't hear about in the last request */
674 continue;
675 }
676
Wink Saville43808972011-01-13 17:39:51 -0800677 // Assume no error
678 responses[i].status = 0;
679
680 // type
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800681 err = at_tok_nextstr(&line, &out);
682 if (err < 0)
683 goto error;
Naina Nalluri2be38ac2016-05-03 14:09:53 -0700684
685 int type_size = strlen(out) + 1;
686 responses[i].type = alloca(type_size);
687 strlcpy(responses[i].type, out, type_size);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800688
Wink Saville43808972011-01-13 17:39:51 -0800689 // APN ignored for v5
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800690 err = at_tok_nextstr(&line, &out);
691 if (err < 0)
692 goto error;
693
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -0700694 int ifname_size = strlen(radioInterfaceName) + 1;
695 responses[i].ifname = alloca(ifname_size);
696 strlcpy(responses[i].ifname, radioInterfaceName, ifname_size);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800697
698 err = at_tok_nextstr(&line, &out);
699 if (err < 0)
700 goto error;
701
Naina Nalluri2be38ac2016-05-03 14:09:53 -0700702 int addresses_size = strlen(out) + 1;
703 responses[i].addresses = alloca(addresses_size);
704 strlcpy(responses[i].addresses, out, addresses_size);
Wink Saville43808972011-01-13 17:39:51 -0800705
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200706 if (isInEmulator()) {
707 /* We are in the emulator - the dns servers are listed
708 * by the following system properties, setup in
709 * /system/etc/init.goldfish.sh:
710 * - net.eth0.dns1
711 * - net.eth0.dns2
712 * - net.eth0.dns3
713 * - net.eth0.dns4
714 */
715 const int dnslist_sz = 128;
716 char* dnslist = alloca(dnslist_sz);
717 const char* separator = "";
718 int nn;
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100719
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200720 dnslist[0] = 0;
721 for (nn = 1; nn <= 4; nn++) {
722 /* Probe net.eth0.dns<n> */
723 char propName[PROP_NAME_MAX];
724 char propValue[PROP_VALUE_MAX];
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100725
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200726 snprintf(propName, sizeof propName, "net.eth0.dns%d", nn);
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100727
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200728 /* Ignore if undefined */
729 if (__system_property_get(propName, propValue) == 0) {
730 continue;
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100731 }
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700732
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200733 /* Append the DNS IP address */
734 strlcat(dnslist, separator, dnslist_sz);
735 strlcat(dnslist, propValue, dnslist_sz);
736 separator = " ";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100737 }
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200738 responses[i].dnses = dnslist;
739
Bjoern Johanssona8bec892017-02-09 22:55:02 -0800740 /* There is only one gateway in the emulator. If WiFi is
741 * configured the interface visible to RIL will be behind a NAT
742 * where the gateway is different. */
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -0700743 responses[i].gateways = hasWifi ? "192.168.200.1" : "10.0.2.2";
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200744 responses[i].mtu = DEFAULT_MTU;
745 }
746 else {
747 /* I don't know where we are, so use the public Google DNS
748 * servers by default and no gateway.
749 */
750 responses[i].dnses = "8.8.8.8 8.8.4.4";
751 responses[i].gateways = "";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100752 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800753 }
754
755 at_response_free(p_response);
756
757 if (t != NULL)
758 RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700759 n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800760 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700761 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800762 responses,
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700763 n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800764
765 return;
766
767error:
768 if (t != NULL)
769 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
770 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700771 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800772 NULL, 0);
773
774 at_response_free(p_response);
775}
776
777static void requestQueryNetworkSelectionMode(
Mark Salyzynba58c202014-03-12 15:20:22 -0700778 void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800779{
780 int err;
781 ATResponse *p_response = NULL;
782 int response = 0;
783 char *line;
784
785 err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response);
786
787 if (err < 0 || p_response->success == 0) {
788 goto error;
789 }
790
791 line = p_response->p_intermediates->line;
792
793 err = at_tok_start(&line);
794
795 if (err < 0) {
796 goto error;
797 }
798
799 err = at_tok_nextint(&line, &response);
800
801 if (err < 0) {
802 goto error;
803 }
804
805 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
806 at_response_free(p_response);
807 return;
808error:
809 at_response_free(p_response);
Wink Saville4dcab4f2012-11-19 16:05:13 -0800810 RLOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800811 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
812}
813
Mark Salyzynba58c202014-03-12 15:20:22 -0700814static void sendCallStateChanged(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800815{
816 RIL_onUnsolicitedResponse (
817 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
818 NULL, 0);
819}
820
Mark Salyzynba58c202014-03-12 15:20:22 -0700821static void requestGetCurrentCalls(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800822{
823 int err;
824 ATResponse *p_response;
825 ATLine *p_cur;
826 int countCalls;
827 int countValidCalls;
Wink Saville3d54e742009-05-18 18:00:44 -0700828 RIL_Call *p_calls;
829 RIL_Call **pp_calls;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800830 int i;
831 int needRepoll = 0;
832
833#ifdef WORKAROUND_ERRONEOUS_ANSWER
834 int prevIncomingOrWaitingLine;
835
836 prevIncomingOrWaitingLine = s_incomingOrWaitingLine;
837 s_incomingOrWaitingLine = -1;
838#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
839
840 err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
841
842 if (err != 0 || p_response->success == 0) {
843 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
844 return;
845 }
846
847 /* count the calls */
848 for (countCalls = 0, p_cur = p_response->p_intermediates
849 ; p_cur != NULL
850 ; p_cur = p_cur->p_next
851 ) {
852 countCalls++;
853 }
854
855 /* yes, there's an array of pointers and then an array of structures */
856
Wink Saville3d54e742009-05-18 18:00:44 -0700857 pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
858 p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
859 memset (p_calls, 0, countCalls * sizeof(RIL_Call));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800860
861 /* init the pointer array */
862 for(i = 0; i < countCalls ; i++) {
863 pp_calls[i] = &(p_calls[i]);
864 }
865
866 for (countValidCalls = 0, p_cur = p_response->p_intermediates
867 ; p_cur != NULL
868 ; p_cur = p_cur->p_next
869 ) {
870 err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
871
872 if (err != 0) {
873 continue;
874 }
875
876#ifdef WORKAROUND_ERRONEOUS_ANSWER
877 if (p_calls[countValidCalls].state == RIL_CALL_INCOMING
878 || p_calls[countValidCalls].state == RIL_CALL_WAITING
879 ) {
880 s_incomingOrWaitingLine = p_calls[countValidCalls].index;
881 }
882#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
883
884 if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
885 && p_calls[countValidCalls].state != RIL_CALL_HOLDING
886 ) {
887 needRepoll = 1;
888 }
889
890 countValidCalls++;
891 }
892
893#ifdef WORKAROUND_ERRONEOUS_ANSWER
894 // Basically:
895 // A call was incoming or waiting
896 // Now it's marked as active
897 // But we never answered it
898 //
899 // This is probably a bug, and the call will probably
900 // disappear from the call list in the next poll
901 if (prevIncomingOrWaitingLine >= 0
902 && s_incomingOrWaitingLine < 0
903 && s_expectAnswer == 0
904 ) {
905 for (i = 0; i < countValidCalls ; i++) {
906
907 if (p_calls[i].index == prevIncomingOrWaitingLine
908 && p_calls[i].state == RIL_CALL_ACTIVE
909 && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX
910 ) {
Wink Saville4dcab4f2012-11-19 16:05:13 -0800911 RLOGI(
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800912 "Hit WORKAROUND_ERRONOUS_ANSWER case."
913 " Repoll count: %d\n", s_repollCallsCount);
914 s_repollCallsCount++;
915 goto error;
916 }
917 }
918 }
919
920 s_expectAnswer = 0;
921 s_repollCallsCount = 0;
922#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
923
Wink Saville3d54e742009-05-18 18:00:44 -0700924 RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
925 countValidCalls * sizeof (RIL_Call *));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800926
927 at_response_free(p_response);
928
929#ifdef POLL_CALL_STATE
930 if (countValidCalls) { // We don't seem to get a "NO CARRIER" message from
931 // smd, so we're forced to poll until the call ends.
932#else
933 if (needRepoll) {
934#endif
935 RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
936 }
937
938 return;
Tomasz Wasilczyk88961c22017-04-11 09:21:08 -0700939#ifdef WORKAROUND_ERRONEOUS_ANSWER
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800940error:
941 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
942 at_response_free(p_response);
Tomasz Wasilczyk88961c22017-04-11 09:21:08 -0700943#endif
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800944}
945
Mark Salyzynba58c202014-03-12 15:20:22 -0700946static void requestDial(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800947{
948 RIL_Dial *p_dial;
949 char *cmd;
950 const char *clir;
951 int ret;
952
953 p_dial = (RIL_Dial *)data;
954
955 switch (p_dial->clir) {
956 case 1: clir = "I"; break; /*invocation*/
957 case 2: clir = "i"; break; /*suppression*/
958 default:
959 case 0: clir = ""; break; /*subscription default*/
960 }
961
962 asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
963
964 ret = at_send_command(cmd, NULL);
965
966 free(cmd);
967
968 /* success or failure is ignored by the upper layer here.
969 it will call GET_CURRENT_CALLS and determine success that way */
970 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
971}
972
Mark Salyzynba58c202014-03-12 15:20:22 -0700973static void requestWriteSmsToSim(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800974{
975 RIL_SMS_WriteArgs *p_args;
976 char *cmd;
977 int length;
978 int err;
979 ATResponse *p_response = NULL;
980
Jim Kayeb6f3f7e2017-12-07 14:06:22 -0800981 if (getSIMStatus() == SIM_ABSENT) {
982 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
983 return;
984 }
985
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800986 p_args = (RIL_SMS_WriteArgs *)data;
987
988 length = strlen(p_args->pdu)/2;
989 asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
990
991 err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response);
992
993 if (err != 0 || p_response->success == 0) goto error;
994
995 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
996 at_response_free(p_response);
997
998 return;
999error:
1000 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1001 at_response_free(p_response);
1002}
1003
Mark Salyzynba58c202014-03-12 15:20:22 -07001004static void requestHangup(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001005{
1006 int *p_line;
1007
1008 int ret;
1009 char *cmd;
1010
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08001011 if (getSIMStatus() == SIM_ABSENT) {
1012 RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
1013 return;
1014 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001015 p_line = (int *)data;
1016
1017 // 3GPP 22.030 6.5.5
1018 // "Releases a specific active call X"
1019 asprintf(&cmd, "AT+CHLD=1%d", p_line[0]);
1020
1021 ret = at_send_command(cmd, NULL);
1022
1023 free(cmd);
1024
1025 /* success or failure is ignored by the upper layer here.
1026 it will call GET_CURRENT_CALLS and determine success that way */
1027 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1028}
1029
Mark Salyzynba58c202014-03-12 15:20:22 -07001030static void requestSignalStrength(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001031{
1032 ATResponse *p_response = NULL;
1033 int err;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001034 char *line;
Jim Kayedc9f31b2017-04-03 13:43:31 -07001035 int count = 0;
1036 // Accept a response that is at least v6, and up to v10
1037 int minNumOfElements=sizeof(RIL_SignalStrength_v6)/sizeof(int);
1038 int maxNumOfElements=sizeof(RIL_SignalStrength_v10)/sizeof(int);
1039 int response[maxNumOfElements];
1040
1041 memset(response, 0, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001042
1043 err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response);
1044
1045 if (err < 0 || p_response->success == 0) {
1046 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1047 goto error;
1048 }
1049
1050 line = p_response->p_intermediates->line;
1051
1052 err = at_tok_start(&line);
1053 if (err < 0) goto error;
1054
Jim Kayedc9f31b2017-04-03 13:43:31 -07001055 for (count = 0; count < maxNumOfElements; count++) {
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -07001056 err = at_tok_nextint(&line, &(response[count]));
Jim Kayedc9f31b2017-04-03 13:43:31 -07001057 if (err < 0 && count < minNumOfElements) goto error;
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -07001058 }
Chih-Wei Huang28059052012-04-30 01:13:27 +08001059
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -07001060 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001061
1062 at_response_free(p_response);
1063 return;
1064
1065error:
Wink Saville4dcab4f2012-11-19 16:05:13 -08001066 RLOGE("requestSignalStrength must never return an error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001067 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1068 at_response_free(p_response);
1069}
1070
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001071/**
1072 * networkModePossible. Decides whether the network mode is appropriate for the
1073 * specified modem
1074 */
1075static int networkModePossible(ModemInfo *mdm, int nm)
1076{
1077 if ((net2modem[nm] & mdm->supportedTechs) == net2modem[nm]) {
1078 return 1;
1079 }
1080 return 0;
1081}
Mark Salyzynba58c202014-03-12 15:20:22 -07001082static void requestSetPreferredNetworkType( int request __unused, void *data,
1083 size_t datalen __unused, RIL_Token t )
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001084{
1085 ATResponse *p_response = NULL;
1086 char *cmd = NULL;
1087 int value = *(int *)data;
1088 int current, old;
1089 int err;
1090 int32_t preferred = net2pmask[value];
1091
Wink Saville4dcab4f2012-11-19 16:05:13 -08001092 RLOGD("requestSetPreferredNetworkType: current: %x. New: %x", PREFERRED_NETWORK(sMdmInfo), preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001093 if (!networkModePossible(sMdmInfo, value)) {
1094 RIL_onRequestComplete(t, RIL_E_MODE_NOT_SUPPORTED, NULL, 0);
1095 return;
1096 }
1097 if (query_ctec(sMdmInfo, &current, NULL) < 0) {
1098 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1099 return;
1100 }
1101 old = PREFERRED_NETWORK(sMdmInfo);
Wink Saville4dcab4f2012-11-19 16:05:13 -08001102 RLOGD("old != preferred: %d", old != preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001103 if (old != preferred) {
1104 asprintf(&cmd, "AT+CTEC=%d,\"%x\"", current, preferred);
Wink Saville4dcab4f2012-11-19 16:05:13 -08001105 RLOGD("Sending command: <%s>", cmd);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001106 err = at_send_command_singleline(cmd, "+CTEC:", &p_response);
1107 free(cmd);
1108 if (err || !p_response->success) {
1109 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1110 return;
1111 }
1112 PREFERRED_NETWORK(sMdmInfo) = value;
1113 if (!strstr( p_response->p_intermediates->line, "DONE") ) {
1114 int current;
1115 int res = parse_technology_response(p_response->p_intermediates->line, &current, NULL);
1116 switch (res) {
1117 case -1: // Error or unable to parse
1118 break;
1119 case 1: // Only able to parse current
1120 case 0: // Both current and preferred were parsed
1121 setRadioTechnology(sMdmInfo, current);
1122 break;
1123 }
1124 }
1125 }
1126 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1127}
1128
Mark Salyzynba58c202014-03-12 15:20:22 -07001129static void requestGetPreferredNetworkType(int request __unused, void *data __unused,
1130 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001131{
1132 int preferred;
1133 unsigned i;
1134
1135 switch ( query_ctec(sMdmInfo, NULL, &preferred) ) {
1136 case -1: // Error or unable to parse
1137 case 1: // Only able to parse current
1138 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1139 break;
1140 case 0: // Both current and preferred were parsed
1141 for ( i = 0 ; i < sizeof(net2pmask) / sizeof(int32_t) ; i++ ) {
1142 if (preferred == net2pmask[i]) {
1143 RIL_onRequestComplete(t, RIL_E_SUCCESS, &i, sizeof(int));
1144 return;
1145 }
1146 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08001147 RLOGE("Unknown preferred mode received from modem: %d", preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001148 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1149 break;
1150 }
1151
1152}
1153
Mark Salyzynba58c202014-03-12 15:20:22 -07001154static void requestCdmaPrlVersion(int request __unused, void *data __unused,
1155 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001156{
1157 int err;
1158 char * responseStr;
1159 ATResponse *p_response = NULL;
1160 const char *cmd;
1161 char *line;
1162
1163 err = at_send_command_singleline("AT+WPRL?", "+WPRL:", &p_response);
1164 if (err < 0 || !p_response->success) goto error;
1165 line = p_response->p_intermediates->line;
1166 err = at_tok_start(&line);
1167 if (err < 0) goto error;
1168 err = at_tok_nextstr(&line, &responseStr);
1169 if (err < 0 || !responseStr) goto error;
1170 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, strlen(responseStr));
1171 at_response_free(p_response);
1172 return;
1173error:
1174 at_response_free(p_response);
1175 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1176}
1177
Mark Salyzynba58c202014-03-12 15:20:22 -07001178static void requestCdmaBaseBandVersion(int request __unused, void *data __unused,
1179 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001180{
1181 int err;
1182 char * responseStr;
1183 ATResponse *p_response = NULL;
1184 const char *cmd;
1185 const char *prefix;
1186 char *line, *p;
1187 int commas;
1188 int skip;
1189 int count = 4;
1190
1191 // Fixed values. TODO: query modem
1192 responseStr = strdup("1.0.0.0");
1193 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, sizeof(responseStr));
1194 free(responseStr);
1195}
1196
Mark Salyzynba58c202014-03-12 15:20:22 -07001197static void requestCdmaDeviceIdentity(int request __unused, void *data __unused,
1198 size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001199{
1200 int err;
1201 int response[4];
1202 char * responseStr[4];
1203 ATResponse *p_response = NULL;
1204 const char *cmd;
1205 const char *prefix;
1206 char *line, *p;
1207 int commas;
1208 int skip;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001209 int count = 4;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001210
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001211 // Fixed values. TODO: Query modem
1212 responseStr[0] = "----";
1213 responseStr[1] = "----";
1214 responseStr[2] = "77777777";
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001215
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001216 err = at_send_command_numeric("AT+CGSN", &p_response);
1217 if (err < 0 || p_response->success == 0) {
1218 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1219 return;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001220 } else {
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001221 responseStr[3] = p_response->p_intermediates->line;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001222 }
1223
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001224 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
1225 at_response_free(p_response);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001226}
1227
Mark Salyzynba58c202014-03-12 15:20:22 -07001228static void requestCdmaGetSubscriptionSource(int request __unused, void *data,
1229 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001230{
1231 int err;
1232 int *ss = (int *)data;
1233 ATResponse *p_response = NULL;
1234 char *cmd = NULL;
1235 char *line = NULL;
1236 int response;
1237
1238 asprintf(&cmd, "AT+CCSS?");
1239 if (!cmd) goto error;
1240
1241 err = at_send_command_singleline(cmd, "+CCSS:", &p_response);
1242 if (err < 0 || !p_response->success)
1243 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001244
1245 line = p_response->p_intermediates->line;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001246 err = at_tok_start(&line);
1247 if (err < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001248
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001249 err = at_tok_nextint(&line, &response);
1250 free(cmd);
1251 cmd = NULL;
1252
1253 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1254
1255 return;
1256error:
1257 free(cmd);
1258 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1259}
1260
Mark Salyzynba58c202014-03-12 15:20:22 -07001261static void requestCdmaSetSubscriptionSource(int request __unused, void *data,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001262 size_t datalen, RIL_Token t)
1263{
1264 int err;
1265 int *ss = (int *)data;
1266 ATResponse *p_response = NULL;
1267 char *cmd = NULL;
1268
1269 if (!ss || !datalen) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001270 RLOGE("RIL_REQUEST_CDMA_SET_SUBSCRIPTION without data!");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001271 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1272 return;
1273 }
1274 asprintf(&cmd, "AT+CCSS=%d", ss[0]);
1275 if (!cmd) goto error;
1276
1277 err = at_send_command(cmd, &p_response);
1278 if (err < 0 || !p_response->success)
1279 goto error;
1280 free(cmd);
1281 cmd = NULL;
1282
1283 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1284
1285 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, ss, sizeof(ss[0]));
1286
1287 return;
1288error:
1289 free(cmd);
1290 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1291}
1292
Mark Salyzynba58c202014-03-12 15:20:22 -07001293static void requestCdmaSubscription(int request __unused, void *data __unused,
1294 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001295{
1296 int err;
1297 int response[5];
1298 char * responseStr[5];
1299 ATResponse *p_response = NULL;
1300 const char *cmd;
1301 const char *prefix;
1302 char *line, *p;
1303 int commas;
1304 int skip;
1305 int count = 5;
1306
1307 // Fixed values. TODO: Query modem
1308 responseStr[0] = "8587777777"; // MDN
1309 responseStr[1] = "1"; // SID
1310 responseStr[2] = "1"; // NID
1311 responseStr[3] = "8587777777"; // MIN
1312 responseStr[4] = "1"; // PRL Version
1313 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001314}
1315
Mark Salyzynba58c202014-03-12 15:20:22 -07001316static void requestCdmaGetRoamingPreference(int request __unused, void *data __unused,
1317 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001318{
1319 int roaming_pref = -1;
1320 ATResponse *p_response = NULL;
1321 char *line;
1322 int res;
1323
1324 res = at_send_command_singleline("AT+WRMP?", "+WRMP:", &p_response);
1325 if (res < 0 || !p_response->success) {
1326 goto error;
1327 }
1328 line = p_response->p_intermediates->line;
1329
1330 res = at_tok_start(&line);
1331 if (res < 0) goto error;
1332
1333 res = at_tok_nextint(&line, &roaming_pref);
1334 if (res < 0) goto error;
1335
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08001336 RIL_onRequestComplete(t, RIL_E_SUCCESS, &roaming_pref, sizeof(roaming_pref));
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001337 return;
1338error:
1339 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1340}
1341
Mark Salyzynba58c202014-03-12 15:20:22 -07001342static void requestCdmaSetRoamingPreference(int request __unused, void *data,
1343 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001344{
1345 int *pref = (int *)data;
1346 ATResponse *p_response = NULL;
1347 char *line;
1348 int res;
1349 char *cmd = NULL;
1350
1351 asprintf(&cmd, "AT+WRMP=%d", *pref);
1352 if (cmd == NULL) goto error;
1353
1354 res = at_send_command(cmd, &p_response);
1355 if (res < 0 || !p_response->success)
1356 goto error;
1357
1358 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1359 free(cmd);
1360 return;
1361error:
1362 free(cmd);
1363 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1364}
1365
1366static int parseRegistrationState(char *str, int *type, int *items, int **response)
1367{
1368 int err;
1369 char *line = str, *p;
1370 int *resp = NULL;
1371 int skip;
1372 int count = 3;
1373 int commas;
1374
Wink Saville4dcab4f2012-11-19 16:05:13 -08001375 RLOGD("parseRegistrationState. Parsing: %s",str);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001376 err = at_tok_start(&line);
1377 if (err < 0) goto error;
1378
1379 /* Ok you have to be careful here
1380 * The solicited version of the CREG response is
1381 * +CREG: n, stat, [lac, cid]
1382 * and the unsolicited version is
1383 * +CREG: stat, [lac, cid]
1384 * The <n> parameter is basically "is unsolicited creg on?"
1385 * which it should always be
1386 *
1387 * Now we should normally get the solicited version here,
1388 * but the unsolicited version could have snuck in
1389 * so we have to handle both
1390 *
1391 * Also since the LAC and CID are only reported when registered,
1392 * we can have 1, 2, 3, or 4 arguments here
1393 *
1394 * finally, a +CGREG: answer may have a fifth value that corresponds
1395 * to the network type, as in;
1396 *
1397 * +CGREG: n, stat [,lac, cid [,networkType]]
1398 */
1399
1400 /* count number of commas */
1401 commas = 0;
1402 for (p = line ; *p != '\0' ;p++) {
1403 if (*p == ',') commas++;
1404 }
1405
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001406 resp = (int *)calloc(commas + 1, sizeof(int));
1407 if (!resp) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001408 switch (commas) {
1409 case 0: /* +CREG: <stat> */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001410 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001411 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001412 resp[1] = -1;
1413 resp[2] = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001414 break;
1415
1416 case 1: /* +CREG: <n>, <stat> */
1417 err = at_tok_nextint(&line, &skip);
1418 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001419 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001420 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001421 resp[1] = -1;
1422 resp[2] = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001423 if (err < 0) goto error;
1424 break;
1425
1426 case 2: /* +CREG: <stat>, <lac>, <cid> */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001427 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001428 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001429 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001430 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001431 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001432 if (err < 0) goto error;
1433 break;
1434 case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
1435 err = at_tok_nextint(&line, &skip);
1436 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001437 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001438 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001439 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001440 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001441 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001442 if (err < 0) goto error;
1443 break;
1444 /* special case for CGREG, there is a fourth parameter
1445 * that is the network type (unknown/gprs/edge/umts)
1446 */
1447 case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
1448 err = at_tok_nextint(&line, &skip);
1449 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001450 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001451 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001452 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001453 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001454 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001455 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001456 err = at_tok_nexthexint(&line, &resp[3]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001457 if (err < 0) goto error;
1458 count = 4;
1459 break;
1460 default:
1461 goto error;
1462 }
Wink Saville8a9e0212013-04-09 12:11:38 -07001463 s_lac = resp[1];
1464 s_cid = resp[2];
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001465 if (response)
1466 *response = resp;
1467 if (items)
1468 *items = commas + 1;
1469 if (type)
1470 *type = techFromModemType(TECH(sMdmInfo));
1471 return 0;
1472error:
1473 free(resp);
1474 return -1;
1475}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001476
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001477#define REG_STATE_LEN 15
1478#define REG_DATA_STATE_LEN 6
Mark Salyzynba58c202014-03-12 15:20:22 -07001479static void requestRegistrationState(int request, void *data __unused,
1480 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001481{
1482 int err;
1483 int *registration;
1484 char **responseStr = NULL;
1485 ATResponse *p_response = NULL;
1486 const char *cmd;
1487 const char *prefix;
1488 char *line;
1489 int i = 0, j, numElements = 0;
1490 int count = 3;
1491 int type, startfrom;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001492
Wink Saville4dcab4f2012-11-19 16:05:13 -08001493 RLOGD("requestRegistrationState");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001494 if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
1495 cmd = "AT+CREG?";
1496 prefix = "+CREG:";
1497 numElements = REG_STATE_LEN;
1498 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1499 cmd = "AT+CGREG?";
1500 prefix = "+CGREG:";
1501 numElements = REG_DATA_STATE_LEN;
1502 } else {
1503 assert(0);
1504 goto error;
1505 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001506
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001507 err = at_send_command_singleline(cmd, prefix, &p_response);
1508
1509 if (err != 0) goto error;
1510
1511 line = p_response->p_intermediates->line;
1512
1513 if (parseRegistrationState(line, &type, &count, &registration)) goto error;
1514
1515 responseStr = malloc(numElements * sizeof(char *));
1516 if (!responseStr) goto error;
1517 memset(responseStr, 0, numElements * sizeof(char *));
1518 /**
1519 * The first '4' bytes for both registration states remain the same.
1520 * But if the request is 'DATA_REGISTRATION_STATE',
1521 * the 5th and 6th byte(s) are optional.
1522 */
1523 if (is3gpp2(type) == 1) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001524 RLOGD("registration state type: 3GPP2");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001525 // TODO: Query modem
1526 startfrom = 3;
1527 if(request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
1528 asprintf(&responseStr[3], "8"); // EvDo revA
1529 asprintf(&responseStr[4], "1"); // BSID
1530 asprintf(&responseStr[5], "123"); // Latitude
1531 asprintf(&responseStr[6], "222"); // Longitude
1532 asprintf(&responseStr[7], "0"); // CSS Indicator
1533 asprintf(&responseStr[8], "4"); // SID
1534 asprintf(&responseStr[9], "65535"); // NID
1535 asprintf(&responseStr[10], "0"); // Roaming indicator
1536 asprintf(&responseStr[11], "1"); // System is in PRL
1537 asprintf(&responseStr[12], "0"); // Default Roaming indicator
1538 asprintf(&responseStr[13], "0"); // Reason for denial
1539 asprintf(&responseStr[14], "0"); // Primary Scrambling Code of Current cell
1540 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1541 asprintf(&responseStr[3], "8"); // Available data radio technology
1542 }
1543 } else { // type == RADIO_TECH_3GPP
Wink Saville4dcab4f2012-11-19 16:05:13 -08001544 RLOGD("registration state type: 3GPP");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001545 startfrom = 0;
1546 asprintf(&responseStr[1], "%x", registration[1]);
1547 asprintf(&responseStr[2], "%x", registration[2]);
1548 if (count > 3)
1549 asprintf(&responseStr[3], "%d", registration[3]);
1550 }
1551 asprintf(&responseStr[0], "%d", registration[0]);
1552
1553 /**
1554 * Optional bytes for DATA_REGISTRATION_STATE request
1555 * 4th byte : Registration denial code
1556 * 5th byte : The max. number of simultaneous Data Calls
1557 */
1558 if(request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1559 // asprintf(&responseStr[4], "3");
1560 // asprintf(&responseStr[5], "1");
1561 }
1562
1563 for (j = startfrom; j < numElements; j++) {
1564 if (!responseStr[i]) goto error;
1565 }
1566 free(registration);
1567 registration = NULL;
1568
1569 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, numElements*sizeof(responseStr));
1570 for (j = 0; j < numElements; j++ ) {
1571 free(responseStr[j]);
1572 responseStr[j] = NULL;
1573 }
1574 free(responseStr);
1575 responseStr = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001576 at_response_free(p_response);
1577
1578 return;
1579error:
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001580 if (responseStr) {
1581 for (j = 0; j < numElements; j++) {
1582 free(responseStr[j]);
1583 responseStr[j] = NULL;
1584 }
1585 free(responseStr);
1586 responseStr = NULL;
1587 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08001588 RLOGE("requestRegistrationState must never return an error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001589 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1590 at_response_free(p_response);
1591}
1592
Mark Salyzynba58c202014-03-12 15:20:22 -07001593static void requestOperator(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001594{
1595 int err;
1596 int i;
1597 int skip;
1598 ATLine *p_cur;
1599 char *response[3];
1600
1601 memset(response, 0, sizeof(response));
1602
1603 ATResponse *p_response = NULL;
1604
1605 err = at_send_command_multiline(
1606 "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
1607 "+COPS:", &p_response);
1608
1609 /* we expect 3 lines here:
1610 * +COPS: 0,0,"T - Mobile"
1611 * +COPS: 0,1,"TMO"
1612 * +COPS: 0,2,"310170"
1613 */
1614
1615 if (err != 0) goto error;
1616
1617 for (i = 0, p_cur = p_response->p_intermediates
1618 ; p_cur != NULL
1619 ; p_cur = p_cur->p_next, i++
1620 ) {
1621 char *line = p_cur->line;
1622
1623 err = at_tok_start(&line);
1624 if (err < 0) goto error;
1625
1626 err = at_tok_nextint(&line, &skip);
1627 if (err < 0) goto error;
1628
1629 // If we're unregistered, we may just get
1630 // a "+COPS: 0" response
1631 if (!at_tok_hasmore(&line)) {
1632 response[i] = NULL;
1633 continue;
1634 }
1635
1636 err = at_tok_nextint(&line, &skip);
1637 if (err < 0) goto error;
1638
1639 // a "+COPS: 0, n" response is also possible
1640 if (!at_tok_hasmore(&line)) {
1641 response[i] = NULL;
1642 continue;
1643 }
1644
1645 err = at_tok_nextstr(&line, &(response[i]));
1646 if (err < 0) goto error;
Wink Saville8a9e0212013-04-09 12:11:38 -07001647 // Simple assumption that mcc and mnc are 3 digits each
1648 if (strlen(response[i]) == 6) {
1649 if (sscanf(response[i], "%3d%3d", &s_mcc, &s_mnc) != 2) {
1650 RLOGE("requestOperator expected mccmnc to be 6 decimal digits");
1651 }
1652 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001653 }
1654
1655 if (i != 3) {
1656 /* expect 3 lines exactly */
1657 goto error;
1658 }
1659
1660 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
1661 at_response_free(p_response);
1662
1663 return;
1664error:
Wink Saville4dcab4f2012-11-19 16:05:13 -08001665 RLOGE("requestOperator must not return error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001666 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1667 at_response_free(p_response);
1668}
1669
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001670static void requestCdmaSendSMS(void *data, size_t datalen, RIL_Token t)
1671{
1672 int err = 1; // Set to go to error:
1673 RIL_SMS_Response response;
1674 RIL_CDMA_SMS_Message* rcsm;
1675
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08001676 if (getSIMStatus() == SIM_ABSENT) {
1677 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
1678 return;
1679 }
1680
Mark Salyzynba58c202014-03-12 15:20:22 -07001681 RLOGD("requestCdmaSendSMS datalen=%zu, sizeof(RIL_CDMA_SMS_Message)=%zu",
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001682 datalen, sizeof(RIL_CDMA_SMS_Message));
1683
1684 // verify data content to test marshalling/unmarshalling:
1685 rcsm = (RIL_CDMA_SMS_Message*)data;
Wink Saville4dcab4f2012-11-19 16:05:13 -08001686 RLOGD("TeleserviceID=%d, bIsServicePresent=%d, \
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001687 uServicecategory=%d, sAddress.digit_mode=%d, \
1688 sAddress.Number_mode=%d, sAddress.number_type=%d, ",
1689 rcsm->uTeleserviceID, rcsm->bIsServicePresent,
1690 rcsm->uServicecategory,rcsm->sAddress.digit_mode,
1691 rcsm->sAddress.number_mode,rcsm->sAddress.number_type);
1692
1693 if (err != 0) goto error;
1694
1695 // Cdma Send SMS implementation will go here:
1696 // But it is not implemented yet.
1697
1698 memset(&response, 0, sizeof(response));
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001699 response.messageRef = 1;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001700 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1701 return;
1702
1703error:
1704 // Cdma Send SMS will always cause send retry error.
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001705 response.messageRef = -1;
1706 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001707}
1708
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001709static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
1710{
1711 int err;
1712 const char *smsc;
1713 const char *pdu;
1714 int tpLayerLength;
1715 char *cmd1, *cmd2;
1716 RIL_SMS_Response response;
1717 ATResponse *p_response = NULL;
1718
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08001719 if (getSIMStatus() == SIM_ABSENT) {
1720 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
1721 return;
1722 }
1723
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001724 memset(&response, 0, sizeof(response));
Mark Salyzynba58c202014-03-12 15:20:22 -07001725 RLOGD("requestSendSMS datalen =%zu", datalen);
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001726
1727 if (s_ims_gsm_fail != 0) goto error;
1728 if (s_ims_gsm_retry != 0) goto error2;
1729
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001730 smsc = ((const char **)data)[0];
1731 pdu = ((const char **)data)[1];
1732
1733 tpLayerLength = strlen(pdu)/2;
1734
1735 // "NULL for default SMSC"
1736 if (smsc == NULL) {
1737 smsc= "00";
1738 }
1739
1740 asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
1741 asprintf(&cmd2, "%s%s", smsc, pdu);
1742
1743 err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response);
1744
Daniele Palmasa5c743e2015-05-06 11:47:59 +02001745 free(cmd1);
1746 free(cmd2);
1747
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001748 if (err != 0 || p_response->success == 0) goto error;
1749
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001750 /* FIXME fill in messageRef and ackPDU */
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001751 response.messageRef = 1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001752 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1753 at_response_free(p_response);
1754
1755 return;
1756error:
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001757 response.messageRef = -2;
1758 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001759 at_response_free(p_response);
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001760 return;
1761error2:
1762 // send retry error.
1763 response.messageRef = -1;
1764 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
1765 at_response_free(p_response);
1766 return;
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08001767}
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001768
1769static void requestImsSendSMS(void *data, size_t datalen, RIL_Token t)
1770{
1771 RIL_IMS_SMS_Message *p_args;
1772 RIL_SMS_Response response;
1773
1774 memset(&response, 0, sizeof(response));
1775
Mark Salyzynba58c202014-03-12 15:20:22 -07001776 RLOGD("requestImsSendSMS: datalen=%zu, "
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001777 "registered=%d, service=%d, format=%d, ims_perm_fail=%d, "
1778 "ims_retry=%d, gsm_fail=%d, gsm_retry=%d",
1779 datalen, s_ims_registered, s_ims_services, s_ims_format,
1780 s_ims_cause_perm_failure, s_ims_cause_retry, s_ims_gsm_fail,
1781 s_ims_gsm_retry);
1782
1783 // figure out if this is gsm/cdma format
1784 // then route it to requestSendSMS vs requestCdmaSendSMS respectively
1785 p_args = (RIL_IMS_SMS_Message *)data;
1786
1787 if (0 != s_ims_cause_perm_failure ) goto error;
1788
1789 // want to fail over ims and this is first request over ims
1790 if (0 != s_ims_cause_retry && 0 == p_args->retry) goto error2;
1791
1792 if (RADIO_TECH_3GPP == p_args->tech) {
1793 return requestSendSMS(p_args->message.gsmMessage,
1794 datalen - sizeof(RIL_RadioTechnologyFamily),
1795 t);
1796 } else if (RADIO_TECH_3GPP2 == p_args->tech) {
1797 return requestCdmaSendSMS(p_args->message.cdmaMessage,
1798 datalen - sizeof(RIL_RadioTechnologyFamily),
1799 t);
1800 } else {
1801 RLOGE("requestImsSendSMS invalid format value =%d", p_args->tech);
1802 }
1803
1804error:
1805 response.messageRef = -2;
1806 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
1807 return;
1808
1809error2:
1810 response.messageRef = -1;
1811 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001812}
1813
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07001814static void requestSimOpenChannel(void *data, size_t datalen, RIL_Token t)
1815{
1816 ATResponse *p_response = NULL;
1817 int32_t session_id;
1818 int err;
1819 char cmd[32];
1820 char dummy;
1821 char *line;
1822
1823 // Max length is 16 bytes according to 3GPP spec 27.007 section 8.45
1824 if (data == NULL || datalen == 0 || datalen > 16) {
1825 ALOGE("Invalid data passed to requestSimOpenChannel");
1826 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1827 return;
1828 }
1829
1830 snprintf(cmd, sizeof(cmd), "AT+CCHO=%s", data);
1831
1832 err = at_send_command_numeric(cmd, &p_response);
1833 if (err < 0 || p_response == NULL || p_response->success == 0) {
1834 ALOGE("Error %d opening logical channel: %d",
1835 err, p_response ? p_response->success : 0);
1836 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1837 at_response_free(p_response);
1838 return;
1839 }
1840
1841 // Ensure integer only by scanning for an extra char but expect one result
1842 line = p_response->p_intermediates->line;
1843 if (sscanf(line, "%" SCNd32 "%c", &session_id, &dummy) != 1) {
1844 ALOGE("Invalid AT response, expected integer, was '%s'", line);
1845 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1846 return;
1847 }
1848
1849 RIL_onRequestComplete(t, RIL_E_SUCCESS, &session_id, sizeof(&session_id));
1850 at_response_free(p_response);
1851}
1852
1853static void requestSimCloseChannel(void *data, size_t datalen, RIL_Token t)
1854{
1855 ATResponse *p_response = NULL;
1856 int32_t session_id;
1857 int err;
1858 char cmd[32];
1859
1860 if (data == NULL || datalen != sizeof(session_id)) {
1861 ALOGE("Invalid data passed to requestSimCloseChannel");
1862 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1863 return;
1864 }
1865 session_id = ((int32_t *)data)[0];
1866 snprintf(cmd, sizeof(cmd), "AT+CCHC=%" PRId32, session_id);
1867 err = at_send_command_singleline(cmd, "+CCHC", &p_response);
1868
1869 if (err < 0 || p_response == NULL || p_response->success == 0) {
1870 ALOGE("Error %d closing logical channel %d: %d",
1871 err, session_id, p_response ? p_response->success : 0);
1872 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1873 at_response_free(p_response);
1874 return;
1875 }
1876
1877 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1878
1879 at_response_free(p_response);
1880}
1881
1882static void requestSimTransmitApduChannel(void *data,
1883 size_t datalen,
1884 RIL_Token t)
1885{
1886 ATResponse *p_response = NULL;
1887 int err;
1888 char *cmd;
1889 char *line;
1890 size_t cmd_size;
1891 RIL_SIM_IO_Response sim_response;
1892 RIL_SIM_APDU *apdu = (RIL_SIM_APDU *)data;
1893
1894 if (apdu == NULL || datalen != sizeof(RIL_SIM_APDU)) {
1895 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1896 return;
1897 }
1898
1899 cmd_size = 10 + (apdu->data ? strlen(apdu->data) : 0);
Wei Wang9cec1e02017-02-08 14:37:37 -08001900 asprintf(&cmd, "AT+CGLA=%d,%zu,%02x%02x%02x%02x%02x%s",
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07001901 apdu->sessionid, cmd_size, apdu->cla, apdu->instruction,
1902 apdu->p1, apdu->p2, apdu->p3, apdu->data ? apdu->data : "");
1903
1904 err = at_send_command_singleline(cmd, "+CGLA", &p_response);
1905 free(cmd);
1906 if (err < 0 || p_response == NULL || p_response->success == 0) {
1907 ALOGE("Error %d transmitting APDU: %d",
1908 err, p_response ? p_response->success : 0);
1909 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1910 at_response_free(p_response);
1911 return;
1912 }
1913
1914 line = p_response->p_intermediates->line;
1915 err = parseSimResponseLine(line, &sim_response);
1916
1917 if (err == 0) {
1918 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1919 &sim_response, sizeof(sim_response));
1920 } else {
1921 ALOGE("Error %d parsing SIM response line: %s", err, line);
1922 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1923 }
1924 at_response_free(p_response);
1925}
1926
Wink Savillef4c4d362009-04-02 01:37:03 -07001927static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001928{
1929 const char *apn;
1930 char *cmd;
1931 int err;
1932 ATResponse *p_response = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001933
Wink Savillef4c4d362009-04-02 01:37:03 -07001934 apn = ((const char **)data)[2];
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001935
1936#ifdef USE_TI_COMMANDS
1937 // Config for multislot class 10 (probably default anyway eh?)
1938 err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
1939 NULL);
1940
1941 err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
1942#endif /* USE_TI_COMMANDS */
1943
1944 int fd, qmistatus;
1945 size_t cur = 0;
1946 size_t len;
1947 ssize_t written, rlen;
1948 char status[32] = {0};
1949 int retry = 10;
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001950 const char *pdp_type;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001951
Wink Saville4dcab4f2012-11-19 16:05:13 -08001952 RLOGD("requesting data connection to APN '%s'", apn);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001953
1954 fd = open ("/dev/qmi", O_RDWR);
1955 if (fd >= 0) { /* the device doesn't exist on the emulator */
1956
Wink Saville4dcab4f2012-11-19 16:05:13 -08001957 RLOGD("opened the qmi device\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001958 asprintf(&cmd, "up:%s", apn);
1959 len = strlen(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001960
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001961 while (cur < len) {
1962 do {
1963 written = write (fd, cmd + cur, len - cur);
1964 } while (written < 0 && errno == EINTR);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001965
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001966 if (written < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001967 RLOGE("### ERROR writing to /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001968 close(fd);
1969 goto error;
1970 }
1971
1972 cur += written;
1973 }
1974
1975 // wait for interface to come online
1976
1977 do {
1978 sleep(1);
1979 do {
1980 rlen = read(fd, status, 31);
1981 } while (rlen < 0 && errno == EINTR);
1982
1983 if (rlen < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001984 RLOGE("### ERROR reading from /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001985 close(fd);
1986 goto error;
1987 } else {
1988 status[rlen] = '\0';
Wink Saville4dcab4f2012-11-19 16:05:13 -08001989 RLOGD("### status: %s", status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001990 }
1991 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
1992
1993 close(fd);
1994
1995 if (retry == 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001996 RLOGE("### Failed to get data connection up\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001997 goto error;
1998 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001999
2000 qmistatus = system("netcfg rmnet0 dhcp");
2001
Wink Saville4dcab4f2012-11-19 16:05:13 -08002002 RLOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002003
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002004 if (qmistatus < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002005
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002006 } else {
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -07002007 bool hasWifi = hasWifiCapability();
2008 const char* radioInterfaceName = getRadioInterfaceName(hasWifi);
2009 if (setInterfaceState(radioInterfaceName, kInterfaceUp) != RIL_E_SUCCESS) {
2010 goto error;
2011 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002012
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002013 if (datalen > 6 * sizeof(char *)) {
2014 pdp_type = ((const char **)data)[6];
2015 } else {
2016 pdp_type = "IP";
2017 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002018
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01002019 asprintf(&cmd, "AT+CGDCONT=1,\"%s\",\"%s\",,0,0", pdp_type, apn);
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002020 //FIXME check for error here
2021 err = at_send_command(cmd, NULL);
2022 free(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002023
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002024 // Set required QoS params to default
2025 err = at_send_command("AT+CGQREQ=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002026
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002027 // Set minimum QoS params to default
2028 err = at_send_command("AT+CGQMIN=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002029
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002030 // packet-domain event reporting
2031 err = at_send_command("AT+CGEREP=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002032
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002033 // Hangup anything that's happening there now
2034 err = at_send_command("AT+CGACT=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002035
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002036 // Start data on PDP context 1
2037 err = at_send_command("ATD*99***1#", &p_response);
2038
2039 if (err < 0 || p_response->success == 0) {
2040 goto error;
2041 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002042 }
2043
Wink Saville43808972011-01-13 17:39:51 -08002044 requestOrSendDataCallList(&t);
2045
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002046 at_response_free(p_response);
2047
2048 return;
2049error:
2050 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2051 at_response_free(p_response);
2052
2053}
2054
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -07002055static void requestDeactivateDataCall(RIL_Token t)
2056{
2057 bool hasWifi = hasWifiCapability();
2058 const char* radioInterfaceName = getRadioInterfaceName(hasWifi);
2059 RIL_Errno rilErrno = setInterfaceState(radioInterfaceName, kInterfaceDown);
2060 RIL_onRequestComplete(t, rilErrno, NULL, 0);
2061}
2062
Mark Salyzynba58c202014-03-12 15:20:22 -07002063static void requestSMSAcknowledge(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002064{
2065 int ackSuccess;
2066 int err;
2067
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002068 if (getSIMStatus() == SIM_ABSENT) {
2069 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2070 return;
2071 }
2072
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002073 ackSuccess = ((int *)data)[0];
2074
2075 if (ackSuccess == 1) {
2076 err = at_send_command("AT+CNMA=1", NULL);
2077 } else if (ackSuccess == 0) {
2078 err = at_send_command("AT+CNMA=2", NULL);
2079 } else {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002080 RLOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002081 goto error;
2082 }
2083
2084 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2085error:
2086 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2087
2088}
2089
Mark Salyzynba58c202014-03-12 15:20:22 -07002090static void requestSIM_IO(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002091{
2092 ATResponse *p_response = NULL;
2093 RIL_SIM_IO_Response sr;
2094 int err;
2095 char *cmd = NULL;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002096 RIL_SIM_IO_v6 *p_args;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002097 char *line;
2098
2099 memset(&sr, 0, sizeof(sr));
2100
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002101 p_args = (RIL_SIM_IO_v6 *)data;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002102
2103 /* FIXME handle pin2 */
2104
2105 if (p_args->data == NULL) {
2106 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
2107 p_args->command, p_args->fileid,
2108 p_args->p1, p_args->p2, p_args->p3);
2109 } else {
2110 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
2111 p_args->command, p_args->fileid,
2112 p_args->p1, p_args->p2, p_args->p3, p_args->data);
2113 }
2114
2115 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
2116
2117 if (err < 0 || p_response->success == 0) {
2118 goto error;
2119 }
2120
2121 line = p_response->p_intermediates->line;
2122
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07002123 err = parseSimResponseLine(line, &sr);
2124 if (err < 0) {
2125 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002126 }
2127
2128 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
2129 at_response_free(p_response);
2130 free(cmd);
2131
2132 return;
2133error:
2134 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2135 at_response_free(p_response);
2136 free(cmd);
2137
2138}
2139
2140static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
2141{
2142 ATResponse *p_response = NULL;
2143 int err;
2144 char* cmd = NULL;
2145 const char** strings = (const char**)data;;
2146
2147 if ( datalen == sizeof(char*) ) {
2148 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
2149 } else if ( datalen == 2*sizeof(char*) ) {
2150 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
2151 } else
2152 goto error;
2153
2154 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
2155 free(cmd);
2156
2157 if (err < 0 || p_response->success == 0) {
2158error:
2159 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
2160 } else {
2161 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2162 }
2163 at_response_free(p_response);
2164}
2165
2166
Mark Salyzynba58c202014-03-12 15:20:22 -07002167static void requestSendUSSD(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002168{
2169 const char *ussdRequest;
2170
2171 ussdRequest = (char *)(data);
2172
2173
2174 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2175
2176// @@@ TODO
2177
2178}
2179
Mark Salyzynba58c202014-03-12 15:20:22 -07002180static void requestExitEmergencyMode(void *data __unused, size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002181{
2182 int err;
2183 ATResponse *p_response = NULL;
2184
2185 err = at_send_command("AT+WSOS=0", &p_response);
2186
2187 if (err < 0 || p_response->success == 0) {
2188 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2189 return;
2190 }
2191
2192 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2193}
2194
2195// TODO: Use all radio types
2196static int techFromModemType(int mdmtype)
2197{
2198 int ret = -1;
2199 switch (1 << mdmtype) {
2200 case MDM_CDMA:
2201 ret = RADIO_TECH_1xRTT;
2202 break;
2203 case MDM_EVDO:
2204 ret = RADIO_TECH_EVDO_A;
2205 break;
2206 case MDM_GSM:
2207 ret = RADIO_TECH_GPRS;
2208 break;
2209 case MDM_WCDMA:
2210 ret = RADIO_TECH_HSPA;
2211 break;
2212 case MDM_LTE:
2213 ret = RADIO_TECH_LTE;
2214 break;
2215 }
2216 return ret;
2217}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002218
Mark Salyzynba58c202014-03-12 15:20:22 -07002219static void requestGetCellInfoList(void *data __unused, size_t datalen __unused, RIL_Token t)
Wink Saville8a9e0212013-04-09 12:11:38 -07002220{
2221 uint64_t curTime = ril_nano_time();
2222 RIL_CellInfo ci[1] =
2223 {
2224 { // ci[0]
2225 1, // cellInfoType
2226 1, // registered
Sanket Padawef0c8ca72016-06-30 15:01:08 -07002227 RIL_TIMESTAMP_TYPE_MODEM,
Wink Saville8a9e0212013-04-09 12:11:38 -07002228 curTime - 1000, // Fake some time in the past
2229 { // union CellInfo
2230 { // RIL_CellInfoGsm gsm
2231 { // gsm.cellIdneityGsm
2232 s_mcc, // mcc
2233 s_mnc, // mnc
2234 s_lac, // lac
2235 s_cid, // cid
Wink Saville8a9e0212013-04-09 12:11:38 -07002236 },
2237 { // gsm.signalStrengthGsm
2238 10, // signalStrength
2239 0 // bitErrorRate
2240 }
2241 }
2242 }
2243 }
2244 };
2245
2246 RIL_onRequestComplete(t, RIL_E_SUCCESS, ci, sizeof(ci));
2247}
2248
2249
Sanket Padawef0c8ca72016-06-30 15:01:08 -07002250static void requestSetCellInfoListRate(void *data, size_t datalen __unused, RIL_Token t)
Wink Saville8a9e0212013-04-09 12:11:38 -07002251{
2252 // For now we'll save the rate but no RIL_UNSOL_CELL_INFO_LIST messages
2253 // will be sent.
2254 assert (datalen == sizeof(int));
2255 s_cell_info_rate_ms = ((int *)data)[0];
2256
2257 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2258}
2259
Etan Cohend3652192014-06-20 08:28:44 -07002260static void requestGetHardwareConfig(void *data, size_t datalen, RIL_Token t)
2261{
2262 // TODO - hook this up with real query/info from radio.
2263
2264 RIL_HardwareConfig hwCfg;
2265
2266 RIL_UNUSED_PARM(data);
2267 RIL_UNUSED_PARM(datalen);
2268
2269 hwCfg.type = -1;
2270
2271 RIL_onRequestComplete(t, RIL_E_SUCCESS, &hwCfg, sizeof(hwCfg));
2272}
2273
Jim Kayed2d82012017-10-06 14:17:47 -07002274static void requestGetTtyMode(void *data, size_t datalen, RIL_Token t)
2275{
2276 int ttyModeResponse;
2277
2278 RIL_UNUSED_PARM(data);
2279 RIL_UNUSED_PARM(datalen);
2280
2281 ttyModeResponse = (getSIMStatus() == SIM_READY) ? 1 // TTY Full
2282 : 0; // TTY Off
2283
2284 RIL_onRequestComplete(t, RIL_E_SUCCESS, &ttyModeResponse, sizeof(ttyModeResponse));
2285}
2286
2287static void requestGetRadioCapability(void *data, size_t datalen, RIL_Token t)
2288{
2289 RIL_RadioCapability radioCapability;
2290
2291 RIL_UNUSED_PARM(data);
2292 RIL_UNUSED_PARM(datalen);
2293
2294 radioCapability.version = RIL_RADIO_CAPABILITY_VERSION;
2295 radioCapability.session = 0;
2296 radioCapability.phase = 0;
2297 radioCapability.rat = 0;
2298 radioCapability.logicalModemUuid[0] = '\0';
2299 radioCapability.status = RC_STATUS_SUCCESS;
2300
2301 RIL_onRequestComplete(t, RIL_E_SUCCESS, &radioCapability, sizeof(radioCapability));
2302}
2303
2304static void requestGetMute(void *data, size_t datalen, RIL_Token t)
2305{
2306 int muteResponse;
2307
2308 RIL_UNUSED_PARM(data);
2309 RIL_UNUSED_PARM(datalen);
2310
2311 muteResponse = 0; // Mute disabled
2312
2313 RIL_onRequestComplete(t, RIL_E_SUCCESS, &muteResponse, sizeof(muteResponse));
2314}
Etan Cohend3652192014-06-20 08:28:44 -07002315
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002316/*** Callback methods from the RIL library to us ***/
2317
2318/**
2319 * Call from RIL to us to make a RIL_REQUEST
2320 *
2321 * Must be completed with a call to RIL_onRequestComplete()
2322 *
2323 * RIL_onRequestComplete() may be called from any thread, before or after
2324 * this function returns.
2325 *
Weilun Du9f471e22017-02-07 10:47:19 -08002326 * Because onRequest function could be called from multiple different thread,
2327 * we must ensure that the underlying at_send_command_* function
2328 * is atomic.
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002329 */
2330static void
2331onRequest (int request, void *data, size_t datalen, RIL_Token t)
2332{
2333 ATResponse *p_response;
2334 int err;
2335
Wink Saville4dcab4f2012-11-19 16:05:13 -08002336 RLOGD("onRequest: %s", requestToString(request));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002337
2338 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
2339 * when RADIO_STATE_UNAVAILABLE.
2340 */
2341 if (sState == RADIO_STATE_UNAVAILABLE
2342 && request != RIL_REQUEST_GET_SIM_STATUS
2343 ) {
2344 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2345 return;
2346 }
2347
2348 /* Ignore all non-power requests when RADIO_STATE_OFF
2349 * (except RIL_REQUEST_GET_SIM_STATUS)
2350 */
Jim Kayed2d82012017-10-06 14:17:47 -07002351 if (sState == RADIO_STATE_OFF) {
2352 switch(request) {
2353 case RIL_REQUEST_BASEBAND_VERSION:
2354 case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
2355 case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE:
2356 case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
2357 case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
2358 case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
2359 case RIL_REQUEST_CDMA_SUBSCRIPTION:
2360 case RIL_REQUEST_DEVICE_IDENTITY:
2361 case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
2362 case RIL_REQUEST_GET_ACTIVITY_INFO:
2363 case RIL_REQUEST_GET_CARRIER_RESTRICTIONS:
2364 case RIL_REQUEST_GET_CURRENT_CALLS:
2365 case RIL_REQUEST_GET_IMEI:
2366 case RIL_REQUEST_GET_MUTE:
2367 case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
2368 case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
2369 case RIL_REQUEST_GET_RADIO_CAPABILITY:
2370 case RIL_REQUEST_GET_SIM_STATUS:
2371 case RIL_REQUEST_NV_RESET_CONFIG:
2372 case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
2373 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
2374 case RIL_REQUEST_QUERY_TTY_MODE:
2375 case RIL_REQUEST_RADIO_POWER:
2376 case RIL_REQUEST_SET_BAND_MODE:
2377 case RIL_REQUEST_SET_CARRIER_RESTRICTIONS:
2378 case RIL_REQUEST_SET_LOCATION_UPDATES:
2379 case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
2380 case RIL_REQUEST_SET_TTY_MODE:
2381 case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
2382 case RIL_REQUEST_STOP_LCE:
2383 case RIL_REQUEST_VOICE_RADIO_TECH:
2384 // Process all the above, even though the radio is off
2385 break;
2386
2387 default:
2388 // For all others, say NOT_AVAILABLE because the radio is off
2389 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2390 return;
2391 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002392 }
2393
2394 switch (request) {
2395 case RIL_REQUEST_GET_SIM_STATUS: {
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002396 RIL_CardStatus_v6 *p_card_status;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002397 char *p_buffer;
2398 int buffer_size;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002399
Wink Savillef6aa7c12009-04-30 14:20:52 -07002400 int result = getCardStatus(&p_card_status);
2401 if (result == RIL_E_SUCCESS) {
2402 p_buffer = (char *)p_card_status;
2403 buffer_size = sizeof(*p_card_status);
2404 } else {
2405 p_buffer = NULL;
2406 buffer_size = 0;
2407 }
2408 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
2409 freeCardStatus(p_card_status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002410 break;
2411 }
2412 case RIL_REQUEST_GET_CURRENT_CALLS:
2413 requestGetCurrentCalls(data, datalen, t);
2414 break;
2415 case RIL_REQUEST_DIAL:
2416 requestDial(data, datalen, t);
2417 break;
2418 case RIL_REQUEST_HANGUP:
2419 requestHangup(data, datalen, t);
2420 break;
2421 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002422 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002423 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002424 case RIL_REQUEST_CONFERENCE:
2425 case RIL_REQUEST_UDUB:
2426 requestCallSelection(data, datalen, t, request);
2427 break;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002428 case RIL_REQUEST_ANSWER:
2429 at_send_command("ATA", NULL);
2430
2431#ifdef WORKAROUND_ERRONEOUS_ANSWER
2432 s_expectAnswer = 1;
2433#endif /* WORKAROUND_ERRONEOUS_ANSWER */
2434
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002435 if (getSIMStatus() != SIM_READY) {
2436 RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
2437 } else {
2438 // Success or failure is ignored by the upper layer here.
2439 // It will call GET_CURRENT_CALLS and determine success that way.
2440 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2441 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002442 break;
2443
2444 case RIL_REQUEST_SEPARATE_CONNECTION:
2445 {
2446 char cmd[12];
2447 int party = ((int*)data)[0];
2448
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002449 if (getSIMStatus() == SIM_ABSENT) {
2450 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2451 return;
2452 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002453 // Make sure that party is in a valid range.
2454 // (Note: The Telephony middle layer imposes a range of 1 to 7.
2455 // It's sufficient for us to just make sure it's single digit.)
2456 if (party > 0 && party < 10) {
2457 sprintf(cmd, "AT+CHLD=2%d", party);
2458 at_send_command(cmd, NULL);
2459 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2460 } else {
2461 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2462 }
2463 }
2464 break;
2465
2466 case RIL_REQUEST_SIGNAL_STRENGTH:
2467 requestSignalStrength(data, datalen, t);
2468 break;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002469 case RIL_REQUEST_VOICE_REGISTRATION_STATE:
2470 case RIL_REQUEST_DATA_REGISTRATION_STATE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002471 requestRegistrationState(request, data, datalen, t);
2472 break;
2473 case RIL_REQUEST_OPERATOR:
2474 requestOperator(data, datalen, t);
2475 break;
2476 case RIL_REQUEST_RADIO_POWER:
2477 requestRadioPower(data, datalen, t);
2478 break;
2479 case RIL_REQUEST_DTMF: {
2480 char c = ((char *)data)[0];
2481 char *cmd;
2482 asprintf(&cmd, "AT+VTS=%c", (int)c);
2483 at_send_command(cmd, NULL);
2484 free(cmd);
2485 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2486 break;
2487 }
2488 case RIL_REQUEST_SEND_SMS:
Chaitanya Saggurthi33bbe432013-09-24 16:16:21 +05302489 case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002490 requestSendSMS(data, datalen, t);
2491 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002492 case RIL_REQUEST_CDMA_SEND_SMS:
2493 requestCdmaSendSMS(data, datalen, t);
2494 break;
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07002495 case RIL_REQUEST_IMS_SEND_SMS:
2496 requestImsSendSMS(data, datalen, t);
2497 break;
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07002498 case RIL_REQUEST_SIM_OPEN_CHANNEL:
2499 requestSimOpenChannel(data, datalen, t);
2500 break;
2501 case RIL_REQUEST_SIM_CLOSE_CHANNEL:
2502 requestSimCloseChannel(data, datalen, t);
2503 break;
2504 case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL:
2505 requestSimTransmitApduChannel(data, datalen, t);
2506 break;
Wink Savillef4c4d362009-04-02 01:37:03 -07002507 case RIL_REQUEST_SETUP_DATA_CALL:
2508 requestSetupDataCall(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002509 break;
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -07002510 case RIL_REQUEST_DEACTIVATE_DATA_CALL:
2511 requestDeactivateDataCall(t);
2512 break;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002513 case RIL_REQUEST_SMS_ACKNOWLEDGE:
2514 requestSMSAcknowledge(data, datalen, t);
2515 break;
2516
2517 case RIL_REQUEST_GET_IMSI:
2518 p_response = NULL;
2519 err = at_send_command_numeric("AT+CIMI", &p_response);
2520
2521 if (err < 0 || p_response->success == 0) {
2522 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2523 } else {
2524 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2525 p_response->p_intermediates->line, sizeof(char *));
2526 }
2527 at_response_free(p_response);
2528 break;
2529
2530 case RIL_REQUEST_GET_IMEI:
2531 p_response = NULL;
2532 err = at_send_command_numeric("AT+CGSN", &p_response);
2533
2534 if (err < 0 || p_response->success == 0) {
2535 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2536 } else {
2537 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2538 p_response->p_intermediates->line, sizeof(char *));
2539 }
2540 at_response_free(p_response);
2541 break;
2542
2543 case RIL_REQUEST_SIM_IO:
2544 requestSIM_IO(data,datalen,t);
2545 break;
2546
2547 case RIL_REQUEST_SEND_USSD:
2548 requestSendUSSD(data, datalen, t);
2549 break;
2550
2551 case RIL_REQUEST_CANCEL_USSD:
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002552 if (getSIMStatus() == SIM_ABSENT) {
2553 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2554 return;
2555 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002556 p_response = NULL;
2557 err = at_send_command_numeric("AT+CUSD=2", &p_response);
2558
2559 if (err < 0 || p_response->success == 0) {
2560 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2561 } else {
2562 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2563 p_response->p_intermediates->line, sizeof(char *));
2564 }
2565 at_response_free(p_response);
2566 break;
2567
2568 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002569 if (getSIMStatus() == SIM_ABSENT) {
2570 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2571 } else {
2572 at_send_command("AT+COPS=0", NULL);
2573 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002574 break;
2575
Wink Savillef4c4d362009-04-02 01:37:03 -07002576 case RIL_REQUEST_DATA_CALL_LIST:
2577 requestDataCallList(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002578 break;
2579
2580 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
2581 requestQueryNetworkSelectionMode(data, datalen, t);
2582 break;
2583
2584 case RIL_REQUEST_OEM_HOOK_RAW:
2585 // echo back data
2586 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2587 break;
2588
2589
2590 case RIL_REQUEST_OEM_HOOK_STRINGS: {
2591 int i;
2592 const char ** cur;
2593
Wink Saville4dcab4f2012-11-19 16:05:13 -08002594 RLOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002595
2596
2597 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
2598 i > 0 ; cur++, i --) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002599 RLOGD("> '%s'", *cur);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002600 }
2601
2602 // echo back strings
2603 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2604 break;
2605 }
2606
2607 case RIL_REQUEST_WRITE_SMS_TO_SIM:
2608 requestWriteSmsToSim(data, datalen, t);
2609 break;
2610
2611 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
2612 char * cmd;
2613 p_response = NULL;
2614 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
2615 err = at_send_command(cmd, &p_response);
2616 free(cmd);
2617 if (err < 0 || p_response->success == 0) {
2618 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2619 } else {
2620 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2621 }
2622 at_response_free(p_response);
2623 break;
2624 }
2625
2626 case RIL_REQUEST_ENTER_SIM_PIN:
2627 case RIL_REQUEST_ENTER_SIM_PUK:
2628 case RIL_REQUEST_ENTER_SIM_PIN2:
2629 case RIL_REQUEST_ENTER_SIM_PUK2:
2630 case RIL_REQUEST_CHANGE_SIM_PIN:
2631 case RIL_REQUEST_CHANGE_SIM_PIN2:
2632 requestEnterSimPin(data, datalen, t);
2633 break;
2634
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07002635 case RIL_REQUEST_IMS_REGISTRATION_STATE: {
2636 int reply[2];
2637 //0==unregistered, 1==registered
2638 reply[0] = s_ims_registered;
2639
2640 //to be used when changed to include service supporated info
2641 //reply[1] = s_ims_services;
2642
2643 // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
2644 reply[1] = s_ims_format;
2645
2646 RLOGD("IMS_REGISTRATION=%d, format=%d ",
2647 reply[0], reply[1]);
2648 if (reply[1] != -1) {
2649 RIL_onRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply));
2650 } else {
2651 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2652 }
2653 break;
2654 }
2655
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002656 case RIL_REQUEST_VOICE_RADIO_TECH:
2657 {
2658 int tech = techFromModemType(TECH(sMdmInfo));
2659 if (tech < 0 )
2660 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2661 else
2662 RIL_onRequestComplete(t, RIL_E_SUCCESS, &tech, sizeof(tech));
2663 }
2664 break;
2665 case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
2666 requestSetPreferredNetworkType(request, data, datalen, t);
2667 break;
2668
2669 case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
2670 requestGetPreferredNetworkType(request, data, datalen, t);
2671 break;
2672
Jun Tian58027012013-07-30 11:07:22 +08002673 case RIL_REQUEST_GET_CELL_INFO_LIST:
2674 requestGetCellInfoList(data, datalen, t);
2675 break;
2676
2677 case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
2678 requestSetCellInfoListRate(data, datalen, t);
2679 break;
2680
Etan Cohend3652192014-06-20 08:28:44 -07002681 case RIL_REQUEST_GET_HARDWARE_CONFIG:
2682 requestGetHardwareConfig(data, datalen, t);
2683 break;
2684
Naveen Kallaa65a16a2014-07-31 16:48:31 -07002685 case RIL_REQUEST_SHUTDOWN:
2686 requestShutdown(t);
2687 break;
2688
Jim Kayed2d82012017-10-06 14:17:47 -07002689 case RIL_REQUEST_QUERY_TTY_MODE:
2690 requestGetTtyMode(data, datalen, t);
2691 break;
2692
2693 case RIL_REQUEST_GET_RADIO_CAPABILITY:
2694 requestGetRadioCapability(data, datalen, t);
2695 break;
2696
2697 case RIL_REQUEST_GET_MUTE:
2698 requestGetMute(data, datalen, t);
2699 break;
2700
2701 case RIL_REQUEST_SET_INITIAL_ATTACH_APN:
2702 case RIL_REQUEST_ALLOW_DATA:
2703 case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
2704 case RIL_REQUEST_SET_CLIR:
2705 case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION:
2706 case RIL_REQUEST_SET_BAND_MODE:
2707 case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
2708 case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
2709 case RIL_REQUEST_SET_LOCATION_UPDATES:
2710 case RIL_REQUEST_SET_TTY_MODE:
2711 case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
2712 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2713 break;
2714
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002715 case RIL_REQUEST_BASEBAND_VERSION:
Jim Kayed2d82012017-10-06 14:17:47 -07002716 requestCdmaBaseBandVersion(request, data, datalen, t);
2717 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002718
2719 case RIL_REQUEST_DEVICE_IDENTITY:
Jim Kayed2d82012017-10-06 14:17:47 -07002720 requestCdmaDeviceIdentity(request, data, datalen, t);
2721 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002722
2723 case RIL_REQUEST_CDMA_SUBSCRIPTION:
Jim Kayed2d82012017-10-06 14:17:47 -07002724 requestCdmaSubscription(request, data, datalen, t);
2725 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002726
Jim Kayed2d82012017-10-06 14:17:47 -07002727 case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
2728 requestCdmaGetSubscriptionSource(request, data, datalen, t);
2729 break;
2730
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002731 case RIL_REQUEST_START_LCE:
2732 case RIL_REQUEST_STOP_LCE:
2733 case RIL_REQUEST_PULL_LCEDATA:
2734 if (getSIMStatus() == SIM_ABSENT) {
2735 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
2736 } else {
2737 RIL_onRequestComplete(t, RIL_E_LCE_NOT_SUPPORTED, NULL, 0);
2738 }
2739 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002740
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002741 case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
2742 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2743 requestCdmaGetRoamingPreference(request, data, datalen, t);
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002744 } else {
2745 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2746 }
2747 break;
2748
2749 case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
2750 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2751 requestCdmaSetSubscriptionSource(request, data, datalen, t);
2752 } else {
2753 // VTS tests expect us to silently do nothing
2754 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2755 }
2756 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002757
2758 case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
2759 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2760 requestCdmaSetRoamingPreference(request, data, datalen, t);
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002761 } else {
2762 // VTS tests expect us to silently do nothing
2763 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2764 }
2765 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002766
2767 case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
2768 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2769 requestExitEmergencyMode(data, datalen, t);
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002770 } else {
2771 // VTS tests expect us to silently do nothing
2772 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2773 }
Jim Kayed2d82012017-10-06 14:17:47 -07002774 break;
2775
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002776 default:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002777 RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002778 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2779 break;
2780 }
2781}
2782
2783/**
2784 * Synchronous call from the RIL to us to return current radio state.
2785 * RADIO_STATE_UNAVAILABLE should be the initial state.
2786 */
2787static RIL_RadioState
2788currentState()
2789{
2790 return sState;
2791}
2792/**
2793 * Call from RIL to us to find out whether a specific request code
2794 * is supported by this implementation.
2795 *
2796 * Return 1 for "supported" and 0 for "unsupported"
2797 */
2798
2799static int
Mark Salyzynba58c202014-03-12 15:20:22 -07002800onSupports (int requestCode __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002801{
2802 //@@@ todo
2803
2804 return 1;
2805}
2806
Mark Salyzynba58c202014-03-12 15:20:22 -07002807static void onCancel (RIL_Token t __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002808{
2809 //@@@todo
2810
2811}
2812
2813static const char * getVersion(void)
2814{
2815 return "android reference-ril 1.0";
2816}
2817
2818static void
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002819setRadioTechnology(ModemInfo *mdm, int newtech)
2820{
Wink Saville4dcab4f2012-11-19 16:05:13 -08002821 RLOGD("setRadioTechnology(%d)", newtech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002822
2823 int oldtech = TECH(mdm);
2824
2825 if (newtech != oldtech) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002826 RLOGD("Tech change (%d => %d)", oldtech, newtech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002827 TECH(mdm) = newtech;
2828 if (techFromModemType(newtech) != techFromModemType(oldtech)) {
2829 int tech = techFromModemType(TECH(sMdmInfo));
2830 if (tech > 0 ) {
2831 RIL_onUnsolicitedResponse(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED,
2832 &tech, sizeof(tech));
2833 }
2834 }
2835 }
2836}
2837
2838static void
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002839setRadioState(RIL_RadioState newState)
2840{
Wink Saville4dcab4f2012-11-19 16:05:13 -08002841 RLOGD("setRadioState(%d)", newState);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002842 RIL_RadioState oldState;
2843
2844 pthread_mutex_lock(&s_state_mutex);
2845
2846 oldState = sState;
2847
2848 if (s_closed > 0) {
2849 // If we're closed, the only reasonable state is
2850 // RADIO_STATE_UNAVAILABLE
2851 // This is here because things on the main thread
2852 // may attempt to change the radio state after the closed
2853 // event happened in another thread
2854 newState = RADIO_STATE_UNAVAILABLE;
2855 }
2856
2857 if (sState != newState || s_closed > 0) {
2858 sState = newState;
2859
2860 pthread_cond_broadcast (&s_state_cond);
2861 }
2862
2863 pthread_mutex_unlock(&s_state_mutex);
2864
2865
2866 /* do these outside of the mutex */
2867 if (sState != oldState) {
2868 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
2869 NULL, 0);
Alex Yakavenka81d14852013-12-04 13:54:37 -08002870 // Sim state can change as result of radio state change
2871 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
2872 NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002873
2874 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
2875 * from the AT reader thread
2876 * Currently, this doesn't happen, but if that changes then these
2877 * will need to be dispatched on the request thread
2878 */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002879 if (sState == RADIO_STATE_ON) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002880 onRadioPowerOn();
2881 }
2882 }
2883}
2884
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002885/** Returns RUIM_NOT_READY on error */
2886static SIM_Status
2887getRUIMStatus()
2888{
2889 ATResponse *p_response = NULL;
2890 int err;
2891 int ret;
2892 char *cpinLine;
2893 char *cpinResult;
2894
2895 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
2896 ret = SIM_NOT_READY;
2897 goto done;
2898 }
2899
2900 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2901
2902 if (err != 0) {
2903 ret = SIM_NOT_READY;
2904 goto done;
2905 }
2906
2907 switch (at_get_cme_error(p_response)) {
2908 case CME_SUCCESS:
2909 break;
2910
2911 case CME_SIM_NOT_INSERTED:
2912 ret = SIM_ABSENT;
2913 goto done;
2914
2915 default:
2916 ret = SIM_NOT_READY;
2917 goto done;
2918 }
2919
2920 /* CPIN? has succeeded, now look at the result */
2921
2922 cpinLine = p_response->p_intermediates->line;
2923 err = at_tok_start (&cpinLine);
2924
2925 if (err < 0) {
2926 ret = SIM_NOT_READY;
2927 goto done;
2928 }
2929
2930 err = at_tok_nextstr(&cpinLine, &cpinResult);
2931
2932 if (err < 0) {
2933 ret = SIM_NOT_READY;
2934 goto done;
2935 }
2936
2937 if (0 == strcmp (cpinResult, "SIM PIN")) {
2938 ret = SIM_PIN;
2939 goto done;
2940 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
2941 ret = SIM_PUK;
2942 goto done;
2943 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
2944 return SIM_NETWORK_PERSONALIZATION;
2945 } else if (0 != strcmp (cpinResult, "READY")) {
2946 /* we're treating unsupported lock types as "sim absent" */
2947 ret = SIM_ABSENT;
2948 goto done;
2949 }
2950
2951 at_response_free(p_response);
2952 p_response = NULL;
2953 cpinResult = NULL;
2954
2955 ret = SIM_READY;
2956
2957done:
2958 at_response_free(p_response);
2959 return ret;
2960}
2961
John Wang309ac292009-07-30 14:53:23 -07002962/** Returns SIM_NOT_READY on error */
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01002963static SIM_Status
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002964getSIMStatus()
2965{
2966 ATResponse *p_response = NULL;
2967 int err;
2968 int ret;
2969 char *cpinLine;
2970 char *cpinResult;
2971
Wink Saville4dcab4f2012-11-19 16:05:13 -08002972 RLOGD("getSIMStatus(). sState: %d",sState);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002973 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2974
2975 if (err != 0) {
John Wang309ac292009-07-30 14:53:23 -07002976 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002977 goto done;
2978 }
2979
2980 switch (at_get_cme_error(p_response)) {
2981 case CME_SUCCESS:
2982 break;
2983
2984 case CME_SIM_NOT_INSERTED:
John Wang309ac292009-07-30 14:53:23 -07002985 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002986 goto done;
2987
2988 default:
John Wang309ac292009-07-30 14:53:23 -07002989 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002990 goto done;
2991 }
2992
2993 /* CPIN? has succeeded, now look at the result */
2994
2995 cpinLine = p_response->p_intermediates->line;
2996 err = at_tok_start (&cpinLine);
2997
2998 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07002999 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003000 goto done;
3001 }
3002
3003 err = at_tok_nextstr(&cpinLine, &cpinResult);
3004
3005 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07003006 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003007 goto done;
3008 }
3009
3010 if (0 == strcmp (cpinResult, "SIM PIN")) {
John Wang309ac292009-07-30 14:53:23 -07003011 ret = SIM_PIN;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003012 goto done;
3013 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
John Wang309ac292009-07-30 14:53:23 -07003014 ret = SIM_PUK;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003015 goto done;
3016 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
John Wang309ac292009-07-30 14:53:23 -07003017 return SIM_NETWORK_PERSONALIZATION;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003018 } else if (0 != strcmp (cpinResult, "READY")) {
3019 /* we're treating unsupported lock types as "sim absent" */
John Wang309ac292009-07-30 14:53:23 -07003020 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003021 goto done;
3022 }
3023
3024 at_response_free(p_response);
3025 p_response = NULL;
3026 cpinResult = NULL;
3027
Jim Kayed2d82012017-10-06 14:17:47 -07003028 ret = (sState == RADIO_STATE_ON) ? SIM_READY : SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003029
3030done:
3031 at_response_free(p_response);
3032 return ret;
3033}
3034
3035
3036/**
Wink Savillef6aa7c12009-04-30 14:20:52 -07003037 * Get the current card status.
3038 *
3039 * This must be freed using freeCardStatus.
3040 * @return: On success returns RIL_E_SUCCESS
3041 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003042static int getCardStatus(RIL_CardStatus_v6 **pp_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07003043 static RIL_AppStatus app_status_array[] = {
John Wang309ac292009-07-30 14:53:23 -07003044 // SIM_ABSENT = 0
Wink Savillef6aa7c12009-04-30 14:20:52 -07003045 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
3046 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07003047 // SIM_NOT_READY = 1
Wink Savillef6aa7c12009-04-30 14:20:52 -07003048 { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
3049 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07003050 // SIM_READY = 2
Wink Savillef6aa7c12009-04-30 14:20:52 -07003051 { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
3052 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07003053 // SIM_PIN = 3
Wink Savillef6aa7c12009-04-30 14:20:52 -07003054 { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
3055 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07003056 // SIM_PUK = 4
Wink Savillef6aa7c12009-04-30 14:20:52 -07003057 { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
3058 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07003059 // SIM_NETWORK_PERSONALIZATION = 5
Wink Savillef6aa7c12009-04-30 14:20:52 -07003060 { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003061 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3062 // RUIM_ABSENT = 6
3063 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
3064 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3065 // RUIM_NOT_READY = 7
3066 { RIL_APPTYPE_RUIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
3067 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3068 // RUIM_READY = 8
3069 { RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
3070 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3071 // RUIM_PIN = 9
3072 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
3073 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3074 // RUIM_PUK = 10
3075 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
3076 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
3077 // RUIM_NETWORK_PERSONALIZATION = 11
3078 { RIL_APPTYPE_RUIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
bohu076e6872017-07-02 21:33:28 -07003079 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3080 // ISIM_ABSENT = 12
3081 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
3082 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3083 // ISIM_NOT_READY = 13
3084 { RIL_APPTYPE_ISIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
3085 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3086 // ISIM_READY = 14
3087 { RIL_APPTYPE_ISIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
3088 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3089 // ISIM_PIN = 15
3090 { RIL_APPTYPE_ISIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
3091 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3092 // ISIM_PUK = 16
3093 { RIL_APPTYPE_ISIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
3094 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
3095 // ISIM_NETWORK_PERSONALIZATION = 17
3096 { RIL_APPTYPE_ISIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
3097 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3098
Wink Savillef6aa7c12009-04-30 14:20:52 -07003099 };
3100 RIL_CardState card_state;
3101 int num_apps;
3102
3103 int sim_status = getSIMStatus();
John Wang309ac292009-07-30 14:53:23 -07003104 if (sim_status == SIM_ABSENT) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07003105 card_state = RIL_CARDSTATE_ABSENT;
3106 num_apps = 0;
3107 } else {
3108 card_state = RIL_CARDSTATE_PRESENT;
bohu076e6872017-07-02 21:33:28 -07003109 num_apps = 3;
Wink Savillef6aa7c12009-04-30 14:20:52 -07003110 }
3111
3112 // Allocate and initialize base card status.
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003113 RIL_CardStatus_v6 *p_card_status = malloc(sizeof(RIL_CardStatus_v6));
Wink Savillef6aa7c12009-04-30 14:20:52 -07003114 p_card_status->card_state = card_state;
3115 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
kun.tang7bb00222017-07-12 11:41:43 +08003116 p_card_status->gsm_umts_subscription_app_index = -1;
3117 p_card_status->cdma_subscription_app_index = -1;
3118 p_card_status->ims_subscription_app_index = -1;
Wink Savillef6aa7c12009-04-30 14:20:52 -07003119 p_card_status->num_applications = num_apps;
3120
3121 // Initialize application status
3122 int i;
3123 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
John Wang309ac292009-07-30 14:53:23 -07003124 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07003125 }
3126
3127 // Pickup the appropriate application status
3128 // that reflects sim_status for gsm.
3129 if (num_apps != 0) {
bohu076e6872017-07-02 21:33:28 -07003130 p_card_status->num_applications = 3;
Wink Savillef6aa7c12009-04-30 14:20:52 -07003131 p_card_status->gsm_umts_subscription_app_index = 0;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003132 p_card_status->cdma_subscription_app_index = 1;
bohu076e6872017-07-02 21:33:28 -07003133 p_card_status->ims_subscription_app_index = 2;
Wink Savillef6aa7c12009-04-30 14:20:52 -07003134
3135 // Get the correct app status
3136 p_card_status->applications[0] = app_status_array[sim_status];
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003137 p_card_status->applications[1] = app_status_array[sim_status + RUIM_ABSENT];
bohu076e6872017-07-02 21:33:28 -07003138 p_card_status->applications[2] = app_status_array[sim_status + ISIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07003139 }
3140
3141 *pp_card_status = p_card_status;
3142 return RIL_E_SUCCESS;
3143}
3144
3145/**
3146 * Free the card status returned by getCardStatus
3147 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003148static void freeCardStatus(RIL_CardStatus_v6 *p_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07003149 free(p_card_status);
3150}
3151
3152/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003153 * SIM ready means any commands that access the SIM will work, including:
3154 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
3155 * (all SMS-related commands)
3156 */
3157
Mark Salyzynba58c202014-03-12 15:20:22 -07003158static void pollSIMState (void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003159{
3160 ATResponse *p_response;
3161 int ret;
3162
Naveen Kalla2baf7232016-10-11 13:49:20 -07003163 if (sState != RADIO_STATE_UNAVAILABLE) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003164 // no longer valid to poll
3165 return;
3166 }
3167
3168 switch(getSIMStatus()) {
John Wang309ac292009-07-30 14:53:23 -07003169 case SIM_ABSENT:
3170 case SIM_PIN:
3171 case SIM_PUK:
3172 case SIM_NETWORK_PERSONALIZATION:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003173 default:
Wink Saville4dcab4f2012-11-19 16:05:13 -08003174 RLOGI("SIM ABSENT or LOCKED");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003175 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003176 return;
3177
John Wang309ac292009-07-30 14:53:23 -07003178 case SIM_NOT_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003179 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
3180 return;
3181
John Wang309ac292009-07-30 14:53:23 -07003182 case SIM_READY:
Wink Saville4dcab4f2012-11-19 16:05:13 -08003183 RLOGI("SIM_READY");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003184 onSIMReady();
3185 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003186 return;
3187 }
3188}
3189
3190/** returns 1 if on, 0 if off, and -1 on error */
3191static int isRadioOn()
3192{
3193 ATResponse *p_response = NULL;
3194 int err;
3195 char *line;
3196 char ret;
3197
3198 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
3199
3200 if (err < 0 || p_response->success == 0) {
3201 // assume radio is off
3202 goto error;
3203 }
3204
3205 line = p_response->p_intermediates->line;
3206
3207 err = at_tok_start(&line);
3208 if (err < 0) goto error;
3209
3210 err = at_tok_nextbool(&line, &ret);
3211 if (err < 0) goto error;
3212
3213 at_response_free(p_response);
3214
3215 return (int)ret;
3216
3217error:
3218
3219 at_response_free(p_response);
3220 return -1;
3221}
3222
3223/**
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003224 * Parse the response generated by a +CTEC AT command
3225 * The values read from the response are stored in current and preferred.
3226 * Both current and preferred may be null. The corresponding value is ignored in that case.
3227 *
3228 * @return: -1 if some error occurs (or if the modem doesn't understand the +CTEC command)
3229 * 1 if the response includes the current technology only
3230 * 0 if the response includes both current technology and preferred mode
3231 */
3232int parse_technology_response( const char *response, int *current, int32_t *preferred )
3233{
3234 int err;
3235 char *line, *p;
3236 int ct;
3237 int32_t pt = 0;
3238 char *str_pt;
3239
3240 line = p = strdup(response);
Wink Saville4dcab4f2012-11-19 16:05:13 -08003241 RLOGD("Response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003242 err = at_tok_start(&p);
3243 if (err || !at_tok_hasmore(&p)) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003244 RLOGD("err: %d. p: %s", err, p);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003245 free(line);
3246 return -1;
3247 }
3248
3249 err = at_tok_nextint(&p, &ct);
3250 if (err) {
3251 free(line);
3252 return -1;
3253 }
3254 if (current) *current = ct;
3255
Wink Saville4dcab4f2012-11-19 16:05:13 -08003256 RLOGD("line remaining after int: %s", p);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003257
3258 err = at_tok_nexthexint(&p, &pt);
3259 if (err) {
3260 free(line);
3261 return 1;
3262 }
3263 if (preferred) {
3264 *preferred = pt;
3265 }
3266 free(line);
3267
3268 return 0;
3269}
3270
Mark Salyzynba58c202014-03-12 15:20:22 -07003271int query_supported_techs( ModemInfo *mdm __unused, int *supported )
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003272{
3273 ATResponse *p_response;
3274 int err, val, techs = 0;
3275 char *tok;
3276 char *line;
3277
Wink Saville4dcab4f2012-11-19 16:05:13 -08003278 RLOGD("query_supported_techs");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003279 err = at_send_command_singleline("AT+CTEC=?", "+CTEC:", &p_response);
3280 if (err || !p_response->success)
3281 goto error;
3282 line = p_response->p_intermediates->line;
3283 err = at_tok_start(&line);
3284 if (err || !at_tok_hasmore(&line))
3285 goto error;
3286 while (!at_tok_nextint(&line, &val)) {
3287 techs |= ( 1 << val );
3288 }
3289 if (supported) *supported = techs;
3290 return 0;
3291error:
3292 at_response_free(p_response);
3293 return -1;
3294}
3295
3296/**
3297 * query_ctec. Send the +CTEC AT command to the modem to query the current
3298 * and preferred modes. It leaves values in the addresses pointed to by
3299 * current and preferred. If any of those pointers are NULL, the corresponding value
3300 * is ignored, but the return value will still reflect if retreiving and parsing of the
3301 * values suceeded.
3302 *
3303 * @mdm Currently unused
3304 * @current A pointer to store the current mode returned by the modem. May be null.
3305 * @preferred A pointer to store the preferred mode returned by the modem. May be null.
3306 * @return -1 on error (or failure to parse)
3307 * 1 if only the current mode was returned by modem (or failed to parse preferred)
3308 * 0 if both current and preferred were returned correctly
3309 */
Mark Salyzynba58c202014-03-12 15:20:22 -07003310int query_ctec(ModemInfo *mdm __unused, int *current, int32_t *preferred)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003311{
3312 ATResponse *response = NULL;
3313 int err;
3314 int res;
3315
Colin Cross5cba4882014-02-05 18:55:42 -08003316 RLOGD("query_ctec. current: %p, preferred: %p", current, preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003317 err = at_send_command_singleline("AT+CTEC?", "+CTEC:", &response);
3318 if (!err && response->success) {
3319 res = parse_technology_response(response->p_intermediates->line, current, preferred);
3320 at_response_free(response);
3321 return res;
3322 }
Colin Cross5cba4882014-02-05 18:55:42 -08003323 RLOGE("Error executing command: %d. response: %p. status: %d", err, response, response? response->success : -1);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003324 at_response_free(response);
3325 return -1;
3326}
3327
3328int is_multimode_modem(ModemInfo *mdm)
3329{
3330 ATResponse *response;
3331 int err;
3332 char *line;
3333 int tech;
3334 int32_t preferred;
3335
3336 if (query_ctec(mdm, &tech, &preferred) == 0) {
3337 mdm->currentTech = tech;
3338 mdm->preferredNetworkMode = preferred;
3339 if (query_supported_techs(mdm, &mdm->supportedTechs)) {
3340 return 0;
3341 }
3342 return 1;
3343 }
3344 return 0;
3345}
3346
3347/**
3348 * Find out if our modem is GSM, CDMA or both (Multimode)
3349 */
3350static void probeForModemMode(ModemInfo *info)
3351{
3352 ATResponse *response;
3353 int err;
3354 assert (info);
3355 // Currently, our only known multimode modem is qemu's android modem,
3356 // which implements the AT+CTEC command to query and set mode.
3357 // Try that first
3358
3359 if (is_multimode_modem(info)) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003360 RLOGI("Found Multimode Modem. Supported techs mask: %8.8x. Current tech: %d",
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003361 info->supportedTechs, info->currentTech);
3362 return;
3363 }
3364
3365 /* Being here means that our modem is not multimode */
3366 info->isMultimode = 0;
3367
3368 /* CDMA Modems implement the AT+WNAM command */
3369 err = at_send_command_singleline("AT+WNAM","+WNAM:", &response);
3370 if (!err && response->success) {
3371 at_response_free(response);
3372 // TODO: find out if we really support EvDo
3373 info->supportedTechs = MDM_CDMA | MDM_EVDO;
3374 info->currentTech = MDM_CDMA;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003375 RLOGI("Found CDMA Modem");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003376 return;
3377 }
3378 if (!err) at_response_free(response);
3379 // TODO: find out if modem really supports WCDMA/LTE
3380 info->supportedTechs = MDM_GSM | MDM_WCDMA | MDM_LTE;
3381 info->currentTech = MDM_GSM;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003382 RLOGI("Found GSM Modem");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003383}
3384
3385/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003386 * Initialize everything that can be configured while we're still in
3387 * AT+CFUN=0
3388 */
Mark Salyzynba58c202014-03-12 15:20:22 -07003389static void initializeCallback(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003390{
3391 ATResponse *p_response = NULL;
3392 int err;
3393
3394 setRadioState (RADIO_STATE_OFF);
3395
3396 at_handshake();
3397
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003398 probeForModemMode(sMdmInfo);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003399 /* note: we don't check errors here. Everything important will
3400 be handled in onATTimeout and onATReaderClosed */
3401
3402 /* atchannel is tolerant of echo but it must */
3403 /* have verbose result codes */
3404 at_send_command("ATE0Q0V1", NULL);
3405
3406 /* No auto-answer */
3407 at_send_command("ATS0=0", NULL);
3408
3409 /* Extended errors */
3410 at_send_command("AT+CMEE=1", NULL);
3411
3412 /* Network registration events */
3413 err = at_send_command("AT+CREG=2", &p_response);
3414
3415 /* some handsets -- in tethered mode -- don't support CREG=2 */
3416 if (err < 0 || p_response->success == 0) {
3417 at_send_command("AT+CREG=1", NULL);
3418 }
3419
3420 at_response_free(p_response);
3421
3422 /* GPRS registration events */
3423 at_send_command("AT+CGREG=1", NULL);
3424
3425 /* Call Waiting notifications */
3426 at_send_command("AT+CCWA=1", NULL);
3427
3428 /* Alternating voice/data off */
3429 at_send_command("AT+CMOD=0", NULL);
3430
3431 /* Not muted */
3432 at_send_command("AT+CMUT=0", NULL);
3433
3434 /* +CSSU unsolicited supp service notifications */
3435 at_send_command("AT+CSSN=0,1", NULL);
3436
3437 /* no connected line identification */
3438 at_send_command("AT+COLP=0", NULL);
3439
3440 /* HEX character set */
3441 at_send_command("AT+CSCS=\"HEX\"", NULL);
3442
3443 /* USSD unsolicited */
3444 at_send_command("AT+CUSD=1", NULL);
3445
3446 /* Enable +CGEV GPRS event notifications, but don't buffer */
3447 at_send_command("AT+CGEREP=1,0", NULL);
3448
3449 /* SMS PDU mode */
3450 at_send_command("AT+CMGF=0", NULL);
3451
3452#ifdef USE_TI_COMMANDS
3453
3454 at_send_command("AT%CPI=3", NULL);
3455
3456 /* TI specific -- notifications when SMS is ready (currently ignored) */
3457 at_send_command("AT%CSTAT=1", NULL);
3458
3459#endif /* USE_TI_COMMANDS */
3460
3461
3462 /* assume radio is off on error */
3463 if (isRadioOn() > 0) {
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003464 setRadioState (RADIO_STATE_ON);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003465 }
3466}
3467
3468static void waitForClose()
3469{
3470 pthread_mutex_lock(&s_state_mutex);
3471
3472 while (s_closed == 0) {
3473 pthread_cond_wait(&s_state_cond, &s_state_mutex);
3474 }
3475
3476 pthread_mutex_unlock(&s_state_mutex);
3477}
3478
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07003479static void sendUnsolImsNetworkStateChanged()
3480{
3481#if 0 // to be used when unsol is changed to return data.
3482 int reply[2];
3483 reply[0] = s_ims_registered;
3484 reply[1] = s_ims_services;
3485 reply[1] = s_ims_format;
3486#endif
3487 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED,
3488 NULL, 0);
3489}
3490
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003491/**
3492 * Called by atchannel when an unsolicited line appears
3493 * This is called on atchannel's reader thread. AT commands may
3494 * not be issued here
3495 */
3496static void onUnsolicited (const char *s, const char *sms_pdu)
3497{
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003498 char *line = NULL, *p;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003499 int err;
3500
3501 /* Ignore unsolicited responses until we're initialized.
3502 * This is OK because the RIL library will poll for initial state
3503 */
3504 if (sState == RADIO_STATE_UNAVAILABLE) {
3505 return;
3506 }
3507
3508 if (strStartsWith(s, "%CTZV:")) {
3509 /* TI specific -- NITZ time */
3510 char *response;
3511
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003512 line = p = strdup(s);
3513 at_tok_start(&p);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003514
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003515 err = at_tok_nextstr(&p, &response);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003516
3517 if (err != 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003518 RLOGE("invalid NITZ line %s\n", s);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003519 } else {
3520 RIL_onUnsolicitedResponse (
3521 RIL_UNSOL_NITZ_TIME_RECEIVED,
3522 response, strlen(response));
3523 }
Ivan Krasin7c0165e2015-12-03 15:50:10 -08003524 free(line);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003525 } else if (strStartsWith(s,"+CRING:")
3526 || strStartsWith(s,"RING")
3527 || strStartsWith(s,"NO CARRIER")
3528 || strStartsWith(s,"+CCWA")
3529 ) {
3530 RIL_onUnsolicitedResponse (
3531 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
3532 NULL, 0);
3533#ifdef WORKAROUND_FAKE_CGEV
Wink Savillef4c4d362009-04-02 01:37:03 -07003534 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003535#endif /* WORKAROUND_FAKE_CGEV */
3536 } else if (strStartsWith(s,"+CREG:")
3537 || strStartsWith(s,"+CGREG:")
3538 ) {
3539 RIL_onUnsolicitedResponse (
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003540 RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003541 NULL, 0);
3542#ifdef WORKAROUND_FAKE_CGEV
Wink Saville7f856802009-06-09 10:23:37 -07003543 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003544#endif /* WORKAROUND_FAKE_CGEV */
3545 } else if (strStartsWith(s, "+CMT:")) {
3546 RIL_onUnsolicitedResponse (
3547 RIL_UNSOL_RESPONSE_NEW_SMS,
3548 sms_pdu, strlen(sms_pdu));
3549 } else if (strStartsWith(s, "+CDS:")) {
3550 RIL_onUnsolicitedResponse (
3551 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
3552 sms_pdu, strlen(sms_pdu));
3553 } else if (strStartsWith(s, "+CGEV:")) {
3554 /* Really, we can ignore NW CLASS and ME CLASS events here,
3555 * but right now we don't since extranous
Wink Savillef4c4d362009-04-02 01:37:03 -07003556 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003557 */
3558 /* can't issue AT commands here -- call on main thread */
Wink Savillef4c4d362009-04-02 01:37:03 -07003559 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003560#ifdef WORKAROUND_FAKE_CGEV
3561 } else if (strStartsWith(s, "+CME ERROR: 150")) {
Wink Savillef4c4d362009-04-02 01:37:03 -07003562 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003563#endif /* WORKAROUND_FAKE_CGEV */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003564 } else if (strStartsWith(s, "+CTEC: ")) {
3565 int tech, mask;
3566 switch (parse_technology_response(s, &tech, NULL))
3567 {
3568 case -1: // no argument could be parsed.
Wink Saville4dcab4f2012-11-19 16:05:13 -08003569 RLOGE("invalid CTEC line %s\n", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003570 break;
3571 case 1: // current mode correctly parsed
3572 case 0: // preferred mode correctly parsed
3573 mask = 1 << tech;
3574 if (mask != MDM_GSM && mask != MDM_CDMA &&
3575 mask != MDM_WCDMA && mask != MDM_LTE) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003576 RLOGE("Unknown technology %d\n", tech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003577 } else {
3578 setRadioTechnology(sMdmInfo, tech);
3579 }
3580 break;
3581 }
3582 } else if (strStartsWith(s, "+CCSS: ")) {
3583 int source = 0;
3584 line = p = strdup(s);
3585 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003586 RLOGE("+CCSS: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003587 return;
3588 }
3589 if (at_tok_start(&p) < 0) {
3590 free(line);
3591 return;
3592 }
3593 if (at_tok_nextint(&p, &source) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003594 RLOGE("invalid +CCSS response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003595 free(line);
3596 return;
3597 }
3598 SSOURCE(sMdmInfo) = source;
3599 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,
3600 &source, sizeof(source));
3601 } else if (strStartsWith(s, "+WSOS: ")) {
3602 char state = 0;
3603 int unsol;
3604 line = p = strdup(s);
3605 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003606 RLOGE("+WSOS: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003607 return;
3608 }
3609 if (at_tok_start(&p) < 0) {
3610 free(line);
3611 return;
3612 }
3613 if (at_tok_nextbool(&p, &state) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003614 RLOGE("invalid +WSOS response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003615 free(line);
3616 return;
3617 }
3618 free(line);
3619
3620 unsol = state ?
3621 RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE : RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
3622
3623 RIL_onUnsolicitedResponse(unsol, NULL, 0);
3624
3625 } else if (strStartsWith(s, "+WPRL: ")) {
3626 int version = -1;
3627 line = p = strdup(s);
3628 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003629 RLOGE("+WPRL: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003630 return;
3631 }
3632 if (at_tok_start(&p) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003633 RLOGE("invalid +WPRL response: %s", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003634 free(line);
3635 return;
3636 }
3637 if (at_tok_nextint(&p, &version) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003638 RLOGE("invalid +WPRL response: %s", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003639 free(line);
3640 return;
3641 }
3642 free(line);
3643 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_PRL_CHANGED, &version, sizeof(version));
3644 } else if (strStartsWith(s, "+CFUN: 0")) {
3645 setRadioState(RADIO_STATE_OFF);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003646 }
3647}
3648
3649/* Called on command or reader thread */
3650static void onATReaderClosed()
3651{
Wink Saville4dcab4f2012-11-19 16:05:13 -08003652 RLOGI("AT channel closed\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003653 at_close();
3654 s_closed = 1;
3655
3656 setRadioState (RADIO_STATE_UNAVAILABLE);
3657}
3658
3659/* Called on command thread */
3660static void onATTimeout()
3661{
Wink Saville4dcab4f2012-11-19 16:05:13 -08003662 RLOGI("AT channel timeout; closing\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003663 at_close();
3664
3665 s_closed = 1;
3666
3667 /* FIXME cause a radio reset here */
3668
3669 setRadioState (RADIO_STATE_UNAVAILABLE);
3670}
3671
Etan Cohend3652192014-06-20 08:28:44 -07003672/* Called to pass hardware configuration information to telephony
3673 * framework.
3674 */
3675static void setHardwareConfiguration(int num, RIL_HardwareConfig *cfg)
3676{
3677 RIL_onUnsolicitedResponse(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, cfg, num*sizeof(*cfg));
3678}
3679
Sanket Padawef0c8ca72016-06-30 15:01:08 -07003680static void usage(char *s __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003681{
3682#ifdef RIL_SHLIB
3683 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
3684#else
3685 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
3686 exit(-1);
3687#endif
3688}
3689
3690static void *
Mark Salyzynba58c202014-03-12 15:20:22 -07003691mainLoop(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003692{
3693 int fd;
3694 int ret;
3695
3696 AT_DUMP("== ", "entering mainLoop()", -1 );
3697 at_set_on_reader_closed(onATReaderClosed);
3698 at_set_on_timeout(onATTimeout);
3699
3700 for (;;) {
3701 fd = -1;
3702 while (fd < 0) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003703 if (isInEmulator()) {
3704 fd = qemu_pipe_open("pipe:qemud:gsm");
3705 } else if (s_port > 0) {
Elliott Hughes7e3bbd42016-10-11 13:50:06 -07003706 fd = socket_network_client("localhost", s_port, SOCK_STREAM);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003707 } else if (s_device_socket) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003708 fd = socket_local_client(s_device_path,
3709 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
3710 SOCK_STREAM);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003711 } else if (s_device_path != NULL) {
3712 fd = open (s_device_path, O_RDWR);
3713 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
3714 /* disable echo on serial ports */
3715 struct termios ios;
3716 tcgetattr( fd, &ios );
3717 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
3718 tcsetattr( fd, TCSANOW, &ios );
3719 }
3720 }
3721
3722 if (fd < 0) {
3723 perror ("opening AT interface. retrying...");
3724 sleep(10);
3725 /* never returns */
3726 }
3727 }
3728
3729 s_closed = 0;
3730 ret = at_open(fd, onUnsolicited);
3731
3732 if (ret < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003733 RLOGE ("AT error %d on at_open\n", ret);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003734 return 0;
3735 }
3736
3737 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
3738
3739 // Give initializeCallback a chance to dispatched, since
3740 // we don't presently have a cancellation mechanism
3741 sleep(1);
3742
3743 waitForClose();
Wink Saville4dcab4f2012-11-19 16:05:13 -08003744 RLOGI("Re-opening after close");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003745 }
3746}
3747
3748#ifdef RIL_SHLIB
3749
3750pthread_t s_tid_mainloop;
3751
3752const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
3753{
3754 int ret;
3755 int fd = -1;
3756 int opt;
3757 pthread_attr_t attr;
3758
3759 s_rilenv = env;
3760
Sandeep Gutta11f27942014-07-10 05:00:25 +05303761 while ( -1 != (opt = getopt(argc, argv, "p:d:s:c:"))) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003762 switch (opt) {
3763 case 'p':
3764 s_port = atoi(optarg);
3765 if (s_port == 0) {
3766 usage(argv[0]);
3767 return NULL;
3768 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08003769 RLOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003770 break;
3771
3772 case 'd':
3773 s_device_path = optarg;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003774 RLOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003775 break;
3776
3777 case 's':
3778 s_device_path = optarg;
3779 s_device_socket = 1;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003780 RLOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003781 break;
3782
Sandeep Gutta11f27942014-07-10 05:00:25 +05303783 case 'c':
3784 RLOGI("Client id received %s\n", optarg);
3785 break;
3786
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003787 default:
3788 usage(argv[0]);
3789 return NULL;
3790 }
3791 }
3792
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003793 if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003794 usage(argv[0]);
3795 return NULL;
3796 }
3797
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003798 sMdmInfo = calloc(1, sizeof(ModemInfo));
3799 if (!sMdmInfo) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003800 RLOGE("Unable to alloc memory for ModemInfo");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003801 return NULL;
3802 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003803 pthread_attr_init (&attr);
3804 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3805 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
3806
3807 return &s_callbacks;
3808}
3809#else /* RIL_SHLIB */
3810int main (int argc, char **argv)
3811{
3812 int ret;
3813 int fd = -1;
3814 int opt;
3815
3816 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
3817 switch (opt) {
3818 case 'p':
3819 s_port = atoi(optarg);
3820 if (s_port == 0) {
3821 usage(argv[0]);
3822 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08003823 RLOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003824 break;
3825
3826 case 'd':
3827 s_device_path = optarg;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003828 RLOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003829 break;
3830
3831 case 's':
3832 s_device_path = optarg;
3833 s_device_socket = 1;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003834 RLOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003835 break;
3836
3837 default:
3838 usage(argv[0]);
3839 }
3840 }
3841
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003842 if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003843 usage(argv[0]);
3844 }
3845
3846 RIL_register(&s_callbacks);
3847
3848 mainLoop(NULL);
3849
3850 return 0;
3851}
3852
3853#endif /* RIL_SHLIB */