1 /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation, nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define LOG_NDEBUG 0
30 #define LOG_TAG "LocSvc_ds_client"
31
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdint.h>
35 #include <stdbool.h>
36 #include <stddef.h>
37 #include <wireless_data_service_v01.h>
38 #include <utils/Log.h>
39 #include <log_util.h>
40 #include <loc_log.h>
41 #include <qmi_client.h>
42 #include <qmi_idl_lib.h>
43 #include <qmi_cci_target_ext.h>
44 #include <qmi_cci_target.h>
45 #include <qmi_cci_common.h>
46 #include <dsi_netctrl.h>
47 #include <ds_client.h>
48
49 #include<sys/time.h>
50
51 //Timeout to wait for wds service notification from qmi
52 #define DS_CLIENT_SERVICE_TIMEOUT (4000)
53 //Max timeout for the service to come up
54 #define DS_CLIENT_SERVICE_TIMEOUT_TOTAL (40000)
55 //Timeout for the service to respond to sync msg
56 #define DS_CLIENT_SYNC_MSG_TIMEOUT (5000)
57 /*Request messages the WDS client can send to the WDS service*/
58 typedef union
59 {
60 /*Requests the service for a list of all profiles present*/
61 wds_get_profile_list_req_msg_v01 *p_get_profile_list_req;
62 /*Requests the service for a profile's settings*/
63 wds_get_profile_settings_req_msg_v01 *p_get_profile_settings_req;
64 }ds_client_req_union_type;
65
66 /*Response indications that are sent by the WDS service*/
67 typedef union
68 {
69 wds_get_profile_list_resp_msg_v01 *p_get_profile_list_resp;
70 wds_get_profile_settings_resp_msg_v01 *p_get_profile_setting_resp;
71 }ds_client_resp_union_type;
72
73 struct event_strings_s
74 {
75 char * str;
76 dsi_net_evt_t evt;
77 };
78
79 struct event_strings_s event_string_tbl[DSI_EVT_MAX] =
80 {
81 NAME_VAL(DSI_EVT_INVALID),
82 NAME_VAL(DSI_EVT_NET_IS_CONN),
83 NAME_VAL(DSI_EVT_NET_NO_NET),
84 NAME_VAL(DSI_EVT_PHYSLINK_DOWN_STATE),
85 NAME_VAL(DSI_EVT_PHYSLINK_UP_STATE),
86 NAME_VAL(DSI_EVT_NET_RECONFIGURED),
87 #ifndef GPS_PDK
88 NAME_VAL(DSI_EVT_WDS_CONNECTED)
89 #endif
90 };
91
92 typedef struct
93 {
94 ds_client_event_ind_cb_type event_cb;
95 void *caller_cookie;
96 }ds_caller_data;
97
98 typedef struct {
99 //Global dsi handle
100 dsi_hndl_t dsi_net_handle;
101 //Handle to caller's data
102 ds_caller_data caller_data;
103 } ds_client_session_data;
104
net_ev_cb(dsi_hndl_t handle,void * user_data,dsi_net_evt_t evt,dsi_evt_payload_t * payload_ptr)105 void net_ev_cb(dsi_hndl_t handle, void* user_data,
106 dsi_net_evt_t evt, dsi_evt_payload_t *payload_ptr)
107 {
108 int i;
109 (void)handle;
110 (void)user_data;
111 (void)payload_ptr;
112 ds_caller_data *callback_data = (ds_caller_data *)user_data;
113
114 LOC_LOGD("%s:%d]: Enter. Callback data: %p\n", __func__, __LINE__, callback_data);
115 if(evt > DSI_EVT_INVALID && evt < DSI_EVT_MAX)
116 {
117 for(i=0;i<DSI_EVT_MAX;i++)
118 {
119 if(event_string_tbl[i].evt == evt)
120 LOC_LOGE("%s:%d]: Callback received: %s",
121 __func__, __LINE__, event_string_tbl[i].str);
122 }
123 switch(evt) {
124 case DSI_EVT_NET_IS_CONN:
125 #ifndef GPS_PDK
126 case DSI_EVT_WDS_CONNECTED:
127 #endif
128 {
129 LOC_LOGD("%s:%d]: Emergency call started\n", __func__, __LINE__);
130 callback_data->event_cb(E_DS_CLIENT_DATA_CALL_CONNECTED,
131 callback_data->caller_cookie);
132 break;
133 }
134 case DSI_EVT_NET_NO_NET:
135 {
136 LOC_LOGD("%s:%d]: Emergency call stopped\n", __func__, __LINE__);
137 callback_data->event_cb(E_DS_CLIENT_DATA_CALL_DISCONNECTED,
138 callback_data->caller_cookie);
139 break;
140 }
141 default:
142 LOC_LOGD("%s:%d]: uninteresting event\n", __func__, __LINE__);
143 }
144 }
145 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
146 }
147
148 /*This function is called to obtain a handle to the QMI WDS service*/
149 static ds_client_status_enum_type
ds_client_qmi_ctrl_point_init(qmi_client_type * p_wds_qmi_client)150 ds_client_qmi_ctrl_point_init(qmi_client_type *p_wds_qmi_client)
151 {
152 qmi_client_type wds_qmi_client, notifier = NULL;
153 ds_client_status_enum_type status = E_DS_CLIENT_SUCCESS;
154 qmi_service_info *p_service_info = NULL;
155 uint32_t num_services = 0, num_entries = 0;
156 qmi_client_error_type ret = QMI_NO_ERR;
157 unsigned char no_signal = 0;
158 qmi_client_os_params os_params;
159 int timeout = 0;
160
161 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
162
163 //Get service object for QMI_WDS service
164 qmi_idl_service_object_type ds_client_service_object =
165 wds_get_service_object_v01();
166 if(ds_client_service_object == NULL) {
167 LOC_LOGE("%s:%d]: wds_get_service_object_v01 failed\n" ,
168 __func__, __LINE__);
169 status = E_DS_CLIENT_FAILURE_INTERNAL;
170 goto err;
171 }
172
173 //get service addressing information
174 ret = qmi_client_get_service_list(ds_client_service_object, NULL, NULL,
175 &num_services);
176 LOC_LOGD("%s:%d]: qmi_client_get_service_list() first try ret %d, "
177 "num_services %d]\n", __func__, __LINE__, ret, num_services);
178 if(ret != QMI_NO_ERR) {
179 //Register for service notification
180 ret = qmi_client_notifier_init(ds_client_service_object, &os_params, ¬ifier);
181 if (ret != QMI_NO_ERR) {
182 LOC_LOGE("%s:%d]: qmi_client_notifier_init failed %d\n",
183 __func__, __LINE__, ret);
184 status = E_DS_CLIENT_FAILURE_INTERNAL;
185 goto err;
186 }
187
188 do {
189 QMI_CCI_OS_SIGNAL_CLEAR(&os_params);
190 ret = qmi_client_get_service_list(ds_client_service_object, NULL,
191 NULL, &num_services);
192 if(ret != QMI_NO_ERR) {
193 QMI_CCI_OS_SIGNAL_WAIT(&os_params, DS_CLIENT_SERVICE_TIMEOUT);
194 no_signal = QMI_CCI_OS_SIGNAL_TIMED_OUT(&os_params);
195 if(!no_signal)
196 ret = qmi_client_get_service_list(ds_client_service_object, NULL,
197 NULL, &num_services);
198 }
199 timeout += DS_CLIENT_SERVICE_TIMEOUT;
200 LOC_LOGV("%s:%d]: qmi_client_get_service_list() returned ret: %d,"
201 "no_signal: %d, total timeout: %d\n", __func__, __LINE__,
202 ret, no_signal, timeout);
203 } while( (timeout < DS_CLIENT_SERVICE_TIMEOUT_TOTAL) &&
204 no_signal &&
205 (ret != QMI_NO_ERR) );
206 }
207
208 //Handle failure cases
209 if(num_services == 0 || ret != QMI_NO_ERR) {
210 if(!no_signal) {
211 LOC_LOGE("%s:%d]: qmi_client_get_service_list failed even though"
212 "service is up! Error: %d \n", __func__, __LINE__, ret);
213 status = E_DS_CLIENT_FAILURE_INTERNAL;
214 }
215 else {
216 LOC_LOGE("%s:%d]: qmi_client_get_service_list failed after retries"
217 "Error: %d \n", __func__, __LINE__, ret);
218 status = E_DS_CLIENT_FAILURE_TIMEOUT;
219 }
220 goto err;
221 }
222
223 LOC_LOGD("%s:%d]: qmi_client_get_service_list succeeded\n", __func__, __LINE__);
224
225 //Success
226 p_service_info = (qmi_service_info *)malloc(num_services * sizeof(qmi_service_info));
227 if(p_service_info == NULL) {
228 LOC_LOGE("%s:%d]: could not allocate memory for serviceInfo !!\n",
229 __func__, __LINE__);
230 status = E_DS_CLIENT_FAILURE_INTERNAL;
231 goto err;
232 }
233 num_entries = num_services;
234
235 //Populate service info
236 ret = qmi_client_get_service_list(ds_client_service_object, p_service_info,
237 &num_entries, &num_services);
238 if(ret != QMI_NO_ERR) {
239 LOC_LOGE("%s:%d]: qmi_client_get_service_list failed. ret: %d \n",
240 __func__, __LINE__, ret);
241 status = E_DS_CLIENT_FAILURE_INTERNAL;
242 goto err;
243 }
244
245 //Initialize wds_qmi_client
246 LOC_LOGD("%s:%d]: Initializing WDS client with qmi_client_init\n", __func__,
247 __LINE__);
248 ret = qmi_client_init(&p_service_info[0], ds_client_service_object,
249 NULL, NULL, NULL, &wds_qmi_client);
250 if(ret != QMI_NO_ERR) {
251 LOC_LOGE("%s:%d]: qmi_client_init Error. ret: %d\n", __func__, __LINE__, ret);
252 status = E_DS_CLIENT_FAILURE_INTERNAL;
253 goto err;
254 }
255 LOC_LOGD("%s:%d]: WDS client initialized with qmi_client_init\n", __func__,
256 __LINE__);
257
258 //Store WDS QMI client handle in the parameter passed in
259 *p_wds_qmi_client = wds_qmi_client;
260
261 status = E_DS_CLIENT_SUCCESS;
262 LOC_LOGD("%s:%d]: init success\n", __func__, __LINE__);
263
264 if(notifier)
265 qmi_client_release(notifier);
266
267 err:
268 if(p_service_info)
269 free(p_service_info);
270
271 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
272 return status;
273 }
274
275 /*This function reads the error code from within the response struct*/
ds_client_convert_qmi_response(uint32_t req_id,ds_client_resp_union_type * resp_union)276 static ds_client_status_enum_type ds_client_convert_qmi_response(
277 uint32_t req_id,
278 ds_client_resp_union_type *resp_union)
279 {
280 ds_client_status_enum_type ret = E_DS_CLIENT_FAILURE_GENERAL;
281 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
282 switch(req_id)
283 {
284 case QMI_WDS_GET_PROFILE_LIST_REQ_V01 :
285 {
286 if(resp_union->p_get_profile_list_resp->resp.error !=
287 QMI_ERR_NONE_V01) {
288 LOC_LOGE("%s:%d]: Response error: %d", __func__, __LINE__,
289 resp_union->p_get_profile_list_resp->resp.error);
290 }
291 else
292 ret = E_DS_CLIENT_SUCCESS;
293 }
294 break;
295
296 case QMI_WDS_GET_PROFILE_SETTINGS_REQ_V01 :
297 {
298 if(resp_union->p_get_profile_setting_resp->resp.error !=
299 QMI_ERR_NONE_V01) {
300 LOC_LOGE("%s:%d]: Response error: %d", __func__, __LINE__,
301 resp_union->p_get_profile_setting_resp->resp.error);
302 }
303 else
304 ret = E_DS_CLIENT_SUCCESS;
305 }
306 break;
307
308 default:
309 LOC_LOGE("%s:%d]: Unknown request ID\n", __func__, __LINE__);
310 }
311 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
312 return ret;
313 }
314
315
ds_client_send_qmi_sync_req(qmi_client_type * ds_client_handle,uint32_t req_id,ds_client_resp_union_type * resp_union,ds_client_req_union_type * req_union)316 static ds_client_status_enum_type ds_client_send_qmi_sync_req(
317 qmi_client_type *ds_client_handle,
318 uint32_t req_id,
319 ds_client_resp_union_type *resp_union,
320 ds_client_req_union_type *req_union)
321 {
322 uint32_t req_len = 0;
323 uint32_t resp_len = 0;
324 ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
325 qmi_client_error_type qmi_ret = QMI_NO_ERR;
326 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
327 switch(req_id)
328 {
329 case QMI_WDS_GET_PROFILE_LIST_REQ_V01 :
330 {
331 req_len = sizeof(wds_get_profile_list_req_msg_v01);
332 resp_len = sizeof(wds_get_profile_list_resp_msg_v01);
333 LOC_LOGD("%s:%d]: req_id = GET_PROFILE_LIST_REQ\n",
334 __func__, __LINE__);
335 }
336 break;
337
338 case QMI_WDS_GET_PROFILE_SETTINGS_REQ_V01 :
339 {
340 req_len = sizeof(wds_get_profile_settings_req_msg_v01);
341 resp_len = sizeof(wds_get_profile_settings_resp_msg_v01);
342 LOC_LOGD("%s:%d]: req_id = GET_PROFILE_SETTINGS_REQ\n",
343 __func__, __LINE__);
344 }
345 break;
346
347 default:
348 LOC_LOGE("%s:%d]: Error unknown req_id=%d\n", __func__, __LINE__,
349 req_id);
350 ret = E_DS_CLIENT_FAILURE_INVALID_PARAMETER;
351 goto err;
352 }
353
354 LOC_LOGD("%s:%d]: req_id=%d, len = %d; resp_len= %d\n", __func__, __LINE__,
355 req_id, req_len, resp_len);
356 //Send msg through QCCI
357 qmi_ret = qmi_client_send_msg_sync(
358 *ds_client_handle,
359 req_id,
360 (void *)req_union->p_get_profile_list_req,
361 req_len,
362 (void *)resp_union->p_get_profile_list_resp,
363 resp_len,
364 DS_CLIENT_SYNC_MSG_TIMEOUT);
365 LOC_LOGD("%s:%d]: qmi_client_send_msg_sync returned: %d", __func__, __LINE__, qmi_ret);
366
367 if(qmi_ret != QMI_NO_ERR) {
368 ret = E_DS_CLIENT_FAILURE_INTERNAL;
369 goto err;
370 }
371
372 ret = ds_client_convert_qmi_response(req_id, resp_union);
373
374 err:
375 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
376 return ret;
377 }
378
379 /*This function obtains the list of supported profiles*/
ds_client_get_profile_list(qmi_client_type * ds_client_handle,ds_client_resp_union_type * profile_list_resp_msg,wds_profile_type_enum_v01 profile_type)380 static ds_client_status_enum_type ds_client_get_profile_list(
381 qmi_client_type *ds_client_handle,
382 ds_client_resp_union_type *profile_list_resp_msg,
383 wds_profile_type_enum_v01 profile_type)
384 {
385 ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
386 ds_client_req_union_type req_union;
387 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
388
389 req_union.p_get_profile_list_req = NULL;
390 req_union.p_get_profile_list_req = (wds_get_profile_list_req_msg_v01 *)
391 calloc(1, sizeof(wds_get_profile_list_req_msg_v01));
392 if(req_union.p_get_profile_list_req == NULL) {
393 LOC_LOGE("%s:%d]: Could not allocate memory for"
394 "wds_get_profile_list_req_msg_v01\n", __func__, __LINE__);
395 goto err;
396 }
397 //Populate required members of the request structure
398 req_union.p_get_profile_list_req->profile_type_valid = 1;
399 req_union.p_get_profile_list_req->profile_type = profile_type;
400 ret = ds_client_send_qmi_sync_req(ds_client_handle,
401 QMI_WDS_GET_PROFILE_LIST_REQ_V01,
402 profile_list_resp_msg, &req_union);
403 if(ret != E_DS_CLIENT_SUCCESS) {
404 LOC_LOGE("%s:%d]: ds_client_send_qmi_req failed. ret: %d\n",
405 __func__, __LINE__, ret);
406 goto err;
407 }
408 err:
409 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
410 if(req_union.p_get_profile_list_req)
411 free(req_union.p_get_profile_list_req);
412 return ret;
413 }
414
415 /*This function obtains settings for the profile specified by
416 the profile_identifier*/
ds_client_get_profile_settings(qmi_client_type * ds_client_handle,ds_client_resp_union_type * profile_settings_resp_msg,wds_profile_identifier_type_v01 * profile_identifier)417 static ds_client_status_enum_type ds_client_get_profile_settings(
418 qmi_client_type *ds_client_handle,
419 ds_client_resp_union_type *profile_settings_resp_msg,
420 wds_profile_identifier_type_v01 *profile_identifier)
421 {
422 ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
423 ds_client_req_union_type req_union;
424
425 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
426 //Since it's a union containing a pointer to a structure,
427 //following entities have the same address
428 //- req_union
429 //- req_union.p_get_profile_settings_req
430 //- req_union.p_get_profile_settings_req->profile
431 //so we can very well assign req_union = profile_identifier
432 req_union.p_get_profile_settings_req =
433 (wds_get_profile_settings_req_msg_v01 *)profile_identifier;
434 ret = ds_client_send_qmi_sync_req(ds_client_handle,
435 QMI_WDS_GET_PROFILE_SETTINGS_REQ_V01,
436 profile_settings_resp_msg, &req_union);
437 if(ret != E_DS_CLIENT_SUCCESS) {
438 LOC_LOGE("%s:%d]: ds_client_send_qmi_req failed. ret: %d\n",
439 __func__, __LINE__, ret);
440 goto err;
441 }
442 err:
443 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
444 return ret;
445 }
446
447 /*
448 Starts data call using the handle and the profile index
449 */
450 ds_client_status_enum_type
ds_client_start_call(dsClientHandleType client_handle,int profile_index,int pdp_type)451 ds_client_start_call(dsClientHandleType client_handle, int profile_index, int pdp_type)
452 {
453 ds_client_status_enum_type ret = E_DS_CLIENT_FAILURE_GENERAL;
454 dsi_call_param_value_t param_info;
455 dsi_hndl_t dsi_handle;
456 ds_client_session_data *ds_global_data = (ds_client_session_data *)client_handle;
457 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
458 if(ds_global_data == NULL) {
459 LOC_LOGE("%s:%d]: Null callback parameter\n", __func__, __LINE__);
460 goto err;
461 }
462 dsi_handle = ds_global_data->dsi_net_handle;
463 //Set profile index as call parameter
464 param_info.buf_val = NULL;
465 param_info.num_val = profile_index;
466 dsi_set_data_call_param(dsi_handle,
467 DSI_CALL_INFO_UMTS_PROFILE_IDX,
468 ¶m_info);
469
470 //Set IP Version as call parameter
471 param_info.buf_val = NULL;
472 param_info.num_val = pdp_type;
473 dsi_set_data_call_param(dsi_handle,
474 DSI_CALL_INFO_IP_VERSION,
475 ¶m_info);
476 LOC_LOGD("%s:%d]: Starting emergency call with profile index %d; pdp_type:%d\n",
477 __func__, __LINE__, profile_index, pdp_type);
478 if(dsi_start_data_call(dsi_handle) == DSI_SUCCESS) {
479 LOC_LOGD("%s:%d]: Sent request to start data call\n",
480 __func__, __LINE__);
481 ret = E_DS_CLIENT_SUCCESS;
482 }
483 else {
484 LOC_LOGE("%s:%d]: Could not send req to start data call \n", __func__, __LINE__);
485 ret = E_DS_CLIENT_FAILURE_GENERAL;
486 goto err;
487 }
488
489 err:
490 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
491 return ret;
492
493 }
494
495 /*Function to open an emergency call. Does the following things:
496 - Obtains a handle to the WDS service
497 - Obtains a list of profiles configured in the modem
498 - Queries each profile and obtains settings to check if emergency calls
499 are supported
500 - Returns the profile index that supports emergency calls
501 - Returns handle to dsi_netctrl*/
502 ds_client_status_enum_type
ds_client_open_call(dsClientHandleType * client_handle,ds_client_cb_data * callback,void * caller_cookie,int * profile_index,int * pdp_type)503 ds_client_open_call(dsClientHandleType *client_handle,
504 ds_client_cb_data *callback,
505 void *caller_cookie,
506 int *profile_index,
507 int *pdp_type)
508 {
509 ds_client_status_enum_type ret = E_DS_CLIENT_FAILURE_GENERAL;
510 ds_client_resp_union_type profile_list_resp_msg;
511 ds_client_resp_union_type profile_settings_resp_msg;
512 wds_profile_identifier_type_v01 profile_identifier;
513 uint32_t i=0;
514 dsi_hndl_t dsi_handle;
515 ds_client_session_data **ds_global_data = (ds_client_session_data **)client_handle;
516 unsigned char call_profile_index_found = 0;
517 uint32_t emergency_profile_index=0;
518 qmi_client_type wds_qmi_client;
519
520 profile_list_resp_msg.p_get_profile_list_resp = NULL;
521 profile_settings_resp_msg.p_get_profile_setting_resp = NULL;
522
523 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
524 if(callback == NULL || ds_global_data == NULL) {
525 LOC_LOGE("%s:%d]: Null callback parameter\n", __func__, __LINE__);
526 goto err;
527 }
528
529 ret = ds_client_qmi_ctrl_point_init(&wds_qmi_client);
530 if(ret != E_DS_CLIENT_SUCCESS) {
531 LOC_LOGE("%s:%d]: ds_client_qmi_ctrl_point_init failed. ret: %d\n",
532 __func__, __LINE__, ret);
533 goto err;
534 }
535
536 //Allocate memory for the response msg to obtain a list of profiles
537 profile_list_resp_msg.p_get_profile_list_resp = (wds_get_profile_list_resp_msg_v01 *)
538 calloc(1, sizeof(wds_get_profile_list_resp_msg_v01));
539 if(profile_list_resp_msg.p_get_profile_list_resp == NULL) {
540 LOC_LOGE("%s:%d]: Could not allocate memory for"
541 "p_get_profile_list_resp\n", __func__, __LINE__);
542 ret = E_DS_CLIENT_FAILURE_NOT_ENOUGH_MEMORY;
543 goto err;
544 }
545
546 LOC_LOGD("%s:%d]: Getting profile list\n", __func__, __LINE__);
547 ret = ds_client_get_profile_list(&wds_qmi_client,
548 &profile_list_resp_msg,
549 WDS_PROFILE_TYPE_3GPP_V01);
550 if(ret != E_DS_CLIENT_SUCCESS) {
551 LOC_LOGE("%s:%d]: ds_client_get_profile_list failed. ret: %d\n",
552 __func__, __LINE__, ret);
553 goto err;
554 }
555 LOC_LOGD("%s:%d]: Got profile list; length = %d\n", __func__, __LINE__,
556 profile_list_resp_msg.p_get_profile_list_resp->profile_list_len);
557
558 //Allocate memory for the response msg to obtain profile settings
559 //We allocate memory for only one response msg and keep re-using it
560 profile_settings_resp_msg.p_get_profile_setting_resp =
561 (wds_get_profile_settings_resp_msg_v01 *)
562 calloc(1, sizeof(wds_get_profile_settings_resp_msg_v01));
563 if(profile_settings_resp_msg.p_get_profile_setting_resp == NULL) {
564 LOC_LOGE("%s:%d]: Could not allocate memory for"
565 "p_get_profile_setting_resp\n", __func__, __LINE__);
566 ret = E_DS_CLIENT_FAILURE_NOT_ENOUGH_MEMORY;
567 goto err;
568 }
569
570 //Loop over the list of profiles to find a profile that supports
571 //emergency calls
572 for(i=0; i < profile_list_resp_msg.p_get_profile_list_resp->profile_list_len; i++) {
573 /*QMI_WDS_GET_PROFILE_SETTINGS_REQ requires an input data
574 structure that is of type wds_profile_identifier_type_v01
575 We have to fill that structure for each profile from the
576 info obtained from the profile list*/
577 //copy profile type
578 profile_identifier.profile_type =
579 profile_list_resp_msg.p_get_profile_list_resp->profile_list[i].profile_type;
580 //copy profile index
581 profile_identifier.profile_index =
582 profile_list_resp_msg.p_get_profile_list_resp->profile_list[i].profile_index;
583
584 ret = ds_client_get_profile_settings(&wds_qmi_client,
585 &profile_settings_resp_msg,
586 &profile_identifier);
587 if(ret != E_DS_CLIENT_SUCCESS) {
588 LOC_LOGE("%s:%d]: ds_client_get_profile_settings failed. ret: %d\n",
589 __func__, __LINE__, ret);
590 goto err;
591 }
592 LOC_LOGD("%s:%d]: Got profile setting for profile %d; name: %s\n",
593 __func__, __LINE__, i,
594 profile_settings_resp_msg.p_get_profile_setting_resp->profile_name);
595
596 if(profile_settings_resp_msg.p_get_profile_setting_resp->support_emergency_calls_valid) {
597 if(profile_settings_resp_msg.p_get_profile_setting_resp->support_emergency_calls) {
598 LOC_LOGD("%s:%d]: Found emergency profile in profile %d"
599 , __func__, __LINE__, i);
600 call_profile_index_found = 1;
601 emergency_profile_index = profile_identifier.profile_index;
602
603 if(profile_settings_resp_msg.p_get_profile_setting_resp->pdp_type_valid) {
604 *pdp_type = (int)profile_settings_resp_msg.p_get_profile_setting_resp->pdp_type;
605 LOC_LOGD("%s:%d]: pdp_type: %d\n", __func__, __LINE__, *pdp_type);
606 switch(*pdp_type) {
607 case WDS_PDP_TYPE_PDP_IPV4_V01:
608 *pdp_type = DSI_IP_VERSION_4;
609 break;
610 case WDS_PDP_TYPE_PDP_IPV6_V01:
611 *pdp_type = DSI_IP_VERSION_6;
612 break;
613 case WDS_PDP_TYPE_PDP_IPV4V6_V01:
614 *pdp_type = DSI_IP_VERSION_4_6;
615 break;
616 default:
617 LOC_LOGE("%s:%d]: pdp_type unknown. Setting default as ipv4/v6\n",
618 __func__, __LINE__);
619 *pdp_type = DSI_IP_VERSION_4;
620
621 }
622 }
623 else {
624 LOC_LOGD("%s:%d]: pdp type not valid in profile setting. Default ipv4\n",
625 __func__, __LINE__);
626 *pdp_type = DSI_IP_VERSION_4;
627 }
628 //Break out of for loop since we found the emergency profile
629 break;
630 }
631 else
632 LOC_LOGE("%s:%d]: Emergency profile valid but not supported in profile: %d "
633 , __func__, __LINE__, i);
634 }
635 //Since this struct is loaded with settings for the next profile,
636 //it is important to clear out the memory to avoid values/flags
637 //from being carried over
638 memset((void *)profile_settings_resp_msg.p_get_profile_setting_resp,
639 0, sizeof(wds_get_profile_settings_resp_msg_v01));
640 }
641
642 //Release qmi client handle
643 if(qmi_client_release(wds_qmi_client) != QMI_NO_ERR) {
644 LOC_LOGE("%s:%d]: Could not release qmi client handle\n",
645 __func__, __LINE__);
646 ret = E_DS_CLIENT_FAILURE_GENERAL;
647 }
648
649 if(call_profile_index_found) {
650 *profile_index = emergency_profile_index;
651 *ds_global_data = (ds_client_session_data *)calloc(1, sizeof(ds_client_session_data));
652 if(*ds_global_data == NULL) {
653 LOC_LOGE("%s:%d]: Could not allocate memory for ds_global_data. Failing\n",
654 __func__, __LINE__);
655 ret = E_DS_CLIENT_FAILURE_NOT_ENOUGH_MEMORY;
656 goto err;
657 }
658
659 (*ds_global_data)->caller_data.event_cb = callback->event_cb;
660 (*ds_global_data)->caller_data.caller_cookie = caller_cookie;
661 dsi_handle = dsi_get_data_srvc_hndl(net_ev_cb, &(*ds_global_data)->caller_data);
662 if(dsi_handle == NULL) {
663 LOC_LOGE("%s:%d]: Could not get data handle. Retry Later\n",
664 __func__, __LINE__);
665 ret = E_DS_CLIENT_RETRY_LATER;
666 goto err;
667 }
668 else
669 (*ds_global_data)->dsi_net_handle = dsi_handle;
670 }
671 else {
672 LOC_LOGE("%s:%d]: Could not find a profile that supports emergency calls",
673 __func__, __LINE__);
674 ret = E_DS_CLIENT_FAILURE_GENERAL;
675 }
676 err:
677 if(profile_list_resp_msg.p_get_profile_list_resp)
678 free(profile_list_resp_msg.p_get_profile_list_resp);
679 if(profile_settings_resp_msg.p_get_profile_setting_resp)
680 free(profile_settings_resp_msg.p_get_profile_setting_resp);
681 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
682 return ret;
683 }
684
ds_client_stop_call(dsClientHandleType client_handle)685 ds_client_status_enum_type ds_client_stop_call(dsClientHandleType client_handle)
686 {
687 ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
688 ds_client_session_data *p_ds_global_data = (ds_client_session_data *)client_handle;
689 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
690
691 if(client_handle == NULL) {
692 LOC_LOGE("%s:%d]: Null argument received. Failing\n", __func__, __LINE__);
693 ret = E_DS_CLIENT_FAILURE_GENERAL;
694 goto err;
695 }
696
697 if(dsi_stop_data_call(p_ds_global_data->dsi_net_handle) == DSI_SUCCESS) {
698 LOC_LOGD("%s:%d]: Sent request to stop data call\n", __func__, __LINE__);
699 }
700 else {
701 LOC_LOGE("%s:%d]: Could not send request to stop data call\n",
702 __func__, __LINE__);
703 ret = E_DS_CLIENT_FAILURE_GENERAL;
704 goto err;
705 }
706
707 err:
708 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
709 return ret;
710 }
711
712 /*
713 Stops data call associated with the data handle
714 */
ds_client_close_call(dsClientHandleType * client_handle)715 void ds_client_close_call(dsClientHandleType *client_handle)
716 {
717 ds_client_session_data **ds_global_data = (ds_client_session_data **)client_handle;
718 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
719 if(client_handle == NULL || *client_handle == NULL) {
720 LOC_LOGE("%s:%d]: Null argument received. Failing\n", __func__, __LINE__);
721 goto err;
722 }
723 dsi_rel_data_srvc_hndl((*ds_global_data)->dsi_net_handle);
724 (*ds_global_data)->dsi_net_handle = NULL;
725 free(*ds_global_data);
726 *ds_global_data = NULL;
727 LOC_LOGD("%s:%d]: Released Data handle\n", __func__, __LINE__);
728 err:
729 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
730 return;
731 }
732
ds_client_init()733 int ds_client_init()
734 {
735 int ret = 0;
736 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
737 if(DSI_SUCCESS != dsi_init(DSI_MODE_GENERAL))
738 {
739 LOC_LOGE("%s:%d]:dsi_init failed\n", __func__, __LINE__);
740 ret = -1;
741 }
742 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
743 return ret;
744 }
745