1690 lines
46 KiB
C
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----------------------------------------------
|
|
|