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 NAME_VAL(DSI_EVT_WDS_CONNECTED)
88 };
89
90 typedef struct
91 {
92 ds_client_event_ind_cb_type event_cb;
93 void *caller_cookie;
94 }ds_caller_data;
95
96 typedef struct {
97 //Global dsi handle
98 dsi_hndl_t dsi_net_handle;
99 //Handle to caller's data
100 ds_caller_data caller_data;
101 } ds_client_session_data;
102
net_ev_cb(dsi_hndl_t handle,void * user_data,dsi_net_evt_t evt,dsi_evt_payload_t * payload_ptr)103 void net_ev_cb(dsi_hndl_t handle, void* user_data,
104 dsi_net_evt_t evt, dsi_evt_payload_t *payload_ptr)
105 {
106 int i;
107 (void)handle;
108 (void)user_data;
109 (void)payload_ptr;
110 ds_caller_data *callback_data = (ds_caller_data *)user_data;
111
112 LOC_LOGD("%s:%d]: Enter. Callback data: %p\n", __func__, __LINE__, callback_data);
113 if(evt > DSI_EVT_INVALID && evt < DSI_EVT_MAX)
114 {
115 for(i=0;i<DSI_EVT_MAX;i++)
116 {
117 if(event_string_tbl[i].evt == evt)
118 LOC_LOGE("%s:%d]: Callback received: %s",
119 __func__, __LINE__, event_string_tbl[i].str);
120 }
121 switch(evt) {
122 case DSI_EVT_NET_IS_CONN:
123 case DSI_EVT_WDS_CONNECTED:
124 {
125 LOC_LOGD("%s:%d]: Emergency call started\n", __func__, __LINE__);
126 callback_data->event_cb(E_DS_CLIENT_DATA_CALL_CONNECTED,
127 callback_data->caller_cookie);
128 break;
129 }
130 case DSI_EVT_NET_NO_NET:
131 {
132 LOC_LOGD("%s:%d]: Emergency call stopped\n", __func__, __LINE__);
133 callback_data->event_cb(E_DS_CLIENT_DATA_CALL_DISCONNECTED,
134 callback_data->caller_cookie);
135 break;
136 }
137 default:
138 LOC_LOGD("%s:%d]: uninteresting event\n", __func__, __LINE__);
139 }
140 }
141 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
142 }
143
144 /*This function is called to obtain a handle to the QMI WDS service*/
145 static ds_client_status_enum_type
ds_client_qmi_ctrl_point_init(qmi_client_type * p_wds_qmi_client)146 ds_client_qmi_ctrl_point_init(qmi_client_type *p_wds_qmi_client)
147 {
148 qmi_client_type wds_qmi_client, notifier = NULL;
149 ds_client_status_enum_type status = E_DS_CLIENT_SUCCESS;
150 qmi_service_info *p_service_info = NULL;
151 uint32_t num_services = 0, num_entries = 0;
152 qmi_client_error_type ret = QMI_NO_ERR;
153 unsigned char no_signal = 0;
154 qmi_client_os_params os_params;
155 int timeout = 0;
156
157 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
158
159 //Get service object for QMI_WDS service
160 qmi_idl_service_object_type ds_client_service_object =
161 wds_get_service_object_v01();
162 if(ds_client_service_object == NULL) {
163 LOC_LOGE("%s:%d]: wds_get_service_object_v01 failed\n" ,
164 __func__, __LINE__);
165 status = E_DS_CLIENT_FAILURE_INTERNAL;
166 goto err;
167 }
168
169 //get service addressing information
170 ret = qmi_client_get_service_list(ds_client_service_object, NULL, NULL,
171 &num_services);
172 LOC_LOGD("%s:%d]: qmi_client_get_service_list() first try ret %d, "
173 "num_services %d]\n", __func__, __LINE__, ret, num_services);
174 if(ret != QMI_NO_ERR) {
175 //Register for service notification
176 ret = qmi_client_notifier_init(ds_client_service_object, &os_params, ¬ifier);
177 if (ret != QMI_NO_ERR) {
178 LOC_LOGE("%s:%d]: qmi_client_notifier_init failed %d\n",
179 __func__, __LINE__, ret);
180 status = E_DS_CLIENT_FAILURE_INTERNAL;
181 goto err;
182 }
183
184 do {
185 QMI_CCI_OS_SIGNAL_CLEAR(&os_params);
186 ret = qmi_client_get_service_list(ds_client_service_object, NULL,
187 NULL, &num_services);
188 if(ret != QMI_NO_ERR) {
189 QMI_CCI_OS_SIGNAL_WAIT(&os_params, DS_CLIENT_SERVICE_TIMEOUT);
190 no_signal = QMI_CCI_OS_SIGNAL_TIMED_OUT(&os_params);
191 if(!no_signal)
192 ret = qmi_client_get_service_list(ds_client_service_object, NULL,
193 NULL, &num_services);
194 }
195 timeout += DS_CLIENT_SERVICE_TIMEOUT;
196 LOC_LOGV("%s:%d]: qmi_client_get_service_list() returned ret: %d,"
197 "no_signal: %d, total timeout: %d\n", __func__, __LINE__,
198 ret, no_signal, timeout);
199 } while( (timeout < DS_CLIENT_SERVICE_TIMEOUT_TOTAL) &&
200 no_signal &&
201 (ret != QMI_NO_ERR) );
202 }
203
204 //Handle failure cases
205 if(num_services == 0 || ret != QMI_NO_ERR) {
206 if(!no_signal) {
207 LOC_LOGE("%s:%d]: qmi_client_get_service_list failed even though"
208 "service is up! Error: %d \n", __func__, __LINE__, ret);
209 status = E_DS_CLIENT_FAILURE_INTERNAL;
210 }
211 else {
212 LOC_LOGE("%s:%d]: qmi_client_get_service_list failed after retries"
213 "Error: %d \n", __func__, __LINE__, ret);
214 status = E_DS_CLIENT_FAILURE_TIMEOUT;
215 }
216 goto err;
217 }
218
219 LOC_LOGD("%s:%d]: qmi_client_get_service_list succeeded\n", __func__, __LINE__);
220
221 //Success
222 p_service_info = (qmi_service_info *)malloc(num_services * sizeof(qmi_service_info));
223 if(p_service_info == NULL) {
224 LOC_LOGE("%s:%d]: could not allocate memory for serviceInfo !!\n",
225 __func__, __LINE__);
226 status = E_DS_CLIENT_FAILURE_INTERNAL;
227 goto err;
228 }
229 num_entries = num_services;
230
231 //Populate service info
232 ret = qmi_client_get_service_list(ds_client_service_object, p_service_info,
233 &num_entries, &num_services);
234 if(ret != QMI_NO_ERR) {
235 LOC_LOGE("%s:%d]: qmi_client_get_service_list failed. ret: %d \n",
236 __func__, __LINE__, ret);
237 status = E_DS_CLIENT_FAILURE_INTERNAL;
238 goto err;
239 }
240
241 //Initialize wds_qmi_client
242 LOC_LOGD("%s:%d]: Initializing WDS client with qmi_client_init\n", __func__,
243 __LINE__);
244 ret = qmi_client_init(&p_service_info[0], ds_client_service_object,
245 NULL, NULL, NULL, &wds_qmi_client);
246 if(ret != QMI_NO_ERR) {
247 LOC_LOGE("%s:%d]: qmi_client_init Error. ret: %d\n", __func__, __LINE__, ret);
248 status = E_DS_CLIENT_FAILURE_INTERNAL;
249 goto err;
250 }
251 LOC_LOGD("%s:%d]: WDS client initialized with qmi_client_init\n", __func__,
252 __LINE__);
253
254 //Store WDS QMI client handle in the parameter passed in
255 *p_wds_qmi_client = wds_qmi_client;
256
257 status = E_DS_CLIENT_SUCCESS;
258 LOC_LOGD("%s:%d]: init success\n", __func__, __LINE__);
259
260 if(notifier)
261 qmi_client_release(notifier);
262
263 err:
264 if(p_service_info)
265 free(p_service_info);
266
267 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
268 return status;
269 }
270
271 /*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)272 static ds_client_status_enum_type ds_client_convert_qmi_response(
273 uint32_t req_id,
274 ds_client_resp_union_type *resp_union)
275 {
276 ds_client_status_enum_type ret = E_DS_CLIENT_FAILURE_GENERAL;
277 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
278 switch(req_id)
279 {
280 case QMI_WDS_GET_PROFILE_LIST_REQ_V01 :
281 {
282 if(resp_union->p_get_profile_list_resp->resp.error !=
283 QMI_ERR_NONE_V01) {
284 LOC_LOGE("%s:%d]: Response error: %d", __func__, __LINE__,
285 resp_union->p_get_profile_list_resp->resp.error);
286 }
287 else
288 ret = E_DS_CLIENT_SUCCESS;
289 }
290 break;
291
292 case QMI_WDS_GET_PROFILE_SETTINGS_REQ_V01 :
293 {
294 if(resp_union->p_get_profile_setting_resp->resp.error !=
295 QMI_ERR_NONE_V01) {
296 LOC_LOGE("%s:%d]: Response error: %d", __func__, __LINE__,
297 resp_union->p_get_profile_setting_resp->resp.error);
298 }
299 else
300 ret = E_DS_CLIENT_SUCCESS;
301 }
302 break;
303
304 default:
305 LOC_LOGE("%s:%d]: Unknown request ID\n", __func__, __LINE__);
306 }
307 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
308 return ret;
309 }
310
311
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)312 static ds_client_status_enum_type ds_client_send_qmi_sync_req(
313 qmi_client_type *ds_client_handle,
314 uint32_t req_id,
315 ds_client_resp_union_type *resp_union,
316 ds_client_req_union_type *req_union)
317 {
318 uint32_t req_len = 0;
319 uint32_t resp_len = 0;
320 ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
321 qmi_client_error_type qmi_ret = QMI_NO_ERR;
322 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
323 switch(req_id)
324 {
325 case QMI_WDS_GET_PROFILE_LIST_REQ_V01 :
326 {
327 req_len = sizeof(wds_get_profile_list_req_msg_v01);
328 resp_len = sizeof(wds_get_profile_list_resp_msg_v01);
329 LOC_LOGD("%s:%d]: req_id = GET_PROFILE_LIST_REQ\n",
330 __func__, __LINE__);
331 }
332 break;
333
334 case QMI_WDS_GET_PROFILE_SETTINGS_REQ_V01 :
335 {
336 req_len = sizeof(wds_get_profile_settings_req_msg_v01);
337 resp_len = sizeof(wds_get_profile_settings_resp_msg_v01);
338 LOC_LOGD("%s:%d]: req_id = GET_PROFILE_SETTINGS_REQ\n",
339 __func__, __LINE__);
340 }
341 break;
342
343 default:
344 LOC_LOGE("%s:%d]: Error unknown req_id=%d\n", __func__, __LINE__,
345 req_id);
346 ret = E_DS_CLIENT_FAILURE_INVALID_PARAMETER;
347 goto err;
348 }
349
350 LOC_LOGD("%s:%d]: req_id=%d, len = %d; resp_len= %d\n", __func__, __LINE__,
351 req_id, req_len, resp_len);
352 //Send msg through QCCI
353 qmi_ret = qmi_client_send_msg_sync(
354 *ds_client_handle,
355 req_id,
356 (void *)req_union->p_get_profile_list_req,
357 req_len,
358 (void *)resp_union->p_get_profile_list_resp,
359 resp_len,
360 DS_CLIENT_SYNC_MSG_TIMEOUT);
361 LOC_LOGD("%s:%d]: qmi_client_send_msg_sync returned: %d", __func__, __LINE__, qmi_ret);
362
363 if(qmi_ret != QMI_NO_ERR) {
364 ret = E_DS_CLIENT_FAILURE_INTERNAL;
365 goto err;
366 }
367
368 ret = ds_client_convert_qmi_response(req_id, resp_union);
369
370 err:
371 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
372 return ret;
373 }
374
375 /*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)376 static ds_client_status_enum_type ds_client_get_profile_list(
377 qmi_client_type *ds_client_handle,
378 ds_client_resp_union_type *profile_list_resp_msg,
379 wds_profile_type_enum_v01 profile_type)
380 {
381 ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
382 ds_client_req_union_type req_union;
383 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
384
385 req_union.p_get_profile_list_req = NULL;
386 req_union.p_get_profile_list_req = (wds_get_profile_list_req_msg_v01 *)
387 calloc(1, sizeof(wds_get_profile_list_req_msg_v01));
388 if(req_union.p_get_profile_list_req == NULL) {
389 LOC_LOGE("%s:%d]: Could not allocate memory for"
390 "wds_get_profile_list_req_msg_v01\n", __func__, __LINE__);
391 goto err;
392 }
393 //Populate required members of the request structure
394 req_union.p_get_profile_list_req->profile_type_valid = 1;
395 req_union.p_get_profile_list_req->profile_type = profile_type;
396 ret = ds_client_send_qmi_sync_req(ds_client_handle,
397 QMI_WDS_GET_PROFILE_LIST_REQ_V01,
398 profile_list_resp_msg, &req_union);
399 if(ret != E_DS_CLIENT_SUCCESS) {
400 LOC_LOGE("%s:%d]: ds_client_send_qmi_req failed. ret: %d\n",
401 __func__, __LINE__, ret);
402 goto err;
403 }
404 err:
405 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
406 if(req_union.p_get_profile_list_req)
407 free(req_union.p_get_profile_list_req);
408 return ret;
409 }
410
411 /*This function obtains settings for the profile specified by
412 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)413 static ds_client_status_enum_type ds_client_get_profile_settings(
414 qmi_client_type *ds_client_handle,
415 ds_client_resp_union_type *profile_settings_resp_msg,
416 wds_profile_identifier_type_v01 *profile_identifier)
417 {
418 ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
419 ds_client_req_union_type req_union;
420
421 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
422 //Since it's a union containing a pointer to a structure,
423 //following entities have the same address
424 //- req_union
425 //- req_union.p_get_profile_settings_req
426 //- req_union.p_get_profile_settings_req->profile
427 //so we can very well assign req_union = profile_identifier
428 req_union.p_get_profile_settings_req =
429 (wds_get_profile_settings_req_msg_v01 *)profile_identifier;
430 ret = ds_client_send_qmi_sync_req(ds_client_handle,
431 QMI_WDS_GET_PROFILE_SETTINGS_REQ_V01,
432 profile_settings_resp_msg, &req_union);
433 if(ret != E_DS_CLIENT_SUCCESS) {
434 LOC_LOGE("%s:%d]: ds_client_send_qmi_req failed. ret: %d\n",
435 __func__, __LINE__, ret);
436 goto err;
437 }
438 err:
439 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
440 return ret;
441 }
442
443 /*
444 Starts data call using the handle and the profile index
445 */
446 ds_client_status_enum_type
ds_client_start_call(dsClientHandleType client_handle,int profile_index,int pdp_type)447 ds_client_start_call(dsClientHandleType client_handle, int profile_index, int pdp_type)
448 {
449 ds_client_status_enum_type ret = E_DS_CLIENT_FAILURE_GENERAL;
450 dsi_call_param_value_t param_info;
451 dsi_hndl_t dsi_handle;
452 ds_client_session_data *ds_global_data = (ds_client_session_data *)client_handle;
453 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
454 if(ds_global_data == NULL) {
455 LOC_LOGE("%s:%d]: Null callback parameter\n", __func__, __LINE__);
456 goto err;
457 }
458 dsi_handle = ds_global_data->dsi_net_handle;
459 //Set profile index as call parameter
460 param_info.buf_val = NULL;
461 param_info.num_val = profile_index;
462 dsi_set_data_call_param(dsi_handle,
463 DSI_CALL_INFO_UMTS_PROFILE_IDX,
464 ¶m_info);
465
466 //Set IP Version as call parameter
467 param_info.buf_val = NULL;
468 param_info.num_val = pdp_type;
469 dsi_set_data_call_param(dsi_handle,
470 DSI_CALL_INFO_IP_VERSION,
471 ¶m_info);
472 LOC_LOGD("%s:%d]: Starting emergency call with profile index %d; pdp_type:%d\n",
473 __func__, __LINE__, profile_index, pdp_type);
474 if(dsi_start_data_call(dsi_handle) == DSI_SUCCESS) {
475 LOC_LOGD("%s:%d]: Sent request to start data call\n",
476 __func__, __LINE__);
477 ret = E_DS_CLIENT_SUCCESS;
478 }
479 else {
480 LOC_LOGE("%s:%d]: Could not send req to start data call \n", __func__, __LINE__);
481 ret = E_DS_CLIENT_FAILURE_GENERAL;
482 goto err;
483 }
484
485 err:
486 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
487 return ret;
488
489 }
490
491 /*Function to open an emergency call. Does the following things:
492 - Obtains a handle to the WDS service
493 - Obtains a list of profiles configured in the modem
494 - Queries each profile and obtains settings to check if emergency calls
495 are supported
496 - Returns the profile index that supports emergency calls
497 - Returns handle to dsi_netctrl*/
498 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)499 ds_client_open_call(dsClientHandleType *client_handle,
500 ds_client_cb_data *callback,
501 void *caller_cookie,
502 int *profile_index,
503 int *pdp_type)
504 {
505 ds_client_status_enum_type ret = E_DS_CLIENT_FAILURE_GENERAL;
506 ds_client_resp_union_type profile_list_resp_msg;
507 ds_client_resp_union_type profile_settings_resp_msg;
508 wds_profile_identifier_type_v01 profile_identifier;
509 uint32_t i=0;
510 dsi_hndl_t dsi_handle;
511 ds_client_session_data **ds_global_data = (ds_client_session_data **)client_handle;
512 unsigned char call_profile_index_found = 0;
513 uint32_t emergency_profile_index=0;
514 qmi_client_type wds_qmi_client;
515
516 profile_list_resp_msg.p_get_profile_list_resp = NULL;
517 profile_settings_resp_msg.p_get_profile_setting_resp = NULL;
518
519 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
520 if(callback == NULL || ds_global_data == NULL) {
521 LOC_LOGE("%s:%d]: Null callback parameter\n", __func__, __LINE__);
522 goto err;
523 }
524
525 ret = ds_client_qmi_ctrl_point_init(&wds_qmi_client);
526 if(ret != E_DS_CLIENT_SUCCESS) {
527 LOC_LOGE("%s:%d]: ds_client_qmi_ctrl_point_init failed. ret: %d\n",
528 __func__, __LINE__, ret);
529 goto err;
530 }
531
532 //Allocate memory for the response msg to obtain a list of profiles
533 profile_list_resp_msg.p_get_profile_list_resp = (wds_get_profile_list_resp_msg_v01 *)
534 calloc(1, sizeof(wds_get_profile_list_resp_msg_v01));
535 if(profile_list_resp_msg.p_get_profile_list_resp == NULL) {
536 LOC_LOGE("%s:%d]: Could not allocate memory for"
537 "p_get_profile_list_resp\n", __func__, __LINE__);
538 ret = E_DS_CLIENT_FAILURE_NOT_ENOUGH_MEMORY;
539 goto err;
540 }
541
542 LOC_LOGD("%s:%d]: Getting profile list\n", __func__, __LINE__);
543 ret = ds_client_get_profile_list(&wds_qmi_client,
544 &profile_list_resp_msg,
545 WDS_PROFILE_TYPE_3GPP_V01);
546 if(ret != E_DS_CLIENT_SUCCESS) {
547 LOC_LOGE("%s:%d]: ds_client_get_profile_list failed. ret: %d\n",
548 __func__, __LINE__, ret);
549 goto err;
550 }
551 LOC_LOGD("%s:%d]: Got profile list; length = %d\n", __func__, __LINE__,
552 profile_list_resp_msg.p_get_profile_list_resp->profile_list_len);
553
554 //Allocate memory for the response msg to obtain profile settings
555 //We allocate memory for only one response msg and keep re-using it
556 profile_settings_resp_msg.p_get_profile_setting_resp =
557 (wds_get_profile_settings_resp_msg_v01 *)
558 calloc(1, sizeof(wds_get_profile_settings_resp_msg_v01));
559 if(profile_settings_resp_msg.p_get_profile_setting_resp == NULL) {
560 LOC_LOGE("%s:%d]: Could not allocate memory for"
561 "p_get_profile_setting_resp\n", __func__, __LINE__);
562 ret = E_DS_CLIENT_FAILURE_NOT_ENOUGH_MEMORY;
563 goto err;
564 }
565
566 //Loop over the list of profiles to find a profile that supports
567 //emergency calls
568 for(i=0; i < profile_list_resp_msg.p_get_profile_list_resp->profile_list_len; i++) {
569 /*QMI_WDS_GET_PROFILE_SETTINGS_REQ requires an input data
570 structure that is of type wds_profile_identifier_type_v01
571 We have to fill that structure for each profile from the
572 info obtained from the profile list*/
573 //copy profile type
574 profile_identifier.profile_type =
575 profile_list_resp_msg.p_get_profile_list_resp->profile_list[i].profile_type;
576 //copy profile index
577 profile_identifier.profile_index =
578 profile_list_resp_msg.p_get_profile_list_resp->profile_list[i].profile_index;
579
580 ret = ds_client_get_profile_settings(&wds_qmi_client,
581 &profile_settings_resp_msg,
582 &profile_identifier);
583 if(ret != E_DS_CLIENT_SUCCESS) {
584 LOC_LOGE("%s:%d]: ds_client_get_profile_settings failed. ret: %d\n",
585 __func__, __LINE__, ret);
586 goto err;
587 }
588 LOC_LOGD("%s:%d]: Got profile setting for profile %d; name: %s\n",
589 __func__, __LINE__, i,
590 profile_settings_resp_msg.p_get_profile_setting_resp->profile_name);
591
592 if(profile_settings_resp_msg.p_get_profile_setting_resp->support_emergency_calls_valid) {
593 if(profile_settings_resp_msg.p_get_profile_setting_resp->support_emergency_calls) {
594 LOC_LOGD("%s:%d]: Found emergency profile in profile %d"
595 , __func__, __LINE__, i);
596 call_profile_index_found = 1;
597 emergency_profile_index = profile_identifier.profile_index;
598
599 if(profile_settings_resp_msg.p_get_profile_setting_resp->pdp_type_valid) {
600 *pdp_type = (int)profile_settings_resp_msg.p_get_profile_setting_resp->pdp_type;
601 LOC_LOGD("%s:%d]: pdp_type: %d\n", __func__, __LINE__, *pdp_type);
602 switch(*pdp_type) {
603 case WDS_PDP_TYPE_PDP_IPV4_V01:
604 *pdp_type = DSI_IP_VERSION_4;
605 break;
606 case WDS_PDP_TYPE_PDP_IPV6_V01:
607 *pdp_type = DSI_IP_VERSION_6;
608 break;
609 case WDS_PDP_TYPE_PDP_IPV4V6_V01:
610 *pdp_type = DSI_IP_VERSION_4_6;
611 break;
612 default:
613 LOC_LOGE("%s:%d]: pdp_type unknown. Setting default as ipv4/v6\n",
614 __func__, __LINE__);
615 *pdp_type = DSI_IP_VERSION_4;
616
617 }
618 }
619 else {
620 LOC_LOGD("%s:%d]: pdp type not valid in profile setting. Default ipv4\n",
621 __func__, __LINE__);
622 *pdp_type = DSI_IP_VERSION_4;
623 }
624 //Break out of for loop since we found the emergency profile
625 break;
626 }
627 else
628 LOC_LOGE("%s:%d]: Emergency profile valid but not supported in profile: %d "
629 , __func__, __LINE__, i);
630 }
631 //Since this struct is loaded with settings for the next profile,
632 //it is important to clear out the memory to avoid values/flags
633 //from being carried over
634 memset((void *)profile_settings_resp_msg.p_get_profile_setting_resp,
635 0, sizeof(wds_get_profile_settings_resp_msg_v01));
636 }
637
638 //Release qmi client handle
639 if(qmi_client_release(wds_qmi_client) != QMI_NO_ERR) {
640 LOC_LOGE("%s:%d]: Could not release qmi client handle\n",
641 __func__, __LINE__);
642 ret = E_DS_CLIENT_FAILURE_GENERAL;
643 }
644
645 if(call_profile_index_found) {
646 *profile_index = emergency_profile_index;
647 *ds_global_data = (ds_client_session_data *)calloc(1, sizeof(ds_client_session_data));
648 if(*ds_global_data == NULL) {
649 LOC_LOGE("%s:%d]: Could not allocate memory for ds_global_data. Failing\n",
650 __func__, __LINE__);
651 ret = E_DS_CLIENT_FAILURE_NOT_ENOUGH_MEMORY;
652 goto err;
653 }
654
655 (*ds_global_data)->caller_data.event_cb = callback->event_cb;
656 (*ds_global_data)->caller_data.caller_cookie = caller_cookie;
657 dsi_handle = dsi_get_data_srvc_hndl(net_ev_cb, &(*ds_global_data)->caller_data);
658 if(dsi_handle == NULL) {
659 LOC_LOGE("%s:%d]: Could not get data handle. Retry Later\n",
660 __func__, __LINE__);
661 ret = E_DS_CLIENT_RETRY_LATER;
662 goto err;
663 }
664 else
665 (*ds_global_data)->dsi_net_handle = dsi_handle;
666 }
667 else {
668 LOC_LOGE("%s:%d]: Could not find a profile that supports emergency calls",
669 __func__, __LINE__);
670 ret = E_DS_CLIENT_FAILURE_GENERAL;
671 }
672 err:
673 if(profile_list_resp_msg.p_get_profile_list_resp)
674 free(profile_list_resp_msg.p_get_profile_list_resp);
675 if(profile_settings_resp_msg.p_get_profile_setting_resp)
676 free(profile_settings_resp_msg.p_get_profile_setting_resp);
677 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
678 return ret;
679 }
680
ds_client_stop_call(dsClientHandleType client_handle)681 ds_client_status_enum_type ds_client_stop_call(dsClientHandleType client_handle)
682 {
683 ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
684 ds_client_session_data *p_ds_global_data = (ds_client_session_data *)client_handle;
685 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
686
687 if(client_handle == NULL) {
688 LOC_LOGE("%s:%d]: Null argument received. Failing\n", __func__, __LINE__);
689 ret = E_DS_CLIENT_FAILURE_GENERAL;
690 goto err;
691 }
692
693 if(dsi_stop_data_call(p_ds_global_data->dsi_net_handle) == DSI_SUCCESS) {
694 LOC_LOGD("%s:%d]: Sent request to stop data call\n", __func__, __LINE__);
695 }
696 else {
697 LOC_LOGE("%s:%d]: Could not send request to stop data call\n",
698 __func__, __LINE__);
699 ret = E_DS_CLIENT_FAILURE_GENERAL;
700 goto err;
701 }
702
703 err:
704 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
705 return ret;
706 }
707
708 /*
709 Stops data call associated with the data handle
710 */
ds_client_close_call(dsClientHandleType * client_handle)711 void ds_client_close_call(dsClientHandleType *client_handle)
712 {
713 ds_client_session_data **ds_global_data = (ds_client_session_data **)client_handle;
714 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
715 if(client_handle == NULL || *client_handle == NULL) {
716 LOC_LOGE("%s:%d]: Null argument received. Failing\n", __func__, __LINE__);
717 goto err;
718 }
719 dsi_rel_data_srvc_hndl((*ds_global_data)->dsi_net_handle);
720 (*ds_global_data)->dsi_net_handle = NULL;
721 free(*ds_global_data);
722 *ds_global_data = NULL;
723 LOC_LOGD("%s:%d]: Released Data handle\n", __func__, __LINE__);
724 err:
725 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
726 return;
727 }
728
ds_client_init()729 int ds_client_init()
730 {
731 int ret = 0;
732 LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
733 if(DSI_SUCCESS != dsi_init(DSI_MODE_GENERAL))
734 {
735 LOC_LOGE("%s:%d]:dsi_init failed\n", __func__, __LINE__);
736 ret = -1;
737 }
738 LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
739 return ret;
740 }
741