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