Network: only strdup when there is actually data
[hayes-ril.git] / network.c
1 /*
2  * This file is part of hayes-ril.
3  *
4  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
5  *
6  * Parts of this code are based on htcgeneric-ril, reference-ril:
7  * Copyright 2006-2011, htcgeneric-ril contributors
8  * Copyright 2006, The Android Open Source Project
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22
23 #define LOG_TAG "RIL-NET"
24 #include <utils/Log.h>
25 #include <telephony/ril.h>
26
27 #include <hayes-ril.h>
28
29 /*
30  * Signal Strength
31  */
32
33 void at2ril_signal_strength(RIL_SignalStrength *ss, int *values)
34 {
35         const int dbm_table[8] = {135,125,115,105,95,85,75,70};
36         const int edbm_table[8] = {120,110,100,90,80,75,70,65};
37         const int ecio_table[8] = {200,150,130,120,110,100,90,80};
38
39         memset(ss, 0, sizeof(RIL_SignalStrength));
40
41         if(ril_device->type == DEV_GSM) {
42                 ss->GW_SignalStrength.signalStrength = values[0];
43                 ss->GW_SignalStrength.bitErrorRate = values[1];
44         } else {
45                 /* 1st # is CDMA, 2nd is EVDO */
46                 ss->CDMA_SignalStrength.dbm = dbm_table[values[0]];
47                 ss->CDMA_SignalStrength.ecio = ecio_table[values[0]];
48                 ss->EVDO_SignalStrength.dbm = edbm_table[values[1]];
49                 ss->EVDO_SignalStrength.ecio = ecio_table[values[1]];
50                 ss->EVDO_SignalStrength.signalNoiseRatio = values[1];
51         }
52 }
53
54 int at_csq_expect(struct at_response *response, void *data, RIL_Token t)
55 {
56         struct at_response_data **response_data = NULL;
57         int response_data_count = 0;
58
59         RIL_SignalStrength ss;
60         int values[2] = { 0 };
61
62         if(response->status == AT_STATUS_UNDEF)
63                 return AT_RESPONSE_UNHANDELD_REASON_STATUS;
64
65         if(response->data == NULL || response->data_count <= 0) {
66                 LOGE("No data given to AT+CSQ response!");
67                 return AT_RESPONSE_HANDLED_ERROR;
68         }
69
70         LOGE("Caught valid AT+CSQ response!");
71
72         response_data_count = at_response_data_process(&response_data, response->data[0], strlen(response->data[0]));
73         if(response_data_count < 2)
74                 goto error_data;
75
76         if(response_data[0]->type != AT_RESPONSE_DATA_NUMERIC)
77                 goto error_data;
78         values[0] = response_data[0]->value.n;
79
80         if(response_data[1]->type != AT_RESPONSE_DATA_NUMERIC)
81                 goto error_data;
82         values[1] = response_data[1]->value.n;
83
84         at2ril_signal_strength(&ss, values);
85
86         RIL_onRequestComplete(t, RIL_E_SUCCESS, &ss, sizeof(RIL_SignalStrength));
87
88         at_response_data_free(response_data, response_data_count);
89
90         return AT_RESPONSE_HANDLED_OK;
91
92 error_data:
93         LOGE("No valid data given to AT+CSQ response!");
94
95         RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
96
97         at_response_data_free(response_data, response_data_count);
98         return AT_RESPONSE_HANDLED_ERROR;
99 }
100
101 void ril_request_signal_strength(RIL_Token t, void *data, size_t length)
102 {
103         at_send_expect_to_func("AT+CSQ", NULL, NULL, t, at_csq_expect);
104 }
105
106 /*
107  * Network registration
108  */
109
110 int at_creg_handle(char **registration_state, struct at_response_data **response_data, int response_data_count)
111 {
112         int state = 0;
113         char *lac = NULL;
114         char *cid = NULL;
115
116         if(registration_state == NULL || response_data == NULL || response_data_count <= 0)
117                 return -1;
118
119         /*
120          * Ok you have to be careful here
121          * The solicited version of the CREG response is
122          * +CREG: n, stat, [lac, cid]
123          * and the unsolicited version is
124          * +CREG: stat, [lac, cid]
125          * The <n> parameter is basically "is unsolicited creg on?"
126          * which it should always be
127          *
128          * Also since the LAC and CID are only reported when registered,
129          * we can have 1, 2, 3, or 4 arguments here
130          *
131          * finally, a +CGREG: answer may have a fifth value that corresponds
132          * to the network type, as in;
133          *
134          *   +CGREG: n, stat [,lac, cid [,networkType]]
135          */
136
137         // Only handle CREG responses
138         switch(response_data_count) {
139                 case 1: // UNSOL response, unregistered
140                         if(response_data[0]->type != AT_RESPONSE_DATA_NUMERIC)
141                                 return -1;
142                         state = response_data[0]->value.n;
143
144                         break;
145                 case 2: // SOL response, unregistered
146                         // Skip first argument
147                         if(response_data[1]->type != AT_RESPONSE_DATA_NUMERIC)
148                                 return -1;
149                         state = response_data[1]->value.n;
150
151                         break;
152                 case 3: // UNSOL response, registered
153                         if(response_data[0]->type != AT_RESPONSE_DATA_NUMERIC)
154                                 return -1;
155                         state = response_data[0]->value.n;
156
157                         if(response_data[1]->type != AT_RESPONSE_DATA_STRING)
158                                 return -1;
159                         lac = response_data[1]->value.s;
160
161                         if(response_data[2]->type != AT_RESPONSE_DATA_STRING)
162                                 return -1;
163                         cid = response_data[2]->value.s;
164
165                         break;
166                 case 4: // SOL response, registered
167                         if(response_data[1]->type != AT_RESPONSE_DATA_NUMERIC)
168                                 return -1;
169                         state = response_data[1]->value.n;
170
171                         if(response_data[2]->type != AT_RESPONSE_DATA_STRING)
172                                 return -1;
173                         lac = response_data[2]->value.s;
174
175                         if(response_data[3]->type != AT_RESPONSE_DATA_STRING)
176                                 return -1;
177                         cid = response_data[3]->value.s;
178
179                         break;
180                 default:
181                         return -1;
182         }
183
184         asprintf(&(registration_state[0]), "%d", state);
185         if(lac != NULL)
186                 registration_state[1] = strdup(lac);
187         if(cid != NULL)
188                 registration_state[2] = strdup(cid);
189
190         return 0;
191 }
192
193 void ril_registration_state_free(char **registration_state)
194 {
195         int i;
196
197         for(i=0 ; i < 14 ; i++) {
198                 if(registration_state[i] != NULL)
199                         free(registration_state[i]);
200         }
201
202
203         free(registration_state);
204 }
205
206 int at_creg_expect(struct at_response *response, void *data, RIL_Token t)
207 {
208         struct at_response_data **response_data = NULL;
209         int response_data_count = 0;
210
211         char **registration_state = NULL;
212         int rc;
213
214         if(response->status == AT_STATUS_UNDEF)
215                 return AT_RESPONSE_UNHANDELD_REASON_STATUS;
216
217         if(response->data == NULL || response->data_count <= 0) {
218                 LOGE("No data given to AT+CREG response!");
219                 return AT_RESPONSE_HANDLED_ERROR;
220         }
221
222         LOGE("Caught valid AT+CREG response!");
223
224         response_data_count = at_response_data_process(&response_data, response->data[0], strlen(response->data[0]));
225         if(response_data_count <= 0)
226                 goto error_data;
227
228         registration_state = calloc(1, sizeof(char *) * 15);
229         rc = at_creg_handle(registration_state, response_data, response_data_count);
230         if(rc < 0) {
231                 ril_registration_state_free(registration_state);
232                 goto error_data;
233         }
234
235         RIL_onRequestComplete(t, RIL_E_SUCCESS, registration_state,  sizeof(char *) * 15);
236
237         ril_registration_state_free(registration_state);
238         at_response_data_free(response_data, response_data_count);
239
240         return AT_RESPONSE_HANDLED_OK;
241
242 error_data:
243         LOGE("No valid data given to AT+CREG response!");
244
245         RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
246
247         at_response_data_free(response_data, response_data_count);
248
249         return AT_RESPONSE_HANDLED_ERROR;
250 }
251
252 void at_creg_unexpect(struct at_response *response)
253 {
254         struct at_response_data **response_data = NULL;
255         int response_data_count = 0;
256
257         char **registration_state = NULL;
258         int rc;
259
260         if(response->data == NULL || response->data_count <= 0) {
261                 LOGE("No data given to AT+CREG unsol!");
262                 return;
263         }
264
265         LOGE("Caught valid AT+CREG unsol!");
266
267         response_data_count = at_response_data_process(&response_data, response->data[0], strlen(response->data[0]));
268         if(response_data_count <= 0)
269                 goto error_data;
270
271         registration_state = calloc(1, sizeof(char *) * 15);
272         rc = at_creg_handle(registration_state, response_data, response_data_count);
273         if(rc < 0) {
274                 ril_registration_state_free(registration_state);
275                 goto error_data;
276         }
277
278         if(ril_globals.registration_state != NULL)
279                 ril_registration_state_free(ril_globals.registration_state);
280
281         ril_globals.registration_state = registration_state;
282
283         RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0);
284
285 error_data:
286         LOGE("No valid data given to AT+CREG unsol!");
287
288         at_response_data_free(response_data, response_data_count);
289 }
290
291 void ril_request_registration_state(RIL_Token t, void *data, size_t length)
292 {
293         if(ril_globals.registration_state != NULL) {
294                 // There is UNSOL data there
295                 RIL_onRequestComplete(t, RIL_E_SUCCESS, ril_globals.registration_state,  sizeof(char *) * 15);
296
297                 ril_registration_state_free(ril_globals.registration_state);
298                 ril_globals.registration_state = NULL;
299         } else {
300                 at_send_expect_to_func("AT+CREG?", NULL, NULL, t, at_creg_expect);
301         }
302 }
303
304 /*
305  * Operator
306  */
307
308 char *at_cops_request(int index)
309 {
310         struct at_response_data **response_data = NULL;
311         struct at_response *response = NULL;
312         int response_data_count = 0;
313         int status = AT_STATUS_UNDEF;
314         char *result = NULL;
315         char *data = NULL;
316
317         asprintf(&data, "3,%d", index);
318
319         status = at_send_expect_status("AT+COPS", data);
320         if(at_status_error(status))
321                 goto error;
322
323         response = at_send_sync("AT+COPS?", NULL);
324         if(response == NULL || response->data == NULL || response->data_count <= 0)
325                 goto error;
326
327         response_data_count = at_response_data_process(&response_data, response->data[0], strlen(response->data[0]));
328         if(response_data_count <= 0)
329                 goto error;
330         if(response_data_count >= 3 && response_data[2]->type == AT_RESPONSE_DATA_STRING) {
331                 result = strdup(response_data[2]->value.s);
332         }
333         at_response_data_free(response_data, response_data_count);
334
335         free(response);
336         free(data);
337
338         return result;
339
340 error:
341         free(data);
342         if(response != NULL)
343                 free(response);
344         if(response_data != NULL)
345                 at_response_data_free(response_data, response_data_count);
346
347         return NULL;
348 }
349
350 void ril_request_operator(RIL_Token t, void *data, size_t length)
351 {
352         char *operator[3] = { NULL };
353
354         // Reuqest long operator string
355         operator[0] = at_cops_request(0);
356         // Reuqest short operator string
357         operator[1] = at_cops_request(1);
358         // Reuqest MCC+MNC string
359         operator[2] = at_cops_request(2);
360
361         RIL_onRequestComplete(t, RIL_E_SUCCESS, operator,  sizeof(operator));
362
363         if(operator[0] != NULL)
364                 free(operator[0]);
365         if(operator[1] != NULL)
366                 free(operator[1]);
367         if(operator[2] != NULL)
368                 free(operator[2]);
369 }