/******************************************************************** Copyright ?2007 LGC Wireless, Inc. All rights reserved File Name: aifg_m.c Description: FSM of AIFG module Version: v9.0.0 Author: Roy Jiang Create Date: 2007-3-12 History: 2007-3-12 v9.0.0 Create *********************************************************************/ //#include "aifg_mpp.h" #include "./include/aifg_var_ext.h" #include "./include/aifg.h" aifg_sap sap[AIFG_MAX_SAP]; aifg_port aifg_pcb[AIFG_MAX_PORT]; aifg_circuit_group cg[AIFG_MAX_CG]; aifg_link_info link_info[SCCP_MAX_LINK]; aifg_dual_server dual_server; aifg_event_code aifg_event; aifg_port *pOpenPort_h = NULL; //List head of opened port aifg_port *pPagPort_h = NULL; //List head of paging port aifg_port *pPagPort_t = NULL; //List tail of paging port static int paging_port_count = 0; //for protection extern inline void aifg_add_paging_port(aifg_port *p); extern inline void aifg_del_paging_port(aifg_port *p); extern void aifg_csta_init(); extern void aifg_csta_proc(); enum REL_CAUSE{ REL_CAUSE_CALL_CONTROL = 0x09, REL_CAUSE_HO_SUCCESS = 0x0B, REL_CAUSE_TIMER_EXPIRE = 0x66, REL_CAUSE_PROTOCOL_ERR = 0x6F, REL_CAUSE_TEMP_FAILURE = 0x29, }; /* Purpose:Init AIFG module. Input: None Output: None */ void aifg_init() { int memsize; memset(&sap, 0, sizeof(sap)); memset(aifg_pcb, 0, sizeof(aifg_port)*AIFG_MAX_PORT); memset(link_info, 0, sizeof(aifg_link_info)*SCCP_MAX_LINK); memsize = (sizeof(sap)+sizeof(aifg_port)*AIFG_MAX_PORT+sizeof(aifg_raw_msg)+sizeof(aifg_msg_pre_decoded) + sizeof(dual_server) + sizeof(aifg_event) + sizeof(cg) + sizeof(aifg_link_info)*SCCP_MAX_LINK + sizeof(SP_UiPriPara))/1024; printf("AIFG memory usage: %d KB\n", memsize); aifg_set_running_mode(AIFG_RUN_MODE_SINGLE); aifg_event = AIFG_SUCCEED; aifg_mpp_init(); aifg_debug_init(); aifg_csta_init(); //for dual server test aifg_set_running_mode(AIFG_RUN_MODE_DUAL); printf("AIFG init completed!\n"); } /* Purpose:10ms routing of AIFG module. Input: None Output: None */ void aifg_proc() { int i; aifg_port *pPort; for (i = 0; i < MSG_PROC_EACH_TIME; i++){ if(AIFG_PROC_FINISH == aifg_mpp_proc()) break; } //process opened port i = 0; pPort = pOpenPort_h; while(pPort != NULL){ aifg_port *pTmpPort = pPort; pPort = pPort->pNextOpenPort; (pTmpPort->timer > 0 ) ? pTmpPort->timer-- : 0; aifg_port_proc(pTmpPort, NULL, NULL); if(++i > AIFG_MAX_PORT) break; } //---------for protection--------------- if(i > AIFG_MAX_PORT) { //memory corrupted, reset all ports pOpenPort_h = NULL; for(i = 0; i < AIFG_MAX_PORT; i++) aifg_port_release(&aifg_pcb[i]); } //---------protection end--------------- aifg_csta_proc(); aifg_debug_timer(); } //FSM--------------------------------------------------------------------------------------- inline void aifg_send_release_ind(aifg_sap_type sapid, int app_port, int aif_port, int cause) { rv_msg.id = AIFG_MSG_ID_RELEASE; rv_msg.app_port = app_port; rv_msg.aif_port = aif_port; rv_msg.cause = cause; sap[sapid].callback_func(AIFG_IND_RV_MSG, &rv_msg); aifg_pcb[aif_port].app_rel_flag = 1; } inline void aifg_reset_timer(int port, int value) { aifg_pcb[port].timer = value; } inline int aifg_get_cause_value(aifg_ie_ptr *cause) { aifg_ie tmp_ie; if(cause->ptr != NULL){ aifg_ie_decode(cause, &tmp_ie); if (tmp_ie.iei == AIFG_IE_ID_BM_CAUSE) return tmp_ie.param.bm_cause.value; else return tmp_ie.param.dt_cause.cause_value; } else return 0x1F; //unspecified } enum RESET_STATE{ RESET_INIT, RESET_WAIT_RESET_COMPLETE, }; int reset_fsm(aifg_port *p, aifg_msg_t *upper_msg, aifg_msg_pre_decoded *peer_msg) { switch(p->ti_stat){ case RESET_INIT: if(AIFG_SAP_MSC == p->sapid) p->timer = AIFG_TIMER_T2; else p->timer = AIFG_TIMER_T13; p->ti_stat = RESET_WAIT_RESET_COMPLETE; break; case RESET_WAIT_RESET_COMPLETE: //Send RESET_ACK if(0 == p->timer){ sd_msg.id = AIFG_MSG_ID_RESET_ACK; aifg_send_udt(p->cgid, &sd_msg, NULL); return AIFG_PROC_FINISH; } break; default: assert(0); goto ERR_PROC; break; } return AIFG_PROC_CONTINUE; ERR_PROC: //release the port return AIFG_ERROR; } enum PAGING_STATE{ PAGING_INIT, PAGING_WAIT_RESP, PAGING_REPAGING, }; int paging_fsm(aifg_port *p, aifg_msg_t *upper_msg, aifg_msg_pre_decoded *peer_msg) { switch(p->ti_stat){ case PAGING_INIT: { //remember imsi or tmsi if (upper_msg->msg.paging.tmsi.flag == 1){ //TMSI, because the TMSI in paging is BCD coding and single byte coding in paging response //so here BCD coded TMSI will be translated to single byte coding int i = 0, j = 0; while (i < 4){ p->imsi[j++] = upper_msg->msg.paging.tmsi.value[i] & 0x0F; p->imsi[j++] = (upper_msg->msg.paging.tmsi.value[i++] & 0xF0) >> 4; } p->imsi_len = j; } else{ p->imsi_len = upper_msg->msg.paging.imsi.imsi_len; memcpy(p->imsi, upper_msg->msg.paging.imsi.imsi, p->imsi_len); } aifg_send_udt(p->cgid, upper_msg, &p->sd_buffer); //add the port paging port list // aifg_add_paging_port(p); p->ti_stat = PAGING_WAIT_RESP; p->timer = AIFG_TIMER_T3113; } break; case PAGING_WAIT_RESP: { if((peer_msg != NULL && AIFG_MSG_ID_PAGING_RESP == peer_msg->msg.completeL3Info.l3msg.id)){ peer_msg->app_port = p->upper_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); return AIFG_PROC_FINISH; } else if(p->timer <= 0){ aifg_debug_print(p-aifg_pcb, AIFG_ERR_PAGING_NOT_RESP, NULL, p-aifg_pcb); goto ERR_PROC; } else if(0 == (p->timer % AIFG_TIMER_REPAGE)) p->ti_stat = PAGING_REPAGING; } break; case PAGING_REPAGING: { //Re-paging PostSp(&p->sd_buffer); p->ti_stat = PAGING_WAIT_RESP; } break; default: assert(0); goto ERR_PROC; break; } return AIFG_PROC_CONTINUE; ERR_PROC: //remove this port from paging list p->app_rel_flag = 1; //no need to release app // aifg_del_paging_port(p); return AIFG_ERROR; } enum LU_STATE{ LU_WAIT_RESPONSE, LU_CLEAR, LU_WAIT_CLEAR_CMP, }; int lu_fsm(aifg_port *p, aifg_msg_t *upper_msg, aifg_msg_pre_decoded *peer_msg) { if (peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_CLR_REQ){ p->rel_cause = aifg_get_cause_value(&peer_msg->msg.clearReq.cause); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); p->ti_stat = LU_CLEAR; p->timer = 0; } switch(p->ti_stat) { case LU_WAIT_RESPONSE: { if(upper_msg != NULL){ if(upper_msg->id == AIFG_MSG_ID_RELEASE){ p->ti_stat = LU_CLEAR; p->app_rel_flag = 1; } else{ aifg_send_dt1(p->link_id, upper_msg, p->ti); } } else if(peer_msg != NULL){ peer_msg->app_port = p->upper_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); } } break; case LU_CLEAR: { sd_msg.aif_port = p - aifg_pcb; //for debug print sd_msg.app_port = p->upper_port;//for debug print sd_msg.pd = AIFG_PD_BSSMAP_DEDICATED; sd_msg.id = AIFG_MSG_ID_CLR_CMD; sd_msg.msg.clearCmd.cause.flag = 1; sd_msg.msg.clearCmd.cause.ext_value.flag = 0; sd_msg.msg.clearCmd.cause.value = REL_CAUSE_CALL_CONTROL; sd_msg.msg.clearCmd.l3HeaderInfo.flag = 0; aifg_send_dt1(p->link_id, &sd_msg, p->ti); p->ti_stat = LU_WAIT_CLEAR_CMP; p->timer = AIFG_TIMER_CLEAR_TIMEOUT; } break; case LU_WAIT_CLEAR_CMP: { if((peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_CLR_CMP) || p->timer <= 0){ link_info[p->link_id].cleared = 1; return AIFG_PROC_FINISH; } } break; default: assert(0); return AIFG_PROC_FINISH; break; } return AIFG_PROC_CONTINUE; } enum HO_STATE{ HO_IDLE, HO_SETUP_NEW_LINK, HO_EXECUTE, HO_WAIT_COMPLETE, HO_CLEAR_OLD_LINK, HO_WAIT_OLD_CLEAR_CMP, HO_CLEAR_NEW_LINK, HO_WAIT_NEW_CLEAR_CMP, }; enum HO_RETURN{ HO_PROCECCED, HO_NOT_PROCECCED, }; int ho_fsm(aifg_port *p, aifg_msg_t *upper_msg, aifg_msg_pre_decoded *peer_msg) { int retVal = HO_PROCECCED; switch(p->ho_stat){ case HO_IDLE: { if (peer_msg->id == AIFG_MSG_ID_HO_REQUIRED){ peer_msg->app_port = p->upper_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); p->app_ho_port = peer_msg->app_port; p->ho_stat = HO_SETUP_NEW_LINK; p->timer = AIFG_TIMER_TRANS_TIMEOUT; } else{ assert(0); retVal = HO_NOT_PROCECCED; goto ERROR_PROC; } } break; case HO_SETUP_NEW_LINK: { if (upper_msg != NULL ){ if (upper_msg->id == AIFG_MSG_ID_HO_REQUEST){ p->new_link = aifg_send_cr(p->sapid, p->cgid, upper_msg); aifg_add_link(p->new_link, p->sapid); link_info[p->new_link].cur_port = p - aifg_pcb; p->ho_stat = HO_EXECUTE; p->timer = AIFG_TIMER_TRANS_TIMEOUT; } else if (upper_msg->id == AIFG_MSG_ID_HO_REQ_REJ){ aifg_send_dt1(p->link_id, upper_msg, -1); p->ho_stat = 0; } else retVal = HO_NOT_PROCECCED; } else if(p->timer == 0) goto ERROR_PROC; else retVal = HO_NOT_PROCECCED; } break; case HO_EXECUTE: { if (upper_msg != NULL){ switch(upper_msg->id) { case AIFG_MSG_ID_HO_CMD: aifg_send_dt1(p->link_id, upper_msg, -1); retVal = HO_PROCECCED; p->ho_stat = HO_WAIT_COMPLETE; p->timer = AIFG_TIMER_TRANS_TIMEOUT; break; default: retVal = HO_NOT_PROCECCED; break; } } else if(peer_msg != NULL){ switch(peer_msg->id) { case AIFG_MSG_ID_HO_FAIL: //rollback to HO_SETUP_NEW_LINK p->ho_stat = HO_SETUP_NEW_LINK; //no break here case AIFG_MSG_ID_HO_REQ_ACK: case AIFG_MSG_ID_QUEUE_IND: peer_msg->app_port = p->app_ho_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); break; default: retVal = HO_NOT_PROCECCED; break; } } else if(p->timer == 0) goto ERROR_PROC; } break; case HO_WAIT_COMPLETE: { if(peer_msg != NULL){ switch(peer_msg->id) { case AIFG_MSG_ID_HO_DETECT: peer_msg->app_port = p->app_ho_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); break; case AIFG_MSG_ID_HO_CMP: p->ho_stat = HO_CLEAR_OLD_LINK; peer_msg->app_port = p->app_ho_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); break; case AIFG_MSG_ID_HO_FAIL: p->ho_stat = HO_CLEAR_NEW_LINK; peer_msg->app_port = p->app_ho_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); break; default: retVal = HO_NOT_PROCECCED; break; } } else if(p->timer == 0) goto ERROR_PROC; else retVal = HO_NOT_PROCECCED; } break; case HO_CLEAR_OLD_LINK: { sd_msg.aif_port = p - aifg_pcb; //for debug print sd_msg.app_port = p->upper_port;//for debug print sd_msg.pd = AIFG_PD_BSSMAP_DEDICATED; sd_msg.id = AIFG_MSG_ID_CLR_CMD; sd_msg.msg.clearCmd.cause.flag = 1; sd_msg.msg.clearCmd.cause.ext_value.flag = 0; sd_msg.msg.clearCmd.cause.value = REL_CAUSE_HO_SUCCESS; sd_msg.msg.clearCmd.l3HeaderInfo.flag = 0; aifg_send_dt1(p->link_id, &sd_msg, p->ti); p->ho_stat = HO_WAIT_OLD_CLEAR_CMP; p->timer = AIFG_TIMER_CLEAR_TIMEOUT; } break; case HO_WAIT_OLD_CLEAR_CMP: { if((peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_CLR_CMP)|| p->timer <= 0){ int old_link = p->link_id; aifg_pcb[link_info[old_link].cur_port].link_id = p->new_link; if(link_info[old_link].ti_number > 0){ //handover all transaction on the old link to the new link int i = 0; while(link_info[old_link].ti_number > 0 && i < AIFG_MAX_TI_PER_LINK){ if(link_info[old_link].ti[TI_FOR_CC][i].en_flag == 1){ aifg_pcb[link_info[old_link].ti[TI_FOR_CC][i].port].link_id = p->new_link; link_info[old_link].ti_number--; } if(link_info[old_link].ti[TI_FOR_SMS][i].en_flag == 1){ aifg_pcb[link_info[old_link].ti[TI_FOR_SMS][i].port].link_id = p->new_link; link_info[old_link].ti_number--; } if(link_info[old_link].ti[TI_FOR_SS][i].en_flag == 1){ aifg_pcb[link_info[old_link].ti[TI_FOR_SS][i].port].link_id = p->new_link; link_info[old_link].ti_number--; } i++; } } link_info[old_link].cleared = 1; aifg_send_rlsd(old_link); p->ho_stat = 0; //Handover completed aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_TRANS_TIMEOUT); } } break; case HO_CLEAR_NEW_LINK: { sd_msg.aif_port = p - aifg_pcb; //for debug print sd_msg.app_port = p->upper_port;//for debug print sd_msg.pd = AIFG_PD_BSSMAP_DEDICATED; sd_msg.id = AIFG_MSG_ID_CLR_CMD; sd_msg.msg.clearCmd.cause.flag = 1; sd_msg.msg.clearCmd.cause.ext_value.flag = 0; sd_msg.msg.clearCmd.cause.value = REL_CAUSE_CALL_CONTROL; sd_msg.msg.clearCmd.l3HeaderInfo.flag = 0; aifg_send_dt1(p->new_link, &sd_msg, p->ti); p->ho_stat = HO_WAIT_NEW_CLEAR_CMP; p->timer = AIFG_TIMER_CLEAR_TIMEOUT; } break; case HO_WAIT_NEW_CLEAR_CMP: if((peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_CLR_CMP)|| p->timer <= 0){ link_info[p->new_link].cleared = 1; aifg_send_rlsd(p->new_link); p->new_link = -1; p->ho_stat = 0; //Handover failed } else retVal = HO_NOT_PROCECCED; break; default: assert(0); goto ERROR_PROC; break; } return retVal; ERROR_PROC: p->ho_stat = 0; return retVal; } enum CC_STATE{ CC_WAIT_SETUP, CC_CONNECTING, CC_CONNECTED, CC_DISCONNECTING, CC_WAIT_RELEASE, CC_RELEASING, CC_WAIT_RELEASE_CMP, CC_RELEASE_CMP, CC_CLEARING, CC_WAIT_CLEAR_CMP, CC_HANDOVER, }; int cc_fsm(aifg_port *p, aifg_msg_t *upper_msg, aifg_msg_pre_decoded *peer_msg) { if (peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_CLR_REQ){ p->rel_cause = aifg_get_cause_value(&peer_msg->msg.clearReq.cause); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); p->ti_stat = CC_CLEARING; p->timer = 0; } switch(p->ti_stat) { case CC_WAIT_SETUP: { if(upper_msg != NULL){ if (upper_msg->pd == AIFG_PD_DTAP_CC && p->ti == -1){ //assign a new ti for the transaction p->ti = aifg_get_ti(p->link_id, p-aifg_pcb, TI_FOR_CC); if(p->ti == -1){ aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, REL_CAUSE_PROTOCOL_ERR); p->rel_cause = REL_CAUSE_PROTOCOL_ERR; p->ti_stat = CC_CLEARING; aifg_debug_print(p-aifg_pcb, AIFG_ERR_CAN_NOT_FIND_TI, NULL, p-aifg_pcb); #ifdef _AIFG_DEBUG_ assert(0); #endif } } switch(upper_msg->id){ case AIFG_MSG_ID_SETUP: p->ti_stat = CC_CONNECTING; aifg_send_dt1(p->link_id, upper_msg, p->ti); break; case AIFG_MSG_ID_RELEASE: p->rel_cause = upper_msg->msg.release.cause1.cause_value; p->ti_stat = CC_RELEASING; p->app_rel_flag = 1; break; default: aifg_send_dt1(p->link_id, upper_msg, p->ti); break; } } else if(peer_msg != NULL){ if(peer_msg->pd == AIFG_PD_DTAP_CC && p->ti == -1){ p->ti = peer_msg->ti; aifg_add_ti(p->link_id, p->ti, TI_FOR_CC, p-aifg_pcb); } switch(peer_msg->id){ case AIFG_MSG_ID_DISCONNECT: p->ti_stat = CC_RELEASING; p->rel_cause = aifg_get_cause_value(&peer_msg->msg.disconnect.cause); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); break; case AIFG_MSG_ID_RELEASE: p->ti_stat = CC_RELEASE_CMP; p->rel_cause = aifg_get_cause_value(&peer_msg->msg.release.cause1); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); break; case AIFG_MSG_ID_RELEASE_CMP: p->ti_stat = CC_CLEARING; p->rel_cause = aifg_get_cause_value(&peer_msg->msg.releaseComp.cause); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); break; case AIFG_MSG_ID_EMERGENCY_SETUP: case AIFG_MSG_ID_SETUP: p->ti_stat = CC_CONNECTING; //no break here default: peer_msg->app_port = p->upper_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); break; } } else if(p->timer == 0){ p->rel_cause = REL_CAUSE_TIMER_EXPIRE; //protocol timeout aifg_debug_print(p-aifg_pcb, AIFG_ERR_PORT_TIMER_OUT, NULL, p-aifg_pcb); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); p->ti_stat = CC_CLEARING; } if (p->ti_stat != CC_WAIT_SETUP && p->ti_stat!=CC_RELEASE_CMP){ //status changed aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_TRANS_TIMEOUT); } } break; case CC_CONNECTING: { if(upper_msg != NULL){ switch(upper_msg->id){ case AIFG_MSG_ID_CONNECT: p->ti_stat = CC_CONNECTED; aifg_send_dt1(p->link_id, upper_msg, p->ti); break; case AIFG_MSG_ID_RELEASE: p->rel_cause = upper_msg->msg.release.cause1.cause_value; if(upper_msg->msg.release.cause1.diag_len > 0){ p->diag_len = upper_msg->msg.release.cause1.diag_len; memcpy(p->diagnostic, upper_msg->msg.release.cause1.diagnostic, p->diag_len); } else p->diag_len = 0; p->ti_stat = CC_DISCONNECTING; p->app_rel_flag = 1; break; default: aifg_send_dt1(p->link_id, upper_msg, p->ti); break; } aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_TRANS_TIMEOUT); } else if(peer_msg != NULL){ switch(peer_msg->id){ case AIFG_MSG_ID_DISCONNECT: p->ti_stat = CC_RELEASING; p->rel_cause = aifg_get_cause_value(&peer_msg->msg.disconnect.cause); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); break; case AIFG_MSG_ID_RELEASE: p->ti_stat = CC_RELEASE_CMP; p->rel_cause = aifg_get_cause_value(&peer_msg->msg.release.cause1); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); break; case AIFG_MSG_ID_RELEASE_CMP: p->ti_stat = CC_CLEARING; p->rel_cause = aifg_get_cause_value(&peer_msg->msg.releaseComp.cause); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); break; case AIFG_MSG_ID_CONNECT: p->ti_stat = CC_CONNECTED; //no break here default: peer_msg->app_port = p->upper_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); break; } aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_TRANS_TIMEOUT); } else if(p->timer == 0){ p->rel_cause = REL_CAUSE_TIMER_EXPIRE; //protocol timeout aifg_debug_print(p-aifg_pcb, AIFG_ERR_PORT_TIMER_OUT, NULL, p-aifg_pcb); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); p->ti_stat = CC_RELEASE_CMP; } if (p->ti_stat!=CC_CONNECTING && p->ti_stat!=CC_RELEASE_CMP){ //status changed aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_TRANS_TIMEOUT); } } break; case CC_CONNECTED: { if(upper_msg != NULL){ if(upper_msg->id == AIFG_MSG_ID_RELEASE){ p->rel_cause = upper_msg->msg.release.cause1.cause_value; if(upper_msg->msg.release.cause1.diag_len > 0){ p->diag_len = upper_msg->msg.release.cause1.diag_len; memcpy(p->diagnostic, upper_msg->msg.release.cause1.diagnostic, p->diag_len); } else p->diag_len = 0; p->ti_stat = CC_DISCONNECTING; p->app_rel_flag = 1; } else aifg_send_dt1(p->link_id, upper_msg, p->ti); } else if(peer_msg != NULL){ switch(peer_msg->id){ case AIFG_MSG_ID_DISCONNECT: p->ti_stat = CC_RELEASING; p->rel_cause = aifg_get_cause_value(&peer_msg->msg.disconnect.cause); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); break; case AIFG_MSG_ID_RELEASE: p->ti_stat = CC_RELEASE_CMP; p->rel_cause = aifg_get_cause_value(&peer_msg->msg.release.cause1); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); break; case AIFG_MSG_ID_RELEASE_CMP: p->ti_stat = CC_CLEARING; p->rel_cause = aifg_get_cause_value(&peer_msg->msg.releaseComp.cause); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); break; default: peer_msg->app_port = p->upper_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); break; } } } break; case CC_DISCONNECTING: { memset(&sd_msg.msg.disconnect, 0 ,sizeof(sd_msg.msg.disconnect)); sd_msg.aif_port = p - aifg_pcb; //for debug print sd_msg.app_port = p->upper_port;//for debug print sd_msg.pd = AIFG_PD_DTAP_CC; sd_msg.id = AIFG_MSG_ID_DISCONNECT; sd_msg.msg.disconnect.cause.flag = 1; sd_msg.msg.disconnect.cause.coding_std = 3; sd_msg.msg.disconnect.cause.location = 1; sd_msg.msg.disconnect.cause.cause_value = p->rel_cause; if(p->diag_len > 0) memcpy(sd_msg.msg.disconnect.cause.diagnostic, p->diagnostic, p->diag_len); sd_msg.msg.disconnect.cause.diag_len = p->diag_len; aifg_send_dt1(p->link_id, &sd_msg, p->ti); p->ti_stat = CC_WAIT_RELEASE; aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_RELEASE_TIMEOUT); } break; case CC_WAIT_RELEASE: { if(peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_RELEASE){ p->ti_stat = CC_RELEASE_CMP; p->timer = AIFG_TIMER_WAIT_RELEASE_CMP; } else if(p->timer == 0){ p->ti_stat = CC_RELEASING; p->rel_cause = REL_CAUSE_TIMER_EXPIRE; } } break; case CC_RELEASE_CMP: { if (p->timer == 0){ memset(&sd_msg.msg.releaseCmp, 0 ,sizeof(sd_msg.msg.releaseCmp)); sd_msg.aif_port = p - aifg_pcb; //for debug print sd_msg.app_port = p->upper_port;//for debug print sd_msg.pd = AIFG_PD_DTAP_CC; sd_msg.id = AIFG_MSG_ID_RELEASE_CMP; sd_msg.msg.releaseCmp.cause.flag = 1; sd_msg.msg.releaseCmp.cause.coding_std = 3; sd_msg.msg.releaseCmp.cause.location = 1; sd_msg.msg.releaseCmp.cause.cause_value = p->rel_cause; aifg_send_dt1(p->link_id, &sd_msg, p->ti); p->ti_stat = CC_CLEARING; aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_WAIT_RELEASE_CMP); } } break; case CC_RELEASING: { memset(&sd_msg.msg.release, 0 ,sizeof(sd_msg.msg.release)); sd_msg.aif_port = p - aifg_pcb; //for debug print sd_msg.app_port = p->upper_port;//for debug print sd_msg.pd = AIFG_PD_DTAP_CC; sd_msg.id = AIFG_MSG_ID_RELEASE; sd_msg.msg.release.cause1.flag = 1; sd_msg.msg.release.cause1.coding_std = 3; sd_msg.msg.release.cause1.location = 1; sd_msg.msg.release.cause1.cause_value = p->rel_cause; aifg_send_dt1(p->link_id, &sd_msg, p->ti); p->ti_stat = CC_WAIT_RELEASE_CMP; aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_RELEASE_TIMEOUT); } break; case CC_WAIT_RELEASE_CMP: { if((peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_RELEASE_CMP) || p->timer == 0){ p->ti_stat = CC_CLEARING; aifg_reset_timer(p-aifg_pcb, 0); } } break; case CC_CLEARING: { if (p->timer <= 0){ if(aifg_del_ti(p->link_id, p->ti, TI_FOR_CC) > 0) return AIFG_PROC_FINISH; else{ //send clear command sd_msg.aif_port = p - aifg_pcb; //for debug print sd_msg.app_port = p->upper_port;//for debug print sd_msg.pd = AIFG_PD_BSSMAP_DEDICATED; sd_msg.id = AIFG_MSG_ID_CLR_CMD; sd_msg.msg.clearCmd.cause.flag = 1; sd_msg.msg.clearCmd.cause.ext_value.flag = 0; sd_msg.msg.clearCmd.cause.value = REL_CAUSE_CALL_CONTROL; sd_msg.msg.clearCmd.l3HeaderInfo.flag = 0; aifg_send_dt1(p->link_id, &sd_msg, p->ti); p->ti_stat = CC_WAIT_CLEAR_CMP; p->timer = AIFG_TIMER_CLEAR_TIMEOUT; } } } break; case CC_WAIT_CLEAR_CMP: { if((peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_CLR_CMP) || p->timer <= 0){ link_info[p->link_id].cleared = 1; return AIFG_PROC_FINISH; } } break; default: assert(0); return AIFG_PROC_FINISH; break; } return AIFG_PROC_CONTINUE; } enum SMS_STATE{ SMS_RP_TRANS, SMS_RELEASING, SMS_CLEARING, SMS_WAIT_CLEAR_CMP, }; int sms_fsm(aifg_port *p, aifg_msg_t *upper_msg, aifg_msg_pre_decoded *peer_msg) { if (peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_CLR_REQ){ p->rel_cause = aifg_get_cause_value(&peer_msg->msg.clearReq.cause); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); p->ti_stat = SMS_CLEARING; p->timer = 0; } switch(p->ti_stat){ case SMS_RP_TRANS: { if (upper_msg != NULL){ if(upper_msg->id == AIFG_MSG_ID_RELEASE){ p->ti_stat = SMS_RELEASING; p->app_rel_flag = 1; } else{ if (upper_msg->pd == AIFG_PD_DTAP_SMS && p->ti == -1){ //assign a new ti for the transaction p->ti = aifg_get_ti(p->link_id, p-aifg_pcb, TI_FOR_SMS); if(p->ti == -1){ aifg_debug_print(p-aifg_pcb, AIFG_ERR_CAN_NOT_FIND_TI, NULL, p-aifg_pcb); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, REL_CAUSE_PROTOCOL_ERR); p->ti_stat = SMS_RELEASING; #ifdef _AIFG_DEBUG_ assert(0); #endif } } aifg_send_dt1(p->link_id, upper_msg, p->ti); aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_TRANS_TIMEOUT); } } else if(peer_msg != NULL){ if(peer_msg->pd == AIFG_PD_DTAP_SMS && p->ti == -1){ p->ti = peer_msg->ti; aifg_add_ti(p->link_id, p->ti, TI_FOR_SMS, p-aifg_pcb); } peer_msg->app_port = p->upper_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_TRANS_TIMEOUT); } else if(p->timer == 0){ aifg_debug_print(p-aifg_pcb, AIFG_ERR_PORT_TIMER_OUT, NULL, p-aifg_pcb); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, REL_CAUSE_TIMER_EXPIRE); p->ti_stat = SMS_RELEASING; } } break; case SMS_RELEASING: { if(aifg_del_ti(p->link_id, p->ti, TI_FOR_SMS) == 0 && link_info[p->link_id].cur_port == p-aifg_pcb){ p->ti_stat = SMS_CLEARING; p->timer = AIFG_TIMER_WAIT_RELEASE_CMP; } else return AIFG_PROC_FINISH; } break; case SMS_CLEARING: { if (p->timer == 0){ sd_msg.aif_port = p - aifg_pcb; //for debug print sd_msg.app_port = p->upper_port;//for debug print sd_msg.pd = AIFG_PD_BSSMAP_DEDICATED; sd_msg.id = AIFG_MSG_ID_CLR_CMD; sd_msg.msg.clearCmd.cause.flag = 1; sd_msg.msg.clearCmd.cause.ext_value.flag = 0; sd_msg.msg.clearCmd.cause.value = REL_CAUSE_CALL_CONTROL; sd_msg.msg.clearCmd.l3HeaderInfo.flag = 0; aifg_send_dt1(p->link_id, &sd_msg, p->ti); p->ti_stat = SMS_WAIT_CLEAR_CMP; p->timer = AIFG_TIMER_CLEAR_TIMEOUT; } } break; case SMS_WAIT_CLEAR_CMP: { if((peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_CLR_CMP) || p->timer <= 0){ link_info[p->link_id].cleared = 1; return AIFG_PROC_FINISH; } } break; default: assert(0); return AIFG_PROC_FINISH; break; } return AIFG_PROC_CONTINUE; } enum SS_STATE{ SS_REGISTERING, SS_CLEARING, SS_WAIT_CLEAR_CMP, }; int ss_fsm(aifg_port *p, aifg_msg_t *upper_msg, aifg_msg_pre_decoded *peer_msg) { if (peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_CLR_REQ){ p->rel_cause = aifg_get_cause_value(&peer_msg->msg.clearReq.cause); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, p->rel_cause); //clear request, BSC may encounter error //send clear command without checking if there exist other transaction sd_msg.aif_port = p - aifg_pcb; //for debug print sd_msg.app_port = p->upper_port;//for debug print sd_msg.pd = AIFG_PD_BSSMAP_DEDICATED; sd_msg.id = AIFG_MSG_ID_CLR_CMD; sd_msg.msg.clearCmd.cause.flag = 1; sd_msg.msg.clearCmd.cause.ext_value.flag = 0; sd_msg.msg.clearCmd.cause.value = REL_CAUSE_CALL_CONTROL; sd_msg.msg.clearCmd.l3HeaderInfo.flag = 0; aifg_send_dt1(p->link_id, &sd_msg, p->ti); p->ti_stat = SS_WAIT_CLEAR_CMP; p->timer = AIFG_TIMER_CLEAR_TIMEOUT; } switch(p->ti_stat){ case SS_REGISTERING: { if(upper_msg != NULL){ if(upper_msg->id == AIFG_MSG_ID_RELEASE_CMP_SS){ p->ti_stat = SS_CLEARING; p->app_rel_flag = 1; } aifg_send_dt1(p->link_id, upper_msg, p->ti); } else if(peer_msg != NULL){ if (peer_msg->pd == AIFG_PD_DTAP_SS && p->ti == -1){ p->ti = peer_msg->ti; aifg_add_ti(p->link_id, p->ti, TI_FOR_SS, p-aifg_pcb); } peer_msg->app_port = p->upper_port; sap[p->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); aifg_reset_timer(p-aifg_pcb, AIFG_TIMER_TRANS_TIMEOUT); } else if(p->timer <= 0){ aifg_debug_print(p-aifg_pcb, AIFG_ERR_PORT_TIMER_OUT, NULL, p-aifg_pcb); aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, REL_CAUSE_TIMER_EXPIRE); p->ti_stat = SS_CLEARING; } } break; case SS_CLEARING: { if(aifg_del_ti(p->link_id, p->ti, TI_FOR_SS) > 0) return AIFG_PROC_FINISH; else{ memset(&sd_msg.msg.clearCmd, 0 ,sizeof(sd_msg.msg.clearCmd)); sd_msg.aif_port = p - aifg_pcb; //for debug print sd_msg.app_port = p->upper_port;//for debug print sd_msg.pd = AIFG_PD_BSSMAP_DEDICATED; sd_msg.id = AIFG_MSG_ID_CLR_CMD; sd_msg.msg.clearCmd.cause.flag = 1; sd_msg.msg.clearCmd.cause.ext_value.flag = 0; sd_msg.msg.clearCmd.cause.value = REL_CAUSE_CALL_CONTROL; sd_msg.msg.clearCmd.l3HeaderInfo.flag = 0; aifg_send_dt1(p->link_id, &sd_msg, p->ti); p->ti_stat = SS_WAIT_CLEAR_CMP; p->timer = AIFG_TIMER_CLEAR_TIMEOUT; } } break; case SS_WAIT_CLEAR_CMP: { if((peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_CLR_CMP) || p->timer <= 0){ link_info[p->link_id].cleared = 1; return AIFG_PROC_FINISH; } } break; } return AIFG_PROC_CONTINUE; } void aifg_port_proc(aifg_port *pPort, aifg_msg_t *upper_msg, aifg_msg_pre_decoded *peer_msg) { switch(pPort->stat){ case AIFG_PORT_INIT: //init { if(upper_msg != NULL){ //the port is activate by upper app switch(upper_msg->id){ case AIFG_MSG_ID_PAGING: assert(AIFG_SAP_MSC == pPort->sapid); //only MSC can send this message pPort->stat = AIFG_PORT_PAGING; paging_fsm(pPort, upper_msg, peer_msg); break; case AIFG_MSG_ID_SETUP: pPort->ti_type = AIFG_TRANS_CC; pPort->ti_stat = 0; pPort->stat = AIFG_PORT_TRANSACTION; pPort->timer = AIFG_TIMER_TRANS_TIMEOUT; cc_fsm(pPort, upper_msg, peer_msg); break; case AIFG_MSG_ID_RP_DATA: pPort->ti_type = AIFG_TRANS_SMS; pPort->ti_stat = 0; pPort->stat = AIFG_PORT_TRANSACTION; pPort->timer = AIFG_TIMER_TRANS_TIMEOUT; sms_fsm(pPort, upper_msg, peer_msg); break; case AIFG_MSG_ID_L3_INFO: { int link_id; assert(AIFG_SAP_BSC == pPort->sapid); //only BSC can send this message pPort->stat = AIFG_PORT_TRANSPARENT; link_id = aifg_send_cr(pPort->sapid, pPort->cgid, upper_msg); if(link_id < 0 || link_id > SCCP_MAX_LINK) goto ERROR_PROC; aifg_add_link(link_id, pPort->sapid); pPort->link_id = link_id; link_info[link_id].cur_port = pPort - aifg_pcb; } break; default: assert(0); goto ERROR_PROC; break; } } else if(peer_msg != NULL){ //the port is activate by peer app switch(peer_msg->id){ case AIFG_MSG_ID_RESET: peer_msg->app_port = -1; pPort->stat = AIFG_PORT_RESET; break; case AIFG_MSG_ID_L3_INFO: peer_msg->app_port = -1; pPort->stat = AIFG_PORT_TRANSACTION; pPort->timer = AIFG_TIMER_TRANS_TIMEOUT; pPort->ti = -1; pPort->ti_stat = 0; if(AIFG_MSG_ID_LU_REQUEST == peer_msg->msg.completeL3Info.l3msg.id) pPort->ti_type = AIFG_TRANS_LU; else if(AIFG_MSG_ID_IMSI_DETACH_IND == peer_msg->msg.completeL3Info.l3msg.id){ pPort->ti_type = AIFG_TRANS_LU; pPort->ti_stat = LU_CLEAR; } else if(AIFG_MSG_ID_CM_REQUEST == peer_msg->msg.completeL3Info.l3msg.id){ switch(peer_msg->msg.completeL3Info.l3msg.msg.cmRequest.type.ptr[0] & 0x0F){ //cm service type case 0x01: //MO Call pPort->ti_type = AIFG_TRANS_CC; break; case 0x04: pPort->ti_type = AIFG_TRANS_SMS; break; case 0x08: pPort->ti_type = AIFG_TRANS_SS; break; default: pPort->ti_type = AIFG_TRANS_UNKNOW; break; } } else{ assert(0); } break; case AIFG_MSG_ID_CM_REQUEST: //the app_port is set to last opened port for this message pPort->stat = AIFG_PORT_TRANSACTION; pPort->timer = AIFG_TIMER_TRANS_TIMEOUT; pPort->ti = -1; pPort->ti_stat = 0; switch(peer_msg->msg.cmReq.type.ptr[0] & 0x0F){ //cm service type case 0x01: //MO Call pPort->ti_type = AIFG_TRANS_CC; break; case 0x04: pPort->ti_type = AIFG_TRANS_SMS; break; case 0x08: pPort->ti_type = AIFG_TRANS_SS; break; default: pPort->ti_type = AIFG_TRANS_UNKNOW; break; } break; case AIFG_MSG_ID_HO_REQUEST: peer_msg->app_port = -1; pPort->stat = AIFG_PORT_TRANSPARENT; break; default: assert(0); //unexpected message goto ERROR_PROC; break; } rv_msg.trace_flag = 0; sap[pPort->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); pPort->upper_port = peer_msg->app_port; //remember new assigned app port if (rv_msg.trace_flag == 1) aifg_pcb[rv_msg.aif_port].trace_flag = rv_msg.trace_flag; //app may enable trace by setting rv_msg.trace_flag } else{ assert(0); goto ERROR_PROC; } } break; case AIFG_PORT_TRANSACTION: { switch(pPort->ti_type){ case AIFG_TRANS_LU: { int ret = lu_fsm(pPort, upper_msg, peer_msg); if(AIFG_PROC_FINISH == ret){ pPort->stat = AIFG_PORT_FINISH; } else if(AIFG_ERROR == ret) goto ERROR_PROC; } break; case AIFG_TRANS_CC: { int ret = -1; /* *when in handover state, we will first try ho_fsm *if the ho_fsm return HO_PROCECCED, the process will end here *else, we will continue to cc_fsm */ if(pPort->ho_stat != 0 || (peer_msg != NULL && peer_msg->id == AIFG_MSG_ID_HO_REQUIRED)){ //perform handover, the ho_stat will be set to 0 when the handover is completed if (HO_PROCECCED == ho_fsm(pPort, upper_msg, peer_msg)) goto CC_FINISH; /*BEWARE: switch-case may break here*/ } ret = cc_fsm(pPort, upper_msg, peer_msg); if(AIFG_PROC_FINISH == ret) pPort->stat = AIFG_PORT_FINISH; else if(AIFG_ERROR == ret) goto ERROR_PROC; } CC_FINISH: break; case AIFG_TRANS_SS: { int ret = ss_fsm(pPort, upper_msg, peer_msg); if(AIFG_PROC_FINISH == ret) pPort->stat = AIFG_PORT_FINISH; else if(AIFG_ERROR == ret) goto ERROR_PROC; } break; case AIFG_TRANS_SMS: { int ret = sms_fsm(pPort, upper_msg, peer_msg); if(AIFG_PROC_FINISH == ret) pPort->stat = AIFG_PORT_FINISH; else if(AIFG_ERROR == ret) goto ERROR_PROC; } break; case AIFG_TRANS_UNKNOW: //for paging response { aifg_pd tmp_pd; if(upper_msg != NULL) tmp_pd = upper_msg->pd; else if(peer_msg != NULL) tmp_pd = peer_msg->pd; else if(pPort->timer == 0) goto ERROR_PROC; else break; //case AIFG_TRANS_UNKNOW may break here switch(tmp_pd) { case AIFG_PD_DTAP_CC: pPort->ti_type = AIFG_TRANS_CC; cc_fsm(pPort, upper_msg, peer_msg); break; case AIFG_PD_DTAP_SMS: pPort->ti_type = AIFG_TRANS_SMS; sms_fsm(pPort, upper_msg, peer_msg); break; case AIFG_PD_DTAP_SS: pPort->ti_type = AIFG_TRANS_SS; ss_fsm(pPort, upper_msg, peer_msg); break; default: if (upper_msg != NULL){ aifg_send_dt1(pPort->link_id, upper_msg, pPort->ti); } else{ peer_msg->app_port = pPort->upper_port; sap[pPort->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); } break; } } break; default: assert(0); break; } } break; case AIFG_PORT_TRANSPARENT: { //transparent transfer if(upper_msg != NULL){ aifg_send_dt1(pPort->link_id, upper_msg, pPort->ti); } else if (peer_msg != NULL){ peer_msg->app_port = pPort->upper_port; sap[pPort->sapid].callback_func(AIFG_IND_RV_MSG, peer_msg); } } break; case AIFG_PORT_PAGING: //paging transaction { int ret = paging_fsm(pPort, upper_msg, peer_msg); if(AIFG_PROC_FINISH == ret){ //assert(NULL != p->sd_buffer); //free(p->sd_buffer); pPort->stat = AIFG_PORT_TRANSACTION; pPort->timer = AIFG_TIMER_TRANS_TIMEOUT; pPort->ti_type = AIFG_TRANS_UNKNOW; pPort->ti_stat = 0; aifg_reset_timer(pPort-aifg_pcb, AIFG_TIMER_TRANS_TIMEOUT); } else if(AIFG_ERROR == ret){ //assert(NULL != p->sd_buffer); //free(p->sd_buffer); goto ERROR_PROC; } } break; case AIFG_PORT_RESET: //reset transaction { int ret = reset_fsm(pPort, upper_msg, peer_msg); if(AIFG_PROC_FINISH == ret) pPort->stat = AIFG_PORT_FINISH; else if(AIFG_ERROR == ret) goto ERROR_PROC; } break; case AIFG_PORT_FINISH: if(pPort->link_id != -1 // && link_info[pPort->link_id].ti_number <= 0 && link_info[pPort->link_id].cleared == 1) { aifg_link_release(pPort->link_id); } else{ if(pPort->link_id != -1 && link_info[pPort->link_id].cur_port == pPort - aifg_pcb) link_info[pPort->link_id].cur_port = -1; aifg_port_release(pPort); } break; default: assert(0); goto ERROR_PROC; break; } return; ERROR_PROC: if(pPort->link_id != -1 && link_info[pPort->link_id].ti_number <= 1) //only one transaction or less // && link_info[pPort->link_id].cleared == 1) { aifg_link_release(pPort->link_id); } else{ if(link_info[pPort->link_id].cur_port == pPort - aifg_pcb) link_info[pPort->link_id].cur_port = -1; aifg_port_release(pPort); } return; } //end of FSM--------------------------------------------------------------------------------- /* Purpose:assign a free port and init Input: int sapid: SAP ID int linkid: Link ID Output: int: Port number, -1 if no port available */ int start_pos = 0; //start position inline int aifg_port_assign(int sapid, int cgid, int linkid) { int i = start_pos; int end_pos = start_pos - 1; if (end_pos < 0){ end_pos = AIFG_MAX_PORT -1 ; } while(i != end_pos){ if(aifg_pcb[i].stat == AIFG_PORT_IDLE){ aifg_pcb[i].sapid = sapid; aifg_pcb[i].cgid = cgid; aifg_pcb[i].link_id = linkid; aifg_pcb[i].upper_port = -1; //not assigned yet aifg_pcb[i].stat = AIFG_PORT_INIT; aifg_pcb[i].timer = 0; aifg_pcb[i].pNextPort = aifg_pcb[i].pPrevPort = NULL; aifg_pcb[i].ti = -1; //not assigned yet aifg_pcb[i].ti_stat = 0; aifg_pcb[i].ti_type = 0; //aifg_pcb[i].sd_buffer = NULL; //add this port to opened port list if(NULL == pOpenPort_h){ //this is the first one pOpenPort_h = &aifg_pcb[i]; aifg_pcb[i].pNextOpenPort = NULL; aifg_pcb[i].pPrevOpenPort = NULL; } else{ //add to the head of the list aifg_pcb[i].pNextOpenPort = pOpenPort_h; aifg_pcb[i].pPrevOpenPort = NULL; pOpenPort_h->pPrevOpenPort = &aifg_pcb[i]; pOpenPort_h = &aifg_pcb[i]; } //set next time start position start_pos = i + 1; if(start_pos >= AIFG_MAX_PORT) start_pos = 0; return i; } if(++i >= AIFG_MAX_PORT) i = 0; //restart from beginning } return -1; } /* Purpose:release a opened port Input: int l_port: port number Output: None */ inline void aifg_port_release(aifg_port *p) { if (p->stat == AIFG_PORT_IDLE) return; if (p->upper_port != -1 && p->app_rel_flag == 0){ //release application if not released aifg_send_release_ind(p->sapid, p->upper_port, p-aifg_pcb, REL_CAUSE_TEMP_FAILURE); } //delete this port from the opened port list if(NULL != p->pPrevOpenPort) p->pPrevOpenPort->pNextOpenPort = p->pNextOpenPort; else pOpenPort_h = p->pNextOpenPort; if(NULL != p->pNextOpenPort) p->pNextOpenPort->pPrevOpenPort = p->pPrevOpenPort; memset(p, 0, sizeof(*p)); aifg_debug_print(p-aifg_pcb, AIFG_EVENT_PORT_RELEASE, NULL, p-aifg_pcb); return; } inline void aifg_link_release(int link_id) { aifg_send_rlsd(link_id); aifg_del_link(link_id); } /* Purpose: Get local port according to specific TI Input: int ti: ti_value int link_id: search port on which link Output: int: local port number, -1 if not found */ inline int aifg_ti2lport(int ti, int link_id, int pd) { int ti_type; assert(ti >=0 && ti < AIFG_MAX_TI_PER_LINK); assert(link_id >=0 && link_id < SCCP_MAX_LINK); switch(pd) { case AIFG_PD_DTAP_CC: ti_type = TI_FOR_CC; break; case AIFG_PD_DTAP_SMS: ti_type = TI_FOR_SMS; break; case AIFG_PD_DTAP_SS: ti_type = TI_FOR_SS; break; default: assert(0); } if(1 == link_info[link_id].ti[ti_type][ti].en_flag) return link_info[link_id].ti[ti_type][ti].port; return -1; } /* Purpose:get the paging port according to the IMSI Input: BYTE imsi_ptr: pointer to imsi buffer Output: local port number, -1 if not found */ inline int aifg_get_paging_port(int cgid, BYTE *imsi_ptr, int imsi_len) { int retVal = -1; aifg_port *pPort = pOpenPort_h; //pPagPort_h; aifg_port *pTmpPort; int i = 0; while (pPort != NULL){ pTmpPort = pPort->pNextOpenPort; //pPort->pNextPort; if(pPort->stat == AIFG_PORT_PAGING){ if(memcmp(pPort->imsi, imsi_ptr, imsi_len) == 0){ if (pPort->cgid == cgid){ retVal = pPort-aifg_pcb; // aifg_del_paging_port(pPort); } else{ pPort->app_rel_flag = 1; // aifg_del_paging_port(pPort); aifg_port_release(pPort); } } } pPort = pTmpPort; if(++i > AIFG_MAX_PORT){ //for protection break; } } return retVal; } inline void aifg_add_paging_port(aifg_port *p) { p->pPrevPort = NULL; p->pNextPort = NULL; if (NULL == pPagPort_t){ assert(pPagPort_h == NULL); //pointer to head should also be NULL pPagPort_h = p; pPagPort_t = p; } else{ p->pPrevPort = pPagPort_t; pPagPort_t->pNextPort = p; pPagPort_t = p; } paging_port_count++; } inline void aifg_del_paging_port(aifg_port *p) { if(pPagPort_h == p) pPagPort_h = p->pNextPort; //update list head if(pPagPort_t == p) pPagPort_t = p->pPrevPort; //update list tail if (p->pPrevPort != NULL){ p->pPrevPort->pNextPort = p->pNextPort; } if (p->pNextPort != NULL){ p->pNextPort->pPrevPort = p->pPrevPort; } p->pNextPort = NULL; p->pPrevPort = NULL; paging_port_count--; } //Circuit group & link management functions------------------------------------- inline int aifg_get_cg(int dpc, int ni) { int i = 0; while(i < AIFG_MAX_CG){ if(cg[i].enable == 1 && cg[i].dpc == dpc && cg[i].ni == ni) return i; i++; } return -1; } /* Purpose: Get SCCP link info from its ID Input: int sccp_link_id: ID of the connection Output: aifg_link_info: SCCP link structure pointer */ inline aifg_link_info *aifg_get_link_info(int linkid) { assert(linkid < SCCP_MAX_LINK); assert(link_info[linkid].en_flag == 1); return &link_info[linkid]; } /* Purpose: Add a sccp link object to the link pool Input: int linkid:ID of the link, assigned by SCCP module int sapid: which sap manage this link int status: next message is CC or DT1 Output: int: result */ inline int aifg_add_link(int linkid, int sapid) { link_info[linkid].en_flag = 1; link_info[linkid].ti_number = 0; link_info[linkid].sapid = sapid; link_info[linkid].cur_port = -1; return AIFG_SUCCEED; } /* Purpose: Delete specific connection from pool Input: int sccp_link_id: ID of the connection Output: int: result */ inline int aifg_del_link(int link_id) { int i = 0; assert(link_id < SCCP_MAX_LINK); if(link_id > SCCP_MAX_LINK) return AIFG_ERROR; //release ports belongs to this link, if any while(link_info[link_id].ti_number > 0){ if (1 == link_info[link_id].ti[TI_FOR_CC][i].en_flag){ link_info[link_id].ti_number--; aifg_port_release(&aifg_pcb[link_info[link_id].ti[TI_FOR_CC][i].port]); } if (1 == link_info[link_id].ti[TI_FOR_SMS][i].en_flag){ link_info[link_id].ti_number--; aifg_port_release(&aifg_pcb[link_info[link_id].ti[TI_FOR_SMS][i].port]); } if (1 == link_info[link_id].ti[TI_FOR_SS][i].en_flag){ link_info[link_id].ti_number--; aifg_port_release(&aifg_pcb[link_info[link_id].ti[TI_FOR_SS][i].port]); } if (++i > AIFG_MAX_TI_PER_LINK) break; } if(aifg_pcb[link_info[link_id].cur_port].ho_stat == 0) aifg_port_release(&aifg_pcb[link_info[link_id].cur_port]); memset(&link_info[link_id], 0, sizeof(aifg_link_info)); return AIFG_SUCCEED; } //end of Circuit group & link management functions--------------------------------- //TI management function definition----------------------------------------------------- /* Purpose: get a new free TI of a link and add it Input: int link_id: link ID int port:port number of upper layer Output: int: new assigned TI, -1 if not found */ inline int aifg_get_ti(int link_id, int port, int ti_type) { int i; assert(link_id < SCCP_MAX_LINK); for(i=0; i < 7; i++){ if (0 == link_info[link_id].ti[ti_type][i].en_flag){ aifg_add_ti(link_id, i, ti_type, port); return i; } } return -1; } /* Purpose: Add a new TI for a existed SCCP link Input: int link_id: link ID of the TI int ti: TI value int port: port number of upper layer Output: None */ inline void aifg_add_ti(int link_id, int ti, int ti_type, int port) { assert(ti <= AIFG_MAX_TI_PER_LINK); assert(link_id < SCCP_MAX_LINK); assert(ti_type < 3); assert(link_info[link_id].ti[ti_type][ti].en_flag != 1); link_info[link_id].ti[ti_type][ti].en_flag = 1; link_info[link_id].ti[ti_type][ti].port = port; link_info[link_id].ti_number++; return; } /* Purpose: Delete a terminated TI Input: int link_id: link ID of the TI int ti: TI value int ti_type: could be 1 of the 3: TI_FOR_CC, TI_FOR_SMS, TI_FOR_SS Output: int: remaining TI number */ inline int aifg_del_ti(int link_id, int ti, int ti_type) { assert(ti <= AIFG_MAX_TI_PER_LINK); assert(link_id < SCCP_MAX_LINK); assert(ti_type < 3); if (ti >= 0 && link_info[link_id].ti[ti_type][ti].en_flag > 0){ link_info[link_id].ti[ti_type][ti].en_flag = 0; link_info[link_id].ti_number--; } return link_info[link_id].ti_number; } //end of TI management function definition----------------------------------------------