blob: 4697f9079c239f45c5d37037e732a2336535fdad [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>
Bjoern Johanssonbc497e72017-07-27 15:41:08 -070037#include <cutils/properties.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080038#include <cutils/sockets.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];
Bjoern Johanssonbc497e72017-07-27 15:41:08 -0700570 return property_get("ro.kernel.qemu.wifi", propValue, "") > 0 &&
Bjoern Johanssona8bec892017-02-09 22:55:02 -0800571 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 */
Bjoern Johanssonbc497e72017-07-27 15:41:08 -0700729 if (property_get(propName, propValue, "") <= 0) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200730 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 Johanssonbc497e72017-07-27 15:41:08 -0700743 if (hasWifi) {
744 responses[i].gateways = "192.168.200.1";
745 } else if (property_get("net.eth0.gw", propValue, "") > 0) {
746 responses[i].gateways = propValue;
747 } else {
748 responses[i].gateways = "";
749 }
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200750 responses[i].mtu = DEFAULT_MTU;
751 }
752 else {
753 /* I don't know where we are, so use the public Google DNS
754 * servers by default and no gateway.
755 */
756 responses[i].dnses = "8.8.8.8 8.8.4.4";
757 responses[i].gateways = "";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100758 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800759 }
760
761 at_response_free(p_response);
762
763 if (t != NULL)
764 RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700765 n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800766 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700767 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800768 responses,
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700769 n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800770
771 return;
772
773error:
774 if (t != NULL)
775 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
776 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700777 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800778 NULL, 0);
779
780 at_response_free(p_response);
781}
782
783static void requestQueryNetworkSelectionMode(
Mark Salyzynba58c202014-03-12 15:20:22 -0700784 void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800785{
786 int err;
787 ATResponse *p_response = NULL;
788 int response = 0;
789 char *line;
790
791 err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response);
792
793 if (err < 0 || p_response->success == 0) {
794 goto error;
795 }
796
797 line = p_response->p_intermediates->line;
798
799 err = at_tok_start(&line);
800
801 if (err < 0) {
802 goto error;
803 }
804
805 err = at_tok_nextint(&line, &response);
806
807 if (err < 0) {
808 goto error;
809 }
810
811 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
812 at_response_free(p_response);
813 return;
814error:
815 at_response_free(p_response);
Wink Saville4dcab4f2012-11-19 16:05:13 -0800816 RLOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800817 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
818}
819
Mark Salyzynba58c202014-03-12 15:20:22 -0700820static void sendCallStateChanged(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800821{
822 RIL_onUnsolicitedResponse (
823 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
824 NULL, 0);
825}
826
Mark Salyzynba58c202014-03-12 15:20:22 -0700827static void requestGetCurrentCalls(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800828{
829 int err;
830 ATResponse *p_response;
831 ATLine *p_cur;
832 int countCalls;
833 int countValidCalls;
Wink Saville3d54e742009-05-18 18:00:44 -0700834 RIL_Call *p_calls;
835 RIL_Call **pp_calls;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800836 int i;
837 int needRepoll = 0;
838
839#ifdef WORKAROUND_ERRONEOUS_ANSWER
840 int prevIncomingOrWaitingLine;
841
842 prevIncomingOrWaitingLine = s_incomingOrWaitingLine;
843 s_incomingOrWaitingLine = -1;
844#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
845
846 err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
847
848 if (err != 0 || p_response->success == 0) {
849 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
850 return;
851 }
852
853 /* count the calls */
854 for (countCalls = 0, p_cur = p_response->p_intermediates
855 ; p_cur != NULL
856 ; p_cur = p_cur->p_next
857 ) {
858 countCalls++;
859 }
860
861 /* yes, there's an array of pointers and then an array of structures */
862
Wink Saville3d54e742009-05-18 18:00:44 -0700863 pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
864 p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
865 memset (p_calls, 0, countCalls * sizeof(RIL_Call));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800866
867 /* init the pointer array */
868 for(i = 0; i < countCalls ; i++) {
869 pp_calls[i] = &(p_calls[i]);
870 }
871
872 for (countValidCalls = 0, p_cur = p_response->p_intermediates
873 ; p_cur != NULL
874 ; p_cur = p_cur->p_next
875 ) {
876 err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
877
878 if (err != 0) {
879 continue;
880 }
881
882#ifdef WORKAROUND_ERRONEOUS_ANSWER
883 if (p_calls[countValidCalls].state == RIL_CALL_INCOMING
884 || p_calls[countValidCalls].state == RIL_CALL_WAITING
885 ) {
886 s_incomingOrWaitingLine = p_calls[countValidCalls].index;
887 }
888#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
889
890 if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
891 && p_calls[countValidCalls].state != RIL_CALL_HOLDING
892 ) {
893 needRepoll = 1;
894 }
895
896 countValidCalls++;
897 }
898
899#ifdef WORKAROUND_ERRONEOUS_ANSWER
900 // Basically:
901 // A call was incoming or waiting
902 // Now it's marked as active
903 // But we never answered it
904 //
905 // This is probably a bug, and the call will probably
906 // disappear from the call list in the next poll
907 if (prevIncomingOrWaitingLine >= 0
908 && s_incomingOrWaitingLine < 0
909 && s_expectAnswer == 0
910 ) {
911 for (i = 0; i < countValidCalls ; i++) {
912
913 if (p_calls[i].index == prevIncomingOrWaitingLine
914 && p_calls[i].state == RIL_CALL_ACTIVE
915 && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX
916 ) {
Wink Saville4dcab4f2012-11-19 16:05:13 -0800917 RLOGI(
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800918 "Hit WORKAROUND_ERRONOUS_ANSWER case."
919 " Repoll count: %d\n", s_repollCallsCount);
920 s_repollCallsCount++;
921 goto error;
922 }
923 }
924 }
925
926 s_expectAnswer = 0;
927 s_repollCallsCount = 0;
928#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
929
Wink Saville3d54e742009-05-18 18:00:44 -0700930 RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
931 countValidCalls * sizeof (RIL_Call *));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800932
933 at_response_free(p_response);
934
935#ifdef POLL_CALL_STATE
936 if (countValidCalls) { // We don't seem to get a "NO CARRIER" message from
937 // smd, so we're forced to poll until the call ends.
938#else
939 if (needRepoll) {
940#endif
941 RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
942 }
943
944 return;
Tomasz Wasilczyk88961c22017-04-11 09:21:08 -0700945#ifdef WORKAROUND_ERRONEOUS_ANSWER
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800946error:
947 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
948 at_response_free(p_response);
Tomasz Wasilczyk88961c22017-04-11 09:21:08 -0700949#endif
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800950}
951
Mark Salyzynba58c202014-03-12 15:20:22 -0700952static void requestDial(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800953{
954 RIL_Dial *p_dial;
955 char *cmd;
956 const char *clir;
957 int ret;
958
959 p_dial = (RIL_Dial *)data;
960
961 switch (p_dial->clir) {
962 case 1: clir = "I"; break; /*invocation*/
963 case 2: clir = "i"; break; /*suppression*/
964 default:
965 case 0: clir = ""; break; /*subscription default*/
966 }
967
968 asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
969
970 ret = at_send_command(cmd, NULL);
971
972 free(cmd);
973
974 /* success or failure is ignored by the upper layer here.
975 it will call GET_CURRENT_CALLS and determine success that way */
976 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
977}
978
Mark Salyzynba58c202014-03-12 15:20:22 -0700979static void requestWriteSmsToSim(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800980{
981 RIL_SMS_WriteArgs *p_args;
982 char *cmd;
983 int length;
984 int err;
985 ATResponse *p_response = NULL;
986
Jim Kayeb6f3f7e2017-12-07 14:06:22 -0800987 if (getSIMStatus() == SIM_ABSENT) {
988 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
989 return;
990 }
991
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800992 p_args = (RIL_SMS_WriteArgs *)data;
993
994 length = strlen(p_args->pdu)/2;
995 asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
996
997 err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response);
998
999 if (err != 0 || p_response->success == 0) goto error;
1000
1001 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1002 at_response_free(p_response);
1003
1004 return;
1005error:
1006 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1007 at_response_free(p_response);
1008}
1009
Mark Salyzynba58c202014-03-12 15:20:22 -07001010static void requestHangup(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001011{
1012 int *p_line;
1013
1014 int ret;
1015 char *cmd;
1016
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08001017 if (getSIMStatus() == SIM_ABSENT) {
1018 RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
1019 return;
1020 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001021 p_line = (int *)data;
1022
1023 // 3GPP 22.030 6.5.5
1024 // "Releases a specific active call X"
1025 asprintf(&cmd, "AT+CHLD=1%d", p_line[0]);
1026
1027 ret = at_send_command(cmd, NULL);
1028
1029 free(cmd);
1030
1031 /* success or failure is ignored by the upper layer here.
1032 it will call GET_CURRENT_CALLS and determine success that way */
1033 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1034}
1035
Mark Salyzynba58c202014-03-12 15:20:22 -07001036static void requestSignalStrength(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001037{
1038 ATResponse *p_response = NULL;
1039 int err;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001040 char *line;
Jim Kayedc9f31b2017-04-03 13:43:31 -07001041 int count = 0;
1042 // Accept a response that is at least v6, and up to v10
1043 int minNumOfElements=sizeof(RIL_SignalStrength_v6)/sizeof(int);
1044 int maxNumOfElements=sizeof(RIL_SignalStrength_v10)/sizeof(int);
1045 int response[maxNumOfElements];
1046
1047 memset(response, 0, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001048
1049 err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response);
1050
1051 if (err < 0 || p_response->success == 0) {
1052 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1053 goto error;
1054 }
1055
1056 line = p_response->p_intermediates->line;
1057
1058 err = at_tok_start(&line);
1059 if (err < 0) goto error;
1060
Jim Kayedc9f31b2017-04-03 13:43:31 -07001061 for (count = 0; count < maxNumOfElements; count++) {
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -07001062 err = at_tok_nextint(&line, &(response[count]));
Jim Kayedc9f31b2017-04-03 13:43:31 -07001063 if (err < 0 && count < minNumOfElements) goto error;
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -07001064 }
Chih-Wei Huang28059052012-04-30 01:13:27 +08001065
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -07001066 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001067
1068 at_response_free(p_response);
1069 return;
1070
1071error:
Wink Saville4dcab4f2012-11-19 16:05:13 -08001072 RLOGE("requestSignalStrength must never return an error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001073 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1074 at_response_free(p_response);
1075}
1076
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001077/**
1078 * networkModePossible. Decides whether the network mode is appropriate for the
1079 * specified modem
1080 */
1081static int networkModePossible(ModemInfo *mdm, int nm)
1082{
1083 if ((net2modem[nm] & mdm->supportedTechs) == net2modem[nm]) {
1084 return 1;
1085 }
1086 return 0;
1087}
Mark Salyzynba58c202014-03-12 15:20:22 -07001088static void requestSetPreferredNetworkType( int request __unused, void *data,
1089 size_t datalen __unused, RIL_Token t )
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001090{
1091 ATResponse *p_response = NULL;
1092 char *cmd = NULL;
1093 int value = *(int *)data;
1094 int current, old;
1095 int err;
1096 int32_t preferred = net2pmask[value];
1097
Wink Saville4dcab4f2012-11-19 16:05:13 -08001098 RLOGD("requestSetPreferredNetworkType: current: %x. New: %x", PREFERRED_NETWORK(sMdmInfo), preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001099 if (!networkModePossible(sMdmInfo, value)) {
1100 RIL_onRequestComplete(t, RIL_E_MODE_NOT_SUPPORTED, NULL, 0);
1101 return;
1102 }
1103 if (query_ctec(sMdmInfo, &current, NULL) < 0) {
1104 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1105 return;
1106 }
1107 old = PREFERRED_NETWORK(sMdmInfo);
Wink Saville4dcab4f2012-11-19 16:05:13 -08001108 RLOGD("old != preferred: %d", old != preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001109 if (old != preferred) {
1110 asprintf(&cmd, "AT+CTEC=%d,\"%x\"", current, preferred);
Wink Saville4dcab4f2012-11-19 16:05:13 -08001111 RLOGD("Sending command: <%s>", cmd);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001112 err = at_send_command_singleline(cmd, "+CTEC:", &p_response);
1113 free(cmd);
1114 if (err || !p_response->success) {
1115 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1116 return;
1117 }
1118 PREFERRED_NETWORK(sMdmInfo) = value;
1119 if (!strstr( p_response->p_intermediates->line, "DONE") ) {
1120 int current;
1121 int res = parse_technology_response(p_response->p_intermediates->line, &current, NULL);
1122 switch (res) {
1123 case -1: // Error or unable to parse
1124 break;
1125 case 1: // Only able to parse current
1126 case 0: // Both current and preferred were parsed
1127 setRadioTechnology(sMdmInfo, current);
1128 break;
1129 }
1130 }
1131 }
1132 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1133}
1134
Mark Salyzynba58c202014-03-12 15:20:22 -07001135static void requestGetPreferredNetworkType(int request __unused, void *data __unused,
1136 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001137{
1138 int preferred;
1139 unsigned i;
1140
1141 switch ( query_ctec(sMdmInfo, NULL, &preferred) ) {
1142 case -1: // Error or unable to parse
1143 case 1: // Only able to parse current
1144 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1145 break;
1146 case 0: // Both current and preferred were parsed
1147 for ( i = 0 ; i < sizeof(net2pmask) / sizeof(int32_t) ; i++ ) {
1148 if (preferred == net2pmask[i]) {
1149 RIL_onRequestComplete(t, RIL_E_SUCCESS, &i, sizeof(int));
1150 return;
1151 }
1152 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08001153 RLOGE("Unknown preferred mode received from modem: %d", preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001154 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1155 break;
1156 }
1157
1158}
1159
Mark Salyzynba58c202014-03-12 15:20:22 -07001160static void requestCdmaPrlVersion(int request __unused, void *data __unused,
1161 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001162{
1163 int err;
1164 char * responseStr;
1165 ATResponse *p_response = NULL;
1166 const char *cmd;
1167 char *line;
1168
1169 err = at_send_command_singleline("AT+WPRL?", "+WPRL:", &p_response);
1170 if (err < 0 || !p_response->success) goto error;
1171 line = p_response->p_intermediates->line;
1172 err = at_tok_start(&line);
1173 if (err < 0) goto error;
1174 err = at_tok_nextstr(&line, &responseStr);
1175 if (err < 0 || !responseStr) goto error;
1176 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, strlen(responseStr));
1177 at_response_free(p_response);
1178 return;
1179error:
1180 at_response_free(p_response);
1181 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1182}
1183
Mark Salyzynba58c202014-03-12 15:20:22 -07001184static void requestCdmaBaseBandVersion(int request __unused, void *data __unused,
1185 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001186{
1187 int err;
1188 char * responseStr;
1189 ATResponse *p_response = NULL;
1190 const char *cmd;
1191 const char *prefix;
1192 char *line, *p;
1193 int commas;
1194 int skip;
1195 int count = 4;
1196
1197 // Fixed values. TODO: query modem
1198 responseStr = strdup("1.0.0.0");
1199 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, sizeof(responseStr));
1200 free(responseStr);
1201}
1202
bohuefa34012017-05-01 14:07:22 -07001203static void requestDeviceIdentity(int request __unused, void *data __unused,
Mark Salyzynba58c202014-03-12 15:20:22 -07001204 size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001205{
1206 int err;
1207 int response[4];
1208 char * responseStr[4];
1209 ATResponse *p_response = NULL;
1210 const char *cmd;
1211 const char *prefix;
1212 char *line, *p;
1213 int commas;
1214 int skip;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001215 int count = 4;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001216
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001217 // Fixed values. TODO: Query modem
1218 responseStr[0] = "----";
1219 responseStr[1] = "----";
1220 responseStr[2] = "77777777";
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001221
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001222 err = at_send_command_numeric("AT+CGSN", &p_response);
1223 if (err < 0 || p_response->success == 0) {
1224 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1225 return;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001226 } else {
bohuefa34012017-05-01 14:07:22 -07001227 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
1228 responseStr[3] = p_response->p_intermediates->line;
1229 } else {
1230 responseStr[0] = p_response->p_intermediates->line;
1231 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001232 }
1233
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001234 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
1235 at_response_free(p_response);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001236}
1237
Mark Salyzynba58c202014-03-12 15:20:22 -07001238static void requestCdmaGetSubscriptionSource(int request __unused, void *data,
1239 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001240{
1241 int err;
1242 int *ss = (int *)data;
1243 ATResponse *p_response = NULL;
1244 char *cmd = NULL;
1245 char *line = NULL;
1246 int response;
1247
1248 asprintf(&cmd, "AT+CCSS?");
1249 if (!cmd) goto error;
1250
1251 err = at_send_command_singleline(cmd, "+CCSS:", &p_response);
1252 if (err < 0 || !p_response->success)
1253 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001254
1255 line = p_response->p_intermediates->line;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001256 err = at_tok_start(&line);
1257 if (err < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001258
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001259 err = at_tok_nextint(&line, &response);
1260 free(cmd);
1261 cmd = NULL;
1262
1263 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1264
1265 return;
1266error:
1267 free(cmd);
1268 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1269}
1270
Mark Salyzynba58c202014-03-12 15:20:22 -07001271static void requestCdmaSetSubscriptionSource(int request __unused, void *data,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001272 size_t datalen, RIL_Token t)
1273{
1274 int err;
1275 int *ss = (int *)data;
1276 ATResponse *p_response = NULL;
1277 char *cmd = NULL;
1278
1279 if (!ss || !datalen) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001280 RLOGE("RIL_REQUEST_CDMA_SET_SUBSCRIPTION without data!");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001281 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1282 return;
1283 }
1284 asprintf(&cmd, "AT+CCSS=%d", ss[0]);
1285 if (!cmd) goto error;
1286
1287 err = at_send_command(cmd, &p_response);
1288 if (err < 0 || !p_response->success)
1289 goto error;
1290 free(cmd);
1291 cmd = NULL;
1292
1293 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1294
1295 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, ss, sizeof(ss[0]));
1296
1297 return;
1298error:
1299 free(cmd);
1300 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1301}
1302
Mark Salyzynba58c202014-03-12 15:20:22 -07001303static void requestCdmaSubscription(int request __unused, void *data __unused,
1304 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001305{
1306 int err;
1307 int response[5];
1308 char * responseStr[5];
1309 ATResponse *p_response = NULL;
1310 const char *cmd;
1311 const char *prefix;
1312 char *line, *p;
1313 int commas;
1314 int skip;
1315 int count = 5;
1316
1317 // Fixed values. TODO: Query modem
1318 responseStr[0] = "8587777777"; // MDN
1319 responseStr[1] = "1"; // SID
1320 responseStr[2] = "1"; // NID
1321 responseStr[3] = "8587777777"; // MIN
1322 responseStr[4] = "1"; // PRL Version
1323 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001324}
1325
Mark Salyzynba58c202014-03-12 15:20:22 -07001326static void requestCdmaGetRoamingPreference(int request __unused, void *data __unused,
1327 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001328{
1329 int roaming_pref = -1;
1330 ATResponse *p_response = NULL;
1331 char *line;
1332 int res;
1333
1334 res = at_send_command_singleline("AT+WRMP?", "+WRMP:", &p_response);
1335 if (res < 0 || !p_response->success) {
1336 goto error;
1337 }
1338 line = p_response->p_intermediates->line;
1339
1340 res = at_tok_start(&line);
1341 if (res < 0) goto error;
1342
1343 res = at_tok_nextint(&line, &roaming_pref);
1344 if (res < 0) goto error;
1345
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08001346 RIL_onRequestComplete(t, RIL_E_SUCCESS, &roaming_pref, sizeof(roaming_pref));
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001347 return;
1348error:
1349 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1350}
1351
Mark Salyzynba58c202014-03-12 15:20:22 -07001352static void requestCdmaSetRoamingPreference(int request __unused, void *data,
1353 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001354{
1355 int *pref = (int *)data;
1356 ATResponse *p_response = NULL;
1357 char *line;
1358 int res;
1359 char *cmd = NULL;
1360
1361 asprintf(&cmd, "AT+WRMP=%d", *pref);
1362 if (cmd == NULL) goto error;
1363
1364 res = at_send_command(cmd, &p_response);
1365 if (res < 0 || !p_response->success)
1366 goto error;
1367
1368 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1369 free(cmd);
1370 return;
1371error:
1372 free(cmd);
1373 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1374}
1375
1376static int parseRegistrationState(char *str, int *type, int *items, int **response)
1377{
1378 int err;
1379 char *line = str, *p;
1380 int *resp = NULL;
1381 int skip;
1382 int count = 3;
1383 int commas;
1384
Wink Saville4dcab4f2012-11-19 16:05:13 -08001385 RLOGD("parseRegistrationState. Parsing: %s",str);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001386 err = at_tok_start(&line);
1387 if (err < 0) goto error;
1388
1389 /* Ok you have to be careful here
1390 * The solicited version of the CREG response is
1391 * +CREG: n, stat, [lac, cid]
1392 * and the unsolicited version is
1393 * +CREG: stat, [lac, cid]
1394 * The <n> parameter is basically "is unsolicited creg on?"
1395 * which it should always be
1396 *
1397 * Now we should normally get the solicited version here,
1398 * but the unsolicited version could have snuck in
1399 * so we have to handle both
1400 *
1401 * Also since the LAC and CID are only reported when registered,
1402 * we can have 1, 2, 3, or 4 arguments here
1403 *
1404 * finally, a +CGREG: answer may have a fifth value that corresponds
1405 * to the network type, as in;
1406 *
1407 * +CGREG: n, stat [,lac, cid [,networkType]]
1408 */
1409
1410 /* count number of commas */
1411 commas = 0;
1412 for (p = line ; *p != '\0' ;p++) {
1413 if (*p == ',') commas++;
1414 }
1415
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001416 resp = (int *)calloc(commas + 1, sizeof(int));
1417 if (!resp) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001418 switch (commas) {
1419 case 0: /* +CREG: <stat> */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001420 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001421 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001422 resp[1] = -1;
1423 resp[2] = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001424 break;
1425
1426 case 1: /* +CREG: <n>, <stat> */
1427 err = at_tok_nextint(&line, &skip);
1428 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001429 err = at_tok_nextint(&line, &resp[0]);
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 resp[1] = -1;
1432 resp[2] = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001433 if (err < 0) goto error;
1434 break;
1435
1436 case 2: /* +CREG: <stat>, <lac>, <cid> */
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 case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
1445 err = at_tok_nextint(&line, &skip);
1446 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001447 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001448 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001449 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001450 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001451 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001452 if (err < 0) goto error;
1453 break;
1454 /* special case for CGREG, there is a fourth parameter
1455 * that is the network type (unknown/gprs/edge/umts)
1456 */
1457 case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
1458 err = at_tok_nextint(&line, &skip);
1459 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001460 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001461 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001462 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001463 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001464 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001465 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001466 err = at_tok_nexthexint(&line, &resp[3]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001467 if (err < 0) goto error;
1468 count = 4;
1469 break;
1470 default:
1471 goto error;
1472 }
Wink Saville8a9e0212013-04-09 12:11:38 -07001473 s_lac = resp[1];
1474 s_cid = resp[2];
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001475 if (response)
1476 *response = resp;
1477 if (items)
1478 *items = commas + 1;
1479 if (type)
1480 *type = techFromModemType(TECH(sMdmInfo));
1481 return 0;
1482error:
1483 free(resp);
1484 return -1;
1485}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001486
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001487#define REG_STATE_LEN 15
1488#define REG_DATA_STATE_LEN 6
Mark Salyzynba58c202014-03-12 15:20:22 -07001489static void requestRegistrationState(int request, void *data __unused,
1490 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001491{
1492 int err;
1493 int *registration;
1494 char **responseStr = NULL;
1495 ATResponse *p_response = NULL;
1496 const char *cmd;
1497 const char *prefix;
1498 char *line;
1499 int i = 0, j, numElements = 0;
1500 int count = 3;
1501 int type, startfrom;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001502
Wink Saville4dcab4f2012-11-19 16:05:13 -08001503 RLOGD("requestRegistrationState");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001504 if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
1505 cmd = "AT+CREG?";
1506 prefix = "+CREG:";
1507 numElements = REG_STATE_LEN;
1508 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1509 cmd = "AT+CGREG?";
1510 prefix = "+CGREG:";
1511 numElements = REG_DATA_STATE_LEN;
1512 } else {
1513 assert(0);
1514 goto error;
1515 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001516
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001517 err = at_send_command_singleline(cmd, prefix, &p_response);
1518
1519 if (err != 0) goto error;
1520
1521 line = p_response->p_intermediates->line;
1522
1523 if (parseRegistrationState(line, &type, &count, &registration)) goto error;
1524
1525 responseStr = malloc(numElements * sizeof(char *));
1526 if (!responseStr) goto error;
1527 memset(responseStr, 0, numElements * sizeof(char *));
1528 /**
1529 * The first '4' bytes for both registration states remain the same.
1530 * But if the request is 'DATA_REGISTRATION_STATE',
1531 * the 5th and 6th byte(s) are optional.
1532 */
1533 if (is3gpp2(type) == 1) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001534 RLOGD("registration state type: 3GPP2");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001535 // TODO: Query modem
1536 startfrom = 3;
1537 if(request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
1538 asprintf(&responseStr[3], "8"); // EvDo revA
1539 asprintf(&responseStr[4], "1"); // BSID
1540 asprintf(&responseStr[5], "123"); // Latitude
1541 asprintf(&responseStr[6], "222"); // Longitude
1542 asprintf(&responseStr[7], "0"); // CSS Indicator
1543 asprintf(&responseStr[8], "4"); // SID
1544 asprintf(&responseStr[9], "65535"); // NID
1545 asprintf(&responseStr[10], "0"); // Roaming indicator
1546 asprintf(&responseStr[11], "1"); // System is in PRL
1547 asprintf(&responseStr[12], "0"); // Default Roaming indicator
1548 asprintf(&responseStr[13], "0"); // Reason for denial
1549 asprintf(&responseStr[14], "0"); // Primary Scrambling Code of Current cell
1550 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1551 asprintf(&responseStr[3], "8"); // Available data radio technology
1552 }
1553 } else { // type == RADIO_TECH_3GPP
Wink Saville4dcab4f2012-11-19 16:05:13 -08001554 RLOGD("registration state type: 3GPP");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001555 startfrom = 0;
1556 asprintf(&responseStr[1], "%x", registration[1]);
1557 asprintf(&responseStr[2], "%x", registration[2]);
1558 if (count > 3)
1559 asprintf(&responseStr[3], "%d", registration[3]);
1560 }
1561 asprintf(&responseStr[0], "%d", registration[0]);
1562
1563 /**
1564 * Optional bytes for DATA_REGISTRATION_STATE request
1565 * 4th byte : Registration denial code
1566 * 5th byte : The max. number of simultaneous Data Calls
1567 */
1568 if(request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1569 // asprintf(&responseStr[4], "3");
1570 // asprintf(&responseStr[5], "1");
1571 }
1572
1573 for (j = startfrom; j < numElements; j++) {
1574 if (!responseStr[i]) goto error;
1575 }
1576 free(registration);
1577 registration = NULL;
1578
1579 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, numElements*sizeof(responseStr));
1580 for (j = 0; j < numElements; j++ ) {
1581 free(responseStr[j]);
1582 responseStr[j] = NULL;
1583 }
1584 free(responseStr);
1585 responseStr = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001586 at_response_free(p_response);
1587
1588 return;
1589error:
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001590 if (responseStr) {
1591 for (j = 0; j < numElements; j++) {
1592 free(responseStr[j]);
1593 responseStr[j] = NULL;
1594 }
1595 free(responseStr);
1596 responseStr = NULL;
1597 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08001598 RLOGE("requestRegistrationState must never return an error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001599 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1600 at_response_free(p_response);
1601}
1602
Mark Salyzynba58c202014-03-12 15:20:22 -07001603static void requestOperator(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001604{
1605 int err;
1606 int i;
1607 int skip;
1608 ATLine *p_cur;
1609 char *response[3];
1610
1611 memset(response, 0, sizeof(response));
1612
1613 ATResponse *p_response = NULL;
1614
1615 err = at_send_command_multiline(
1616 "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
1617 "+COPS:", &p_response);
1618
1619 /* we expect 3 lines here:
1620 * +COPS: 0,0,"T - Mobile"
1621 * +COPS: 0,1,"TMO"
1622 * +COPS: 0,2,"310170"
1623 */
1624
1625 if (err != 0) goto error;
1626
1627 for (i = 0, p_cur = p_response->p_intermediates
1628 ; p_cur != NULL
1629 ; p_cur = p_cur->p_next, i++
1630 ) {
1631 char *line = p_cur->line;
1632
1633 err = at_tok_start(&line);
1634 if (err < 0) goto error;
1635
1636 err = at_tok_nextint(&line, &skip);
1637 if (err < 0) goto error;
1638
1639 // If we're unregistered, we may just get
1640 // a "+COPS: 0" response
1641 if (!at_tok_hasmore(&line)) {
1642 response[i] = NULL;
1643 continue;
1644 }
1645
1646 err = at_tok_nextint(&line, &skip);
1647 if (err < 0) goto error;
1648
1649 // a "+COPS: 0, n" response is also possible
1650 if (!at_tok_hasmore(&line)) {
1651 response[i] = NULL;
1652 continue;
1653 }
1654
1655 err = at_tok_nextstr(&line, &(response[i]));
1656 if (err < 0) goto error;
Wink Saville8a9e0212013-04-09 12:11:38 -07001657 // Simple assumption that mcc and mnc are 3 digits each
1658 if (strlen(response[i]) == 6) {
1659 if (sscanf(response[i], "%3d%3d", &s_mcc, &s_mnc) != 2) {
1660 RLOGE("requestOperator expected mccmnc to be 6 decimal digits");
1661 }
1662 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001663 }
1664
1665 if (i != 3) {
1666 /* expect 3 lines exactly */
1667 goto error;
1668 }
1669
1670 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
1671 at_response_free(p_response);
1672
1673 return;
1674error:
Wink Saville4dcab4f2012-11-19 16:05:13 -08001675 RLOGE("requestOperator must not return error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001676 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1677 at_response_free(p_response);
1678}
1679
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001680static void requestCdmaSendSMS(void *data, size_t datalen, RIL_Token t)
1681{
1682 int err = 1; // Set to go to error:
1683 RIL_SMS_Response response;
1684 RIL_CDMA_SMS_Message* rcsm;
1685
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08001686 if (getSIMStatus() == SIM_ABSENT) {
1687 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
1688 return;
1689 }
1690
Mark Salyzynba58c202014-03-12 15:20:22 -07001691 RLOGD("requestCdmaSendSMS datalen=%zu, sizeof(RIL_CDMA_SMS_Message)=%zu",
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001692 datalen, sizeof(RIL_CDMA_SMS_Message));
1693
1694 // verify data content to test marshalling/unmarshalling:
1695 rcsm = (RIL_CDMA_SMS_Message*)data;
Wink Saville4dcab4f2012-11-19 16:05:13 -08001696 RLOGD("TeleserviceID=%d, bIsServicePresent=%d, \
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001697 uServicecategory=%d, sAddress.digit_mode=%d, \
1698 sAddress.Number_mode=%d, sAddress.number_type=%d, ",
1699 rcsm->uTeleserviceID, rcsm->bIsServicePresent,
1700 rcsm->uServicecategory,rcsm->sAddress.digit_mode,
1701 rcsm->sAddress.number_mode,rcsm->sAddress.number_type);
1702
1703 if (err != 0) goto error;
1704
1705 // Cdma Send SMS implementation will go here:
1706 // But it is not implemented yet.
1707
1708 memset(&response, 0, sizeof(response));
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001709 response.messageRef = 1;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001710 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1711 return;
1712
1713error:
1714 // Cdma Send SMS will always cause send retry error.
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001715 response.messageRef = -1;
1716 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001717}
1718
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001719static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
1720{
1721 int err;
1722 const char *smsc;
1723 const char *pdu;
1724 int tpLayerLength;
1725 char *cmd1, *cmd2;
1726 RIL_SMS_Response response;
1727 ATResponse *p_response = NULL;
1728
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08001729 if (getSIMStatus() == SIM_ABSENT) {
1730 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
1731 return;
1732 }
1733
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001734 memset(&response, 0, sizeof(response));
Mark Salyzynba58c202014-03-12 15:20:22 -07001735 RLOGD("requestSendSMS datalen =%zu", datalen);
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001736
1737 if (s_ims_gsm_fail != 0) goto error;
1738 if (s_ims_gsm_retry != 0) goto error2;
1739
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001740 smsc = ((const char **)data)[0];
1741 pdu = ((const char **)data)[1];
1742
1743 tpLayerLength = strlen(pdu)/2;
1744
1745 // "NULL for default SMSC"
1746 if (smsc == NULL) {
1747 smsc= "00";
1748 }
1749
1750 asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
1751 asprintf(&cmd2, "%s%s", smsc, pdu);
1752
1753 err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response);
1754
Daniele Palmasa5c743e2015-05-06 11:47:59 +02001755 free(cmd1);
1756 free(cmd2);
1757
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001758 if (err != 0 || p_response->success == 0) goto error;
1759
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001760 /* FIXME fill in messageRef and ackPDU */
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001761 response.messageRef = 1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001762 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1763 at_response_free(p_response);
1764
1765 return;
1766error:
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001767 response.messageRef = -2;
1768 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001769 at_response_free(p_response);
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001770 return;
1771error2:
1772 // send retry error.
1773 response.messageRef = -1;
1774 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
1775 at_response_free(p_response);
1776 return;
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08001777}
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001778
1779static void requestImsSendSMS(void *data, size_t datalen, RIL_Token t)
1780{
1781 RIL_IMS_SMS_Message *p_args;
1782 RIL_SMS_Response response;
1783
1784 memset(&response, 0, sizeof(response));
1785
Mark Salyzynba58c202014-03-12 15:20:22 -07001786 RLOGD("requestImsSendSMS: datalen=%zu, "
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001787 "registered=%d, service=%d, format=%d, ims_perm_fail=%d, "
1788 "ims_retry=%d, gsm_fail=%d, gsm_retry=%d",
1789 datalen, s_ims_registered, s_ims_services, s_ims_format,
1790 s_ims_cause_perm_failure, s_ims_cause_retry, s_ims_gsm_fail,
1791 s_ims_gsm_retry);
1792
1793 // figure out if this is gsm/cdma format
1794 // then route it to requestSendSMS vs requestCdmaSendSMS respectively
1795 p_args = (RIL_IMS_SMS_Message *)data;
1796
1797 if (0 != s_ims_cause_perm_failure ) goto error;
1798
1799 // want to fail over ims and this is first request over ims
1800 if (0 != s_ims_cause_retry && 0 == p_args->retry) goto error2;
1801
1802 if (RADIO_TECH_3GPP == p_args->tech) {
1803 return requestSendSMS(p_args->message.gsmMessage,
1804 datalen - sizeof(RIL_RadioTechnologyFamily),
1805 t);
1806 } else if (RADIO_TECH_3GPP2 == p_args->tech) {
1807 return requestCdmaSendSMS(p_args->message.cdmaMessage,
1808 datalen - sizeof(RIL_RadioTechnologyFamily),
1809 t);
1810 } else {
1811 RLOGE("requestImsSendSMS invalid format value =%d", p_args->tech);
1812 }
1813
1814error:
1815 response.messageRef = -2;
1816 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
1817 return;
1818
1819error2:
1820 response.messageRef = -1;
1821 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001822}
1823
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07001824static void requestSimOpenChannel(void *data, size_t datalen, RIL_Token t)
1825{
1826 ATResponse *p_response = NULL;
1827 int32_t session_id;
1828 int err;
1829 char cmd[32];
1830 char dummy;
1831 char *line;
1832
1833 // Max length is 16 bytes according to 3GPP spec 27.007 section 8.45
1834 if (data == NULL || datalen == 0 || datalen > 16) {
1835 ALOGE("Invalid data passed to requestSimOpenChannel");
1836 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1837 return;
1838 }
1839
1840 snprintf(cmd, sizeof(cmd), "AT+CCHO=%s", data);
1841
1842 err = at_send_command_numeric(cmd, &p_response);
1843 if (err < 0 || p_response == NULL || p_response->success == 0) {
1844 ALOGE("Error %d opening logical channel: %d",
1845 err, p_response ? p_response->success : 0);
1846 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1847 at_response_free(p_response);
1848 return;
1849 }
1850
1851 // Ensure integer only by scanning for an extra char but expect one result
1852 line = p_response->p_intermediates->line;
1853 if (sscanf(line, "%" SCNd32 "%c", &session_id, &dummy) != 1) {
1854 ALOGE("Invalid AT response, expected integer, was '%s'", line);
1855 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1856 return;
1857 }
1858
1859 RIL_onRequestComplete(t, RIL_E_SUCCESS, &session_id, sizeof(&session_id));
1860 at_response_free(p_response);
1861}
1862
1863static void requestSimCloseChannel(void *data, size_t datalen, RIL_Token t)
1864{
1865 ATResponse *p_response = NULL;
1866 int32_t session_id;
1867 int err;
1868 char cmd[32];
1869
1870 if (data == NULL || datalen != sizeof(session_id)) {
1871 ALOGE("Invalid data passed to requestSimCloseChannel");
1872 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1873 return;
1874 }
1875 session_id = ((int32_t *)data)[0];
1876 snprintf(cmd, sizeof(cmd), "AT+CCHC=%" PRId32, session_id);
1877 err = at_send_command_singleline(cmd, "+CCHC", &p_response);
1878
1879 if (err < 0 || p_response == NULL || p_response->success == 0) {
1880 ALOGE("Error %d closing logical channel %d: %d",
1881 err, session_id, p_response ? p_response->success : 0);
1882 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1883 at_response_free(p_response);
1884 return;
1885 }
1886
1887 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1888
1889 at_response_free(p_response);
1890}
1891
1892static void requestSimTransmitApduChannel(void *data,
1893 size_t datalen,
1894 RIL_Token t)
1895{
1896 ATResponse *p_response = NULL;
1897 int err;
1898 char *cmd;
1899 char *line;
1900 size_t cmd_size;
1901 RIL_SIM_IO_Response sim_response;
1902 RIL_SIM_APDU *apdu = (RIL_SIM_APDU *)data;
1903
1904 if (apdu == NULL || datalen != sizeof(RIL_SIM_APDU)) {
1905 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1906 return;
1907 }
1908
1909 cmd_size = 10 + (apdu->data ? strlen(apdu->data) : 0);
Wei Wang9cec1e02017-02-08 14:37:37 -08001910 asprintf(&cmd, "AT+CGLA=%d,%zu,%02x%02x%02x%02x%02x%s",
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07001911 apdu->sessionid, cmd_size, apdu->cla, apdu->instruction,
1912 apdu->p1, apdu->p2, apdu->p3, apdu->data ? apdu->data : "");
1913
1914 err = at_send_command_singleline(cmd, "+CGLA", &p_response);
1915 free(cmd);
1916 if (err < 0 || p_response == NULL || p_response->success == 0) {
1917 ALOGE("Error %d transmitting APDU: %d",
1918 err, p_response ? p_response->success : 0);
1919 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1920 at_response_free(p_response);
1921 return;
1922 }
1923
1924 line = p_response->p_intermediates->line;
1925 err = parseSimResponseLine(line, &sim_response);
1926
1927 if (err == 0) {
1928 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1929 &sim_response, sizeof(sim_response));
1930 } else {
1931 ALOGE("Error %d parsing SIM response line: %s", err, line);
1932 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1933 }
1934 at_response_free(p_response);
1935}
1936
Wink Savillef4c4d362009-04-02 01:37:03 -07001937static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001938{
1939 const char *apn;
1940 char *cmd;
1941 int err;
1942 ATResponse *p_response = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001943
Wink Savillef4c4d362009-04-02 01:37:03 -07001944 apn = ((const char **)data)[2];
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001945
1946#ifdef USE_TI_COMMANDS
1947 // Config for multislot class 10 (probably default anyway eh?)
1948 err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
1949 NULL);
1950
1951 err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
1952#endif /* USE_TI_COMMANDS */
1953
1954 int fd, qmistatus;
1955 size_t cur = 0;
1956 size_t len;
1957 ssize_t written, rlen;
1958 char status[32] = {0};
1959 int retry = 10;
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001960 const char *pdp_type;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001961
Wink Saville4dcab4f2012-11-19 16:05:13 -08001962 RLOGD("requesting data connection to APN '%s'", apn);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001963
1964 fd = open ("/dev/qmi", O_RDWR);
1965 if (fd >= 0) { /* the device doesn't exist on the emulator */
1966
Wink Saville4dcab4f2012-11-19 16:05:13 -08001967 RLOGD("opened the qmi device\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001968 asprintf(&cmd, "up:%s", apn);
1969 len = strlen(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001970
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001971 while (cur < len) {
1972 do {
1973 written = write (fd, cmd + cur, len - cur);
1974 } while (written < 0 && errno == EINTR);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001975
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001976 if (written < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001977 RLOGE("### ERROR writing to /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001978 close(fd);
1979 goto error;
1980 }
1981
1982 cur += written;
1983 }
1984
1985 // wait for interface to come online
1986
1987 do {
1988 sleep(1);
1989 do {
1990 rlen = read(fd, status, 31);
1991 } while (rlen < 0 && errno == EINTR);
1992
1993 if (rlen < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001994 RLOGE("### ERROR reading from /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001995 close(fd);
1996 goto error;
1997 } else {
1998 status[rlen] = '\0';
Wink Saville4dcab4f2012-11-19 16:05:13 -08001999 RLOGD("### status: %s", status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002000 }
2001 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
2002
2003 close(fd);
2004
2005 if (retry == 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002006 RLOGE("### Failed to get data connection up\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002007 goto error;
2008 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002009
2010 qmistatus = system("netcfg rmnet0 dhcp");
2011
Wink Saville4dcab4f2012-11-19 16:05:13 -08002012 RLOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002013
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002014 if (qmistatus < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002015
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002016 } else {
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -07002017 bool hasWifi = hasWifiCapability();
2018 const char* radioInterfaceName = getRadioInterfaceName(hasWifi);
2019 if (setInterfaceState(radioInterfaceName, kInterfaceUp) != RIL_E_SUCCESS) {
2020 goto error;
2021 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002022
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002023 if (datalen > 6 * sizeof(char *)) {
2024 pdp_type = ((const char **)data)[6];
2025 } else {
2026 pdp_type = "IP";
2027 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002028
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01002029 asprintf(&cmd, "AT+CGDCONT=1,\"%s\",\"%s\",,0,0", pdp_type, apn);
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002030 //FIXME check for error here
2031 err = at_send_command(cmd, NULL);
2032 free(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002033
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002034 // Set required QoS params to default
2035 err = at_send_command("AT+CGQREQ=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002036
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002037 // Set minimum QoS params to default
2038 err = at_send_command("AT+CGQMIN=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002039
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002040 // packet-domain event reporting
2041 err = at_send_command("AT+CGEREP=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002042
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002043 // Hangup anything that's happening there now
2044 err = at_send_command("AT+CGACT=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002045
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07002046 // Start data on PDP context 1
2047 err = at_send_command("ATD*99***1#", &p_response);
2048
2049 if (err < 0 || p_response->success == 0) {
2050 goto error;
2051 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002052 }
2053
Wink Saville43808972011-01-13 17:39:51 -08002054 requestOrSendDataCallList(&t);
2055
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002056 at_response_free(p_response);
2057
2058 return;
2059error:
2060 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2061 at_response_free(p_response);
2062
2063}
2064
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -07002065static void requestDeactivateDataCall(RIL_Token t)
2066{
2067 bool hasWifi = hasWifiCapability();
2068 const char* radioInterfaceName = getRadioInterfaceName(hasWifi);
2069 RIL_Errno rilErrno = setInterfaceState(radioInterfaceName, kInterfaceDown);
2070 RIL_onRequestComplete(t, rilErrno, NULL, 0);
2071}
2072
Mark Salyzynba58c202014-03-12 15:20:22 -07002073static void requestSMSAcknowledge(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002074{
2075 int ackSuccess;
2076 int err;
2077
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002078 if (getSIMStatus() == SIM_ABSENT) {
2079 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2080 return;
2081 }
2082
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002083 ackSuccess = ((int *)data)[0];
2084
2085 if (ackSuccess == 1) {
2086 err = at_send_command("AT+CNMA=1", NULL);
2087 } else if (ackSuccess == 0) {
2088 err = at_send_command("AT+CNMA=2", NULL);
2089 } else {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002090 RLOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002091 goto error;
2092 }
2093
2094 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2095error:
2096 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2097
2098}
2099
Mark Salyzynba58c202014-03-12 15:20:22 -07002100static void requestSIM_IO(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002101{
2102 ATResponse *p_response = NULL;
2103 RIL_SIM_IO_Response sr;
2104 int err;
2105 char *cmd = NULL;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002106 RIL_SIM_IO_v6 *p_args;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002107 char *line;
2108
2109 memset(&sr, 0, sizeof(sr));
2110
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002111 p_args = (RIL_SIM_IO_v6 *)data;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002112
2113 /* FIXME handle pin2 */
2114
2115 if (p_args->data == NULL) {
2116 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
2117 p_args->command, p_args->fileid,
2118 p_args->p1, p_args->p2, p_args->p3);
2119 } else {
2120 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
2121 p_args->command, p_args->fileid,
2122 p_args->p1, p_args->p2, p_args->p3, p_args->data);
2123 }
2124
2125 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
2126
2127 if (err < 0 || p_response->success == 0) {
2128 goto error;
2129 }
2130
2131 line = p_response->p_intermediates->line;
2132
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07002133 err = parseSimResponseLine(line, &sr);
2134 if (err < 0) {
2135 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002136 }
2137
2138 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
2139 at_response_free(p_response);
2140 free(cmd);
2141
2142 return;
2143error:
2144 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2145 at_response_free(p_response);
2146 free(cmd);
2147
2148}
2149
2150static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
2151{
2152 ATResponse *p_response = NULL;
2153 int err;
2154 char* cmd = NULL;
2155 const char** strings = (const char**)data;;
2156
2157 if ( datalen == sizeof(char*) ) {
2158 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
2159 } else if ( datalen == 2*sizeof(char*) ) {
2160 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
2161 } else
2162 goto error;
2163
2164 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
2165 free(cmd);
2166
2167 if (err < 0 || p_response->success == 0) {
2168error:
2169 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
2170 } else {
2171 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2172 }
2173 at_response_free(p_response);
2174}
2175
2176
Mark Salyzynba58c202014-03-12 15:20:22 -07002177static void requestSendUSSD(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002178{
2179 const char *ussdRequest;
2180
2181 ussdRequest = (char *)(data);
2182
2183
2184 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2185
2186// @@@ TODO
2187
2188}
2189
Mark Salyzynba58c202014-03-12 15:20:22 -07002190static void requestExitEmergencyMode(void *data __unused, size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002191{
2192 int err;
2193 ATResponse *p_response = NULL;
2194
2195 err = at_send_command("AT+WSOS=0", &p_response);
2196
2197 if (err < 0 || p_response->success == 0) {
2198 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2199 return;
2200 }
2201
2202 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2203}
2204
2205// TODO: Use all radio types
2206static int techFromModemType(int mdmtype)
2207{
2208 int ret = -1;
2209 switch (1 << mdmtype) {
2210 case MDM_CDMA:
2211 ret = RADIO_TECH_1xRTT;
2212 break;
2213 case MDM_EVDO:
2214 ret = RADIO_TECH_EVDO_A;
2215 break;
2216 case MDM_GSM:
2217 ret = RADIO_TECH_GPRS;
2218 break;
2219 case MDM_WCDMA:
2220 ret = RADIO_TECH_HSPA;
2221 break;
2222 case MDM_LTE:
2223 ret = RADIO_TECH_LTE;
2224 break;
2225 }
2226 return ret;
2227}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002228
Mark Salyzynba58c202014-03-12 15:20:22 -07002229static void requestGetCellInfoList(void *data __unused, size_t datalen __unused, RIL_Token t)
Wink Saville8a9e0212013-04-09 12:11:38 -07002230{
2231 uint64_t curTime = ril_nano_time();
2232 RIL_CellInfo ci[1] =
2233 {
2234 { // ci[0]
2235 1, // cellInfoType
2236 1, // registered
Sanket Padawef0c8ca72016-06-30 15:01:08 -07002237 RIL_TIMESTAMP_TYPE_MODEM,
Wink Saville8a9e0212013-04-09 12:11:38 -07002238 curTime - 1000, // Fake some time in the past
2239 { // union CellInfo
2240 { // RIL_CellInfoGsm gsm
2241 { // gsm.cellIdneityGsm
2242 s_mcc, // mcc
2243 s_mnc, // mnc
2244 s_lac, // lac
2245 s_cid, // cid
Wink Saville8a9e0212013-04-09 12:11:38 -07002246 },
2247 { // gsm.signalStrengthGsm
2248 10, // signalStrength
2249 0 // bitErrorRate
2250 }
2251 }
2252 }
2253 }
2254 };
2255
2256 RIL_onRequestComplete(t, RIL_E_SUCCESS, ci, sizeof(ci));
2257}
2258
2259
Sanket Padawef0c8ca72016-06-30 15:01:08 -07002260static void requestSetCellInfoListRate(void *data, size_t datalen __unused, RIL_Token t)
Wink Saville8a9e0212013-04-09 12:11:38 -07002261{
2262 // For now we'll save the rate but no RIL_UNSOL_CELL_INFO_LIST messages
2263 // will be sent.
2264 assert (datalen == sizeof(int));
2265 s_cell_info_rate_ms = ((int *)data)[0];
2266
2267 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2268}
2269
Etan Cohend3652192014-06-20 08:28:44 -07002270static void requestGetHardwareConfig(void *data, size_t datalen, RIL_Token t)
2271{
2272 // TODO - hook this up with real query/info from radio.
2273
2274 RIL_HardwareConfig hwCfg;
2275
2276 RIL_UNUSED_PARM(data);
2277 RIL_UNUSED_PARM(datalen);
2278
2279 hwCfg.type = -1;
2280
2281 RIL_onRequestComplete(t, RIL_E_SUCCESS, &hwCfg, sizeof(hwCfg));
2282}
2283
Jim Kayed2d82012017-10-06 14:17:47 -07002284static void requestGetTtyMode(void *data, size_t datalen, RIL_Token t)
2285{
2286 int ttyModeResponse;
2287
2288 RIL_UNUSED_PARM(data);
2289 RIL_UNUSED_PARM(datalen);
2290
2291 ttyModeResponse = (getSIMStatus() == SIM_READY) ? 1 // TTY Full
2292 : 0; // TTY Off
2293
2294 RIL_onRequestComplete(t, RIL_E_SUCCESS, &ttyModeResponse, sizeof(ttyModeResponse));
2295}
2296
2297static void requestGetRadioCapability(void *data, size_t datalen, RIL_Token t)
2298{
2299 RIL_RadioCapability radioCapability;
2300
2301 RIL_UNUSED_PARM(data);
2302 RIL_UNUSED_PARM(datalen);
2303
2304 radioCapability.version = RIL_RADIO_CAPABILITY_VERSION;
2305 radioCapability.session = 0;
2306 radioCapability.phase = 0;
2307 radioCapability.rat = 0;
2308 radioCapability.logicalModemUuid[0] = '\0';
2309 radioCapability.status = RC_STATUS_SUCCESS;
2310
2311 RIL_onRequestComplete(t, RIL_E_SUCCESS, &radioCapability, sizeof(radioCapability));
2312}
2313
2314static void requestGetMute(void *data, size_t datalen, RIL_Token t)
2315{
2316 int muteResponse;
2317
2318 RIL_UNUSED_PARM(data);
2319 RIL_UNUSED_PARM(datalen);
2320
2321 muteResponse = 0; // Mute disabled
2322
2323 RIL_onRequestComplete(t, RIL_E_SUCCESS, &muteResponse, sizeof(muteResponse));
2324}
Etan Cohend3652192014-06-20 08:28:44 -07002325
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002326/*** Callback methods from the RIL library to us ***/
2327
2328/**
2329 * Call from RIL to us to make a RIL_REQUEST
2330 *
2331 * Must be completed with a call to RIL_onRequestComplete()
2332 *
2333 * RIL_onRequestComplete() may be called from any thread, before or after
2334 * this function returns.
2335 *
Weilun Du9f471e22017-02-07 10:47:19 -08002336 * Because onRequest function could be called from multiple different thread,
2337 * we must ensure that the underlying at_send_command_* function
2338 * is atomic.
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002339 */
2340static void
2341onRequest (int request, void *data, size_t datalen, RIL_Token t)
2342{
2343 ATResponse *p_response;
2344 int err;
2345
Wink Saville4dcab4f2012-11-19 16:05:13 -08002346 RLOGD("onRequest: %s", requestToString(request));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002347
2348 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
2349 * when RADIO_STATE_UNAVAILABLE.
2350 */
2351 if (sState == RADIO_STATE_UNAVAILABLE
2352 && request != RIL_REQUEST_GET_SIM_STATUS
2353 ) {
2354 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2355 return;
2356 }
2357
2358 /* Ignore all non-power requests when RADIO_STATE_OFF
2359 * (except RIL_REQUEST_GET_SIM_STATUS)
2360 */
Jim Kayed2d82012017-10-06 14:17:47 -07002361 if (sState == RADIO_STATE_OFF) {
2362 switch(request) {
2363 case RIL_REQUEST_BASEBAND_VERSION:
2364 case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
2365 case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE:
2366 case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
2367 case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
2368 case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
2369 case RIL_REQUEST_CDMA_SUBSCRIPTION:
2370 case RIL_REQUEST_DEVICE_IDENTITY:
2371 case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
2372 case RIL_REQUEST_GET_ACTIVITY_INFO:
2373 case RIL_REQUEST_GET_CARRIER_RESTRICTIONS:
2374 case RIL_REQUEST_GET_CURRENT_CALLS:
2375 case RIL_REQUEST_GET_IMEI:
2376 case RIL_REQUEST_GET_MUTE:
2377 case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
2378 case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
2379 case RIL_REQUEST_GET_RADIO_CAPABILITY:
2380 case RIL_REQUEST_GET_SIM_STATUS:
2381 case RIL_REQUEST_NV_RESET_CONFIG:
2382 case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
2383 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
2384 case RIL_REQUEST_QUERY_TTY_MODE:
2385 case RIL_REQUEST_RADIO_POWER:
2386 case RIL_REQUEST_SET_BAND_MODE:
2387 case RIL_REQUEST_SET_CARRIER_RESTRICTIONS:
2388 case RIL_REQUEST_SET_LOCATION_UPDATES:
2389 case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
2390 case RIL_REQUEST_SET_TTY_MODE:
2391 case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
2392 case RIL_REQUEST_STOP_LCE:
2393 case RIL_REQUEST_VOICE_RADIO_TECH:
2394 // Process all the above, even though the radio is off
2395 break;
2396
2397 default:
2398 // For all others, say NOT_AVAILABLE because the radio is off
2399 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2400 return;
2401 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002402 }
2403
2404 switch (request) {
2405 case RIL_REQUEST_GET_SIM_STATUS: {
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002406 RIL_CardStatus_v6 *p_card_status;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002407 char *p_buffer;
2408 int buffer_size;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002409
Wink Savillef6aa7c12009-04-30 14:20:52 -07002410 int result = getCardStatus(&p_card_status);
2411 if (result == RIL_E_SUCCESS) {
2412 p_buffer = (char *)p_card_status;
2413 buffer_size = sizeof(*p_card_status);
2414 } else {
2415 p_buffer = NULL;
2416 buffer_size = 0;
2417 }
2418 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
2419 freeCardStatus(p_card_status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002420 break;
2421 }
2422 case RIL_REQUEST_GET_CURRENT_CALLS:
2423 requestGetCurrentCalls(data, datalen, t);
2424 break;
2425 case RIL_REQUEST_DIAL:
2426 requestDial(data, datalen, t);
2427 break;
2428 case RIL_REQUEST_HANGUP:
2429 requestHangup(data, datalen, t);
2430 break;
2431 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002432 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002433 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002434 case RIL_REQUEST_CONFERENCE:
2435 case RIL_REQUEST_UDUB:
2436 requestCallSelection(data, datalen, t, request);
2437 break;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002438 case RIL_REQUEST_ANSWER:
2439 at_send_command("ATA", NULL);
2440
2441#ifdef WORKAROUND_ERRONEOUS_ANSWER
2442 s_expectAnswer = 1;
2443#endif /* WORKAROUND_ERRONEOUS_ANSWER */
2444
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002445 if (getSIMStatus() != SIM_READY) {
2446 RIL_onRequestComplete(t, RIL_E_MODEM_ERR, NULL, 0);
2447 } else {
2448 // Success or failure is ignored by the upper layer here.
2449 // It will call GET_CURRENT_CALLS and determine success that way.
2450 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2451 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002452 break;
2453
2454 case RIL_REQUEST_SEPARATE_CONNECTION:
2455 {
2456 char cmd[12];
2457 int party = ((int*)data)[0];
2458
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002459 if (getSIMStatus() == SIM_ABSENT) {
2460 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2461 return;
2462 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002463 // Make sure that party is in a valid range.
2464 // (Note: The Telephony middle layer imposes a range of 1 to 7.
2465 // It's sufficient for us to just make sure it's single digit.)
2466 if (party > 0 && party < 10) {
2467 sprintf(cmd, "AT+CHLD=2%d", party);
2468 at_send_command(cmd, NULL);
2469 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2470 } else {
2471 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2472 }
2473 }
2474 break;
2475
2476 case RIL_REQUEST_SIGNAL_STRENGTH:
2477 requestSignalStrength(data, datalen, t);
2478 break;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002479 case RIL_REQUEST_VOICE_REGISTRATION_STATE:
2480 case RIL_REQUEST_DATA_REGISTRATION_STATE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002481 requestRegistrationState(request, data, datalen, t);
2482 break;
2483 case RIL_REQUEST_OPERATOR:
2484 requestOperator(data, datalen, t);
2485 break;
2486 case RIL_REQUEST_RADIO_POWER:
2487 requestRadioPower(data, datalen, t);
2488 break;
2489 case RIL_REQUEST_DTMF: {
2490 char c = ((char *)data)[0];
2491 char *cmd;
2492 asprintf(&cmd, "AT+VTS=%c", (int)c);
2493 at_send_command(cmd, NULL);
2494 free(cmd);
2495 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2496 break;
2497 }
2498 case RIL_REQUEST_SEND_SMS:
Chaitanya Saggurthi33bbe432013-09-24 16:16:21 +05302499 case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002500 requestSendSMS(data, datalen, t);
2501 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002502 case RIL_REQUEST_CDMA_SEND_SMS:
2503 requestCdmaSendSMS(data, datalen, t);
2504 break;
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07002505 case RIL_REQUEST_IMS_SEND_SMS:
2506 requestImsSendSMS(data, datalen, t);
2507 break;
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07002508 case RIL_REQUEST_SIM_OPEN_CHANNEL:
2509 requestSimOpenChannel(data, datalen, t);
2510 break;
2511 case RIL_REQUEST_SIM_CLOSE_CHANNEL:
2512 requestSimCloseChannel(data, datalen, t);
2513 break;
2514 case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL:
2515 requestSimTransmitApduChannel(data, datalen, t);
2516 break;
Wink Savillef4c4d362009-04-02 01:37:03 -07002517 case RIL_REQUEST_SETUP_DATA_CALL:
2518 requestSetupDataCall(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002519 break;
Bjoern Johanssone1ac3f22017-03-22 14:54:00 -07002520 case RIL_REQUEST_DEACTIVATE_DATA_CALL:
2521 requestDeactivateDataCall(t);
2522 break;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002523 case RIL_REQUEST_SMS_ACKNOWLEDGE:
2524 requestSMSAcknowledge(data, datalen, t);
2525 break;
2526
2527 case RIL_REQUEST_GET_IMSI:
2528 p_response = NULL;
2529 err = at_send_command_numeric("AT+CIMI", &p_response);
2530
2531 if (err < 0 || p_response->success == 0) {
2532 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2533 } else {
2534 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2535 p_response->p_intermediates->line, sizeof(char *));
2536 }
2537 at_response_free(p_response);
2538 break;
2539
2540 case RIL_REQUEST_GET_IMEI:
2541 p_response = NULL;
2542 err = at_send_command_numeric("AT+CGSN", &p_response);
2543
2544 if (err < 0 || p_response->success == 0) {
2545 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2546 } else {
2547 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2548 p_response->p_intermediates->line, sizeof(char *));
2549 }
2550 at_response_free(p_response);
2551 break;
2552
2553 case RIL_REQUEST_SIM_IO:
2554 requestSIM_IO(data,datalen,t);
2555 break;
2556
2557 case RIL_REQUEST_SEND_USSD:
2558 requestSendUSSD(data, datalen, t);
2559 break;
2560
2561 case RIL_REQUEST_CANCEL_USSD:
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002562 if (getSIMStatus() == SIM_ABSENT) {
2563 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2564 return;
2565 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002566 p_response = NULL;
2567 err = at_send_command_numeric("AT+CUSD=2", &p_response);
2568
2569 if (err < 0 || p_response->success == 0) {
2570 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2571 } else {
2572 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2573 p_response->p_intermediates->line, sizeof(char *));
2574 }
2575 at_response_free(p_response);
2576 break;
2577
2578 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002579 if (getSIMStatus() == SIM_ABSENT) {
2580 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2581 } else {
2582 at_send_command("AT+COPS=0", NULL);
2583 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002584 break;
2585
Wink Savillef4c4d362009-04-02 01:37:03 -07002586 case RIL_REQUEST_DATA_CALL_LIST:
2587 requestDataCallList(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002588 break;
2589
2590 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
2591 requestQueryNetworkSelectionMode(data, datalen, t);
2592 break;
2593
2594 case RIL_REQUEST_OEM_HOOK_RAW:
2595 // echo back data
2596 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2597 break;
2598
2599
2600 case RIL_REQUEST_OEM_HOOK_STRINGS: {
2601 int i;
2602 const char ** cur;
2603
Wink Saville4dcab4f2012-11-19 16:05:13 -08002604 RLOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002605
2606
2607 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
2608 i > 0 ; cur++, i --) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002609 RLOGD("> '%s'", *cur);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002610 }
2611
2612 // echo back strings
2613 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2614 break;
2615 }
2616
2617 case RIL_REQUEST_WRITE_SMS_TO_SIM:
2618 requestWriteSmsToSim(data, datalen, t);
2619 break;
2620
2621 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
2622 char * cmd;
2623 p_response = NULL;
2624 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
2625 err = at_send_command(cmd, &p_response);
2626 free(cmd);
2627 if (err < 0 || p_response->success == 0) {
2628 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2629 } else {
2630 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2631 }
2632 at_response_free(p_response);
2633 break;
2634 }
2635
2636 case RIL_REQUEST_ENTER_SIM_PIN:
2637 case RIL_REQUEST_ENTER_SIM_PUK:
2638 case RIL_REQUEST_ENTER_SIM_PIN2:
2639 case RIL_REQUEST_ENTER_SIM_PUK2:
2640 case RIL_REQUEST_CHANGE_SIM_PIN:
2641 case RIL_REQUEST_CHANGE_SIM_PIN2:
2642 requestEnterSimPin(data, datalen, t);
2643 break;
2644
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07002645 case RIL_REQUEST_IMS_REGISTRATION_STATE: {
2646 int reply[2];
2647 //0==unregistered, 1==registered
2648 reply[0] = s_ims_registered;
2649
2650 //to be used when changed to include service supporated info
2651 //reply[1] = s_ims_services;
2652
2653 // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
2654 reply[1] = s_ims_format;
2655
2656 RLOGD("IMS_REGISTRATION=%d, format=%d ",
2657 reply[0], reply[1]);
2658 if (reply[1] != -1) {
2659 RIL_onRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply));
2660 } else {
2661 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2662 }
2663 break;
2664 }
2665
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002666 case RIL_REQUEST_VOICE_RADIO_TECH:
2667 {
2668 int tech = techFromModemType(TECH(sMdmInfo));
2669 if (tech < 0 )
2670 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2671 else
2672 RIL_onRequestComplete(t, RIL_E_SUCCESS, &tech, sizeof(tech));
2673 }
2674 break;
2675 case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
2676 requestSetPreferredNetworkType(request, data, datalen, t);
2677 break;
2678
2679 case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
2680 requestGetPreferredNetworkType(request, data, datalen, t);
2681 break;
2682
Jun Tian58027012013-07-30 11:07:22 +08002683 case RIL_REQUEST_GET_CELL_INFO_LIST:
2684 requestGetCellInfoList(data, datalen, t);
2685 break;
2686
2687 case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
2688 requestSetCellInfoListRate(data, datalen, t);
2689 break;
2690
Etan Cohend3652192014-06-20 08:28:44 -07002691 case RIL_REQUEST_GET_HARDWARE_CONFIG:
2692 requestGetHardwareConfig(data, datalen, t);
2693 break;
2694
Naveen Kallaa65a16a2014-07-31 16:48:31 -07002695 case RIL_REQUEST_SHUTDOWN:
2696 requestShutdown(t);
2697 break;
2698
Jim Kayed2d82012017-10-06 14:17:47 -07002699 case RIL_REQUEST_QUERY_TTY_MODE:
2700 requestGetTtyMode(data, datalen, t);
2701 break;
2702
2703 case RIL_REQUEST_GET_RADIO_CAPABILITY:
2704 requestGetRadioCapability(data, datalen, t);
2705 break;
2706
2707 case RIL_REQUEST_GET_MUTE:
2708 requestGetMute(data, datalen, t);
2709 break;
2710
2711 case RIL_REQUEST_SET_INITIAL_ATTACH_APN:
2712 case RIL_REQUEST_ALLOW_DATA:
2713 case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
2714 case RIL_REQUEST_SET_CLIR:
2715 case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION:
2716 case RIL_REQUEST_SET_BAND_MODE:
2717 case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
2718 case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
2719 case RIL_REQUEST_SET_LOCATION_UPDATES:
2720 case RIL_REQUEST_SET_TTY_MODE:
2721 case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
2722 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2723 break;
2724
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002725 case RIL_REQUEST_BASEBAND_VERSION:
Jim Kayed2d82012017-10-06 14:17:47 -07002726 requestCdmaBaseBandVersion(request, data, datalen, t);
2727 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002728
2729 case RIL_REQUEST_DEVICE_IDENTITY:
bohuefa34012017-05-01 14:07:22 -07002730 requestDeviceIdentity(request, data, datalen, t);
Jim Kayed2d82012017-10-06 14:17:47 -07002731 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002732
2733 case RIL_REQUEST_CDMA_SUBSCRIPTION:
Jim Kayed2d82012017-10-06 14:17:47 -07002734 requestCdmaSubscription(request, data, datalen, t);
2735 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002736
Jim Kayed2d82012017-10-06 14:17:47 -07002737 case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
2738 requestCdmaGetSubscriptionSource(request, data, datalen, t);
2739 break;
2740
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002741 case RIL_REQUEST_START_LCE:
2742 case RIL_REQUEST_STOP_LCE:
2743 case RIL_REQUEST_PULL_LCEDATA:
2744 if (getSIMStatus() == SIM_ABSENT) {
2745 RIL_onRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
2746 } else {
2747 RIL_onRequestComplete(t, RIL_E_LCE_NOT_SUPPORTED, NULL, 0);
2748 }
2749 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002750
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002751 case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
2752 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2753 requestCdmaGetRoamingPreference(request, data, datalen, t);
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002754 } else {
2755 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2756 }
2757 break;
2758
2759 case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
2760 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2761 requestCdmaSetSubscriptionSource(request, data, datalen, t);
2762 } else {
2763 // VTS tests expect us to silently do nothing
2764 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2765 }
2766 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002767
2768 case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
2769 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2770 requestCdmaSetRoamingPreference(request, data, datalen, t);
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002771 } else {
2772 // VTS tests expect us to silently do nothing
2773 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2774 }
2775 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002776
2777 case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
2778 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2779 requestExitEmergencyMode(data, datalen, t);
Jim Kayeb6f3f7e2017-12-07 14:06:22 -08002780 } else {
2781 // VTS tests expect us to silently do nothing
2782 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2783 }
Jim Kayed2d82012017-10-06 14:17:47 -07002784 break;
2785
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002786 default:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002787 RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002788 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2789 break;
2790 }
2791}
2792
2793/**
2794 * Synchronous call from the RIL to us to return current radio state.
2795 * RADIO_STATE_UNAVAILABLE should be the initial state.
2796 */
2797static RIL_RadioState
2798currentState()
2799{
2800 return sState;
2801}
2802/**
2803 * Call from RIL to us to find out whether a specific request code
2804 * is supported by this implementation.
2805 *
2806 * Return 1 for "supported" and 0 for "unsupported"
2807 */
2808
2809static int
Mark Salyzynba58c202014-03-12 15:20:22 -07002810onSupports (int requestCode __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002811{
2812 //@@@ todo
2813
2814 return 1;
2815}
2816
Mark Salyzynba58c202014-03-12 15:20:22 -07002817static void onCancel (RIL_Token t __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002818{
2819 //@@@todo
2820
2821}
2822
2823static const char * getVersion(void)
2824{
2825 return "android reference-ril 1.0";
2826}
2827
2828static void
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002829setRadioTechnology(ModemInfo *mdm, int newtech)
2830{
Wink Saville4dcab4f2012-11-19 16:05:13 -08002831 RLOGD("setRadioTechnology(%d)", newtech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002832
2833 int oldtech = TECH(mdm);
2834
2835 if (newtech != oldtech) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002836 RLOGD("Tech change (%d => %d)", oldtech, newtech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002837 TECH(mdm) = newtech;
2838 if (techFromModemType(newtech) != techFromModemType(oldtech)) {
2839 int tech = techFromModemType(TECH(sMdmInfo));
2840 if (tech > 0 ) {
2841 RIL_onUnsolicitedResponse(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED,
2842 &tech, sizeof(tech));
2843 }
2844 }
2845 }
2846}
2847
2848static void
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002849setRadioState(RIL_RadioState newState)
2850{
Wink Saville4dcab4f2012-11-19 16:05:13 -08002851 RLOGD("setRadioState(%d)", newState);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002852 RIL_RadioState oldState;
2853
2854 pthread_mutex_lock(&s_state_mutex);
2855
2856 oldState = sState;
2857
2858 if (s_closed > 0) {
2859 // If we're closed, the only reasonable state is
2860 // RADIO_STATE_UNAVAILABLE
2861 // This is here because things on the main thread
2862 // may attempt to change the radio state after the closed
2863 // event happened in another thread
2864 newState = RADIO_STATE_UNAVAILABLE;
2865 }
2866
2867 if (sState != newState || s_closed > 0) {
2868 sState = newState;
2869
2870 pthread_cond_broadcast (&s_state_cond);
2871 }
2872
2873 pthread_mutex_unlock(&s_state_mutex);
2874
2875
2876 /* do these outside of the mutex */
2877 if (sState != oldState) {
2878 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
2879 NULL, 0);
Alex Yakavenka81d14852013-12-04 13:54:37 -08002880 // Sim state can change as result of radio state change
2881 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
2882 NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002883
2884 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
2885 * from the AT reader thread
2886 * Currently, this doesn't happen, but if that changes then these
2887 * will need to be dispatched on the request thread
2888 */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002889 if (sState == RADIO_STATE_ON) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002890 onRadioPowerOn();
2891 }
2892 }
2893}
2894
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002895/** Returns RUIM_NOT_READY on error */
2896static SIM_Status
2897getRUIMStatus()
2898{
2899 ATResponse *p_response = NULL;
2900 int err;
2901 int ret;
2902 char *cpinLine;
2903 char *cpinResult;
2904
2905 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
2906 ret = SIM_NOT_READY;
2907 goto done;
2908 }
2909
2910 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2911
2912 if (err != 0) {
2913 ret = SIM_NOT_READY;
2914 goto done;
2915 }
2916
2917 switch (at_get_cme_error(p_response)) {
2918 case CME_SUCCESS:
2919 break;
2920
2921 case CME_SIM_NOT_INSERTED:
2922 ret = SIM_ABSENT;
2923 goto done;
2924
2925 default:
2926 ret = SIM_NOT_READY;
2927 goto done;
2928 }
2929
2930 /* CPIN? has succeeded, now look at the result */
2931
2932 cpinLine = p_response->p_intermediates->line;
2933 err = at_tok_start (&cpinLine);
2934
2935 if (err < 0) {
2936 ret = SIM_NOT_READY;
2937 goto done;
2938 }
2939
2940 err = at_tok_nextstr(&cpinLine, &cpinResult);
2941
2942 if (err < 0) {
2943 ret = SIM_NOT_READY;
2944 goto done;
2945 }
2946
2947 if (0 == strcmp (cpinResult, "SIM PIN")) {
2948 ret = SIM_PIN;
2949 goto done;
2950 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
2951 ret = SIM_PUK;
2952 goto done;
2953 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
2954 return SIM_NETWORK_PERSONALIZATION;
2955 } else if (0 != strcmp (cpinResult, "READY")) {
2956 /* we're treating unsupported lock types as "sim absent" */
2957 ret = SIM_ABSENT;
2958 goto done;
2959 }
2960
2961 at_response_free(p_response);
2962 p_response = NULL;
2963 cpinResult = NULL;
2964
2965 ret = SIM_READY;
2966
2967done:
2968 at_response_free(p_response);
2969 return ret;
2970}
2971
John Wang309ac292009-07-30 14:53:23 -07002972/** Returns SIM_NOT_READY on error */
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01002973static SIM_Status
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002974getSIMStatus()
2975{
2976 ATResponse *p_response = NULL;
2977 int err;
2978 int ret;
2979 char *cpinLine;
2980 char *cpinResult;
2981
Wink Saville4dcab4f2012-11-19 16:05:13 -08002982 RLOGD("getSIMStatus(). sState: %d",sState);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002983 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2984
2985 if (err != 0) {
John Wang309ac292009-07-30 14:53:23 -07002986 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002987 goto done;
2988 }
2989
2990 switch (at_get_cme_error(p_response)) {
2991 case CME_SUCCESS:
2992 break;
2993
2994 case CME_SIM_NOT_INSERTED:
John Wang309ac292009-07-30 14:53:23 -07002995 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002996 goto done;
2997
2998 default:
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 /* CPIN? has succeeded, now look at the result */
3004
3005 cpinLine = p_response->p_intermediates->line;
3006 err = at_tok_start (&cpinLine);
3007
3008 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07003009 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003010 goto done;
3011 }
3012
3013 err = at_tok_nextstr(&cpinLine, &cpinResult);
3014
3015 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07003016 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003017 goto done;
3018 }
3019
3020 if (0 == strcmp (cpinResult, "SIM PIN")) {
John Wang309ac292009-07-30 14:53:23 -07003021 ret = SIM_PIN;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003022 goto done;
3023 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
John Wang309ac292009-07-30 14:53:23 -07003024 ret = SIM_PUK;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003025 goto done;
3026 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
John Wang309ac292009-07-30 14:53:23 -07003027 return SIM_NETWORK_PERSONALIZATION;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003028 } else if (0 != strcmp (cpinResult, "READY")) {
3029 /* we're treating unsupported lock types as "sim absent" */
John Wang309ac292009-07-30 14:53:23 -07003030 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003031 goto done;
3032 }
3033
3034 at_response_free(p_response);
3035 p_response = NULL;
3036 cpinResult = NULL;
3037
Jim Kayed2d82012017-10-06 14:17:47 -07003038 ret = (sState == RADIO_STATE_ON) ? SIM_READY : SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003039
3040done:
3041 at_response_free(p_response);
3042 return ret;
3043}
3044
3045
3046/**
Wink Savillef6aa7c12009-04-30 14:20:52 -07003047 * Get the current card status.
3048 *
3049 * This must be freed using freeCardStatus.
3050 * @return: On success returns RIL_E_SUCCESS
3051 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003052static int getCardStatus(RIL_CardStatus_v6 **pp_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07003053 static RIL_AppStatus app_status_array[] = {
John Wang309ac292009-07-30 14:53:23 -07003054 // SIM_ABSENT = 0
Wink Savillef6aa7c12009-04-30 14:20:52 -07003055 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
3056 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07003057 // SIM_NOT_READY = 1
Wink Savillef6aa7c12009-04-30 14:20:52 -07003058 { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
3059 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07003060 // SIM_READY = 2
Wink Savillef6aa7c12009-04-30 14:20:52 -07003061 { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
3062 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07003063 // SIM_PIN = 3
Wink Savillef6aa7c12009-04-30 14:20:52 -07003064 { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
3065 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07003066 // SIM_PUK = 4
Wink Savillef6aa7c12009-04-30 14:20:52 -07003067 { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
3068 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07003069 // SIM_NETWORK_PERSONALIZATION = 5
Wink Savillef6aa7c12009-04-30 14:20:52 -07003070 { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003071 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3072 // RUIM_ABSENT = 6
3073 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
3074 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3075 // RUIM_NOT_READY = 7
3076 { RIL_APPTYPE_RUIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
3077 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3078 // RUIM_READY = 8
3079 { RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
3080 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3081 // RUIM_PIN = 9
3082 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
3083 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3084 // RUIM_PUK = 10
3085 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
3086 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
3087 // RUIM_NETWORK_PERSONALIZATION = 11
3088 { RIL_APPTYPE_RUIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
bohu076e6872017-07-02 21:33:28 -07003089 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3090 // ISIM_ABSENT = 12
3091 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
3092 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3093 // ISIM_NOT_READY = 13
3094 { RIL_APPTYPE_ISIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
3095 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3096 // ISIM_READY = 14
3097 { RIL_APPTYPE_ISIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
3098 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
3099 // ISIM_PIN = 15
3100 { RIL_APPTYPE_ISIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
3101 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3102 // ISIM_PUK = 16
3103 { RIL_APPTYPE_ISIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
3104 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
3105 // ISIM_NETWORK_PERSONALIZATION = 17
3106 { RIL_APPTYPE_ISIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
3107 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
3108
Wink Savillef6aa7c12009-04-30 14:20:52 -07003109 };
3110 RIL_CardState card_state;
3111 int num_apps;
3112
3113 int sim_status = getSIMStatus();
John Wang309ac292009-07-30 14:53:23 -07003114 if (sim_status == SIM_ABSENT) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07003115 card_state = RIL_CARDSTATE_ABSENT;
3116 num_apps = 0;
3117 } else {
3118 card_state = RIL_CARDSTATE_PRESENT;
bohu076e6872017-07-02 21:33:28 -07003119 num_apps = 3;
Wink Savillef6aa7c12009-04-30 14:20:52 -07003120 }
3121
3122 // Allocate and initialize base card status.
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003123 RIL_CardStatus_v6 *p_card_status = malloc(sizeof(RIL_CardStatus_v6));
Wink Savillef6aa7c12009-04-30 14:20:52 -07003124 p_card_status->card_state = card_state;
3125 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
kun.tang7bb00222017-07-12 11:41:43 +08003126 p_card_status->gsm_umts_subscription_app_index = -1;
3127 p_card_status->cdma_subscription_app_index = -1;
3128 p_card_status->ims_subscription_app_index = -1;
Wink Savillef6aa7c12009-04-30 14:20:52 -07003129 p_card_status->num_applications = num_apps;
3130
3131 // Initialize application status
3132 int i;
3133 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
John Wang309ac292009-07-30 14:53:23 -07003134 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07003135 }
3136
3137 // Pickup the appropriate application status
3138 // that reflects sim_status for gsm.
3139 if (num_apps != 0) {
bohu076e6872017-07-02 21:33:28 -07003140 p_card_status->num_applications = 3;
Wink Savillef6aa7c12009-04-30 14:20:52 -07003141 p_card_status->gsm_umts_subscription_app_index = 0;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003142 p_card_status->cdma_subscription_app_index = 1;
bohu076e6872017-07-02 21:33:28 -07003143 p_card_status->ims_subscription_app_index = 2;
Wink Savillef6aa7c12009-04-30 14:20:52 -07003144
3145 // Get the correct app status
3146 p_card_status->applications[0] = app_status_array[sim_status];
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003147 p_card_status->applications[1] = app_status_array[sim_status + RUIM_ABSENT];
bohu076e6872017-07-02 21:33:28 -07003148 p_card_status->applications[2] = app_status_array[sim_status + ISIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07003149 }
3150
3151 *pp_card_status = p_card_status;
3152 return RIL_E_SUCCESS;
3153}
3154
3155/**
3156 * Free the card status returned by getCardStatus
3157 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003158static void freeCardStatus(RIL_CardStatus_v6 *p_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07003159 free(p_card_status);
3160}
3161
3162/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003163 * SIM ready means any commands that access the SIM will work, including:
3164 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
3165 * (all SMS-related commands)
3166 */
3167
Mark Salyzynba58c202014-03-12 15:20:22 -07003168static void pollSIMState (void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003169{
3170 ATResponse *p_response;
3171 int ret;
3172
Naveen Kalla2baf7232016-10-11 13:49:20 -07003173 if (sState != RADIO_STATE_UNAVAILABLE) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003174 // no longer valid to poll
3175 return;
3176 }
3177
3178 switch(getSIMStatus()) {
John Wang309ac292009-07-30 14:53:23 -07003179 case SIM_ABSENT:
3180 case SIM_PIN:
3181 case SIM_PUK:
3182 case SIM_NETWORK_PERSONALIZATION:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003183 default:
Wink Saville4dcab4f2012-11-19 16:05:13 -08003184 RLOGI("SIM ABSENT or LOCKED");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003185 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003186 return;
3187
John Wang309ac292009-07-30 14:53:23 -07003188 case SIM_NOT_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003189 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
3190 return;
3191
John Wang309ac292009-07-30 14:53:23 -07003192 case SIM_READY:
Wink Saville4dcab4f2012-11-19 16:05:13 -08003193 RLOGI("SIM_READY");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003194 onSIMReady();
3195 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003196 return;
3197 }
3198}
3199
3200/** returns 1 if on, 0 if off, and -1 on error */
3201static int isRadioOn()
3202{
3203 ATResponse *p_response = NULL;
3204 int err;
3205 char *line;
3206 char ret;
3207
3208 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
3209
3210 if (err < 0 || p_response->success == 0) {
3211 // assume radio is off
3212 goto error;
3213 }
3214
3215 line = p_response->p_intermediates->line;
3216
3217 err = at_tok_start(&line);
3218 if (err < 0) goto error;
3219
3220 err = at_tok_nextbool(&line, &ret);
3221 if (err < 0) goto error;
3222
3223 at_response_free(p_response);
3224
3225 return (int)ret;
3226
3227error:
3228
3229 at_response_free(p_response);
3230 return -1;
3231}
3232
3233/**
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003234 * Parse the response generated by a +CTEC AT command
3235 * The values read from the response are stored in current and preferred.
3236 * Both current and preferred may be null. The corresponding value is ignored in that case.
3237 *
3238 * @return: -1 if some error occurs (or if the modem doesn't understand the +CTEC command)
3239 * 1 if the response includes the current technology only
3240 * 0 if the response includes both current technology and preferred mode
3241 */
3242int parse_technology_response( const char *response, int *current, int32_t *preferred )
3243{
3244 int err;
3245 char *line, *p;
3246 int ct;
3247 int32_t pt = 0;
3248 char *str_pt;
3249
3250 line = p = strdup(response);
Wink Saville4dcab4f2012-11-19 16:05:13 -08003251 RLOGD("Response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003252 err = at_tok_start(&p);
3253 if (err || !at_tok_hasmore(&p)) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003254 RLOGD("err: %d. p: %s", err, p);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003255 free(line);
3256 return -1;
3257 }
3258
3259 err = at_tok_nextint(&p, &ct);
3260 if (err) {
3261 free(line);
3262 return -1;
3263 }
3264 if (current) *current = ct;
3265
Wink Saville4dcab4f2012-11-19 16:05:13 -08003266 RLOGD("line remaining after int: %s", p);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003267
3268 err = at_tok_nexthexint(&p, &pt);
3269 if (err) {
3270 free(line);
3271 return 1;
3272 }
3273 if (preferred) {
3274 *preferred = pt;
3275 }
3276 free(line);
3277
3278 return 0;
3279}
3280
Mark Salyzynba58c202014-03-12 15:20:22 -07003281int query_supported_techs( ModemInfo *mdm __unused, int *supported )
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003282{
3283 ATResponse *p_response;
3284 int err, val, techs = 0;
3285 char *tok;
3286 char *line;
3287
Wink Saville4dcab4f2012-11-19 16:05:13 -08003288 RLOGD("query_supported_techs");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003289 err = at_send_command_singleline("AT+CTEC=?", "+CTEC:", &p_response);
3290 if (err || !p_response->success)
3291 goto error;
3292 line = p_response->p_intermediates->line;
3293 err = at_tok_start(&line);
3294 if (err || !at_tok_hasmore(&line))
3295 goto error;
3296 while (!at_tok_nextint(&line, &val)) {
3297 techs |= ( 1 << val );
3298 }
3299 if (supported) *supported = techs;
3300 return 0;
3301error:
3302 at_response_free(p_response);
3303 return -1;
3304}
3305
3306/**
3307 * query_ctec. Send the +CTEC AT command to the modem to query the current
3308 * and preferred modes. It leaves values in the addresses pointed to by
3309 * current and preferred. If any of those pointers are NULL, the corresponding value
3310 * is ignored, but the return value will still reflect if retreiving and parsing of the
3311 * values suceeded.
3312 *
3313 * @mdm Currently unused
3314 * @current A pointer to store the current mode returned by the modem. May be null.
3315 * @preferred A pointer to store the preferred mode returned by the modem. May be null.
3316 * @return -1 on error (or failure to parse)
3317 * 1 if only the current mode was returned by modem (or failed to parse preferred)
3318 * 0 if both current and preferred were returned correctly
3319 */
Mark Salyzynba58c202014-03-12 15:20:22 -07003320int query_ctec(ModemInfo *mdm __unused, int *current, int32_t *preferred)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003321{
3322 ATResponse *response = NULL;
3323 int err;
3324 int res;
3325
Colin Cross5cba4882014-02-05 18:55:42 -08003326 RLOGD("query_ctec. current: %p, preferred: %p", current, preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003327 err = at_send_command_singleline("AT+CTEC?", "+CTEC:", &response);
3328 if (!err && response->success) {
3329 res = parse_technology_response(response->p_intermediates->line, current, preferred);
3330 at_response_free(response);
3331 return res;
3332 }
Colin Cross5cba4882014-02-05 18:55:42 -08003333 RLOGE("Error executing command: %d. response: %p. status: %d", err, response, response? response->success : -1);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003334 at_response_free(response);
3335 return -1;
3336}
3337
3338int is_multimode_modem(ModemInfo *mdm)
3339{
3340 ATResponse *response;
3341 int err;
3342 char *line;
3343 int tech;
3344 int32_t preferred;
3345
3346 if (query_ctec(mdm, &tech, &preferred) == 0) {
3347 mdm->currentTech = tech;
3348 mdm->preferredNetworkMode = preferred;
3349 if (query_supported_techs(mdm, &mdm->supportedTechs)) {
3350 return 0;
3351 }
3352 return 1;
3353 }
3354 return 0;
3355}
3356
3357/**
3358 * Find out if our modem is GSM, CDMA or both (Multimode)
3359 */
3360static void probeForModemMode(ModemInfo *info)
3361{
3362 ATResponse *response;
3363 int err;
3364 assert (info);
3365 // Currently, our only known multimode modem is qemu's android modem,
3366 // which implements the AT+CTEC command to query and set mode.
3367 // Try that first
3368
3369 if (is_multimode_modem(info)) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003370 RLOGI("Found Multimode Modem. Supported techs mask: %8.8x. Current tech: %d",
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003371 info->supportedTechs, info->currentTech);
3372 return;
3373 }
3374
3375 /* Being here means that our modem is not multimode */
3376 info->isMultimode = 0;
3377
3378 /* CDMA Modems implement the AT+WNAM command */
3379 err = at_send_command_singleline("AT+WNAM","+WNAM:", &response);
3380 if (!err && response->success) {
3381 at_response_free(response);
3382 // TODO: find out if we really support EvDo
3383 info->supportedTechs = MDM_CDMA | MDM_EVDO;
3384 info->currentTech = MDM_CDMA;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003385 RLOGI("Found CDMA Modem");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003386 return;
3387 }
3388 if (!err) at_response_free(response);
3389 // TODO: find out if modem really supports WCDMA/LTE
3390 info->supportedTechs = MDM_GSM | MDM_WCDMA | MDM_LTE;
3391 info->currentTech = MDM_GSM;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003392 RLOGI("Found GSM Modem");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003393}
3394
3395/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003396 * Initialize everything that can be configured while we're still in
3397 * AT+CFUN=0
3398 */
Mark Salyzynba58c202014-03-12 15:20:22 -07003399static void initializeCallback(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003400{
3401 ATResponse *p_response = NULL;
3402 int err;
3403
3404 setRadioState (RADIO_STATE_OFF);
3405
3406 at_handshake();
3407
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003408 probeForModemMode(sMdmInfo);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003409 /* note: we don't check errors here. Everything important will
3410 be handled in onATTimeout and onATReaderClosed */
3411
3412 /* atchannel is tolerant of echo but it must */
3413 /* have verbose result codes */
3414 at_send_command("ATE0Q0V1", NULL);
3415
3416 /* No auto-answer */
3417 at_send_command("ATS0=0", NULL);
3418
3419 /* Extended errors */
3420 at_send_command("AT+CMEE=1", NULL);
3421
3422 /* Network registration events */
3423 err = at_send_command("AT+CREG=2", &p_response);
3424
3425 /* some handsets -- in tethered mode -- don't support CREG=2 */
3426 if (err < 0 || p_response->success == 0) {
3427 at_send_command("AT+CREG=1", NULL);
3428 }
3429
3430 at_response_free(p_response);
3431
3432 /* GPRS registration events */
3433 at_send_command("AT+CGREG=1", NULL);
3434
3435 /* Call Waiting notifications */
3436 at_send_command("AT+CCWA=1", NULL);
3437
3438 /* Alternating voice/data off */
3439 at_send_command("AT+CMOD=0", NULL);
3440
3441 /* Not muted */
3442 at_send_command("AT+CMUT=0", NULL);
3443
3444 /* +CSSU unsolicited supp service notifications */
3445 at_send_command("AT+CSSN=0,1", NULL);
3446
3447 /* no connected line identification */
3448 at_send_command("AT+COLP=0", NULL);
3449
3450 /* HEX character set */
3451 at_send_command("AT+CSCS=\"HEX\"", NULL);
3452
3453 /* USSD unsolicited */
3454 at_send_command("AT+CUSD=1", NULL);
3455
3456 /* Enable +CGEV GPRS event notifications, but don't buffer */
3457 at_send_command("AT+CGEREP=1,0", NULL);
3458
3459 /* SMS PDU mode */
3460 at_send_command("AT+CMGF=0", NULL);
3461
3462#ifdef USE_TI_COMMANDS
3463
3464 at_send_command("AT%CPI=3", NULL);
3465
3466 /* TI specific -- notifications when SMS is ready (currently ignored) */
3467 at_send_command("AT%CSTAT=1", NULL);
3468
3469#endif /* USE_TI_COMMANDS */
3470
3471
3472 /* assume radio is off on error */
3473 if (isRadioOn() > 0) {
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003474 setRadioState (RADIO_STATE_ON);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003475 }
3476}
3477
3478static void waitForClose()
3479{
3480 pthread_mutex_lock(&s_state_mutex);
3481
3482 while (s_closed == 0) {
3483 pthread_cond_wait(&s_state_cond, &s_state_mutex);
3484 }
3485
3486 pthread_mutex_unlock(&s_state_mutex);
3487}
3488
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07003489static void sendUnsolImsNetworkStateChanged()
3490{
3491#if 0 // to be used when unsol is changed to return data.
3492 int reply[2];
3493 reply[0] = s_ims_registered;
3494 reply[1] = s_ims_services;
3495 reply[1] = s_ims_format;
3496#endif
3497 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED,
3498 NULL, 0);
3499}
3500
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003501/**
3502 * Called by atchannel when an unsolicited line appears
3503 * This is called on atchannel's reader thread. AT commands may
3504 * not be issued here
3505 */
3506static void onUnsolicited (const char *s, const char *sms_pdu)
3507{
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003508 char *line = NULL, *p;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003509 int err;
3510
3511 /* Ignore unsolicited responses until we're initialized.
3512 * This is OK because the RIL library will poll for initial state
3513 */
3514 if (sState == RADIO_STATE_UNAVAILABLE) {
3515 return;
3516 }
3517
3518 if (strStartsWith(s, "%CTZV:")) {
3519 /* TI specific -- NITZ time */
3520 char *response;
3521
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003522 line = p = strdup(s);
3523 at_tok_start(&p);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003524
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003525 err = at_tok_nextstr(&p, &response);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003526
3527 if (err != 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003528 RLOGE("invalid NITZ line %s\n", s);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003529 } else {
3530 RIL_onUnsolicitedResponse (
3531 RIL_UNSOL_NITZ_TIME_RECEIVED,
3532 response, strlen(response));
3533 }
Ivan Krasin7c0165e2015-12-03 15:50:10 -08003534 free(line);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003535 } else if (strStartsWith(s,"+CRING:")
3536 || strStartsWith(s,"RING")
3537 || strStartsWith(s,"NO CARRIER")
3538 || strStartsWith(s,"+CCWA")
3539 ) {
3540 RIL_onUnsolicitedResponse (
3541 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
3542 NULL, 0);
3543#ifdef WORKAROUND_FAKE_CGEV
Wink Savillef4c4d362009-04-02 01:37:03 -07003544 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003545#endif /* WORKAROUND_FAKE_CGEV */
3546 } else if (strStartsWith(s,"+CREG:")
3547 || strStartsWith(s,"+CGREG:")
3548 ) {
3549 RIL_onUnsolicitedResponse (
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003550 RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003551 NULL, 0);
3552#ifdef WORKAROUND_FAKE_CGEV
Wink Saville7f856802009-06-09 10:23:37 -07003553 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003554#endif /* WORKAROUND_FAKE_CGEV */
3555 } else if (strStartsWith(s, "+CMT:")) {
3556 RIL_onUnsolicitedResponse (
3557 RIL_UNSOL_RESPONSE_NEW_SMS,
3558 sms_pdu, strlen(sms_pdu));
3559 } else if (strStartsWith(s, "+CDS:")) {
3560 RIL_onUnsolicitedResponse (
3561 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
3562 sms_pdu, strlen(sms_pdu));
3563 } else if (strStartsWith(s, "+CGEV:")) {
3564 /* Really, we can ignore NW CLASS and ME CLASS events here,
3565 * but right now we don't since extranous
Wink Savillef4c4d362009-04-02 01:37:03 -07003566 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003567 */
3568 /* can't issue AT commands here -- call on main thread */
Wink Savillef4c4d362009-04-02 01:37:03 -07003569 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003570#ifdef WORKAROUND_FAKE_CGEV
3571 } else if (strStartsWith(s, "+CME ERROR: 150")) {
Wink Savillef4c4d362009-04-02 01:37:03 -07003572 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003573#endif /* WORKAROUND_FAKE_CGEV */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003574 } else if (strStartsWith(s, "+CTEC: ")) {
3575 int tech, mask;
3576 switch (parse_technology_response(s, &tech, NULL))
3577 {
3578 case -1: // no argument could be parsed.
Wink Saville4dcab4f2012-11-19 16:05:13 -08003579 RLOGE("invalid CTEC line %s\n", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003580 break;
3581 case 1: // current mode correctly parsed
3582 case 0: // preferred mode correctly parsed
3583 mask = 1 << tech;
3584 if (mask != MDM_GSM && mask != MDM_CDMA &&
3585 mask != MDM_WCDMA && mask != MDM_LTE) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003586 RLOGE("Unknown technology %d\n", tech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003587 } else {
3588 setRadioTechnology(sMdmInfo, tech);
3589 }
3590 break;
3591 }
3592 } else if (strStartsWith(s, "+CCSS: ")) {
3593 int source = 0;
3594 line = p = strdup(s);
3595 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003596 RLOGE("+CCSS: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003597 return;
3598 }
3599 if (at_tok_start(&p) < 0) {
3600 free(line);
3601 return;
3602 }
3603 if (at_tok_nextint(&p, &source) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003604 RLOGE("invalid +CCSS response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003605 free(line);
3606 return;
3607 }
3608 SSOURCE(sMdmInfo) = source;
3609 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,
3610 &source, sizeof(source));
3611 } else if (strStartsWith(s, "+WSOS: ")) {
3612 char state = 0;
3613 int unsol;
3614 line = p = strdup(s);
3615 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003616 RLOGE("+WSOS: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003617 return;
3618 }
3619 if (at_tok_start(&p) < 0) {
3620 free(line);
3621 return;
3622 }
3623 if (at_tok_nextbool(&p, &state) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003624 RLOGE("invalid +WSOS response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003625 free(line);
3626 return;
3627 }
3628 free(line);
3629
3630 unsol = state ?
3631 RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE : RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
3632
3633 RIL_onUnsolicitedResponse(unsol, NULL, 0);
3634
3635 } else if (strStartsWith(s, "+WPRL: ")) {
3636 int version = -1;
3637 line = p = strdup(s);
3638 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003639 RLOGE("+WPRL: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003640 return;
3641 }
3642 if (at_tok_start(&p) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003643 RLOGE("invalid +WPRL response: %s", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003644 free(line);
3645 return;
3646 }
3647 if (at_tok_nextint(&p, &version) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003648 RLOGE("invalid +WPRL response: %s", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003649 free(line);
3650 return;
3651 }
3652 free(line);
3653 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_PRL_CHANGED, &version, sizeof(version));
3654 } else if (strStartsWith(s, "+CFUN: 0")) {
3655 setRadioState(RADIO_STATE_OFF);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003656 }
3657}
3658
3659/* Called on command or reader thread */
3660static void onATReaderClosed()
3661{
Wink Saville4dcab4f2012-11-19 16:05:13 -08003662 RLOGI("AT channel closed\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003663 at_close();
3664 s_closed = 1;
3665
3666 setRadioState (RADIO_STATE_UNAVAILABLE);
3667}
3668
3669/* Called on command thread */
3670static void onATTimeout()
3671{
Wink Saville4dcab4f2012-11-19 16:05:13 -08003672 RLOGI("AT channel timeout; closing\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003673 at_close();
3674
3675 s_closed = 1;
3676
3677 /* FIXME cause a radio reset here */
3678
3679 setRadioState (RADIO_STATE_UNAVAILABLE);
3680}
3681
Etan Cohend3652192014-06-20 08:28:44 -07003682/* Called to pass hardware configuration information to telephony
3683 * framework.
3684 */
3685static void setHardwareConfiguration(int num, RIL_HardwareConfig *cfg)
3686{
3687 RIL_onUnsolicitedResponse(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, cfg, num*sizeof(*cfg));
3688}
3689
Sanket Padawef0c8ca72016-06-30 15:01:08 -07003690static void usage(char *s __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003691{
3692#ifdef RIL_SHLIB
3693 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
3694#else
3695 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
3696 exit(-1);
3697#endif
3698}
3699
3700static void *
Mark Salyzynba58c202014-03-12 15:20:22 -07003701mainLoop(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003702{
3703 int fd;
3704 int ret;
3705
3706 AT_DUMP("== ", "entering mainLoop()", -1 );
3707 at_set_on_reader_closed(onATReaderClosed);
3708 at_set_on_timeout(onATTimeout);
3709
3710 for (;;) {
3711 fd = -1;
3712 while (fd < 0) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003713 if (isInEmulator()) {
3714 fd = qemu_pipe_open("pipe:qemud:gsm");
3715 } else if (s_port > 0) {
Elliott Hughes7e3bbd42016-10-11 13:50:06 -07003716 fd = socket_network_client("localhost", s_port, SOCK_STREAM);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003717 } else if (s_device_socket) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003718 fd = socket_local_client(s_device_path,
3719 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
3720 SOCK_STREAM);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003721 } else if (s_device_path != NULL) {
3722 fd = open (s_device_path, O_RDWR);
3723 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
3724 /* disable echo on serial ports */
3725 struct termios ios;
3726 tcgetattr( fd, &ios );
3727 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
3728 tcsetattr( fd, TCSANOW, &ios );
3729 }
3730 }
3731
3732 if (fd < 0) {
3733 perror ("opening AT interface. retrying...");
3734 sleep(10);
3735 /* never returns */
3736 }
3737 }
3738
3739 s_closed = 0;
3740 ret = at_open(fd, onUnsolicited);
3741
3742 if (ret < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003743 RLOGE ("AT error %d on at_open\n", ret);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003744 return 0;
3745 }
3746
3747 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
3748
3749 // Give initializeCallback a chance to dispatched, since
3750 // we don't presently have a cancellation mechanism
3751 sleep(1);
3752
3753 waitForClose();
Wink Saville4dcab4f2012-11-19 16:05:13 -08003754 RLOGI("Re-opening after close");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003755 }
3756}
3757
3758#ifdef RIL_SHLIB
3759
3760pthread_t s_tid_mainloop;
3761
3762const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
3763{
3764 int ret;
3765 int fd = -1;
3766 int opt;
3767 pthread_attr_t attr;
3768
3769 s_rilenv = env;
3770
Sandeep Gutta11f27942014-07-10 05:00:25 +05303771 while ( -1 != (opt = getopt(argc, argv, "p:d:s:c:"))) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003772 switch (opt) {
3773 case 'p':
3774 s_port = atoi(optarg);
3775 if (s_port == 0) {
3776 usage(argv[0]);
3777 return NULL;
3778 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08003779 RLOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003780 break;
3781
3782 case 'd':
3783 s_device_path = optarg;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003784 RLOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003785 break;
3786
3787 case 's':
3788 s_device_path = optarg;
3789 s_device_socket = 1;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003790 RLOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003791 break;
3792
Sandeep Gutta11f27942014-07-10 05:00:25 +05303793 case 'c':
3794 RLOGI("Client id received %s\n", optarg);
3795 break;
3796
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003797 default:
3798 usage(argv[0]);
3799 return NULL;
3800 }
3801 }
3802
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003803 if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003804 usage(argv[0]);
3805 return NULL;
3806 }
3807
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003808 sMdmInfo = calloc(1, sizeof(ModemInfo));
3809 if (!sMdmInfo) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003810 RLOGE("Unable to alloc memory for ModemInfo");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003811 return NULL;
3812 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003813 pthread_attr_init (&attr);
3814 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3815 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
3816
3817 return &s_callbacks;
3818}
3819#else /* RIL_SHLIB */
3820int main (int argc, char **argv)
3821{
3822 int ret;
3823 int fd = -1;
3824 int opt;
3825
3826 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
3827 switch (opt) {
3828 case 'p':
3829 s_port = atoi(optarg);
3830 if (s_port == 0) {
3831 usage(argv[0]);
3832 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08003833 RLOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003834 break;
3835
3836 case 'd':
3837 s_device_path = optarg;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003838 RLOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003839 break;
3840
3841 case 's':
3842 s_device_path = optarg;
3843 s_device_socket = 1;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003844 RLOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003845 break;
3846
3847 default:
3848 usage(argv[0]);
3849 }
3850 }
3851
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003852 if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003853 usage(argv[0]);
3854 }
3855
3856 RIL_register(&s_callbacks);
3857
3858 mainLoop(NULL);
3859
3860 return 0;
3861}
3862
3863#endif /* RIL_SHLIB */