Files
svc.ems/plat/aif/src/aifg_m.c
2024-09-27 15:39:34 +08:00

1690 lines
46 KiB
C

/********************************************************************
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----------------------------------------------