1 /****************************************************************************** 2 @file: loc_eng_ni.cpp 3 @brief: module for network initiated interactions 4 5 DESCRIPTION 6 LOC_API network initiated operation support 7 8 INITIALIZATION AND SEQUENCING REQUIREMENTS 9 10 ----------------------------------------------------------------------------- 11 Copyright (c) 2009 QUALCOMM Incorporated. 12 All Rights Reserved. QUALCOMM Proprietary and Confidential. 13 ----------------------------------------------------------------------------- 14 ******************************************************************************/ 15 16 /*===================================================================== 17 EDIT HISTORY FOR MODULE 18 19 This section contains comments describing changes made to the module. 20 Notice that changes are listed in reverse chronological order. 21 22 when who what, where, why 23 -------- --- ------------------------------------------------------- 24 07/30/09 dx Initial version 25 26 $Id: 27 ======================================================================*/ 28 29 #define LOG_NDDEBUG 0 30 #define LOG_NIDEBUG 0 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <pthread.h> 35 #include <string.h> 36 #include <ctype.h> 37 #include <unistd.h> 38 #include <time.h> 39 40 #include <rpc/rpc.h> 41 #include <loc_api_rpc_glue.h> 42 #include <loc_eng.h> 43 #include <loc_eng_ni.h> 44 45 #define LOG_TAG "lib_locapi" 46 #include <utils/Log.h> 47 48 // comment this out to enable logging 49 // #undef LOGD 50 // #define LOGD(...) {} 51 52 /*============================================================================= 53 * 54 * DATA DECLARATION 55 * 56 *============================================================================*/ 57 58 const GpsNiInterface sLocEngNiInterface = 59 { 60 sizeof(GpsNiInterface), 61 loc_eng_ni_init, 62 loc_eng_ni_respond, 63 }; 64 65 boolean loc_eng_ni_data_init = FALSE; 66 loc_eng_ni_data_s_type loc_eng_ni_data; 67 68 extern loc_eng_data_s_type loc_eng_data; 69 70 /*============================================================================= 71 * 72 * FUNCTION DECLARATIONS 73 * 74 *============================================================================*/ 75 76 /*=========================================================================== 77 78 FUNCTION respond_from_enum 79 80 DESCRIPTION 81 Returns the name of the response 82 83 RETURN VALUE 84 response name string 85 86 ===========================================================================*/ 87 static const char* respond_from_enum(rpc_loc_ni_user_resp_e_type resp) 88 { 89 switch (resp) 90 { 91 case RPC_LOC_NI_LCS_NOTIFY_VERIFY_ACCEPT: 92 return "accept"; 93 case RPC_LOC_NI_LCS_NOTIFY_VERIFY_DENY: 94 return "deny"; 95 case RPC_LOC_NI_LCS_NOTIFY_VERIFY_NORESP: 96 return "no response"; 97 default: 98 return NULL; 99 } 100 } 101 102 /*=========================================================================== 103 104 FUNCTION loc_ni_respond 105 106 DESCRIPTION 107 Displays the NI request and awaits user input. If a previous request is 108 in session, the new one is handled using sys.ni_default_response (if exists); 109 otherwise, it is denied. 110 111 DEPENDENCY 112 Do not lock the data by mutex loc_ni_lock 113 114 RETURN VALUE 115 none 116 117 ===========================================================================*/ 118 static void loc_ni_respond(rpc_loc_ni_user_resp_e_type resp, 119 const rpc_loc_ni_event_s_type *request_pass_back 120 ) 121 { 122 LOGD("Sending NI response: %s\n", respond_from_enum(resp)); 123 124 rpc_loc_ioctl_data_u_type data; 125 rpc_loc_ioctl_callback_s_type callback_payload; 126 127 memcpy(&data.rpc_loc_ioctl_data_u_type_u.user_verify_resp.ni_event_pass_back, 128 request_pass_back, sizeof (rpc_loc_ni_event_s_type)); 129 data.rpc_loc_ioctl_data_u_type_u.user_verify_resp.user_resp = resp; 130 131 loc_eng_ioctl( 132 loc_eng_data.client_handle, 133 RPC_LOC_IOCTL_INFORM_NI_USER_RESPONSE, 134 &data, 135 LOC_IOCTL_DEFAULT_TIMEOUT, 136 &callback_payload 137 ); 138 } 139 140 /*=========================================================================== 141 142 FUNCTION loc_ni_fill_notif_verify_type 143 144 DESCRIPTION 145 Fills need_notify, need_verify, etc. 146 147 RETURN VALUE 148 none 149 150 ===========================================================================*/ 151 static boolean loc_ni_fill_notif_verify_type(GpsNiNotification *notif, 152 rpc_loc_ni_notify_verify_e_type notif_priv) 153 { 154 notif->notify_flags = 0; 155 notif->default_response = GPS_NI_RESPONSE_NORESP; 156 157 switch (notif_priv) 158 { 159 case RPC_LOC_NI_USER_NO_NOTIFY_NO_VERIFY: 160 notif->notify_flags = 0; 161 break; 162 163 case RPC_LOC_NI_USER_NOTIFY_ONLY: 164 notif->notify_flags = GPS_NI_NEED_NOTIFY; 165 break; 166 167 case RPC_LOC_NI_USER_NOTIFY_VERIFY_ALLOW_NO_RESP: 168 notif->notify_flags = GPS_NI_NEED_NOTIFY | GPS_NI_NEED_VERIFY; 169 notif->default_response = GPS_NI_RESPONSE_ACCEPT; 170 break; 171 172 case RPC_LOC_NI_USER_NOTIFY_VERIFY_NOT_ALLOW_NO_RESP: 173 notif->notify_flags = GPS_NI_NEED_NOTIFY | GPS_NI_NEED_VERIFY; 174 notif->default_response = GPS_NI_RESPONSE_DENY; 175 break; 176 177 case RPC_LOC_NI_USER_PRIVACY_OVERRIDE: 178 notif->notify_flags = GPS_NI_PRIVACY_OVERRIDE; 179 break; 180 181 default: 182 return FALSE; 183 } 184 185 return TRUE; 186 } 187 188 /*=========================================================================== 189 190 FUNCTION hexcode 191 192 DESCRIPTION 193 Converts a binary array into a Hex string. E.g., 1F 00 3F --> "1F003F" 194 195 RETURN VALUE 196 bytes encoded 197 198 ===========================================================================*/ 199 static int hexcode(char *hexstring, int string_size, const char *data, int data_size) 200 { 201 int i; 202 for (i = 0; i < data_size; i++) 203 { 204 char ch = data[i]; 205 if (i*2 + 3 <= string_size) 206 { 207 snprintf(&hexstring[i*2], 3, "%02X", ch); 208 } 209 else { 210 break; 211 } 212 } 213 return i; 214 } 215 216 static GpsNiEncodingType convert_encoding_type(int loc_encoding) 217 { 218 GpsNiEncodingType enc = GPS_ENC_UNKNOWN; 219 220 switch (loc_encoding) 221 { 222 case RPC_LOC_NI_SUPL_UTF8: 223 enc = GPS_ENC_SUPL_UTF8; 224 break; 225 case RPC_LOC_NI_SUPL_UCS2: 226 enc = GPS_ENC_SUPL_UCS2; 227 break; 228 case RPC_LOC_NI_SUPL_GSM_DEFAULT: 229 enc = GPS_ENC_SUPL_GSM_DEFAULT; 230 break; 231 default: 232 break; 233 } 234 235 return enc; 236 } 237 238 /*=========================================================================== 239 240 FUNCTION loc_ni_request_handler 241 242 DESCRIPTION 243 Displays the NI request and awaits user input. If a previous request is 244 in session, it is ignored. 245 246 RETURN VALUE 247 none 248 249 ===========================================================================*/ 250 static void loc_ni_request_handler(const char *msg, const rpc_loc_ni_event_s_type *ni_req) 251 { 252 GpsNiNotification notif; 253 notif.size = sizeof(notif); 254 strlcpy(notif.text, "[text]", sizeof notif.text); // defaults 255 strlcpy(notif.requestor_id, "[requestor id]", sizeof notif.requestor_id); 256 257 /* If busy, use default or deny */ 258 if (loc_eng_ni_data.notif_in_progress) 259 { 260 #if 0 261 /* Cannot be here because the current thread is in RPC client */ 262 /* XXX Consider adding an event queue to process overlapped NI requests */ 263 loc_ni_user_resp_e_type response = 264 sys.ni_default_resp == 1 /* accept */ ? 265 LOC_NI_LCS_NOTIFY_VERIFY_ACCEPT : 266 LOC_NI_LCS_NOTIFY_VERIFY_DENY; 267 268 loc_ni_respond(response, ni_req); */ 269 #endif 270 LOGW("loc_ni_request_handler, notification in progress, new NI request ignored, type: %d", 271 ni_req->event); 272 } 273 else { 274 /* Print notification */ 275 LOGD("NI Notification: %s, event: %d", msg, ni_req->event); 276 277 pthread_mutex_lock(&loc_eng_ni_data.loc_ni_lock); 278 279 /* Save request */ 280 memcpy(&loc_eng_ni_data.loc_ni_request, ni_req, sizeof loc_eng_ni_data.loc_ni_request); 281 282 /* Set up NI response waiting */ 283 loc_eng_ni_data.notif_in_progress = TRUE; 284 loc_eng_ni_data.current_notif_id = abs(rand()); 285 286 /* Fill in notification */ 287 notif.notification_id = loc_eng_ni_data.current_notif_id; 288 289 const rpc_loc_ni_vx_notify_verify_req_s_type *vx_req; 290 const rpc_loc_ni_supl_notify_verify_req_s_type *supl_req; 291 const rpc_loc_ni_umts_cp_notify_verify_req_s_type *umts_cp_req; 292 293 switch (ni_req->event) 294 { 295 case RPC_LOC_NI_EVENT_VX_NOTIFY_VERIFY_REQ: 296 vx_req = &ni_req->payload.rpc_loc_ni_event_payload_u_type_u.vx_req; 297 notif.ni_type = GPS_NI_TYPE_VOICE; 298 notif.timeout = LOC_NI_NO_RESPONSE_TIME; // vx_req->user_resp_timer_val; 299 memset(notif.extras, 0, sizeof notif.extras); 300 memset(notif.text, 0, sizeof notif.text); 301 memset(notif.requestor_id, 0, sizeof notif.requestor_id); 302 303 // Requestor ID 304 hexcode(notif.requestor_id, sizeof notif.requestor_id, 305 vx_req->requester_id.requester_id, 306 vx_req->requester_id.requester_id_length); 307 308 notif.text_encoding = 0; // No text and no encoding 309 notif.requestor_id_encoding = convert_encoding_type(vx_req->encoding_scheme); 310 311 // Set default_response & notify_flags 312 loc_ni_fill_notif_verify_type(¬if, vx_req->notification_priv_type); 313 314 break; 315 316 case RPC_LOC_NI_EVENT_UMTS_CP_NOTIFY_VERIFY_REQ: 317 umts_cp_req = &ni_req->payload.rpc_loc_ni_event_payload_u_type_u.umts_cp_req; 318 notif.ni_type = GPS_NI_TYPE_UMTS_CTRL_PLANE; 319 notif.timeout = LOC_NI_NO_RESPONSE_TIME; // umts_cp_req->user_response_timer; 320 memset(notif.extras, 0, sizeof notif.extras); 321 memset(notif.text, 0, sizeof notif.text); 322 memset(notif.requestor_id, 0, sizeof notif.requestor_id); 323 324 // Stores notification text 325 hexcode(notif.text, sizeof notif.text, 326 #if (AMSS_VERSION==3200) 327 umts_cp_req->notification_text.notification_text_val, 328 #else 329 umts_cp_req->notification_text, 330 #endif 331 umts_cp_req->notification_length); 332 333 // Stores requestor ID 334 hexcode(notif.requestor_id, sizeof notif.requestor_id, 335 #if (AMSS_VERSION==3200) 336 umts_cp_req->requestor_id.requestor_id_string.requestor_id_string_val, 337 #else 338 umts_cp_req->requestor_id.requestor_id_string, 339 #endif 340 umts_cp_req->requestor_id.string_len); 341 342 notif.text_encoding = convert_encoding_type(umts_cp_req->datacoding_scheme); 343 notif.requestor_id_encoding = convert_encoding_type(umts_cp_req->datacoding_scheme); 344 345 // Set default_response & notify_flags 346 loc_ni_fill_notif_verify_type(¬if, umts_cp_req->notification_priv_type); 347 348 break; 349 350 case RPC_LOC_NI_EVENT_SUPL_NOTIFY_VERIFY_REQ: 351 supl_req = &ni_req->payload.rpc_loc_ni_event_payload_u_type_u.supl_req; 352 notif.ni_type = GPS_NI_TYPE_UMTS_SUPL; 353 notif.timeout = LOC_NI_NO_RESPONSE_TIME; // supl_req->user_response_timer; 354 memset(notif.extras, 0, sizeof notif.extras); 355 memset(notif.text, 0, sizeof notif.text); 356 memset(notif.requestor_id, 0, sizeof notif.requestor_id); 357 358 // Client name 359 if (supl_req->flags & RPC_LOC_NI_CLIENT_NAME_PRESENT) 360 { 361 hexcode(notif.text, sizeof notif.text, 362 #if (AMSS_VERSION==3200) 363 supl_req->client_name.client_name_string.client_name_string_val, /* buffer */ 364 #else 365 supl_req->client_name.client_name_string, /* buffer */ 366 #endif 367 supl_req->client_name.string_len /* length */ 368 ); 369 LOGD("SUPL NI: client_name: %s len=%d", notif.text, supl_req->client_name.string_len); 370 } else { 371 LOGD("SUPL NI: client_name not present."); 372 } 373 374 // Requestor ID 375 if (supl_req->flags & RPC_LOC_NI_REQUESTOR_ID_PRESENT) 376 { 377 hexcode(notif.requestor_id, sizeof notif.requestor_id, 378 #if (AMSS_VERSION==3200) 379 supl_req->requestor_id.requestor_id_string.requestor_id_string_val, /* buffer */ 380 #else 381 supl_req->requestor_id.requestor_id_string, /* buffer */ 382 #endif 383 supl_req->requestor_id.string_len /* length */ 384 ); 385 LOGD("SUPL NI: requestor_id: %s len=%d", notif.requestor_id, supl_req->requestor_id.string_len); 386 } else { 387 LOGD("SUPL NI: requestor_id not present."); 388 } 389 390 // Encoding type 391 if (supl_req->flags & RPC_LOC_NI_ENCODING_TYPE_PRESENT) 392 { 393 notif.text_encoding = convert_encoding_type(supl_req->datacoding_scheme); 394 notif.requestor_id_encoding = convert_encoding_type(supl_req->datacoding_scheme); 395 } else { 396 notif.text_encoding = notif.requestor_id_encoding = GPS_ENC_UNKNOWN; 397 } 398 399 // Set default_response & notify_flags 400 loc_ni_fill_notif_verify_type(¬if, ni_req->payload.rpc_loc_ni_event_payload_u_type_u.supl_req.notification_priv_type); 401 402 break; 403 404 default: 405 LOGE("loc_ni_request_handler, unknown request event: %d", ni_req->event); 406 return; 407 } 408 409 /* Log requestor ID and text for debugging */ 410 LOGI("Notification: notif_type: %d, timeout: %d, default_resp: %d", notif.ni_type, notif.timeout, notif.default_response); 411 LOGI(" requestor_id: %s (encoding: %d)", notif.requestor_id, notif.requestor_id_encoding); 412 LOGI(" text: %s text (encoding: %d)", notif.text, notif.text_encoding); 413 414 /* For robustness, always sets a timeout to clear up the notification status, even though 415 * the OEM layer in java does not do so. 416 **/ 417 loc_eng_ni_data.response_time_left = 5 + (notif.timeout != 0 ? notif.timeout : LOC_NI_NO_RESPONSE_TIME); 418 LOGI("Automatically sends 'no response' in %d seconds (to clear status)\n", loc_eng_ni_data.response_time_left); 419 420 pthread_mutex_unlock(&loc_eng_ni_data.loc_ni_lock); 421 422 /* Notify callback */ 423 if (loc_eng_data.ni_notify_cb != NULL) 424 { 425 loc_eng_data.ni_notify_cb(¬if); 426 } 427 } 428 } 429 430 /*=========================================================================== 431 432 FUNCTION loc_ni_process_user_response 433 434 DESCRIPTION 435 Handles user input from the UI 436 437 RETURN VALUE 438 error code (0 for successful, -1 for error) 439 440 ===========================================================================*/ 441 int loc_ni_process_user_response(GpsUserResponseType userResponse) 442 { 443 LOGD("NI response from UI: %d", userResponse); 444 445 rpc_loc_ni_user_resp_e_type resp; 446 switch (userResponse) 447 { 448 case GPS_NI_RESPONSE_ACCEPT: 449 resp = RPC_LOC_NI_LCS_NOTIFY_VERIFY_ACCEPT; 450 break; 451 case GPS_NI_RESPONSE_DENY: 452 resp = RPC_LOC_NI_LCS_NOTIFY_VERIFY_DENY; 453 break; 454 case GPS_NI_RESPONSE_NORESP: 455 resp = RPC_LOC_NI_LCS_NOTIFY_VERIFY_NORESP; 456 break; 457 default: 458 return -1; 459 } 460 461 loc_ni_respond(resp, &loc_eng_ni_data.loc_ni_request); 462 463 /* Make the NI respond */ 464 pthread_mutex_lock(&loc_eng_ni_data.loc_ni_lock); 465 loc_eng_ni_data.notif_in_progress = FALSE; 466 loc_eng_ni_data.response_time_left = 0; 467 loc_eng_ni_data.current_notif_id = -1; 468 pthread_mutex_unlock(&loc_eng_ni_data.loc_ni_lock); 469 470 return 0; 471 } 472 473 /*=========================================================================== 474 475 FUNCTION loc_eng_ni_callback 476 477 DESCRIPTION 478 Loc API callback handler 479 480 RETURN VALUE 481 error code (0 for success) 482 483 ===========================================================================*/ 484 int loc_eng_ni_callback ( 485 rpc_loc_event_mask_type loc_event, /* event mask */ 486 const rpc_loc_event_payload_u_type* loc_event_payload /* payload */ 487 ) 488 { 489 int rc = 0; 490 const rpc_loc_ni_event_s_type *ni_req = &loc_event_payload->rpc_loc_event_payload_u_type_u.ni_request; 491 if (loc_event == RPC_LOC_EVENT_NI_NOTIFY_VERIFY_REQUEST) 492 { 493 switch (ni_req->event) 494 { 495 case RPC_LOC_NI_EVENT_VX_NOTIFY_VERIFY_REQ: 496 LOGI("VX Notification"); 497 loc_ni_request_handler("VX Notify", ni_req); 498 break; 499 500 case RPC_LOC_NI_EVENT_UMTS_CP_NOTIFY_VERIFY_REQ: 501 LOGI("UMTS CP Notification\n"); 502 loc_ni_request_handler("UMTS CP Notify", ni_req); 503 break; 504 505 case RPC_LOC_NI_EVENT_SUPL_NOTIFY_VERIFY_REQ: 506 LOGI("SUPL Notification\n"); 507 loc_ni_request_handler("SUPL Notify", ni_req); 508 break; 509 510 default: 511 LOGE("Unknown NI event: %x\n", (int) ni_req->event); 512 break; 513 } 514 } 515 return rc; 516 } 517 518 /*=========================================================================== 519 520 FUNCTION loc_ni_thread_proc 521 522 ===========================================================================*/ 523 static void loc_ni_thread_proc(void *unused) 524 { 525 LOGI("Starting Loc NI thread...\n"); 526 527 while (1) 528 { 529 /* wakes up every second to check timed out requests */ 530 sleep(1); 531 532 pthread_mutex_lock(&loc_eng_ni_data.loc_ni_lock); 533 534 if (loc_eng_ni_data.notif_in_progress && loc_eng_ni_data.response_time_left > 0) 535 { 536 loc_eng_ni_data.response_time_left--; 537 if (loc_eng_ni_data.response_time_left <= 0) 538 { 539 loc_ni_respond(RPC_LOC_NI_LCS_NOTIFY_VERIFY_NORESP, &loc_eng_ni_data.loc_ni_request); 540 loc_eng_ni_data.notif_in_progress = FALSE; 541 } 542 } 543 544 pthread_mutex_unlock(&loc_eng_ni_data.loc_ni_lock); 545 } /* while (1) */ 546 } 547 548 /*=========================================================================== 549 FUNCTION loc_eng_ni_init 550 551 DESCRIPTION 552 This function initializes the NI interface 553 554 DEPENDENCIES 555 NONE 556 557 RETURN VALUE 558 None 559 560 SIDE EFFECTS 561 N/A 562 563 ===========================================================================*/ 564 void loc_eng_ni_init(GpsNiCallbacks *callbacks) 565 { 566 LOGD("loc_eng_ni_init: entered."); 567 568 if (!loc_eng_ni_data_init) 569 { 570 pthread_mutex_init(&loc_eng_ni_data.loc_ni_lock, NULL); 571 callbacks->create_thread_cb("loc_api_ni", loc_ni_thread_proc, NULL); 572 loc_eng_ni_data_init = TRUE; 573 } 574 575 loc_eng_ni_data.notif_in_progress = FALSE; 576 loc_eng_ni_data.current_notif_id = -1; 577 loc_eng_ni_data.response_time_left = 0; 578 579 srand(time(NULL)); 580 loc_eng_data.ni_notify_cb = callbacks->notify_cb; 581 } 582 583 /*=========================================================================== 584 FUNCTION loc_eng_ni_respond 585 586 DESCRIPTION 587 This function sends an NI respond to the modem processor 588 589 DEPENDENCIES 590 NONE 591 592 RETURN VALUE 593 None 594 595 SIDE EFFECTS 596 N/A 597 598 ===========================================================================*/ 599 void loc_eng_ni_respond(int notif_id, GpsUserResponseType user_response) 600 { 601 if (notif_id == loc_eng_ni_data.current_notif_id && loc_eng_ni_data.notif_in_progress) 602 { 603 LOGI("loc_eng_ni_respond: send user response %d for notif %d", user_response, notif_id); 604 loc_ni_process_user_response(user_response); 605 } else { 606 LOGE("loc_eng_ni_respond: notif_id %d mismatch or notification not in progress, response: %d", 607 notif_id, user_response); 608 } 609 } 610