• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &notifier);
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                             &param_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                             &param_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