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, ¬ifier);
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 ¶m_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 ¶m_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