/*---------------------------------------------------------------------------* * handle setup response message from userland *---------------------------------------------------------------------------*/ void n_connect_response(struct call_desc *cd, int response, int cause) { struct isdn_l3_driver *d = cd->l3drv; int chstate; T400_stop(cd); cd->response = response; cd->cause_out = cause; switch(response) { case SETUP_RESP_ACCEPT: next_l3state(cd, EV_SETACRS); chstate = BCH_ST_USED; break; case SETUP_RESP_REJECT: next_l3state(cd, EV_SETRJRS); chstate = BCH_ST_FREE; break; case SETUP_RESP_DNTCRE: next_l3state(cd, EV_SETDCRS); chstate = BCH_ST_FREE; break; default: /* failsafe */ next_l3state(cd, EV_SETDCRS); chstate = BCH_ST_FREE; NDBGL3(L3_ERR, "unknown response, doing SETUP_RESP_DNTCRE"); break; } if((cd->channelid >= 0) && (cd->channelid < d->nbch)) { d->bch_state[cd->channelid] = chstate; /* * XXX: don't call l2 function for active cards */ if (d->l3driver->N_DOWNLOAD == NULL) i4b_l2_channel_set_state(cd->l3drv, cd->channelid, chstate); update_controller_leds(d); } else { NDBGL3(L3_MSG, "Warning, invalid channelid %d, response = %d\n", cd->channelid, response); } }
/*---------------------------------------------------------------------------* * L3 FSM state U12 event RELEASE from L2 *---------------------------------------------------------------------------*/ static void F_12J(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_12J executing"); i4b_l3_tx_release_complete(cd, 0); i4b_l4_disconnect_ind(cd); freecd_by_cd(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U19 event RELEASE COMPLETE from L2 *---------------------------------------------------------------------------*/ static void F_19K(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_19K executing"); T308_stop(cd); i4b_l4_disconnect_ind(cd); freecd_by_cd(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U3 event CONNECT from L2 *---------------------------------------------------------------------------*/ static void F_03O(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_03O executing"); T310_stop(cd); i4b_l3_tx_connect_ack(cd); /* CONNECT ACK to network */ i4b_l4_connect_active_ind(cd); }
/*---------------------------------------------------------------------------* * L3 FSM some states event RELEASE COMPLETE from L2 *---------------------------------------------------------------------------*/ static void F_RELCP(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_RELCP executing"); i4b_l3_stop_all_timers(cd); i4b_l4_disconnect_ind(cd); freecd_by_cd(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U1 event CONNECT from L2 (XXX !) *---------------------------------------------------------------------------*/ static void F_01O(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_01O executing"); T303_stop(cd); i4b_l3_tx_connect_ack(cd); i4b_l4_connect_active_ind(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U1 event CALL PROCEEDING from L2 *---------------------------------------------------------------------------*/ static void F_01M(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_01M executing"); T303_stop(cd); T310_start(cd); i4b_l4_proceeding_ind(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U1 event RELEASE COMPLETE from L2 *---------------------------------------------------------------------------*/ static void F_01K(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_01K executing"); T303_stop(cd); i4b_l4_disconnect_ind(cd); /* tell l4 we were rejected */ freecd_by_cd(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U12 event release req from L4 *---------------------------------------------------------------------------*/ static void F_12C(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_12C executing"); i4b_l3_tx_release(cd, 1); cd->T308_first_to = 1; T308_start(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U3 event PROGESS IND from L2 *---------------------------------------------------------------------------*/ static void F_03P(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_03P executing"); T310_stop(cd); #ifdef NOTDEF i4b_l4_progress_ind(cd); #endif }
/*---------------------------------------------------------------------------* * L3 FSM relevant states event DL ESTABLISH IND from L2 *---------------------------------------------------------------------------*/ static void F_DLEI(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_DLEI executing"); /* XXX */ /* remain in current state */ }
/*---------------------------------------------------------------------------* * L3 FSM state U1 event disconnect req from L4 *---------------------------------------------------------------------------*/ static void F_01B(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_01B executing"); /* cause from L4 */ i4b_l3_tx_disconnect(cd); T303_stop(cd); T305_start(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U8 event T313 timeout *---------------------------------------------------------------------------*/ static void F_08Z(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_08Z executing"); cd->cause_out = 102; /* recovery on timer expiry */ i4b_l3_tx_disconnect(cd); T305_start(cd); i4b_l4_disconnect_ind(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U3 event release req from L4 *---------------------------------------------------------------------------*/ static void F_03C(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_03C executing"); T310_stop(cd); cd->cause_out = 6; i4b_l3_tx_release(cd, 1); /* 0 = don't send cause */ cd->T308_first_to = 1; T308_start(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U10 event DL RELEASE IND from L2 *---------------------------------------------------------------------------*/ static void F_DLRIA(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_DLRIA executing"); if(cd->T309 == TIMER_IDLE) T309_start(cd); DL_Est_Req(ctrl_desc[cd->controller].unit); }
/*---------------------------------------------------------------------------* * timer T303 start *---------------------------------------------------------------------------*/ void T303_start(call_desc_t *cd) { if (cd->T303 == TIMER_ACTIVE) return; NDBGL3(L3_T_MSG, "cr = %d", cd->cr); cd->T303 = TIMER_ACTIVE; START_TIMER(cd->T303_callout, T303_timeout, cd, T303VAL); }
/*---------------------------------------------------------------------------* * timer T303 start *---------------------------------------------------------------------------*/ void T303_start(call_desc_t *cd) { if (cd->T303 == TIMER_ACTIVE) return; NDBGL3(L3_T_MSG, "cr = %d", cd->cr); cd->T303 = TIMER_ACTIVE; callout_reset(&cd->T303_timeout, T303VAL, (void *)T303_timeout, cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U0 event STATUS from L2 *---------------------------------------------------------------------------*/ static void F_00I(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_00I executing"); if(cd->call_state != 0) { cd->cause_out = 101; i4b_l3_tx_release_complete(cd, 1); /* 1 = send cause */ } cd->Q931state = ST_U0; }
/*---------------------------------------------------------------------------* * L3 FSM any state event T309 timeout *---------------------------------------------------------------------------*/ static void F_309TO(call_desc_t *cd) { NDBGL3(L3_F_ERR, "FSM function F_309TO executing"); /* XXX */ #ifdef NOTDEF i4b_l4_dl_fail_ind(cd); #endif freecd_by_cd(cd); }
/*---------------------------------------------------------------------------* * timer T303 stop *---------------------------------------------------------------------------*/ void T303_stop(call_desc_t *cd) { CRIT_VAR; CRIT_BEG; if(cd->T303 != TIMER_IDLE) { STOP_TIMER(cd->T303_callout, T303_timeout, cd); cd->T303 = TIMER_IDLE; } CRIT_END; NDBGL3(L3_T_MSG, "cr = %d", cd->cr); }
/*---------------------------------------------------------------------------* * event handler *---------------------------------------------------------------------------*/ void next_l3state(call_desc_t *cd, int event) { int currstate, newstate; if(event > N_EVENTS) panic("i4b_l3fsm.c: event > N_EVENTS\n"); currstate = cd->Q931state; if(currstate > N_STATES) panic("i4b_l3fsm.c: currstate > N_STATES\n"); newstate = l3state_tab[event][currstate].newstate; if(newstate > N_STATES) panic("i4b_l3fsm.c: newstate > N_STATES\n"); NDBGL3(L3_F_MSG, "L3 FSM event [%s]: [%s => %s]", l3event_text[event], l3state_text[currstate], l3state_text[newstate]); /* execute function */ (*l3state_tab[event][currstate].func)(cd); if(newstate == ST_ILL) { newstate = currstate; NDBGL3(L3_F_ERR, "FSM illegal state, state = %s, event = %s!", l3state_text[newstate], l3event_text[event]); } if(newstate != ST_SUSE) cd->Q931state = newstate; }
/*---------------------------------------------------------------------------* * send command to the lower layers *---------------------------------------------------------------------------*/ void n_mgmt_command(struct isdn_l3_driver *d, int cmd, void *parm) { int i; switch(cmd) { case CMR_DOPEN: NDBGL3(L3_MSG, "CMR_DOPEN for isdnif %d", d->isdnif); for(i=0; i < num_call_desc; i++) { if(call_desc[i].isdnif == d->isdnif) { call_desc[i].cdid = CDID_UNUSED; } } d->dl_est = DL_DOWN; for (i = 0; i < d->nbch; i++) d->bch_state[i] = BCH_ST_FREE; d->tei = -1; break; case CMR_DCLOSE: NDBGL3(L3_MSG, "CMR_DCLOSE for isdnif %d", d->isdnif); break; default: NDBGL3(L3_MSG, "unknown cmd %d for isdnif %d", cmd, d->isdnif); break; } i4b_mdl_command_req(d, cmd, parm); }
/*---------------------------------------------------------------------------* * timer T313 stop *---------------------------------------------------------------------------*/ void T313_stop(call_desc_t *cd) { CRIT_VAR; CRIT_BEG; if(cd->T313 != TIMER_IDLE) { cd->T313 = TIMER_IDLE; callout_stop(&cd->T313_timeout); } CRIT_END; NDBGL3(L3_T_MSG, "cr = %d", cd->cr); }
/*---------------------------------------------------------------------------* * L3 FSM some states event disconnect request from L4 *---------------------------------------------------------------------------*/ static void F_DCRQ(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_DCRQ executing"); /* stop T310 in case this is the result of an incoming call for a */ /* calledback connection */ if(cd->T310 == TIMER_ACTIVE) T310_stop(cd); /* cause from L4 */ i4b_l3_tx_disconnect(cd); T305_start(cd); cd->Q931state = ST_U11; }
/*---------------------------------------------------------------------------* * L3 FSM some states event DISCONNECT from L2 *---------------------------------------------------------------------------*/ static void F_DISC(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_DISC executing"); i4b_l3_stop_all_timers(cd); /* * no disconnect ind to L4, no jump to state U12 * instead we issue a RELEASE and jump to U19 */ i4b_l3_tx_release(cd, 0); cd->T308_first_to = 1; T308_start(cd); cd->Q931state = ST_U19; }
/*---------------------------------------------------------------------------* * L3 FSM state U6 event alert req from L4 *---------------------------------------------------------------------------*/ static void F_06D(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_06D executing"); if(i4b_get_dl_stat(cd) == DL_DOWN) { DL_Est_Req(ctrl_desc[cd->controller].unit); cd->Q931state = ST_IWL; } else { i4b_l3_tx_alert(cd); cd->Q931state = ST_U7; } }
/*---------------------------------------------------------------------------* * L3 FSM state U19 event STATUS from L2 *---------------------------------------------------------------------------*/ static void F_19I(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_19I executing"); if(cd->call_state == 0) { i4b_l4_status_ind(cd); freecd_by_cd(cd); cd->Q931state = ST_U0; } else { cd->Q931state = ST_U19; } }
/*---------------------------------------------------------------------------* * L3 FSM state U1 event SETUP ACK from L2 *---------------------------------------------------------------------------*/ static void F_01L(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_01L executing"); T303_stop(cd); /* * since this implementation does NOT support overlap sending, * we react here as if we received a CALL PROCEEDING because * several PBX's react with a SETUP ACK even if the called * number is complete AND we sent a SENDING COMPLETE in the * preceding SETUP message. (-hm) */ T310_start(cd); i4b_l4_proceeding_ind(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U6 event incoming setup accept from L4 *---------------------------------------------------------------------------*/ static void F_06E(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_06E executing"); if(i4b_get_dl_stat(cd) == DL_DOWN) { DL_Est_Req(ctrl_desc[cd->controller].unit); cd->Q931state = ST_IWA; } else { i4b_l3_tx_connect(cd); cd->Q931state = ST_U8; } T313_start(cd); }
/*---------------------------------------------------------------------------* * L3 FSM state U1 event T303 timeout *---------------------------------------------------------------------------*/ static void F_01U(call_desc_t *cd) { NDBGL3(L3_F_MSG, "FSM function F_01U executing"); if(cd->T303_first_to == 1) { cd->T303_first_to = 0; i4b_l3_tx_setup(cd); T303_start(cd); cd->Q931state = ST_U1; } else { i4b_l4_disconnect_ind(cd); freecd_by_cd(cd); cd->Q931state = ST_U0; } }