• 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 #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, &notifier);
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                             &param_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                             &param_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