-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathevent_qlinkdatanode.c
2792 lines (2341 loc) · 75.3 KB
/
event_qlinkdatanode.c
1
#include <pthread.h>#include <errno.h>#include <unistd.h>#include <fcntl.h>#include <sys/select.h>#include <sys/time.h>#include <time.h>#include <string.h>#include "event_qlinkdatanode.h"#include "queue_qlinkdatanode.h"#include "feature_macro_qlinkdatanode.h"#include "at_qlinkdatanode.h"#include "socket_qlinkdatanode.h"#include "common_qlinkdatanode.h"#include "qmi_sender_qlinkdatanode.h"#include "msq_qlinkdatanode.h"/******************************External Functions*******************************/extern void w_acqDataHdlr(void);extern void w_resumeMdmHdlr(void);extern void w_suspendMdmHdlr(void);extern void add_req_into_queue(rsmp_transmit_buffer_s_type *rc, rsmp_state_s_type state);extern void enqueue_and_resume_mdmEmodem(rsmp_transmit_buffer_s_type *rc, rsmp_state_s_type state);extern void add_timer_apdu_rsp_timeout_ext(char type, char opt);extern int mdmEmodem_check_busy(void);extern void mdmEmodem_standby_mode_switch(int ctrl_word);extern int mdmEmodem_check_if_running(void);extern void set_ChannelNum(const int val);extern void set_acq_data_state(Acq_Data_State state);extern Acq_Data_State get_acq_data_state(void);extern int proto_update_flow_state(rsmp_state_s_type state);/******************************External Variables*******************************/extern bool isQueued;extern bool isWaitToSusp;extern bool isWaitToRcvr;extern bool isFTMPowerOffInd;extern bool isTermSuspNow;extern bool isMdmEmodemRunning;extern bool isDumpApdu;extern bool RcvrMdmEmodemConn;extern bool isNeedToSendIDMsg;extern At_Config at_config;extern rsmp_recv_buffer_s_type g_rsmp_recv_buffer;extern rsmp_transmit_buffer_s_type g_rsmp_transmit_buffer[THD_IDX_MAX+1];extern APDU_Setting APDU_setting;extern Chk_Net_State chk_net_state;extern Acq_Data_State acq_data_state;extern Conf_State uartconfig_state;extern pthread_mutex_t acq_data_state_mtx;extern Suspend_Mdm_State suspend_state;extern pthread_mutex_t apdu_sender_mtx;extern pthread_cond_t apdu_sender_cond;extern bool isEnableApduSenderMtx;extern bool isApduSenderMtxLocked;extern bool isMifiConnected;extern bool isRegOn;extern bool isEnableManualApdu;extern bool isApduSentToMdm;extern pthread_cond_t rst_uim_cond;extern char URC_special_mark_array[MAX_SPEC_URC_ARR_LEN];extern Net_Info rsmp_net_info;extern bool is1stRunOnMdmEmodem;extern pthread_mutex_t i1r_mtx;extern Dev_Info rsmp_dev_info;extern rsmp_control_block_type flow_info;extern bool isSockListenerRecvPdpActMsg;extern pthread_mutex_t evtloop_mtx;extern bool isPwrDwnRspAcq;extern bool PowerUpUsimAfterRecvingUrcRpt;extern bool MdmEmodemIsRcvrWhenSetPd;extern bool isRstingUsim;extern bool isRegOffForPoorSig;extern bool isNeedToNotifyServCondVar;extern pthread_mutex_t rst_uim_mtx;extern bool isUimRstOperCplt;#ifdef FEATURE_ENABLE_TIMER_SYSTEMextern Evt ApduRsp_timeout_ext_evt;extern Evt ID_auth_rsp_timeout_evt;extern Evt remote_USIM_data_rsp_timeout_evt;extern Evt Idle_Timer_evt;extern Evt power_down_notification_timeout_evt;extern Evt ate0_rsp_timeout_evt;extern Evt pdp_act_check_routine_evt;extern Evt Custom_Timer_evt;extern bool isNotNeedIdleTimer;#endifextern int ChannelNum;#ifdef FEATURE_ENABLE_RWLOCK_CHAN_LCKextern pthread_rwlock_t ChannelLock;#elseextern pthread_mutex_t ChannelLock;#endifextern int evtloop_pipe[2];extern int chan_num_pipe[2];extern int flow_state_pipe[2];extern int thread_idx_pipe[2];extern pthread_mutex_t log_file_mtx;extern unsigned long thread_id_array[THD_IDX_MAX];extern pthread_mutex_t apdu_sender_mtx;// 20160304 jackliextern pthread_cond_t apdu_sender_cond;// 20160304 jackliextern pthread_mutex_t apdu_mtx; // 20160304 jackliextern bool isApduSentToMdm;// 20160304 jackliextern int DMS_wr_fd;extern bool isUimPwrDwnMssage;extern unsigned char g_record_ID_timeout_conut;static APDU_Cache_S_Type APDU_cache;/******************************Local Variables*******************************/static pthread_t evtloop_tid;static int evtloopStarted = 0;static pthread_mutex_t evtloop_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t evtloop_cond = PTHREAD_COND_INITIALIZER;static pthread_mutex_t list_mutex;static fd_set read_fds;static fd_set write_fds;static Evt evtloop_read_event;static Evt *watch_table[MAX_FD_EVENTS];static Evt ReadReadies_list;static Evt timer_list;static Evt timeouts_list;static bool isAllTimersExpired = true;static char Custom_Timer_cb_type = 0xff;#ifdef FEATURE_ENABLE_WAKEUP_EVENTstatic int WakeupRead_fd;static int WakeupWrite_fd;static Evt wakeup_event;#endif // FEATURE_ENABLE_WAKEUP_EVENT#ifdef FEATURE_ENABLE_MDMEmodem_CUSTOMED_AT_CMDbool isYYDaemonNeedtoSendATCmd = false;bool isFactoryWriteIMEI5360 = false;#endif // FEATURE_ENABLE_MDMEmodem_CUSTOMED_AT_CMD#ifdef FEATURE_ENABLE_MDMEmodem_CUSTOMED_AT_CMDextern Proc_Msg_At_Cmd_Cfg_S_Type proc_msg_at_config;#endifstatic int maxfdp1 = 0;/******************************Global Variables*******************************/#if defined(FEATURE_ENABLE_TIMER_SYSTEM)bool isATEvtAct = false;//Description:// The bool variables as isXXXTimerExpired below are represented if XXX timer is expired.// And when XXX timers are expired and messages they waited for are recved, app would clear// timeout events in Timeouts_list according to isXXXTimerExpired.bool isApduRspExtTimerExpired = false;bool isIdAuthRspTimerExpired = false;bool isRemoteUsimDataRspTimerExpired = false;bool isPwrDwnNotificationTimerExpired = false;bool isAte0RspTimerExpired = false;//Description:// If other thread request to utilize mdmEmodem, this bool var will be set true.// (notify_EvtLoop():The request 0x02 and 0x03 are prior to idle timer timeout.)static bool isMdmEmodemReq = false;#endifstatic bool isApduRspExtCbEndUnexpV01 = false;#ifdef FEATURE_ENHANCED_STATUS_INFO_UPLOAD//Description:// Once it is time to upload status information, status_info_upload_acq_info() will be called for sure.// And status_info_upload_acq_info() will be the first step of uploading a status info msg. So update // StatInfReqNum here is timely. And when status info msg is prepared to sent out, and this var is larger // than 0 after it minus 1, this status info msg is not allowed to send out for that there exists a new status// info msg which will be sent out soon. // When status info msg is added into queue by add_node(), this var must be decreased by 1. Because// this var is for real-time check.int StatInfReqNum = 0;#endif#ifdef FEATURE_ENABLE_OUT_OF_TRAFFIC_AND_DATE_0206 extern bool isCancelRecoveryNet;#endif//Description:// If recovering action is pending for busy mdmEmodem in RecvCallback(), isRcvrPendForBusy will be set true.//bool isRcvrPendForBusy = false;/******************************Advanced Declaration*******************************/static int check_timer(Evt *tev);static int clear_timer(Evt *tev);static void init_list(Evt * list){ memset(list, 0, sizeof(Evt)); list->next_evt = NULL; list->prev_evt = NULL; list->fd = -1; return;} //Description:// If arg "list" is ReadReadies_list and: // arg "ev" is evtloop_read_event, "ev" will be added at the last position of ReadReadies_list.// arg "ev" is other events except evtloop_read_event, "ev" will be added at the last position of ReadReadies_list before evtloop_read_event.// If arg "list" is not ReadReadies_list and: // arg "ev" is added right behind arg "list".static void add_to_list(Evt *ev, Evt *list){ if(ev == NULL) { LOG("ERROR: Wrong param input. ev=null.\n"); return; }else if(list == NULL){ LOG("ERROR: Wrong param input. list=null.\n"); return; } if(list == &ReadReadies_list) { Evt *cur = list; if(ev->fd == evtloop_pipe[0]) { for(; cur->next_evt!=NULL; cur=cur->next_evt); ev->prev_evt = cur; ev->next_evt = NULL; cur->next_evt = ev; }else { for(; cur->next_evt!=NULL; cur=cur->next_evt); if(cur->fd == evtloop_pipe[0]) cur = cur->prev_evt; ev->next_evt = cur->next_evt; ev->prev_evt = cur; cur->next_evt = ev; if(ev->next_evt != NULL) ev->next_evt->prev_evt = ev; } }else { ev->next_evt = list->next_evt; ev->prev_evt = list; list->next_evt= ev; if(ev->next_evt != NULL) ev->next_evt->prev_evt = ev; }}//Function://Remove the specified ev out of the list in which ev is queuedstatic void remove_from_list(Evt *ev){ Evt *next = ev->next_evt; Evt *prev = ev->prev_evt; ev->next_evt= NULL; ev->prev_evt= NULL; prev->next_evt= next; if(next != NULL) next->prev_evt = prev; return;}void add_timer(Evt *ev, struct timeval *tv){ Evt *cur; Evt *prev; struct timeval now; int pos = 1; if(tv == NULL){ LOG("ERROR: Wrong parameter input. tv=null.\n"); return; } gettimeofday(&now, NULL); timeradd(&now, tv, &(ev->timeout)); if(check_timer(ev)){ LOG("ERROR: The ev (%x) has been already added in Timers_list! Now, clear it anyway.\n", (unsigned int)ev); clear_timer(ev); } cur = timer_list.next_evt; prev = &timer_list; for(; cur!=NULL; ) { if(!timercmp(&cur->timeout, &ev->timeout, <)) break; prev = cur; cur = cur->next_evt; pos ++; } add_to_list(ev, prev); isAllTimersExpired = false;#ifdef FEATURE_ENABLE_PRINT_TIMER_LIST { Evt *tmp = timer_list.next_evt;#ifndef FEATURE_DEBUG_LOG_FILE LOG2("^^^^^^^^^^timer_list^^^^^^^^^^\n"); for(; tmp!=NULL; tmp=tmp->next_evt){ LOG2("@@@@@@timer %x(evt)@@@@@@\n", (unsigned int)tmp); } LOG2("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");#else pthread_mutex_lock(&log_file_mtx); LOG2("\n"); LOG4(" ^^^^^^^^^^timer_list^^^^^^^^^^\n"); for(; tmp!=NULL; tmp=tmp->next_evt){ LOG4(" @@@@@@timer %x(evt)@@@@@@\n", (unsigned int)tmp); } LOG4(" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"); pthread_mutex_unlock(&log_file_mtx);#endif }#endif // FEATURE_ENABLE_PRINT_TIMER_LIST return;}//NOTE: Special for AT_eventstatic void arrange_watch_table(int idx){ int i; Evt *ev = watch_table[idx]; if(idx >= MAX_FD_EVENTS){ LOG("ERROR: Wrong param (idx: %d) input.\n", idx); return; }else if(idx == MAX_FD_EVENTS-1){ LOG("Already traversed watch_table. No need to arrange it.\n"); return; } for( i=0; i<MAX_FD_EVENTS; i++){ if(i == idx) continue; if(ev == watch_table[i]){// LOG("Redundant event(%x) found in watch_table[%d].\n", (unsigned int)(watch_table[i]), i); watch_table[i] = NULL; continue; //Safer } } return;}//Note:// Don't pass a local (non-static) data pointer to arg "param"!void set_evt(Evt *ev, int fd, bool persist, evt_cb func, void *param){ memset(ev, 0, sizeof(Evt)); ev->fd = fd; ev->index = -1; ev->persist = persist; ev->cb_func = func; ev->param = param; fcntl(fd, F_SETFL, O_NONBLOCK);}void add_evt(Evt *ev, char tag){ int i = 0; pthread_mutex_lock(&list_mutex); for(; i < MAX_FD_EVENTS; i++){ #ifdef FEATURE_ENABLE_ADD_EVT_DETAIL_LOG LOG("Check watch_table[%d].\n", i); #endif if (watch_table[i] == NULL){ #ifdef FEATURE_ENABLE_ADD_EVT_DETAIL_LOG LOG("watch_table[%d] is available.\n",i); #endif switch(tag){ case 'r': FD_SET(ev->fd, &read_fds);break; case 'w': FD_SET(ev->fd, &write_fds);break; default: { LOG("ERROR: Wrong param \"tag\" input. tag=%c.\n", tag); pthread_mutex_unlock(&list_mutex); return; } }// switch(tag) watch_table[i] = ev; ev->index = i; #ifdef FEATURE_ENABLE_ADD_EVT_DETAIL_LOG LOG("Add %x(evt) into watch_table[%d].\n", (unsigned int)ev, i); #endif if(ev->fd >= maxfdp1) maxfdp1= ev->fd+1; arrange_watch_table(i); break; }else{ #ifdef FEATURE_ENABLE_ADD_EVT_DETAIL_LOG LOG("watch_table[%d] is occupied by %x(evt).\n", i, (unsigned int)(watch_table[i])); #endif } } pthread_mutex_unlock(&list_mutex); return;}#ifdef FEATURE_ENABLE_WAKEUP_EVENTvoid trigger_EventLoop(void){ int ret = -1; if(!pthread_equal(pthread_self(), evtloop_tid)){ do{ if(ret==0) LOG("ERROR: write() failed. ret=%d.\n", ret); ret = write(WakeupWrite_fd, " ", 1); }while((ret < 0 && errno == EINTR) || (ret == 0)); if(ret < 0){ LOG("ERROR: write() failed. errno=%d.\n", errno); } } return;}#endif // FEATURE_ENABLE_WAKEUP_EVENT//Function://Remove the ev from watch_table and fd list.void remove_evt(Evt *ev){ if(ev == NULL){ LOG("Param ev is empty.\n"); return; } if(ev->index >= 0 && ev->index <= MAX_FD_EVENTS-1) { watch_table[ev->index] = NULL; } ev->index = -1; if(FD_ISSET(ev->fd, &read_fds)) { FD_CLR(ev->fd, &read_fds); } else if (FD_ISSET(ev->fd, &write_fds)) { FD_CLR(ev->fd, &write_fds); } else { //It should never reach here. LOG("ERROR: fd not found!\n"); return; } /*recalulate the maxfdp1 for the next select*/ if(ev->fd+1 == maxfdp1) { int n = 0, i = 0; for(; i<MAX_FD_EVENTS; i++) { Evt * rev = watch_table[i]; if(rev != NULL && rev->fd > n) { n = rev->fd; } } maxfdp1 = n+1; }}//Function://Check if tev argument has been monitored in timer_list.//Return Values:// 1: The timer tev is in timer_list.// 0: The timer tev is not in timer_list.//-1: Wrong param input. tev=null.static int check_timer(Evt *tev){ Evt *cur = timer_list.next_evt; int ret = 0; if(tev == NULL){ LOG("ERROR: Wrong param input. tev=null.\n"); return -1; } if(isAllTimersExpired) { return 0; }else if(cur == NULL){ LOG("ERROR: isAllTimersExpired=%d, but timer_list.next_evt=null!" "Now, isAllTimersExpired is changed to 1.\n", isAllTimersExpired); isAllTimersExpired = true; return 0; } while(cur != NULL) { if(tev == cur){ ret = 1; break; } cur = cur->next_evt; } return ret;}//Return Values:// 1: There exists some rsp timers. (Like Apdu rsp ext timer, ID auth rsp timer, etc.)// 0: No rsp timer found.//Note:// Not check ate0 rsp timer.int check_rsp_timers(void){ Evt *cur = timer_list.next_evt; int ret = 0; if(isAllTimersExpired){ return 0; }else if(cur == NULL){ LOG("ERROR: isAllTimersExpired=%d, but timer_list.next_evt=null!" "Now, isAllTimersExpired is changed to 1.\n", isAllTimersExpired); isAllTimersExpired = true; return 0; } if(1 == (ret = check_timer(&ApduRsp_timeout_ext_evt))) goto __EXIT_OF_CHECK_RSP_TIMERS__; if(1 == (ret = check_timer(&ID_auth_rsp_timeout_evt))) goto __EXIT_OF_CHECK_RSP_TIMERS__; if(1 == (ret = check_timer(&remote_USIM_data_rsp_timeout_evt))) goto __EXIT_OF_CHECK_RSP_TIMERS__; if(1 == (ret = check_timer(&power_down_notification_timeout_evt))) goto __EXIT_OF_CHECK_RSP_TIMERS__;__EXIT_OF_CHECK_RSP_TIMERS__: return ret;}//Return Values:// 1: Custom timer is existed in Timers_list.// 0: Custom timer is not existed in Timers_list.int check_custom_timer(void){ Evt *cur = timer_list.next_evt; int ret = 0; if(isAllTimersExpired){ return 0; }else if(cur == NULL){ LOG("ERROR: isAllTimersExpired=%d, but timer_list.next_evt=null!" "Now, isAllTimersExpired is changed to 1.\n", isAllTimersExpired); isAllTimersExpired = true; return 0; } ret = check_timer(&Custom_Timer_evt); return ret;}//Return Values:// 1: Idle timer is existed in Timers_list.// 0: Idle timer is not existed in Timers_list.int check_idle_timer(void){ Evt *cur = timer_list.next_evt; int ret = 0; if(isAllTimersExpired){ return 0; }else if(cur == NULL){ LOG("ERROR: isAllTimersExpired=%d, but timer_list.next_evt=null!" "Now, isAllTimersExpired is changed to 1.\n", isAllTimersExpired); isAllTimersExpired = true; return 0; } ret = check_timer(&Idle_Timer_evt); return ret;}//Return Values:// 1: Pdp act check routine timer is existed in Timers_list.// 0: Pdp act check routine timer is not existed in Timers_list.int check_pdp_act_check_routine_timer(void){ Evt *cur = timer_list.next_evt; int ret = 0; if(isAllTimersExpired){ return 0; }else if(cur == NULL){ LOG("ERROR: isAllTimersExpired=%d, but timer_list.next_evt=null!" "Now, isAllTimersExpired is changed to 1.\n", isAllTimersExpired); isAllTimersExpired = true; return 0; } ret = check_timer(&pdp_act_check_routine_evt); return ret;}int check_apdu_rsp_timeout_ext_timer(void){ Evt *cur = timer_list.next_evt; int ret = 0; if(isAllTimersExpired){ return 0; }else if(cur == NULL){ LOG("ERROR: isAllTimersExpired=0, but timer_list.next_evt=null!" "Now, isAllTimersExpired is changed to 1.\n"); isAllTimersExpired = true; return 0; } ret = check_timer(&ApduRsp_timeout_ext_evt); return ret;}int check_id_auth_rsp_timeout_timer(void){ Evt *cur = timer_list.next_evt; int ret = 0; if(isAllTimersExpired){ return 0; }else if(cur == NULL){ LOG("ERROR: isAllTimersExpired=0, but timer_list.next_evt=null!" "Now, isAllTimersExpired is changed to 1.\n"); isAllTimersExpired = true; return 0; } ret = check_timer(&ID_auth_rsp_timeout_evt); return ret;}int check_remote_USIM_data_rsp_timeout_timer(void){ Evt *cur = timer_list.next_evt; int ret = 0; if(isAllTimersExpired){ return 0; }else if(cur == NULL){ LOG("ERROR: isAllTimersExpired=0, but timer_list.next_evt=null!" "Now, isAllTimersExpired is changed to 1.\n"); isAllTimersExpired = true; return 0; } ret = check_timer(&remote_USIM_data_rsp_timeout_evt); return ret;}//return value:// 0: no timer is in the "timer_list".// 1: timers is processed.static int calc_NextTimeout(struct timeval *tv){ Evt *tev = timer_list.next_evt; struct timeval now; gettimeofday(&now, NULL); if(tev == NULL){ return 0; } if(timercmp(&tev->timeout, &now, >)){ timersub(&tev->timeout, &now, tv); }else{ tv->tv_sec = tv->tv_usec = 0; } return 1;}//function:// Move expired timer into "timeouts_list" from "timer_list".static void process_Timeouts(void){ struct timeval now; Evt *tev = timer_list.next_evt; Evt *next_tev = NULL; int count = 1; pthread_mutex_lock(&list_mutex); gettimeofday(&now, NULL); if(tev != NULL) { while(tev != NULL) { if(!timercmp(&now, &tev->timeout, >)) break; LOG("Timer 0x%x expired.\n", (unsigned int)tev); next_tev = tev->next_evt; remove_from_list(tev); if( tev != &ApduRsp_timeout_ext_evt && tev != &ID_auth_rsp_timeout_evt && tev != &remote_USIM_data_rsp_timeout_evt && tev != &Idle_Timer_evt && tev != &power_down_notification_timeout_evt && tev != &ate0_rsp_timeout_evt ) { //Applicable Conditions: //pdp_act_check_routine_evt if(tev == &pdp_act_check_routine_evt) LOG("Pdp act check routine timer expired!\n"); add_to_list(tev, &timeouts_list); }#ifdef FEATURE_ENABLE_MDMEmodem_IDLE_TIMEOUT_TIMER else if(tev == &Idle_Timer_evt && isMdmEmodemReq == false) { LOG("Idle timer of mdmEmodem expired!\n"); // Do not set isMdmEmodemReq true here! add_to_list(tev, &timeouts_list); }else if(tev == &Idle_Timer_evt && isMdmEmodemReq == true) { isMdmEmodemReq = false; // Reset LOG("NOTICE: Req to utilize mdmEmodem. Timer dumped.\n"); }#endif #ifdef FEATURE_ENABLE_APDU_RSP_TIMEOUT_SYS else if(tev == &ApduRsp_timeout_ext_evt) { LOG("ApduRsp ext timer expired!\n"); add_to_list(tev, &timeouts_list); // Add to Timeouts_list in advance if(isATEvtAct){ isATEvtAct = false; // Reset isApduRspExtTimerExpired = true; LOG("AT evt is active. Check if APDU rsp come.\n"); } // if(isATEvtAct) }#endif#ifdef FEATURE_ENABLE_ID_AUTH_RSP_TIMER else if(tev == &ID_auth_rsp_timeout_evt) { LOG("ID auth rsp timer expired!\n"); add_to_list(tev, &timeouts_list); // Add to Timeouts_list in advance if(isATEvtAct){ isATEvtAct = false; // Reset isIdAuthRspTimerExpired = true; LOG("AT evt is active. Check if ID auth rsp come.\n"); } // if(isATEvtAct) }#endif#ifdef FEATURE_ENABLE_REMOTE_USIM_DATA_RSP_TIMER else if(tev == &remote_USIM_data_rsp_timeout_evt) { LOG("remote USIM data rsp timer expired!\n"); add_to_list(tev, &timeouts_list); // Add to Timeouts_list in advance if(isATEvtAct){ isATEvtAct = false; // Reset isRemoteUsimDataRspTimerExpired = true; LOG("AT evt is active. Check if remote USIM data rsp come.\n"); } // if(isATEvtAct) }#endif#ifdef FEATURE_ENABLE_POWER_DOWN_NOTIFICATION_TIMER else if(tev == &power_down_notification_timeout_evt) { LOG("power down notification timer expired!\n"); add_to_list(tev, &timeouts_list); // Add to Timeouts_list in advance if(isATEvtAct){ isATEvtAct = false; // Reset isPwrDwnNotificationTimerExpired = true; LOG("AT evt is active. Check if pwr dwn notification rsp come.\n"); } // if(isATEvtAct) }#endif#ifdef FEATURE_ENABLE_ATE0_RSP_TIMER else if(tev == &ate0_rsp_timeout_evt){ LOG("ate0 rsp timer expired!\n"); add_to_list(tev, &timeouts_list); // Add to Timeouts_list in advance if(isATEvtAct){ isATEvtAct = false; // Reset isAte0RspTimerExpired = true; LOG("AT evt is active. Check if ate0 rsp come.\n"); } // if(isATEvtAct) }#endif tev = next_tev; count++; } //not timeout#if defined(FEATURE_ENABLE_MDMEmodem_IDLE_TIMEOUT_TIMER) while( tev != NULL ) { //ServRsp timer and ApduRsp ext timer will be cleared in r_acqDataHdlr(). if(isMdmEmodemReq == true && tev == &Idle_Timer_evt){ remove_from_list(tev); isMdmEmodemReq = false; break; } tev = tev->next_evt; }#endif } // if(tev != NULL) if(timer_list.next_evt == NULL) { isAllTimersExpired = true; } pthread_mutex_unlock(&list_mutex); return;}//Return Value:// 1: Assigned timer event is removed from timer_list.// 0: No assigned timer event found in timer_list.static int clear_timer(Evt *tev){ Evt *cur = timer_list.next_evt; int ret = 0; if(tev == NULL){ return ret; } if(cur == NULL){ return ret; } for(; cur!=NULL; cur=cur->next_evt){ if(tev == cur){ remove_from_list(tev); LOG("Timer 0x%x is cleared out of timer_list.\n", (unsigned int)tev); ret = 1; break; } } // for if(timer_list.next_evt == NULL) isAllTimersExpired = true; return ret;}void clr_idle_timer(void){ if(isAllTimersExpired) return; clear_timer(&Idle_Timer_evt); //Don't care if idle timer of mdmEmodem exists. return;}void clr_ApduRsp_ext_timer(void){ if(isAllTimersExpired) return; clear_timer(&ApduRsp_timeout_ext_evt); return;}void clr_ID_auth_rsp_timer(void){ if(isAllTimersExpired) return; clear_timer(&ID_auth_rsp_timeout_evt); return;}void clr_remote_USIM_data_rsp_timer(void){ if(isAllTimersExpired) return; clear_timer(&remote_USIM_data_rsp_timeout_evt); return;}void clr_power_down_notification_timer(void){ if(isAllTimersExpired) return; clear_timer(&power_down_notification_timeout_evt); return;}void clr_ate0_rsp_timer(void){ if(isAllTimersExpired) return; clear_timer(&ate0_rsp_timeout_evt); return;}void clr_pdp_check_act_routine_timer(void){ if(isAllTimersExpired) return; clear_timer(&pdp_act_check_routine_evt); return;}//Description:// It will be called when power down or factory reset msg is recved.// So power down notification timer is not allowed to be cleared!void clr_all_timers(void){ clr_idle_timer(); clr_ApduRsp_ext_timer(); clr_ID_auth_rsp_timer(); clr_remote_USIM_data_rsp_timer(); clr_pdp_check_act_routine_timer();}void clr_all_rsp_timers(void){ clr_ApduRsp_ext_timer(); clr_ID_auth_rsp_timer(); clr_remote_USIM_data_rsp_timer();}//Function:// Remove specified tev out of the Timeouts_list.//Param:// tev == null : Clear all timeout evt in Timeouts_list.// tev != null : Clear "tev" in Timeouts_list.void clr_timeout_evt(Evt *tev){ Evt *cur_ev = timeouts_list.next_evt; bool Clr_All = false; if(NULL == tev){ LOG("Clear all timeout evts in Timeouts_list.\n"); Clr_All = true; } if(NULL == cur_ev){ return; } if(!Clr_All){ for(; cur_ev!=NULL; cur_ev=cur_ev->next_evt){ if(cur_ev == tev){ remove_from_list(tev); break; } } }else{ // true == Clr_All for(; cur_ev!=NULL; cur_ev=cur_ev->next_evt){ remove_from_list(cur_ev); } } return;}//The number of ready events. Except for AT event and socket event, no other events will be included.static void process_Readies(fd_set *rfds, fd_set *wfds){ int i = 0; pthread_mutex_lock(&list_mutex); for(; i < MAX_FD_EVENTS; i++) { Evt *ev = watch_table[i]; // Not include timer evt if(ev != NULL) { if(FD_ISSET(ev->fd, rfds)) { add_to_list(ev, &ReadReadies_list); if (ev->persist == false) { remove_evt(ev); }#ifdef FEATURE_ENABLE_APDU_RSP_TIMEOUT_SYS if(ev == &(at_config.AT_event) && check_timer(&ApduRsp_timeout_ext_evt)) isATEvtAct = true;#endif#ifdef FEATURE_ENABLE_ID_AUTH_RSP_TIMER if(ev == &(at_config.AT_event) && check_timer(&ID_auth_rsp_timeout_evt)) isATEvtAct = true;#endif #ifdef FEATURE_ENABLE_REMOTE_USIM_DATA_RSP_TIMER if(ev == &(at_config.AT_event) && check_timer(&remote_USIM_data_rsp_timeout_evt)) isATEvtAct = true;#endif#ifdef FEATURE_ENABLE_MDMEmodem_IDLE_TIMEOUT_TIMER if(ev == &evtloop_read_event && check_timer(&Idle_Timer_evt)) { isMdmEmodemReq = true; }#endif#ifdef FEATURE_ENABLE_POWER_DOWN_NOTIFICATION_TIMER if(ev == &(at_config.AT_event) && check_timer(&power_down_notification_timeout_evt)) isATEvtAct = true;#endif #ifdef FEATURE_ENABLE_ATE0_RSP_TIMER if(ev == &(at_config.AT_event) && check_timer(&ate0_rsp_timeout_evt)) isATEvtAct = true;#endif }else{ } } // if(ev != NULL) } // for(; i < MAX_FD_EVENTS; i++) pthread_mutex_unlock(&list_mutex); return;}//NOTE:// "fire_Readies" include firing timeouts event.static void fire_Readies(void){ Evt *ev = NULL; //NOTE: Can't change sequence below! ev = ReadReadies_list.next_evt; while(ev != NULL){ Evt *next = ev->next_evt; remove_from_list(ev); ev->cb_func(ev->param); ev = next; } ev = timeouts_list.next_evt; while(ev != NULL){ Evt *next = ev->next_evt; remove_from_list(ev); ev->cb_func(ev->param); ev = next; }}#ifdef FEATURE_ENABLE_WAKEUP_EVENTstatic void WakeupCallback(void *param){ char buff; int ret; do{ ret = read(WakeupRead_fd, &buff, 1); }while(ret > 0 || (ret < 0 && errno == EINTR)); LOG("EvtLoop is waken up!\n"); return;}#endif // FEATURE_ENABLE_WAKEUP_EVENT#ifdef FEATURE_ENABLE_MDMEmodem_CUSTOMED_AT_CMDstatic int conv_proc_msg_to_ctrl_word(int msg){ return (msg-5);}#endif//Description://When notify_EvtLoop(0x02) is called, you should "push" ChannelNum into pipe "chan_num_pipe".//Param://num://0-4 : ChannelNum value 0-4.//5 : ChannelNum value -1.void push_ChannelNum(const int chan_num){ int ret = -1; char send_buf = chan_num; LOG6("~~~~ push_ChannelNum (%d)~~~~\n", chan_num); do{ ret = write(chan_num_pipe[1], &send_buf, 1); }while ((ret<0 && (errno==EINTR || errno==EAGAIN)) || (ret==0)); if(ret<0){ LOG("ERROR: write() failed. errno=%d.\n", errno); }}static int pop_ChannelNum(void){ int ret = -1, pop_ChanNum = -99; char recv_buf = 0xff; do{ ret = read(chan_num_pipe[0], &recv_buf, sizeof(recv_buf)); }while(ret == 0 || (ret < 0 && (errno == EINTR || errno == EAGAIN))); if(ret < 0){ LOG("ERROR: read() failed. errno=%d.\n", errno); pop_ChanNum = -99; }else{ pop_ChanNum = (int)recv_buf; } LOG6("~~~~ pop_ChannelNum (%d)~~~~\n", pop_ChanNum); return pop_ChanNum;}//Description://When notify_EvtLoop(0x01) is called, you should "push" flow_state into pipe "flow_state_pipe".void push_flow_state(const rsmp_state_s_type fs){ int written_bytes = -1; rsmp_state_s_type send_buf = fs; LOG6("~~~~ push_flow_state (%d)~~~~\n", fs); do{ written_bytes = write(flow_state_pipe[1], &send_buf, sizeof(send_buf)); }while ((written_bytes<0 && (errno==EINTR || errno==EAGAIN)) || (written_bytes==0)); if(written_bytes<0){ LOG("ERROR: write() failed. errno=%d.\n", errno); }}static rsmp_state_s_type pop_flow_state(void){ int read_bytes = -1; rsmp_state_s_type recv_buf, ret_val; do{ read_bytes = read(flow_state_pipe[0], &recv_buf, sizeof(recv_buf)); }while(read_bytes == 0 || (read_bytes < 0 && (errno == EINTR || errno == EAGAIN))); if(read_bytes < 0){ LOG("ERROR: read() failed. errno=%d.\n", errno); ret_val = FLOW_STATE_MAX; }else{ ret_val = recv_buf; } LOG6("~~~~ pop_flow_state (%d)~~~~\n", ret_val); return ret_val;}//Description://When notify_EvtLoop(0x01) is called, you should "push" thread idx into pipe "thread_idx_pipe".void push_thread_idx(const Thread_Idx_E_Type tid){ int written_bytes = -1; Thread_Idx_E_Type send_buf = tid; LOG6("~~~~ push_thread_idx (%d)~~~~\n", tid); do{ written_bytes = write(thread_idx_pipe[1], &send_buf, sizeof(send_buf)); }while ((written_bytes<0 && (errno==EINTR || errno==EAGAIN)) || (written_bytes==0)); if(written_bytes<0){ LOG("ERROR: write() failed. errno=%d.\n", errno); }}static Thread_Idx_E_Type pop_thread_idx(void){ int read_bytes = -1; Thread_Idx_E_Type recv_buf, ret_val; do{ read_bytes = read(thread_idx_pipe[0], &recv_buf, sizeof(recv_buf)); }while(read_bytes == 0 || (read_bytes < 0 && (errno == EINTR || errno == EAGAIN))); if(read_bytes < 0){ LOG("ERROR: read() failed. errno=%d.\n", errno); ret_val = THD_IDX_MAX; }else{ ret_val = recv_buf; } LOG6("~~~~ pop_thread_idx (%d)~~~~\n", ret_val); return ret_val;}void save_transmitting_apdu_into_cache(void *data, int data_len){ if(NULL == data) { LOG("ERROR: Wrong pointer data found! data=null.\n"); return -1; } if(data_len <= 0){ LOG("ERROR: Wrong data_len (%d) found!\n", data_len); return -1; } APDU_cache.data_len = data_len; if(APDU_cache.data != NULL) free(APDU_cache.data); APDU_cache.data = malloc(data_len); memcpy(APDU_cache.data, data, data_len);}//Parameter:// msg: // 0x00: It is the request of sending out APDUs, which comes from QMI parser.// 0x01: It is the request of sending out private protocol packet.// 0x02: It is the request of restoring the connection between server and mdmEmodem. Not to set ChannelNum before calling this.// NOTICE: 1. isRegOffForPoorSig is set outside.// 2. Before calling notify_EvtLoop(0x02), if there is an intermediate state, you must set it!// 3. When notify_EvtLoop(0x02) is called, you should "push" ChannelNum into pipe "chan_num_pipe".// 0x03: It is the request of suspending mdmEmodem. Not to set ChannelNum before calling this.// 0x04: It is the request of write at cmd to sim5360 from yy_daemon.void notify_EvtLoop(const char msg){ int n = -1; LOG6("~~~~ notify_EvtLoop start (%d) ~~~~\n", msg); do{ n = write(evtloop_pipe[1], &msg, 1); }while ((n<0 && (errno==EINTR || errno==EAGAIN)) || (n==0)); if(n<0){ LOG("ERROR: write() failed. errno=%d.\n", errno); } LOG6("~~~~ notify_EvtLoop end (%d) ~~~~\n", msg); return;}static void process_events(void *param){ char buff; int ret; rsmp_transmit_buffer_s_type *rc = NULL; rsmp_state_s_type fs = FLOW_STATE_IDLE; Thread_Idx_E_Type tid = THD_IDX_MAX; //static bool brunflag_pre00 = false; //static bool brunflag_pre01 = false; LOG6("~~~~ process_events start ~~~~\n"); ACQ_CHANNEL_LOCK_WR; do{ ret = read(evtloop_pipe[0], &buff, sizeof(buff)); }while(ret == 0 || (ret < 0 && (errno == EINTR || errno == EAGAIN))); if(ret < 0) { LOG("ERROR: read() failed. errno=%d.\n", errno); goto __EXIT_OF_RECVCALLBACK__; }else{ // ret > 0 if(true == isFTMPowerOffInd && 0x02 != buff && 0x01 != buff){ LOG("NOTICE: App is being shut down, so incoming requests (0x%02x) need to be dumped.\n", buff); goto __EXIT_OF_RECVCALLBACK__; //Rls ChannelLock then. } if(buff == 0x00){ rc = &g_rsmp_transmit_buffer[THD_IDX_PARSER]; fs = FLOW_STATE_APDU_COMM; }else if(buff == 0x01){ tid = pop_thread_idx(); rc = &g_rsmp_transmit_buffer[tid]; fs = pop_flow_state(); }else if(buff != 0x02 && buff != 0x03 && buff != 04){ LOG("ERROR: Wrong notification found. buff=0x%02x.\n", buff); goto __EXIT_OF_RECVCALLBACK__; } } if(isWaitToSusp == true && buff == 0x00) { LOG("APDU came, and isWaitToSusp=1. Now, cancel the suspension plan.\n"); isWaitToSusp = false; } if(0x00 == buff || 0x01 == buff){ clr_idle_timer(); } if(0x00 == buff){ clr_pdp_check_act_routine_timer(); } if(0x00 == buff) { //The apdu may be added into queue later, but it was saved into cache. save_transmitting_apdu_into_cache(rc->data, rc->size); add_timer_apdu_rsp_timeout_ext(1, 0); if(isDumpApdu) { LOG("NOTICE: App recvs APDU from modem, so isDumpApdu will be set false.\n"); isDumpApdu = false; } } LOG("ChannelNum = %d, buff = 0x%02x.\n", ChannelNum, buff); switch(buff){ case 0x00: case 0x01: { if(ChannelNum == 1 || ChannelNum == 2) { if(ChannelNum == 2){ LOG("Request to utilize mdmEmodem. Terminate suspension of mdmEmodem now!\n"); add_req_into_queue(rc, fs); isTermSuspNow = true; //Not need to set RcvrMdmEmodemConnWhenSuspTerm }else{ // ChannelNum == 1 LOG("Request to utilize mdmEmodem. Change Channel to 4 from 1.\n"); ChannelNum = 4; enqueue_and_resume_mdmEmodem(rc, fs); } }else{ // ChannelNum == 0 or 3 (available) -1 or 4 (recovering) if(ChannelNum == 0 || ChannelNum == 3){ if(mdmEmodem_check_busy()){ // Fixed by rjf at 20150724 LOG("NOTICE: mdmEmodem is performing task. Wait...\n"); add_req_into_queue(rc, fs); break; } proto_update_flow_state(fs); if(THD_IDX_EVTLOOP != tid){ //Fixed by rjf at 20151030 rsmp_transmit_buffer_s_type *p_req_cfg = &g_rsmp_transmit_buffer[THD_IDX_EVTLOOP]; reset_rsmp_transmit_buffer(p_req_cfg); //Hard copy p_req_cfg->size = rc->size; p_req_cfg->data = malloc(p_req_cfg->size); memcpy(p_req_cfg->data, rc->data, p_req_cfg->size); } ACQ_ACQ_DATA_STATE_MTX; acq_data_state = ACQ_DATA_STATE_CIPSEND_1; w_acqDataHdlr(); RLS_ACQ_DATA_STATE_MTX; }else{ // ChannelNum == -1 or 4 //Reason for not need to resume mdmEmodem: // No matter if ChannelNum equals -1 or 4, mdmEmodem is restoring its server connection. add_req_into_queue(rc, fs); } } break; } // case 0x00 or case 0x01 case 0x02: { int pop_ChanNum = pop_ChannelNum(); if(isWaitToRcvr){ LOG("NOTICE: isWaitToRcvr=1, so wait for recovering...\n"); //ChannelNum has been poped out and dumped //isWaitToRcvr can't be reset! break; }#ifdef FEATURE_ENABLE_OUT_OF_TRAFFIC_AND_DATE_0206 LOG("Debug: isCancelRecoveryNet = %d \n",isCancelRecoveryNet); if (isCancelRecoveryNet == true){ LOG("Now need close net of Emodem \n"); if(!mdmEmodem_check_busy()){ LOG("Now, go to suspend mdmEmodem.\n"); ChannelNum = pop_ChanNum==5?-1:pop_ChanNum; RcvrMdmEmodemConn = true; // Add by rjf at 20150811 suspend_state = SUSPEND_STATE_CIPCLOSE; w_suspendMdmHdlr(); }else{ LOG("MdmEmodem is busy now. Wait to recover it...\n"); //Dump this pop_ChanNum in case that ChanNum of new rcvr req can't be read isWaitToRcvr = true; } break; } #endif if(!mdmEmodem_check_if_running()){ LOG("Now, go to resume mdmEmodem.\n"); ChannelNum = pop_ChanNum==5?-1:pop_ChanNum; w_resumeMdmHdlr(); }else{ if(!mdmEmodem_check_busy()){ LOG("Now, go to suspend mdmEmodem.\n"); ChannelNum = pop_ChanNum==5?-1:pop_ChanNum; RcvrMdmEmodemConn = true; // Add by rjf at 20150811 suspend_state = SUSPEND_STATE_CIPCLOSE; w_suspendMdmHdlr(); }else{ LOG("MdmEmodem is busy now. Wait to recover it...\n"); //Dump this pop_ChanNum in case that ChanNum of new rcvr req can't be read isWaitToRcvr = true; } } break; } // case 0x02 case 0x03: { if(isWaitToSusp){ LOG("NOTICE: isWaitToSusp=1, so wait for suspending...\n"); //isWaitToSusp can't be reset! break; } if(!mdmEmodem_check_if_running()){ LOG("ERROR: Unable to suspend mdmEmodem for that isMdmEmodemRunning = 0!\n"); }else { if(!mdmEmodem_check_busy()){ bool Directly_Break = false; if(-1 == ChannelNum){ //Situation Presentation: //When PDP activation report came and notify_EvtLoop(0x03) is called, EvtLoop might not be available. But during this time, //ChannelNum could be set -1. Once ChannelNum has been set -1, a recovering process should be on work. Directly_Break = true; }else if(0 == ChannelNum){ //It may be out-of-date! //Skip setting ChannelNum to 3 ChannelNum = 2; }else if(2 == ChannelNum){ // Add by rjf at 20151014 //Situation Presentation: //This is in situation where pdp act msg is recved and pdp check is running by idle timer. Directly_Break = true; }else if(3 == ChannelNum){ // Add by rjf at 20151012 //Situation Presentation: //In net_act_evt_hdlr(), ChannelNum will be set to 3 when app is trying to suspend mdmEmodem. ChannelNum = 2; }else{ //Situation Presentation: //ChannelNum will be set to 3 when sock listener recv dialup msg and mdmEmodem is not suspended or being suspended. LOG("ERROR: Wrong ChannelNum(%d) found! Dialing report recved but ChannelNum doesn't match it.\n", ChannelNum); return; } if(!Directly_Break){ LOG("Now, go to suspend mdmEmodem.\n"); suspend_state = SUSPEND_STATE_CIPCLOSE; w_suspendMdmHdlr(); } }else{ LOG("MdmEmodem is busy now. Wait to suspend it...\n"); isWaitToSusp = true; } } break; } // case 0x03#ifdef FEATURE_ENABLE_MDMEmodem_CUSTOMED_AT_CMD case 0x04: { if(mdmEmodem_check_if_running()) { if(mdmEmodem_check_busy()) { if( strlen(proc_msg_at_config.cmd_str) && strstr(proc_msg_at_config.cmd_str, "SIMEI")) { LOG("The mdmEmodem is busy, but IMEI5360 comes\n"); isFactoryWriteIMEI5360 = true; }else { LOG("The mdmEmodem is busy, so isYYDaemonNeedtoSendATCmd will be set true.\n"); isYYDaemonNeedtoSendATCmd = true; } break; } proto_update_flow_state(FLOW_STATE_MDMEmodem_AT_CMD_REQ); ACQ_ACQ_DATA_STATE_MTX; acq_data_state = ACQ_DATA_STATE_CUSTOM_AT_CMD; w_acqDataHdlr(); RLS_ACQ_DATA_STATE_MTX; }else { ChannelNum = 4; isYYDaemonNeedtoSendATCmd = true; w_resumeMdmHdlr(); } break; } // case 0x04 case 0x05: case 0x06: { int ctrl_word = conv_proc_msg_to_ctrl_word(buff); LOG("NOTICE: Other process request to control mdmEmodem. ctrl_word=%d.\n", ctrl_word); mdmEmodem_standby_mode_switch(ctrl_word); break; } // case 0x05#endif // FEATURE_ENABLE_MDMEmodem_CUSTOMED_AT_CMD default: { //Not possible to reach here. The case of wrong buff val will be terminated before enter into this switch structure. break; } }__EXIT_OF_RECVCALLBACK__: RLS_CHANNEL_LOCK; LOG6("~~~~ process_events end ~~~~\n");}//NOTE:// If some formal request of QMI has been interrupted by unexpected error, new QMI request will// continue to flush in, and formal error won't affect new request.void EvtLoop(void){ int n; fd_set rfds; struct timeval tv; struct timeval *ptv = NULL; for(;;) { memcpy(&rfds, &read_fds, sizeof(fd_set)); if(isAllTimersExpired == false) { if(0 == calc_NextTimeout(&tv)) { ptv = NULL; }else{ ptv = &tv; } }else{ ptv = NULL; } n = select(maxfdp1, &rfds, NULL, NULL, ptv); LOG("select() return %d.\n", n); if (n < 0) { if (errno == EINTR) continue; LOG("ERROR. errno=%s(%d).\n", strerror(errno), errno); return; } process_Readies(&rfds, NULL); if(isAllTimersExpired == false) { process_Timeouts(); } fire_Readies(); } return;}static void *initEvtLoop(void *param){ int ret;#ifdef FEATURE_ENABLE_WAKEUP_EVENT int file_des[2];#endif // FEATURE_ENABLE_WAKEUP_EVENT pthread_mutex_init(&list_mutex, NULL); FD_ZERO(&read_fds); FD_ZERO(&write_fds); init_list(&timer_list); init_list(&timeouts_list); init_list(&ReadReadies_list); memset(watch_table, 0, sizeof(watch_table));#ifdef FEATURE_ENABLE_WAKEUP_EVENT ret = pipe(file_des);#else ret = 0;#endif // FEATURE_ENABLE_WAKEUP_EVENT *((int *)param) = ret; pthread_mutex_lock(&evtloop_mutex); evtloopStarted = 1; pthread_cond_broadcast(&evtloop_cond); pthread_mutex_unlock(&evtloop_mutex);#ifdef FEATURE_ENABLE_WAKEUP_EVENT if (ret < 0) { LOG("ERROR: pipe() error. errno=%d.\n", errno); return NULL; } WakeupRead_fd = file_des[0]; WakeupWrite_fd = file_des[1]; fcntl(WakeupRead_fd, F_SETFL, O_NONBLOCK); set_evt (&wakeup_event, WakeupRead_fd, true, WakeupCallback, NULL); add_evt (&wakeup_event, 'r'); LOG("NOTICE: wakeup_event=0x%x.\n", (unsigned int)(&wakeup_event));#endif // FEATURE_ENABLE_WAKEUP_EVENT set_evt (&evtloop_read_event, evtloop_pipe[0], true, process_events, NULL); add_evt(&evtloop_read_event, 'r'); LOG("NOTICE: evtloop_read_event=0x%x. evtloop_pipe[0]=%d.\n", (unsigned int)(&evtloop_read_event), evtloop_pipe[0]); EvtLoop(); LOG("ERROR: EvtLoop() ended unexpectedly.\n"); while(1){ sleep(0x00ffffff); } return NULL;}int startEvtLoopThread(void){ int ret; pthread_attr_t attr; int result; evtloopStarted = 0; pthread_mutex_lock(&evtloop_mutex); pthread_attr_init (&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); #ifdef FEATURE_ENABLE_SYSTEM_RESTORATION pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);#endif__EVTLOOP_PTHREAD_CREATE_AGAIN__: ret = pthread_create(&evtloop_tid, &attr, initEvtLoop, (void *)(&result)); if(ret != 0) { LOG("ERROR: pthread_create() failed. errno=%d.\n", errno); if(EAGAIN == errno){ sleep(1); goto __EVTLOOP_PTHREAD_CREATE_AGAIN__; } return 0; }#ifdef FEATURE_ENABLE_PRINT_TID LOG("NOTICE: evtloop_tid = %lu.\n", (unsigned long)evtloop_tid);#endif thread_id_array[THD_IDX_EVTLOOP] = (unsigned long)evtloop_tid; while (evtloopStarted == 0) { pthread_cond_wait(&evtloop_cond, &evtloop_mutex); } pthread_mutex_unlock(&evtloop_mutex); if (result < 0){ LOG("ERROR: initEvtLoop() error.\n"); return 0; } return 1;}#ifdef FEATURE_ENABLE_TIMER_SYSTEM#ifdef FEATURE_ENABLE_APDU_RSP_TIMEOUT_SYS#define PROTO_PACK_APDU_DATA_OFFSET (14)#define APDU_DATA_FIRST_ID_BYTE_IDX (1)#define APDU_DATA_SECOND_ID_BYTE_IDX (4)//Description:// According to APDU data buffered by arg "cache", it determines the type of APDU cmd.// The data in arg "cache" is packed with private protocol header.//Parameters:// cache_type : // 0x00 : The APDU data is packed with private protocol header.// 0x01 : The APDU data is pure data.//Return Values:// 1~4: Indicate different types of APDU.// 1: 2nd byte --- 0x88// 2: 0x00 0xc0 0x00 0x00 0x35// 3: 0x00 0xc0 0x00 0x00 0x10// 4: 0x00 0xc0 0x00 0x00 0x31// 0: Unexpected type of APDU found.// -1: Wrong param input.static int check_APDU_type(void *cache, int cache_type){ char *apdu_head_ptr = NULL; char first_id_byte = 0xff, second_id_byte = 0xff; int ret = -99; if(!cache){ LOG("ERROR: Arg cache is empty!\n"); return -1; } if(cache_type != 0 && cache_type != 1){ LOG("ERROR: Wrong mode (%d) found!\n", cache_type); return -1; } if(0 == cache_type){ apdu_head_ptr = cache+PROTO_PACK_APDU_DATA_OFFSET; }else{ apdu_head_ptr = cache; } first_id_byte = *(apdu_head_ptr+APDU_DATA_FIRST_ID_BYTE_IDX); second_id_byte = *(apdu_head_ptr+APDU_DATA_SECOND_ID_BYTE_IDX); switch(first_id_byte) { case 0x88: ret = 1; break; case 0xc0: { if(second_id_byte == 0x35) ret = 2; else if(second_id_byte == 0x10) ret = 3; else if(second_id_byte == 0x31) ret = 4; else ret = 0; break; } default: ret = 0; break; } // switch end return ret;}//Description://When uimdrv doesn't recv rsp of APDU cmd, its state machine will be blocked. So app need to generate//an APDU rsp to uimdrv for subsequent operation of setting uimdrv poweroff.//Parameters://cache : The buffer of APDU data.//cache_type : //0x00 : The APDU data in arg "cache" is packed with private protocol//0x01 : The APDU data in arg "cache" is pure data.//0x02 : Special type -only need rsp 0x88 //Return Values:// 1: Generation succeed.// 0 : Unable to generate an APDU rsp.//-1 : Wrong param(s) input.//-2 : check_APDU_type() error.//Notice://Input arg cache is a complete protocol packet of APDU.int generate_manual_APDU_and_resp_to_modem(void *cache, int cache_type){ int apdu_type = 0; LOG("Test: the status var value 10 cache_type=%d.\n", cache_type); if(!cache){ LOG("ERROR: Arg cache is empty!\n"); return -1; } if(cache_type != 0 && cache_type != 1 && cache_type != 2){ LOG("ERROR: Wrong cache_type (%d) found!\n", cache_type); return -1; } if(cache_type == 2) { apdu_type = 88; }else { apdu_type = check_APDU_type(cache, cache_type); } if(apdu_type < 0) { LOG("ERROR: cache_type=%d, check_APDU_type() error. Return val: %d.\n", cache_type, apdu_type); return -2; }else if(apdu_type == 0) { char first_id_byte; char second_id_byte; if(0 == cache_type){ first_id_byte = *((char *)cache+PROTO_PACK_APDU_DATA_OFFSET+APDU_DATA_FIRST_ID_BYTE_IDX); second_id_byte = *((char *)cache+PROTO_PACK_APDU_DATA_OFFSET+APDU_DATA_SECOND_ID_BYTE_IDX); }else{ first_id_byte = *((char *)cache+APDU_DATA_FIRST_ID_BYTE_IDX); second_id_byte = *((char *)cache+APDU_DATA_SECOND_ID_BYTE_IDX); } LOG("ERROR: Unexpected APDU cmd found in cache. " "APDU content: 2nd byte: 0x%02x, 5th byte: 0x%02x.\n", first_id_byte, second_id_byte); return 0; }else { reset_rsmp_recv_buffer(); switch(apdu_type) { case 1: //0x88 { unsigned char rsp_buf[] = {0x98, 0x62}; if(APDU_setting.is2GCard) { rsp_buf[1] = 0x04; } g_rsmp_recv_buffer.size = sizeof(rsp_buf); g_rsmp_recv_buffer.data = malloc(g_rsmp_recv_buffer.size); memcpy(g_rsmp_recv_buffer.data, (void *)rsp_buf, g_rsmp_recv_buffer.size); break; } case 2: { unsigned char rsp_buf[] = {0xdb, 0x08, 0x31, 0x62, 0xb9, 0x96, 0x67, 0xd0, 0x9e, 0x4a, 0x10, 0x22, 0x00, 0x61, 0x50, 0x5a, 0x6e, 0xf7, 0x96, 0xb0, 0x27, 0x85, 0x2b, 0x0e, 0xaf, 0x99, 0x3e, 0x10, 0x09, 0x65, 0x6f, 0xb1, 0xef, 0x96, 0x5e, 0xc2, 0xc1, 0x1a, 0x3d, 0x3b, 0x2d, 0xc9, 0xc0, 0xe5, 0x08, 0x5a, 0x58, 0xb6, 0xf1, 0x96, 0x9e, 0xf0, 0x8f, 0x90, 0x00}; g_rsmp_recv_buffer.size = sizeof(rsp_buf)+1; g_rsmp_recv_buffer.data = malloc(g_rsmp_recv_buffer.size); memcpy(g_rsmp_recv_buffer.data, &(APDU_setting.head_byte), 1); memcpy((unsigned char *)(g_rsmp_recv_buffer.data)+1, (void *)rsp_buf, sizeof(rsp_buf)); break; } case 3: { unsigned char rsp_buf[] = {0xDC, 0x0E, 0x23, 0xD0, 0x98, 0x25, 0x0C, 0x48, 0x5C, 0x2C, 0x8E, 0xE4, 0x91, 0x87, 0x9E, 0x54, 0x90, 0x00}; g_rsmp_recv_buffer.size = sizeof(rsp_buf)+1; g_rsmp_recv_buffer.data = malloc(g_rsmp_recv_buffer.size); memcpy(g_rsmp_recv_buffer.data, &(APDU_setting.head_byte), 1); memcpy((unsigned char *)(g_rsmp_recv_buffer.data)+1, (void *)rsp_buf, sizeof(rsp_buf)); break; } case 4: { unsigned char rsp_buf[] = {0xdb, 0x04, 0xda, 0xce, 0x02, 0x51, 0x10, 0x09, 0x65, 0x04, 0x2e, 0x65, 0x47, 0xd9, 0xd5, 0xc6, 0x3b, 0xd8, 0x21, 0x5e, 0xa1, 0x83, 0x35, 0x10, 0x0d, 0x3b, 0xda, 0x38, 0x61, 0x88, 0x54, 0x30, 0xc2, 0x5e, 0x18, 0xc3, 0x94, 0x89, 0x3b, 0xc3, 0x08, 0x00, 0x3b, 0x1e, 0xf4, 0xce, 0xe7, 0x35, 0x13, 0x90, 0x00}; g_rsmp_recv_buffer.size = sizeof(rsp_buf)+1; g_rsmp_recv_buffer.data = malloc(g_rsmp_recv_buffer.size); memcpy(g_rsmp_recv_buffer.data, &(APDU_setting.head_byte), 1); memcpy((unsigned char *)(g_rsmp_recv_buffer.data)+1, (void *)rsp_buf, sizeof(rsp_buf)); break; } case 88: { g_rsmp_recv_buffer.size = 1; g_rsmp_recv_buffer.data = malloc(g_rsmp_recv_buffer.size); ((unsigned char*)(g_rsmp_recv_buffer.data))[0] = 0x88; break; } default: { LOG("ERROR: Wrong APDU type (%d) found!\n", apdu_type); break; } } // switch end } //20160304 jackli { int retr =-1;char buf=1; do{ if(retr == 0){ LOG("write() failed. retr=%d.\n", retr); } retr = write(DMS_wr_fd, &buf, 1); }while ((retr<0 && (errno==EINTR || errno==EAGAIN)) || (retr==0)); //Not care the result, but keep listening to the QMI DMS. if(retr < 0){ LOG("ERROR: write() failed. ret=%d. errno=%d.\n", retr, errno); }} return 1;}void ApduRsp_timeout_ext_cb(void *userdata){ int ret; static bool brunflag_Emodembusy = false; LOG6("~~~~ ApduRsp_timeout_ext_cb ~~~~\n"); if(isApduRspExtCbEndUnexpV01){ LOG("isApduRspExtCbEndUnexpV01 = 1.\n"); isApduRspExtCbEndUnexpV01 = false; goto __CHECK_MDMEmodem_REG_AND_SIG_AGAIN__; } clr_idle_timer(); // Add by rjf at 20151014 clr_pdp_check_act_routine_timer(); // Add by rjf at 20151014 isDumpApdu = true; isEnableManualApdu = true; // Fixed by rjf at 20150805 #ifdef FEATURE_NEW_APDU_COMM APDU_setting.proc_step = 0; //reset APDU_setting.proc_step#endif //FEATURE_NEW_APDU_COMM queue_clr_apdu_node(); // Add by rjf at 20151012 (The APDU cache and APDU node are non-interfering.) queue_clr_stat_inf_node(); // Add by rjf at 20151029 (Uploading queued stat inf node would trigger the ID auth if APDU rsp timed out, and this is not allowed.) ret = generate_manual_APDU_and_resp_to_modem(APDU_cache.data, 0); if(ret != 1) { LOG("ERROR: generate_manual_APDU_and_resp_to_modem() failed. ret=%d.\n", ret); return; } if(isRegOffForPoorSig){ LOG("NOTICE: isRegOffForPoorSig = 1. Subsequent operation is unnecessary.\n"); return; } if(isWaitToSusp) { isWaitToSusp = false; } isNeedToNotifyServCondVar = true; //Assume registration fell, so not upload status info now. isRegOffForPoorSig = true; isNeedToSendIDMsg = true; sock_update_reg_urc_state(REG_URC_STATE_REGISTRATION_FAIL);//Add by rjf at 20150812 rsmp_net_info.basic_val = 0x01; // Add by rjf at 20150909 //Fixed by rjf at 20151023 (When acq_data_state == ACQ_DATA_STATE_RECVING but chk_net_state != //CHK_NET_STATE_MAX, it is not in recving the priv proto rsp. So not ought to set waiting state.) ACQ_ACQ_DATA_STATE_MTX; if(ACQ_DATA_STATE_RECVING == acq_data_state && CHK_NET_STATE_MAX == chk_net_state && CONF_STATE_MAX == uartconfig_state) { set_at_evt_waiting(); } RLS_ACQ_DATA_STATE_MTX;#ifdef FEATURE_ENABLE_APDURSP_TIMEOUT_EXT_CB_APDU_DATA_LOG#ifndef FEATURE_DEBUG_QXDM #ifndef FEATURE_DEBUG_LOG_FILE int i = 0; LOG("The content of APDU_cache:"); for(; i<APDU_cache.data_len; i++) LOG2("%02x ", get_byte_of_void_mem(APDU_cache.data, i) ); LOG2("\n"); #else int i = 1; pthread_mutex_lock(&log_file_mtx); LOG2("The content of APDU_cache: \n"); for(; i<=APDU_cache.data_len; i++){ if(i%20 == 1) LOG4(" %02x", get_byte_of_void_mem(APDU_cache.data, i-1) ); else LOG3(" %02x", get_byte_of_void_mem(APDU_cache.data, i-1) ); if(i%20 == 0) //Default val of i is 1 LOG3("\n"); } if((i-1)%20 != 0) // Avoid print redundant line break LOG3("\n"); pthread_mutex_unlock(&log_file_mtx); #endif /*FEATURE_DEBUG_LOG_FILE*/#else //Tips: The var "buf" above need to be non-variable. //| at_qlinkdatanode.c: In function 'ApduRsp_timeout_ext_cb': //| at_qlinkdatanode.c:6666:3: error: jump into scope of identifier with variably modified type //| at_qlinkdatanode.c:6779:4: note: label '__CHECK_MDMEmodem_REG_AND_SIG_AGAIN__' defined here //| at_qlinkdatanode.c:6733:9: note: 'buf' declared here#endif /*FEATURE_DEBUG_QXDM*/#endif /*FEATURE_ENABLE_APDURSP_TIMEOUT_EXT_CB_APDU_DATA_LOG*/ //Reset USIM //reg_urc_state has been updated to REG_URC_STATE_REGISTRATION_FELL if(!isRstingUsim) { isRstingUsim = true; pthread_mutex_lock(&rst_uim_mtx); #ifdef FEATURE_ENHANCED_qlinkdatanode_RUN_STAT_IND msq_send_qlinkdatanode_run_stat_ind(6);#endif proto_update_flow_state(FLOW_STATE_RESET_UIM); notify_DmsSender(0x04); LOG("NOTICE: Wait 3s for LPM setting to take effect.\n"); sleep(3); notify_UimSender(0x00); while(isUimRstOperCplt == false) { pthread_cond_wait(&rst_uim_cond, &rst_uim_mtx); } isUimRstOperCplt = false; // reset pthread_mutex_unlock(&rst_uim_mtx); }else{ LOG("NOTICE: USIM rst is ongoing!\n"); } //Decide how to power up USIM ACQ_CHANNEL_LOCK_WR; LOG("ChannelNum = %d.\n", ChannelNum); switch(ChannelNum) { case -1: case 4: { if(4 == ChannelNum){ LOG("ChannelNum is changed to -1 from 4.\n"); ChannelNum = -1; } MdmEmodemIsRcvrWhenSetPd = true; break; } // case -1 or 4 case 0: case 3: { int rssi = -1, reg_stat = -1; if(3 == ChannelNum){ LOG("ChannelNum is changed to 0 from 3.\n"); ChannelNum = 0; }__CHECK_MDMEmodem_REG_AND_SIG_AGAIN__: if(!mdmEmodem_check_busy()) { //Notice: //mdmEmodem_check_XXX() will be called by threads except AT_thread. rssi = mdmEmodem_check_CSQ(); LOG("rssi = %d.\n", rssi); if(rssi == -1){ LOG("ERROR: mdmEmodem_check_CSQ() error.\n"); LOG("Flow Ends Here!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); return; }else if(rssi < CSQ_VAL_THRESHOLD_OF_POOR_SIG || rssi == 99){ LOG("For poor signal, go to recover mdmEmodem.\n"); pthread_mutex_lock(&evtloop_mtx); push_ChannelNum(5); notify_EvtLoop(0x02); pthread_mutex_unlock(&evtloop_mtx); break; } reg_stat = mdmEmodem_check_CGREG(); LOG("reg_stat = %d.\n", reg_stat); if(reg_stat == -1){ LOG("ERROR: mdmEmodem_check_CGREG() error.\n"); LOG("Flow Ends Here!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); return; }else if(reg_stat != 1 && reg_stat != 5){ LOG("For registration fall, go to recover mdmEmodem.\n"); pthread_mutex_lock(&evtloop_mtx); push_ChannelNum(5); notify_EvtLoop(0x02); pthread_mutex_unlock(&evtloop_mtx); break; } }else { //Situation Presentation: //When timeout cb was executed, timeout evt has been removed from Timeouts_list and timers_list. //If mdmEmodem_check_busy() returns 1, acq_data_state is not ACQ_DATA_STATE_RECVING. So, //it is impossible that APDU rsp is recved (ApduRsp ext timer would be cleared.) after executing operations below. //But if APDU cmd is not sent out and ApduRsp ext timer timed out, the operations below may not //stop calling clr_ApduRsp_ext_timer(). So we must create a timer rather than ApduRsp ext timer. LOG("NOTICE: mdmEmodem is busy now. Check reg and sig later...\n");#ifdef FEATURE_ENABLE_Emodem_BUSY_ISSUE if (brunflag_Emodembusy == false) { brunflag_Emodembusy = true; LOG("MdmEmodem is busy. Restart reboot\n"); //system("reboot"); yy_popen_call("reboot -f"); } #endif isApduRspExtCbEndUnexpV01 = true; add_timer_Custom_Timer_timeout(0, 200*1000, 0x00, 0x00); break; } if(0 != URC_special_mark_array[SPEC_URC_ARR_IDX_VIRT_USIM_PWR_DWN]){ LOG("\"+SIMCARD: NOT AVAILABLE\" recved already. Now, go to power up virt card.\n"); upload_status_info_and_power_up_virt_USIM_later(); //After handling this URC rpt, the corresponding elem in URC_special_mark_array should be cleared. URC_special_mark_array[SPEC_URC_ARR_IDX_VIRT_USIM_PWR_DWN] = 0x00; }else{ LOG("\"+SIMCARD: NOT AVAILABLE\" not recved. Wait to power up virt card.\n"); #ifndef FEATURE_QMI_ASYNC_REQ_UIM_PD if(!isUimPwrDwn){ #error not wait for recving "+SIMCARD: NOT AVAILABLE" any more??? //Situation Presentation: // sender_set_uim_power_down() not returned and "+SIMCARD: NOT AVAILABLE" not recved. PowerUpUsimAfterPowerDown = true; }else{ //Situation Presentation: // sender_set_uim_power_down() returned but "+SIMCARD: NOT AVAILABLE" not recved. PowerUpUsimAfterRecvingUrcRpt = true; } #else PowerUpUsimAfterRecvingUrcRpt = true; #endif } // Not recv "+SIMCARD: NOT AVAILABLE" break; } // case 0 or 3 case 2: { if(isTermSuspNow){ //Not reset isTermSuspNow! LOG("ChannelNum=2 and isTermSuspNow=1. Now, wait to recover mdmEmodem later.\n"); //ChannelNum will be update to -1 or 4 later. So, proper action is "break". }else{ LOG("ERROR: ChannelNum=2 and isTermSuspNow=0! No rcvr action will be offered for powering up virt card.\n"); } break; } // case 2 default: { // case 1 LOG("ERROR: Wrong ChannelNum (%d) found!\n", ChannelNum); break; } } RLS_CHANNEL_LOCK; return;}//Param:// type:// 1: When APDUs are recved from modem, APDU rsp ext timer will be added with arg "type" equaled 1.// 2: When APDUs are sent out to server, APDU rsp ext timer will be added with arg "type" equaled 2.// opt:// 0: Not call trigger_EventLoop().// non-0: Call trigger_EventLoop().void add_timer_apdu_rsp_timeout_ext(char type, char opt){ if(!check_apdu_rsp_timeout_ext_timer()) { struct timeval tv; memset(&tv, 0, sizeof(tv)); if(1 == type){ tv.tv_sec = DEFAULT_APDU_RSP_EXT_PHASE_1_TIMEOUT_SEC; tv.tv_usec = DEFAULT_APDU_RSP_EXT_PHASE_1_TIMEOUT_USEC; }else if(2 == type){ tv.tv_sec = DEFAULT_APDU_RSP_EXT_PHASE_2_TIMEOUT_SEC; tv.tv_usec = DEFAULT_APDU_RSP_EXT_PHASE_2_TIMEOUT_USEC; } set_evt(&ApduRsp_timeout_ext_evt, -1, false, ApduRsp_timeout_ext_cb, NULL); add_timer(&ApduRsp_timeout_ext_evt, &tv); LOG("NOTICE: ApduRsp_timeout_ext_evt=%x.\n", (unsigned int)(&ApduRsp_timeout_ext_evt)); if(opt) trigger_EventLoop(); }else{ LOG("ERROR: Apdu rsp timeout ext timer has been added already!\n"); }}#endif // FEATURE_ENABLE_APDU_RSP_TIMEOUT_SYS#ifdef FEATURE_ENABLE_SERVER_RSP_TIMERstatic void ID_Auth_rsp_timeout_cb(void *userdata){#ifdef FEATURE_ENABLE_IDCHECK_NEW_TIMEOUT_PROCESS// add by jack li 20161123 start//static unsigned char record_ID_timeout_conut = 0; static bool b_seconed_countflag = false; LOG6("~~~~ ID_Auth_rsp_timeout_cb jack~~~~\n"); LOG("Debug: g_record_ID_timeout_conut = %d \n", g_record_ID_timeout_conut); LOG("Debug: flow_info.flow_state = %d \n", flow_info.flow_state ); LOG("Debug: b_seconed_countflag = %d \n", b_seconed_countflag ); isNeedToSendIDMsg = true; // Send ID authentication message ACQ_CHANNEL_LOCK_WR; if(3 == ChannelNum){ ChannelNum = 4; }else if(0 == ChannelNum){ ChannelNum = -1; }else if(-1 != ChannelNum && 4 != ChannelNum){ LOG("ERROR: Wrong ChannelNum (%d) found.\n", ChannelNum); return; } RLS_CHANNEL_LOCK; // if (flow_info.flow_state == FLOW_STATE_ID_AUTH){ if((g_record_ID_timeout_conut <= 2) && (b_seconed_countflag == false)){ acq_data_state = ACQ_DATA_STATE_CIPSEND_1; w_acqDataHdlr(); }else if ((g_record_ID_timeout_conut == 3) && (b_seconed_countflag == false)){ b_seconed_countflag = true; RcvrMdmEmodemConn = true; suspend_state = SUSPEND_STATE_CIPCLOSE; w_suspendMdmHdlr(); }else if ((g_record_ID_timeout_conut < 6) && (b_seconed_countflag == true)){ acq_data_state = ACQ_DATA_STATE_CIPSEND_1; w_acqDataHdlr(); }else{ g_record_ID_timeout_conut = 0; b_seconed_countflag = false; RcvrMdmEmodemConn = true; suspend_state = SUSPEND_STATE_CIPCLOSE; w_suspendMdmHdlr(); } g_record_ID_timeout_conut++; // } // add by jack li 20161123 end#else LOG6("~~~~ ID_Auth_rsp_timeout_cb ~~~~\n"); isNeedToSendIDMsg = true; // Send ID authentication message ACQ_CHANNEL_LOCK_WR; if(3 == ChannelNum){ ChannelNum = 4; }else if(0 == ChannelNum){ ChannelNum = -1; }else if(-1 != ChannelNum && 4 != ChannelNum){ LOG("ERROR: Wrong ChannelNum (%d) found.\n", ChannelNum); return; } RLS_CHANNEL_LOCK; RcvrMdmEmodemConn = true; suspend_state = SUSPEND_STATE_CIPCLOSE; w_suspendMdmHdlr(); #endif}static void Remote_USIM_Data_rsp_timeout_cb(void *userdata){ int length; rsmp_transmit_buffer_s_type *p_req_cfg = &g_rsmp_transmit_buffer[THD_IDX_EVTLOOP]; LOG6("~~~~ Remote_USIM_Data_rsp_timeout_cb ~~~~\n"); queue_clr_apdu_node(); reset_rsmp_transmit_buffer(p_req_cfg); p_req_cfg->data = proto_encode_raw_data(NULL, &length, REQ_TYPE_REMOTE_UIM_DATA, NULL, NULL); p_req_cfg->size = length; LOG("flow_state changed to %d from %d.\n", FLOW_STATE_REMOTE_UIM_DATA_REQ, flow_info.flow_state); proto_update_flow_state(FLOW_STATE_REMOTE_UIM_DATA_REQ); ACQ_ACQ_DATA_STATE_MTX; acq_data_state = ACQ_DATA_STATE_CIPSEND_1; w_acqDataHdlr(); RLS_ACQ_DATA_STATE_MTX;}void add_timer_ID_auth_rsp_timeout(void){ if(!check_id_auth_rsp_timeout_timer()){ // Add by rjf at 20151009 struct timeval tv; memset(&tv, 0, sizeof(tv)); tv.tv_sec = DEFAULT_ID_AUTH_RSP_TIMEOUT_SEC; tv.tv_usec = DEFAULT_ID_AUTH_RSP_TIMEOUT_USEC; set_evt(&ID_auth_rsp_timeout_evt, -1, false, ID_Auth_rsp_timeout_cb, NULL); add_timer(&ID_auth_rsp_timeout_evt, &tv); LOG("NOTICE: Add id auth timeout timer. ID_auth_rsp_timeout_evt=%x.\n", (unsigned int)(&ID_auth_rsp_timeout_evt)); }else{ LOG("ERROR: Id auth timeout timer has been added already!\n"); }}void add_timer_remote_USIM_data_rsp_timeout(void){ if(!check_remote_USIM_data_rsp_timeout_timer()){ // Add by rjf at 20151009 struct timeval tv; memset(&tv, 0, sizeof(tv)); tv.tv_sec = DEFAULT_REMOTE_USIM_DATA_RSP_TIMEOUT_SEC; tv.tv_usec = DEFAULT_REMOTE_USIM_DATA_RSP_TIMEOUT_USEC; set_evt(&remote_USIM_data_rsp_timeout_evt, -1, false, Remote_USIM_Data_rsp_timeout_cb, NULL); add_timer(&remote_USIM_data_rsp_timeout_evt, &tv); LOG("NOTICE: Add remote USIM data rsp timeout timer. remote_USIM_data_rsp_timeout_evt=%x.\n", (unsigned int)(&remote_USIM_data_rsp_timeout_evt)); }else{ LOG("ERROR: Remote USIM data rsp timeout timer has been added already!\n"); }}#endif // FEATURE_ENABLE_SERVER_RSP_TIMER#ifdef FEATURE_ENABLE_PDP_ACT_CHECK_TIMERstatic void pdp_act_check_routine_cb(void *userdata){ if(isFTMPowerOffInd) { return; } if(isSockListenerRecvPdpActMsg){ LOG("net_act_evt_hdlr() is running...\n"); return; } LOG6("~~~~ pdp_act_check_routine_cb ~~~~\n"); if(1 != sock_inet_conn_test()) { if(isRegOn) { LOG("ChannelNum=0, net_stat=0 and isRegOn=1. Now, add pdp act check rountine timer again.\n"); add_timer_pdp_act_check_routine(); }else{ LOG("ChannelNum=0, net_stat=0 and isRegOn=0. Now, dump pdp act check routine.\n"); } }else if(!isMifiConnected) { char pre_cnd = 0x00; LOG("ChannelNum=0 but net_stat=1. Now, go to set network context.\n"); isMifiConnected = true; set_ChannelNum(3);#ifdef FEATURE_ENABLE_MSGQ msq_send_dialup_ind();#endif pthread_mutex_lock(&i1r_mtx); if(is1stRunOnMdmEmodem == true){ init_dev_info(&rsmp_dev_info); } is1stRunOnMdmEmodem = false; pthread_mutex_unlock(&i1r_mtx); pre_cnd = rsmp_net_info.basic_val; if(pre_cnd != 0x04){ update_net_info(0x02, 0x01, 0x00, 0x00); net_info_processor(pre_cnd, rsmp_net_info); //status_info_upload_acq_info() inside. } if(true == isTermSuspNow || true == isWaitToRcvr || true == isQueued) { LOG("isTermSuspNow=%d, isWaitToRcvr=%d, isQueued=%d. Now, wait to suspend mdmEmodem automatically.\n", isTermSuspNow, isWaitToRcvr, isQueued); }else{ //FIXME: Not allow to set AT_event to waiting state for that mdmEmodem may be busy. if(false == isNotNeedIdleTimer && 0 == check_rsp_timers() //Dialup is complete, so not need to check registration. && false == isSockListenerRecvPdpActMsg // Add by rjf at 20151014 (Avoid the collision between pdp check in Idle timer cb and pdp act msg processing in sock listener.) ){ LOG("Set up idle timer for mdmEmodem.\n"); add_timer_mdmEmodem_idle_timeout(0x00); } } }else{ //Who set isNetOn true, who suspend mdmEmodem. LOG("net_act_evt_hdlr() is running...\n"); }}void add_timer_pdp_act_check_routine(void){ if(0 == check_pdp_act_check_routine_timer()){ struct timeval tv; memset(&tv, 0, sizeof(tv)); tv.tv_sec = DEFAULT_PDP_ACT_CHECK_INTERVAL_SEC; tv.tv_usec = DEFAULT_PDP_ACT_CHECK_INTERVAL_USEC; set_evt(&pdp_act_check_routine_evt, -1, false, pdp_act_check_routine_cb, NULL); add_timer(&pdp_act_check_routine_evt, &tv); LOG("NOTICE: pdp_act_check_routine_evt=%x.\n", (unsigned int)(&pdp_act_check_routine_evt)); }else{ LOG("ERROR: pdp act check routine timer has been added already!\n"); }}#endif // FEATURE_ENABLE_PDP_ACT_CHECK_TIMER#ifdef FEATURE_ENABLE_MDMEmodem_IDLE_TIMEOUT_TIMERstatic void Idle_Timer_timeout_cb(void *userdata){ LOG6("~~~~ Idle_Timer_timeout_cb ~~~~\n"); LOG("Debug: ChannelNum = %d.\n",ChannelNum); if(isFTMPowerOffInd){ return; } if(isSockListenerRecvPdpActMsg){ LOG("net_act_evt_hdlr() is running...\n"); return; } if(mdmEmodem_check_if_running()) { if(check_ChannelNum(2)){ LOG("Suspension for mdmEmodem is ongoing!\n"); }else{ if(!mdmEmodem_check_busy()) { ACQ_CHANNEL_LOCK_WR; if(0 == ChannelNum) { int net_stat = sock_inet_conn_test(); LOG("Debug: net_stat = %d.\n",net_stat); LOG("Debug: isMifiConnected = %d.\n",isMifiConnected); if(1 != net_stat){ //If sock_inet_conn_test() returns -1, it is regarded as conn failure. LOG("ChannelNum = 0 and network link is unavailable. Now, add pdp act check routine timer.\n"); add_timer_pdp_act_check_routine(); RLS_CHANNEL_LOCK; return; }else if((!isMifiConnected) || (net_stat == 1)){ char pre_cnd = 0x00; LOG("ChannelNum =0 but network link is available. Now, go to set network context.\n"); isMifiConnected = true; ChannelNum = 3;#ifdef FEATURE_ENABLE_MSGQ msq_send_dialup_ind();#endif // FEATURE_ENABLE_MSGQ pthread_mutex_lock(&i1r_mtx); if(is1stRunOnMdmEmodem == true){ init_dev_info(&rsmp_dev_info); } is1stRunOnMdmEmodem = false; pthread_mutex_unlock(&i1r_mtx); pre_cnd = rsmp_net_info.basic_val; if(pre_cnd != 0x04){ update_net_info(0x02, 0x01, 0x00, 0x00); net_info_processor(pre_cnd, rsmp_net_info); //status_info_upload_acq_info() inside. sleep(1); // Add by rjf at 20151009 (Sleep 1 sec for avoiding suspending mdmEmodem before completing status info upload.) } }else{ //Who set isNetOn true, who suspend mdmEmodem. LOG("net_act_evt_hdlr() is running...\n"); RLS_CHANNEL_LOCK; return; } //Go to suspend mdmEmodem }else if(2 == ChannelNum){ LOG("ERROR: ChannelNum = 2, but an idle timer is expired. Nothing will be done to this timeout.\n"); RLS_CHANNEL_LOCK; return; }else if(4 == ChannelNum){ LOG("ChannelNum=4, isQueued=%d.\n", isQueued); if(isQueued == true){ LOG("Wait for resuming mdmEmodem...\n"); RLS_CHANNEL_LOCK; return; }else{ LOG("Prepare to suspend mdmEmodem...\n"); isWaitToSusp = true; RLS_CHANNEL_LOCK; return; } }else if(3 != ChannelNum){ // if(-1 == cn || 1 == cn) LOG("ERROR: ChannelNum=%d, but an idle timer found!\n", ChannelNum); RLS_CHANNEL_LOCK; return; } RLS_CHANNEL_LOCK;#ifdef FEATURE_ENABLE_MDMEmodem_CUSTOMED_AT_CMD if(isYYDaemonNeedtoSendATCmd){ isYYDaemonNeedtoSendATCmd = false; proto_update_flow_state(FLOW_STATE_MDMEmodem_AT_CMD_REQ); ACQ_ACQ_DATA_STATE_MTX; acq_data_state = (ACQ_DATA_STATE_CUSTOM_AT_CMD); w_acqDataHdlr(); RLS_ACQ_DATA_STATE_MTX; return; }#endif // FEATURE_ENABLE_MDMEmodem_CUSTOMED_AT_CMD //ChannelNum == 3 LOG("ChannelNum=%d. Go to suspend mdmEmodem.\n", get_ChannelNum()); pthread_mutex_lock(&evtloop_mtx); notify_EvtLoop(0x03); pthread_mutex_unlock(&evtloop_mtx); }else{ LOG("NOTICE: Suspension delayed for waiting mdmEmodem completed its task. acq_data_state=%d. \n", get_acq_data_state()); set_ChannelNum(3); isWaitToSusp = true; } } }else{ LOG("mdmEmodem has been suspended already!\n"); }}void add_timer_mdmEmodem_idle_timeout(char opt){ if(0 == check_idle_timer()){ struct timeval tv; memset(&tv, 0, sizeof(tv)); tv.tv_sec = DEFAULT_MDMEmodem_IDLE_TIMER_SEC; tv.tv_usec = DEFAULT_MDMEmodem_IDLE_TIMER_USEC; set_evt(&Idle_Timer_evt, -1, false, Idle_Timer_timeout_cb, NULL); add_timer(&Idle_Timer_evt, &tv); LOG("NOTICE: Idle_Timer_evt=%x.\n", (unsigned int)(&Idle_Timer_evt)); if(0x01 == opt) trigger_EventLoop(); }else{ LOG("NOTICE: Idle timer has been added already!\n"); }}#endif // FEATURE_ENABLE_MDMEmodem_IDLE_TIMEOUT_TIMER#ifdef FEATURE_ENABLE_POWER_DOWN_NOTIFICATION_TIMERvoid power_down_notification_timeout_cb(void *userdata){ LOG6("~~~~ power_down_notification_timeout_cb ~~~~\n"); ACQ_CHANNEL_LOCK_WR; LOG("ChannelNum=%d.\n", ChannelNum); if(3 == ChannelNum || 0 == ChannelNum){ ChannelNum = -1; isPwrDwnRspAcq = true; suspend_state = SUSPEND_STATE_CIPCLOSE; w_suspendMdmHdlr(); RLS_CHANNEL_LOCK; // Added by rjf at 20151014 return; } RLS_CHANNEL_LOCK; //Maintain ChannelNum ACQ_ACQ_DATA_STATE_MTX; set_at_evt_waiting(); RLS_ACQ_DATA_STATE_MTX; isMdmEmodemRunning = false; // Set it false in advance. #ifdef FEATURE_ENABLE_MDMEmodem_SOFT_SHUTDOWN mdmEmodem_shutdown(); #endif LOG("Send msg to notify other processes.\n"); msq_send_pd_rsp();}void add_timer_power_down_notification_timeout(void){ struct timeval tv; memset(&tv, 0, sizeof(tv)); tv.tv_sec = DEFAULT_POWER_DOWN_NOTIFICATION_RSP_SEC; tv.tv_usec = DEFAULT_POWER_DOWN_NOTIFICATION_RSP_USEC; set_evt(&power_down_notification_timeout_evt, -1, false, power_down_notification_timeout_cb, NULL); add_timer(&power_down_notification_timeout_evt, &tv); LOG("NOTICE: power_down_notification_timeout_evt=%x.\n", (unsigned int)(&power_down_notification_timeout_evt)); trigger_EventLoop(); // It is indispensable.}#endif // FEATURE_ENABLE_POWER_DOWN_NOTIFICATION_TIMERstatic void Custom_Timer_timeout_cb(void *userdata){ char cb_type = Custom_Timer_cb_type; LOG6("~~~~ Custom_Timer_timeout_cb (%02x) ~~~~\n", cb_type); switch(cb_type) { case 0x00:{ //isApduRspExtCbEndUnexpV01 should be set true before. ApduRsp_timeout_ext_cb(NULL); break; } //case 0x00 default: LOG("ERROR: Wrong cb_type (%02x) found. Nothing will be done!\n", cb_type); break; }}//Param://cb_type://0x00: Call ApduRsp_timeout_ext_cb() and isApduRspExtCbEndUnexpV01 equals true.void add_timer_Custom_Timer_timeout(int sec, int usec, char cb_type, char opt){ if(0 == check_custom_timer()){ struct timeval tv; memset(&tv, 0, sizeof(tv)); tv.tv_sec = sec; tv.tv_usec = usec; Custom_Timer_cb_type = cb_type; set_evt(&Custom_Timer_evt, -1, false, Custom_Timer_timeout_cb, NULL); add_timer(&Custom_Timer_evt, &tv); LOG("NOTICE: Custom_Timer_evt=%x.\n", (unsigned int)(&Custom_Timer_evt)); if(0x01 == opt) trigger_EventLoop(); }else{ LOG("ERROR: Custom timer has been added already!\n"); }}//Return Values:// 1: Normal situation.// 0: goto __AFTER_SENDING_DATA_TO_MDM__;int clr_invalid_timer(void){ if(flow_info.req_type == REQ_TYPE_APDU){ if(isDumpApdu){ // FIXME LOG("APDU comes and isDumpApdu = 1. So dump the APDU.\n"); isDumpApdu = false; //No matter if ApduRsp ext timer is expired isApduRspExtTimerExpired = false; clr_timeout_evt(&ApduRsp_timeout_ext_evt); // No matter if ApduRsp_timeout_ext_evt is in Timeouts_list clr_ApduRsp_ext_timer(); // No matter if ApduRsp ext timer is set// clr_ApduRsp_timer(); return 0; } //Clear the lapsed (expired) ApduRsp_timeout_evt or ApduRsp_timeout_ext_evt out of Timeouts_list. if(true == isApduRspExtTimerExpired) { isApduRspExtTimerExpired = false; // reset LOG("NOTICE: Clear ApduRsp ext timer in Timeouts_list.\n"); clr_timeout_evt(&ApduRsp_timeout_ext_evt); } //Clear the lapsed (not expired) ApduRsp_timeout_evt or ApduRsp_timeout_ext_evt out of timer_list //If isXXXTimerExpired was true before a series of operations about isXXXTimerExpired above, isATEvtAct had been set false already. Although the action below is acceptable. //If isXXXTimerExpired was false before a series of operations about isXXXTimerExpired above, isATEvtAct was true. So it is right time to set it false. isATEvtAct = false; //No matter if these timers exist, it will try to clear timer anyway. So it may consume some time. //Not add into "if...else..." in case that one timer is expired and another is not. clr_ApduRsp_ext_timer(); } else{ // Non-APDU //Reset vars isApduRspExtTimerExpired = false; } //*****ID auth rsp timer***** if(flow_info.req_type == REQ_TYPE_ID){ //Recv ID auth rsp, and clear expired ID auth rsp timer in Timeouts_list. if(isIdAuthRspTimerExpired){ isIdAuthRspTimerExpired = false; LOG("NOTICE: Clear ID auth rsp timer in Timeouts_list.\n"); clr_timeout_evt(&ID_auth_rsp_timeout_evt); } isATEvtAct = false; clr_ID_auth_rsp_timer(); }else{ //Reset vars isIdAuthRspTimerExpired = false; } //*****remote USIM data rsp timer***** if(flow_info.req_type == REQ_TYPE_REMOTE_UIM_DATA){ //Recv ID auth rsp, and clear expired ID auth rsp timer in Timeouts_list. if(isRemoteUsimDataRspTimerExpired){ isRemoteUsimDataRspTimerExpired = false; LOG("NOTICE: Clear remote USIM data rsp timer in Timeouts_list.\n"); clr_timeout_evt(&remote_USIM_data_rsp_timeout_evt); } isATEvtAct = false; clr_remote_USIM_data_rsp_timer(); }else{ //Reset vars isRemoteUsimDataRspTimerExpired = false; } return 1;}#endif // FEATURE_ENABLE_TIMER_SYSTEM