doc: charts: illustrate new plan for ts and lchans
Add lchan and timeslot FSM charts to illustrate planning of how osmo-bsc should handle lchan assignment and release. Modify assignment, handover, lchan-release charts according to the new plan. Change-Id: I18d60de5ee932c962aad0a532965a55d570bb936
This commit is contained in:
parent
c4bb31dcad
commit
44fcc9f11e
|
@ -7,11 +7,24 @@ msc: \
|
|||
$(builddir)/assignment.png \
|
||||
$(builddir)/lchan-release.png \
|
||||
$(builddir)/ms-channel-request.png \
|
||||
$(builddir)/timeslot.png \
|
||||
$(builddir)/lchan.png \
|
||||
$(builddir)/ts-and-lchan-fsm-lifecycle.png \
|
||||
$(builddir)/handover-inter-bsc-mo.png \
|
||||
$(builddir)/handover-inter-bsc-mt.png \
|
||||
$(NULL)
|
||||
|
||||
dot: \
|
||||
$(builddir)/timeslot-fsm.png \
|
||||
$(builddir)/lchan-fsm.png \
|
||||
$(NULL)
|
||||
|
||||
$(builddir)/%.png: $(srcdir)/%.msc
|
||||
mscgen -T png -o $@ $<
|
||||
|
||||
$(builddir)/%.png: $(srcdir)/%.dot
|
||||
dot -Tpng $< > $@
|
||||
|
||||
.PHONY: poll
|
||||
poll:
|
||||
while true; do $(MAKE) msc; sleep 1; done
|
||||
while true; do $(MAKE) msc dot; sleep 1; done
|
||||
|
|
|
@ -1,190 +1,126 @@
|
|||
msc {
|
||||
hscale=3;
|
||||
ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_gscon[label="BSC conn FSM"], bsc_mgcp[label="BSC mgcp FSM"], mgw[label="MGW"], msc_[label="MSC"];
|
||||
ms [label="MS/BTS"], bsc_lchan[label="BSC lchan FSM"],
|
||||
bsc_gscon[label="BSC conn FSM"], bsc_mgcp[label="BSC mgcp FSM"], mgw_msc[label="MGW/MSC"];
|
||||
|
||||
ms note msc_ [label="lchan allocation sequence for BSSMAP Assignment Request"];
|
||||
ms note mgw_msc [label="lchan allocation sequence for BSSMAP Assignment Request"];
|
||||
|
||||
bsc <= msc_ [label="BSSMAP Assignment Request"];
|
||||
bsc box bsc [label="bssmap_handle_assignm_req()"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_A_ASSIGNMENT_CMD"];
|
||||
bsc_gscon <= mgw_msc [label="BSSMAP Assignment Request"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ASSIGNMENT_\nWAIT_LCHAN"];
|
||||
|
||||
--- [label="is the chan_mode a speech mode?"];
|
||||
bsc_lchan <- bsc_gscon [label="lchan_select_by_chan_mode(chan_mode)"];
|
||||
|||;
|
||||
--- [label="IF returned lchan is NULL"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
---;
|
||||
|||;
|
||||
bsc_gscon box bsc_gscon [label="store lchan pointer in conn->lchan_for_assignment"];
|
||||
bsc_lchan <- bsc_gscon [label="lchan_activate(FOR_ASSIGNMENT)"];
|
||||
...;
|
||||
|||;
|
||||
--- [label="on lchan FSM error or timeout"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_gscon box bsc_gscon [label="'forget' all about conn->lchan_for_assignment"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
--- [label="END: 'on error'"];
|
||||
...;
|
||||
...;
|
||||
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_CRCX_BTS (MGCP_MGW_TIMEOUT = 4s)"];
|
||||
--- [label="IF lchan FSM decides that it is an lchan for speech"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_ENSURE_MGW_ENDPOINT"];
|
||||
--- [label="IF there is an MGW endpoint for the BTS already (conn->user_plane.fi_bts)"];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
|
||||
--- [label="ELSE: no MGW endpoint for the BTS side yet"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ASSIGNMENT_\nWAIT_CRCX_BTS"];
|
||||
bsc_gscon box bsc_gscon [label="assignment_created_mgw_endpoint = true"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_create()"];
|
||||
bsc_mgcp => mgw [label="CRCX (for BTS)"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_CRCX (MGCP_MGW_TIMEOUT = 4s)"];
|
||||
bsc_gscon note bsc_mgcp [label="two timeouts running in parallel"];
|
||||
bsc_gscon note bsc_mgcp [label="note: #define MGCP_MGW_TIMEOUT exists twice,
|
||||
once in libosmo-mgcp-client,
|
||||
once in bsc_subscr_conn_fsm.c"];
|
||||
bsc_mgcp -> bsc_gscon [label="mgcp_conn_create() exits"];
|
||||
bsc_gscon -> bsc [label="bssmap_handle_assignm_req() exits"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_CRCX_RESP (MGCP_MGW_TIMEOUT = 4s)"];
|
||||
bsc_mgcp => mgw_msc [label="CRCX (for BTS)"];
|
||||
bsc_gscon note bsc_mgcp [label="conn FSM relies on mgcp FSM timeout"];
|
||||
...;
|
||||
--- [label="On Timeout"];
|
||||
bsc_gscon note bsc_gscon [label="The conn FSM likely timeouts first"];
|
||||
bsc_gscon => msc_ [label="BSSMAP Assignment Failure"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
bsc_mgcp note bsc_mgcp [label="The MGCP FSM will timeout right after that, and terminate itself,
|
||||
emitting the parent_term event set upon mgcp_conn_create():"];
|
||||
bsc_mgcp note bsc_mgcp [label="On timeouit, the MGCP FSM will terminate, emitting the parent_term
|
||||
event set upon mgcp_conn_create():"];
|
||||
bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_FAIL_BTS"];
|
||||
bsc_gscon note bsc_gscon [label="GSCON_EV_MGW_FAIL_BTS is handled by the conn FSM allstate
|
||||
handler. It sets conn->user_plane.fi_bts = NULL. There is code
|
||||
that would emit a BSSMAP Assignment Failure, but not in
|
||||
ST_ACTIVE"];
|
||||
--- [label="end: 'On Timeout'"];
|
||||
handler. It sets conn->user_plane.fi_bts = NULL."];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_ERROR"];
|
||||
bsc_lchan note bsc_gscon [label="conn FSM timeout handler exits and relies on the lchan FSM
|
||||
signalling error, which should actually happen immediately:"];
|
||||
bsc_gscon <- bsc_lchan [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
bsc_gscon box bsc_gscon [label="'forget' all about conn->lchan_for_assignment"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
|
||||
--- [label="END: 'On Timeout'"];
|
||||
...;
|
||||
|
||||
bsc_mgcp <= mgw [label="CRCX OK (for BTS)"];
|
||||
bsc_mgcp <= mgw_msc [label="CRCX OK (for BTS)"];
|
||||
bsc_mgcp box bsc_mgcp [label="libosmo-mgcp-client fsm_crcx_resp_cb()"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_READY"];
|
||||
bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_CRCX_RESP_BTS"];
|
||||
--- [label="end: 'is the chan_mode a speech mode?'"];
|
||||
|
||||
bsc_gscon note bsc_gscon [label="for mode=sign, we're still handling GSCON_EV_A_ASSIGNMENT_CMD;
|
||||
for speech mode, we're handling GSCON_EV_MGW_CRCX_RESP_BTS"];
|
||||
bsc <- bsc_gscon [label="gsm0808_assign_req()"];
|
||||
|
||||
bsc box bsc [label="lchan_alloc(): pick available lchan"];
|
||||
bsc box bsc [label="rsl_chan_activate_lchan()"];
|
||||
|
||||
--- [label="is the chosen lchan on dynamic timeslot that is currently used as PDCH?"];
|
||||
bts <= bsc [label="i) RSL RF Chan Release of PDCH (Osmocom dyn TS)"];
|
||||
bts <= bsc [label="OR ii) RSL PDCH Deact (ip.access dyn TS)"];
|
||||
bsc -> bsc_gscon [label="gsm0808_assign_req() returns early"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_ASS_COMPL (GSM0808_T10_VALUE=6s)"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ASSIGNMENT_\nWAIT_LCHAN"];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
|
||||
--- [label="END: lchan FSM decides that it is an lchan for speech"];
|
||||
...;
|
||||
bts note bsc_gscon [linecolor="red",
|
||||
label="Osmocom style dyn TS use lchan->act_timer to watch over RF Chan Release, but there
|
||||
seems to be no timer watching over PDCH Deact!"];
|
||||
...;
|
||||
bts => bsc [label="i) RSL RF Chan Release ACK (Osmocom dyn TS)"];
|
||||
bts => bsc [label="OR ii) RSL PDCH Deact ACK (ip.access dyn TS)"];
|
||||
bsc box bsc [label="rsl_chan_activate_lchan() re-invoked"];
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_ACT_REQ"];
|
||||
bts <= bsc [label="RSL Chan Activ"];
|
||||
--- [label="else (no dyn TS switchover)"];
|
||||
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_ACT_REQ"];
|
||||
bts <= bsc [label="RSL Chan Activ"];
|
||||
bsc -> bsc_gscon [label="gsm0808_assign_req() returns"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_ASS_COMPL (GSM0808_T10_VALUE=6s)"];
|
||||
---;
|
||||
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ACTIVE"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ASSIGNMENT_\nWAIT_COMPLETE\nT10, 6s"];
|
||||
ms <= bsc_gscon [label="RR Assignment"];
|
||||
...;
|
||||
--- [label="On Timeout"];
|
||||
bsc_gscon => msc_ [label="BSSMAP Assignment Failure"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_LCHAN_RELEASE"];
|
||||
bsc_gscon box bsc_gscon [label="'forget' all about conn->lchan_for_assignment"];
|
||||
--- [label="IF assignment_created_mgw_endpoint == true"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
|
||||
bsc_gscon note bsc_mgcp [label="If the MGW endpoint didn't exist before the Assignment, release
|
||||
it now. If there was one before this, it is probably still in use by a previous lchan, so
|
||||
keep it in place."];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
bsc_gscon note bsc_mgcp [linecolor="red",
|
||||
label="The mgcp FSM from CRCX above apparently lacks a cleanup action for this case.
|
||||
It should be cleaned up eventually when the conn is torn down, but we should
|
||||
release RTP endpoints as soon as possible."];
|
||||
--- [label="end: 'On Timeout'"];
|
||||
--- [label="END: 'On Timeout'"];
|
||||
...;
|
||||
|
||||
bts => bsc [label="RSL Chan Activ ACK"];
|
||||
bsc box bsc [label="rsl_rx_chan_act_ack()"];
|
||||
bsc box bsc [label="Stop lchan->act_timer"];
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_ACTIVE"];
|
||||
bsc -> bsc [label="S_LCHAN_ACTIVATE_ACK"];
|
||||
bsc box bsc [label="bsc_api.c handle_chan_ack()"];
|
||||
ms <= bsc [label="RR Assignment Command"];
|
||||
|
||||
...;
|
||||
ms note bsc_gscon [label="We rely on the overall conn FSM ST_WAIT_ASS_COMPL timeout."];
|
||||
...;
|
||||
|
||||
ms => bsc [label="RR Assignment Complete"];
|
||||
bsc box bsc [label="handle_ass_compl()"];
|
||||
--- [label="Release old lchan"];
|
||||
bsc box bsc [label="_lchan_handle_release(sacch_deact=0)"];
|
||||
bsc box bsc [label="rsl_release_sapis_from(start=1)"];
|
||||
bts <= bsc [label="RSL Release Request (Local End)..."];
|
||||
bts <= bsc [label="...for each SAPI except link_id=0"];
|
||||
bsc box bsc [label="rsl_release_request(link_id=0)"];
|
||||
bts <= bsc [label="RSL Release Request (Local End) for link_id=0"];
|
||||
bsc box bsc [label="_lchan_handle_release() returns here, the remaining release is asynchronous;
|
||||
see `End: 'Release old lchan'` below."];
|
||||
...;
|
||||
bts note bsc_gscon [linecolor="red",
|
||||
label="There seems to be no timer watching over RSL Release Request!"];
|
||||
...;
|
||||
bts => bsc [label="RSL Release Confirm..."];
|
||||
bts => bsc [label="...for each SAPI and link_id=0"];
|
||||
bsc abox bsc [label="start T3111"];
|
||||
...;
|
||||
bsc box bsc [label="T3111 expires"];
|
||||
bsc abox bsc [label="Start lchan->act_timer with lchan_deact_tmr_cb"];
|
||||
bts <= bsc [label="RSL RF Channel Release"];
|
||||
...;
|
||||
--- [label="On timeout"];
|
||||
bsc box bsc [label="lchan_deact_tmr_cb()"];
|
||||
bsc box bsc [label="rsl_lchan_mark_broken(): state=LCHAN_S_BROKEN"];
|
||||
bsc box bsc [label="lchan_free()"];
|
||||
bsc -> bsc [label="S_LCHAN_UNEXPECTED_RELEASE"];
|
||||
bsc box bsc [label="bsc_api.c handle_release()"];
|
||||
bsc box bsc [label="bsc->assign_fail()"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_RR_ASS_FAIL"];
|
||||
bsc note bsc_gscon [linecolor="orange",
|
||||
label="The name 'RR_ASS_FAIL' might suggest the event means an actual RR Assignment
|
||||
Failure message being received. Maybe this should be called GSCON_EV_ASSIGNMENT_ERROR."];
|
||||
...;
|
||||
bsc box bsc [label="bsc->clear_request()"];
|
||||
bsc box bsc [label="bsc_clear_request encodes a BSSMAP Clear Request message and passes it on
|
||||
to the conn FSM as data argument via:"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_TX_SCCP"];
|
||||
bsc_gscon => msc_ [label="BSSMAP Clear Request"];
|
||||
bsc note bsc_gscon [linecolor="red",
|
||||
label="Instead of sending an arbitrary message, the conn FSM should
|
||||
be explicitly instructed to clear the connection, to be able
|
||||
to notice if the MSC failed to respond to the Clear Request.
|
||||
Currently, this relies on the MSC responding with a Clear
|
||||
Command, hopefully, some time later."];
|
||||
--- [label="End: 'On timeout'"];
|
||||
...;
|
||||
bts => bsc [label="RSL RF Channel Release Ack"];
|
||||
bsc box bsc [label="Stop lchan->act_timer"];
|
||||
bsc box bsc [label="Stop lchan->T3111"];
|
||||
--- [label="End: 'Release old lchan'"];
|
||||
bsc box bsc [label="still in handle_ass_compl()"];
|
||||
bsc note bsc [label="officially take over new lchan: conn->lchan = conn->secondary_lchan"];
|
||||
--- [label="is BTS using IPA Abis? (osmo-bts, ip.access)"];
|
||||
bts <= bsc [label="IPACC CRCX"];
|
||||
---;
|
||||
bsc -> bsc [label="handle_ass_compl() calls bsc_api->assign_compl()"];
|
||||
--- [label="is BTS using IPA Abis? (osmo-bts, ip.access) && conn->user_plane.rtp_ip"];
|
||||
bsc box bsc [label="bsc_assign_compl()"];
|
||||
bsc note bsc [label="set ass_compl.valid = true,
|
||||
postponing GSCON_EV_RR_ASS_COMPL until after the
|
||||
IPACC MDCX ACK received in osmo_bsc_audio.c"];
|
||||
bsc box bsc [label="exit early: bsc_assign_compl()"];
|
||||
bsc box bsc [label="exit early: handle_ass_compl()"];
|
||||
bsc box bsc [label="osmo_bsc_audio.c"];
|
||||
bts => bsc [label="IPACC CRCX ACK"];
|
||||
bts <= bsc [label="IPACC MDCX"];
|
||||
bts => bsc [label="IPACC MDCX ACK"];
|
||||
bsc box bsc [label="handle_abisip_signal()"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_RR_ASS_COMPL"];
|
||||
--- [label="else"];
|
||||
bsc box bsc [label="bsc_assign_compl()"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_RR_ASS_COMPL"];
|
||||
--- ;
|
||||
|
||||
--- [label="is chan_mode a speech mode?"];
|
||||
ms => bsc_gscon [label="RR Assignment Complete"];
|
||||
bsc_gscon -> bsc_lchan [label="OLD lchan: LCHAN_EV_LCHAN_RELEASE"];
|
||||
bsc_gscon box bsc_gscon [label="conn->lchan = conn->lchan_for_assignment"];
|
||||
--- [label="IF: chan_mode a speech mode?"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_MDCX_BTS"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_modify()"];
|
||||
bsc_mgcp note bsc_mgcp [label="same mgcp FSM as above, for BTS side"];
|
||||
bsc_mgcp => mgw [label="MDCX (for BTS)"];
|
||||
bsc_mgcp <= mgw [label="MDCX OK"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_MDCX_RESP"];
|
||||
bsc_mgcp => mgw_msc [label="MDCX (for BTS)"];
|
||||
...;
|
||||
--- [label="On Timeout"];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_RELEASE"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Clear Request"];
|
||||
--- [label="END: 'On Timeout'"];
|
||||
...;
|
||||
bsc_mgcp <= mgw_msc [label="MDCX OK"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_READY"];
|
||||
bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_MDCX_RESP_BTS"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_CRCX_MSC"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_create()"];
|
||||
bsc_mgcp note bsc_mgcp [label="second mgcp FSM for MSC side"];
|
||||
bsc_mgcp => mgw [label="CRCX (for MSC)"];
|
||||
bsc_mgcp <= mgw [label="CRCX OK (for MSC)"];
|
||||
bsc_mgcp => mgw_msc [label="CRCX (for MSC)"];
|
||||
...;
|
||||
--- [label="On Timeout"];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_RELEASE"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Assignment Failure"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Clear Request"];
|
||||
--- [label="END: 'On Timeout'"];
|
||||
...;
|
||||
bsc_mgcp <= mgw_msc [label="CRCX OK (for MSC)"];
|
||||
bsc_gscon <- bsc_mgcp [label="GSCON_EV_MGW_CRCX_RESP_MSC"];
|
||||
---;
|
||||
--- [label="END: chan_mode a speech mode?"];
|
||||
|
||||
bsc_gscon => msc_ [label="BSSMAP Assignment Complete"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Assignment Complete"];
|
||||
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
msc {
|
||||
hscale=2;
|
||||
ms [label="MS via BTS"], bsc_lchan[label="BSC lchan FSM"], bsc_gscon[label="BSC conn FSM"],
|
||||
msc_[label="MSC"];
|
||||
|
||||
ms note msc_ [label="inter-BSC Handover to another BSS"];
|
||||
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
bsc_gscon box bsc_gscon [label="bsc_handover_start(): init conn->ho"];
|
||||
bsc_gscon -> bsc_gscon [label="GSCON_EV_HO_START (inter-BSC MO)"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MO_\nWAIT_HO_CMD\nT7"];
|
||||
bsc_gscon => msc_ [label="BSSMAP Handover Required"];
|
||||
...;
|
||||
--- [label="On Timeout"];
|
||||
ms note bsc_gscon [label="MS happily continues on the old lchan."];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
bsc_gscon box bsc_gscon [label="handover_end(fail)"];
|
||||
--- [label="END: 'On Timeout'"];
|
||||
...;
|
||||
bsc_gscon <= msc_ [label="BSSMAP Handover Command"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MO_\nWAIT_CLEAR_CMD\nT8"];
|
||||
ms <= bsc_gscon [label="RR Handover Command"];
|
||||
...;
|
||||
--- [label="On Timeout"];
|
||||
ms note bsc_gscon [label="MS happily continues on the old lchan."];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
bsc_gscon box bsc_gscon [label="handover_end(fail)"];
|
||||
--- [label="END: 'On Timeout'"];
|
||||
...;
|
||||
msc_ note msc_ [label="Remote BSS reported Handover Complete to the MSC, this connection has been
|
||||
superseded."];
|
||||
bsc_gscon <= msc_ [label="BSSMAP Clear Command"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_CLEARING"];
|
||||
bsc_gscon => msc_ [label="BSSMAP Clear Complete"];
|
||||
bsc_lchan <- bsc_gscon [label="LCHAN_EV_RELEASE"];
|
||||
ms <=> bsc_lchan [label="release procedure (async)"];
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
msc {
|
||||
hscale=3;
|
||||
ms [label="MS via BTS"], bsc_lchan[label="BSC lchan FSM"], bsc_gscon[label="BSC conn FSM"],
|
||||
bsc_mgcp[label="BSC mgcp FSM"], mgw_msc[label="MGW/MSC"];
|
||||
|
||||
ms note mgw_msc [label="inter-BSC Handover, from remote BSS"];
|
||||
|
||||
bsc_gscon <= mgw_msc [label="N-Connect: BSSMAP Handover Request"];
|
||||
bsc_gscon box bsc_gscon [label="bsc_subscr_con_allocate()"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_WAIT_LCHAN"];
|
||||
bsc_gscon box bsc_gscon [label="lchan_select_by_chan_mode()"];
|
||||
bsc_lchan <- bsc_gscon [label="lchan_activate(lchan, FOR_HANDOVER)"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_TS_READY"];
|
||||
...;
|
||||
--- [label="on no lchan, lchan FSM error or timeout"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_gscon box bsc_gscon [label="handover_end(fail)"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Handover Failure"];
|
||||
ms note bsc_gscon [label="MS happily continues on the old lchan."];
|
||||
--- [label="END: 'on error'"];
|
||||
...;
|
||||
|
||||
--- [label="IF lchan FSM decides that it is an lchan for speech"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_MGW_ENDPOINT_AVAILABLE"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_ENSURE_MGW_ENDPOINT"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_CRCX_BTS"];
|
||||
bsc_gscon box bsc_gscon [label="handover_created_mgw_endpoint = true"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_create()"];
|
||||
bsc_mgcp => mgw_msc [label="CRCX (for BTS)"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_CRCX_RESP (MGCP_MGW_TIMEOUT = 4s)"];
|
||||
bsc_gscon note bsc_mgcp [label="conn FSM relies on mgcp FSM timeout"];
|
||||
...;
|
||||
--- [label="On Timeout"];
|
||||
bsc_mgcp note bsc_mgcp [label="On timeout, the MGCP FSM will terminate, emitting the parent_term
|
||||
event set upon mgcp_conn_create():"];
|
||||
bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_FAIL_BTS"];
|
||||
bsc_gscon note bsc_gscon [label="GSCON_EV_MGW_FAIL_BTS is handled by the conn FSM allstate
|
||||
handler. It sets conn->user_plane.fi_bts = NULL."];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_ERROR"];
|
||||
bsc_lchan note bsc_gscon [label="conn FSM error handler exits and relies on the lchan FSM
|
||||
signalling error, which should actually happen immediately:"];
|
||||
bsc_gscon <- bsc_lchan [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
|
||||
bsc_gscon box bsc_gscon [label="handover_end(fail)"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Handover Failure"];
|
||||
ms note bsc_gscon [label="MS happily continues on the old lchan."];
|
||||
--- [label="END: 'On Timeout'"];
|
||||
...;
|
||||
|
||||
bsc_mgcp <= mgw_msc [label="CRCX OK (for BTS)"];
|
||||
bsc_mgcp box bsc_mgcp [label="libosmo-mgcp-client fsm_crcx_resp_cb()"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_READY"];
|
||||
bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_CRCX_RESP_BTS"];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_ACTIV_ACK"];
|
||||
bsc_gscon note bsc_gscon [label="MSC-side CRCX needs from Handover Required the RTP IP address
|
||||
and port of the MSC's MGW; from MGW CRCX ACK (BTS) the conn->user_plane.mgw_endpoint; The
|
||||
Call-ID, which we actually derive from the SCCP connection ID"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_WAIT_CRCX_MSC"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_create()"];
|
||||
bsc_mgcp note bsc_mgcp [label="second mgcp FSM for MSC side"];
|
||||
bsc_mgcp => mgw_msc [label="CRCX (for MSC)"];
|
||||
...;
|
||||
--- [label="On Timeout"];
|
||||
bsc_mgcp note bsc_mgcp [label="On timeout, the MGCP FSM will terminate, emitting the parent_term
|
||||
event set upon mgcp_conn_create():"];
|
||||
bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_FAIL_MSC"];
|
||||
bsc_gscon note bsc_gscon [label="GSCON_EV_MGW_FAIL_MSC is handled by the conn FSM allstate
|
||||
handler. It sets conn->user_plane.fi_msc = NULL."];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_RELEASE"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete() (FSM for BTS)"];
|
||||
bsc_gscon box bsc_gscon [label="handover_end(fail)"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Handover Failure"];
|
||||
ms note bsc_gscon [label="MS happily continues on the old lchan."];
|
||||
--- [label="END: 'On Timeout'"];
|
||||
...;
|
||||
bsc_mgcp <= mgw_msc [label="CRCX OK (for MSC)"];
|
||||
bsc_gscon <- bsc_mgcp [label="GSCON_EV_MGW_CRCX_RESP_MSC"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_WAIT_LCHAN"];
|
||||
--- [label="END: chan_mode a speech mode?"];
|
||||
--- [label="END: lchan FSM decides that it is an lchan for speech"];
|
||||
...;
|
||||
...;
|
||||
|
||||
bsc_lchan note bsc_lchan [label="TODO: when does the MS send RLL Establish Ind? I guess like
|
||||
this:"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_RLL_ESTABLISH"];
|
||||
ms => bsc_lchan [label="RLL Establish Ind"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ACTIVE"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_\nWAIT_HO_ACCEPT\nsanity timer?"];
|
||||
bsc_gscon box bsc_gscon [label="Compose RR Handover Command"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Handover Request Acknowledge"];
|
||||
mgw_msc note mgw_msc [label="MSC forwards the RR HO Cmd to the remote BSS"];
|
||||
|
||||
...;
|
||||
--- [label="On timeout"];
|
||||
bsc_lchan <- bsc_gscon [label="NEW lchan: LCHAN_EV_RELEASE"];
|
||||
ms <=> bsc_lchan [label="release procedure (async)"];
|
||||
bsc_gscon box bsc_gscon [label="handover_end(fail)"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Clear Request"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
|
||||
ms note bsc_gscon [label="MS happily continues on the old lchan."];
|
||||
--- [label="END: On timeout"];
|
||||
...;
|
||||
ms => bsc_gscon [label="RR Handover Accept"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Handover Detect"];
|
||||
mgw_msc note mgw_msc [label="MSC switches call to new path"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_WAIT_SABM\nT3105"];
|
||||
...;
|
||||
ms => bsc_gscon [label="SABM"];
|
||||
bsc_lchan note bsc_lchan [label="SABM: Layer 2 message containing ?"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_\nWAIT_MDCX_BTS\nT?"];
|
||||
bsc_lchan note bsc_lchan [label="TODO: what is UA?"];
|
||||
ms <= bsc_gscon [label="RR UA"];
|
||||
bsc_gscon note bsc_gscon [label="TODO: at what point do we know the information needed for BTS
|
||||
MDCX?"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_modify()"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_MDCX_RESP"];
|
||||
bsc_mgcp => mgw_msc [label="MDCX (for BTS)"];
|
||||
...;
|
||||
--- [label="Should the Handover Complete arrive early"];
|
||||
ms => bsc_gscon [label="RR Handover Complete"];
|
||||
bsc_gscon box bsc_gscon [label="handover_complete_received = true"];
|
||||
---;
|
||||
...;
|
||||
--- [label="On timeout of the mgcp FSM"];
|
||||
bsc_gscon note mgw_msc [label="MGCP FSM terminates"];
|
||||
bsc_gscon <- bsc_mgcp [label="GSCON_EV_MGW_FAIL_BTS"];
|
||||
bsc_lchan note bsc_gscon [label="The phone has already taken on the new lchan, but now we happen
|
||||
to not be able to use it. The only sensible thing is to end the conn."];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Clear Request\n(Equipment Failure)"];
|
||||
bsc_lchan <- bsc_gscon [label="NEW lchan: LCHAN_EV_RELEASE"];
|
||||
ms <=> bsc_lchan [label="release procedure (async)"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
|
||||
--- [label="END: On timeout of the mgcp FSM"];
|
||||
...;
|
||||
bsc_mgcp <= mgw_msc [label="MDCX OK"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_READY"];
|
||||
bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_MDCX_RESP_BTS"];
|
||||
--- [label="IF !handover_complete_received"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_MT_WAIT_HO_COMPL\nT?"];
|
||||
--- [label="ELSE"];
|
||||
bsc_gscon -> bsc_gscon [label="gscon_handover_post_complete()"];
|
||||
---;
|
||||
...;
|
||||
ms => bsc_gscon [label="RR Handover Complete"];
|
||||
bsc_gscon box bsc_gscon [label="gscon_handover_post_complete()"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Handover Complete"];
|
||||
bsc_gscon note bsc_gscon [label="handover_end(success), conn->ho = NULL"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
}
|
241
doc/handover.msc
241
doc/handover.msc
|
@ -1,170 +1,123 @@
|
|||
# Handover between cells, intra-BSC
|
||||
msc {
|
||||
hscale=3;
|
||||
ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_gscon[label="BSC conn FSM"], bsc_mgcp[label="BSC mgcp FSM"], mgw[label="MGW"];
|
||||
ms [label="MS via BTS"], bsc_lchan[label="BSC lchan FSM"], bsc_gscon[label="BSC conn FSM"],
|
||||
bsc_mgcp[label="BSC mgcp FSM"], mgw_msc[label="MGW/MSC"];
|
||||
|
||||
ms note mgw [label="intra-BSC Handover sequence"];
|
||||
ms note mgw_msc [label="intra-BSC Handover sequence"];
|
||||
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
bsc box bsc [label="bsc_handover_start(): init conn->ho"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_HO_START"];
|
||||
bsc <- bsc_gscon [label="bsc_handover_start_gscon()"];
|
||||
|
||||
bsc box bsc [label="lchan_alloc(): pick available lchan"];
|
||||
bsc box bsc [label="rsl_chan_activate_lchan()"];
|
||||
|
||||
--- [label="is the chosen lchan on dynamic timeslot that is currently used as PDCH?"];
|
||||
bts <= bsc [label="i) RSL RF Chan Release of PDCH (Osmocom dyn TS)"];
|
||||
bts <= bsc [label="OR ii) RSL PDCH Deact (ip.access dyn TS)"];
|
||||
bsc -> bsc_gscon [label="bsc_handover_start_gscon() returns early"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_HO_COMPL (no timeout, relies on T3103 below)"];
|
||||
bsc_gscon box bsc_gscon [label="bsc_handover_start(): init conn->ho"];
|
||||
bsc_gscon -> bsc_gscon [label="GSCON_EV_HO_START (intra-BSC)"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_LCHAN"];
|
||||
bsc_lchan <- bsc_gscon [label="lchan_activate(lchan, FOR_HANDOVER)"];
|
||||
...;
|
||||
--- [label="on lchan FSM error or timeout"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_gscon box bsc_gscon [label="handover_end(fail)"];
|
||||
ms note bsc_gscon [label="MS happily continues on the old lchan."];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
--- [label="END: 'on error'"];
|
||||
...;
|
||||
bts note bsc_gscon [linecolor="red",
|
||||
label="Osmocom style dyn TS use lchan->act_timer to watch over RF Chan Release, but there
|
||||
seems to be no timer watching over PDCH Deact!"];
|
||||
...;
|
||||
bts => bsc [label="i) RSL RF Chan Release ACK (Osmocom dyn TS)"];
|
||||
bts => bsc [label="OR ii) RSL PDCH Deact ACK (ip.access dyn TS)"];
|
||||
bsc box bsc [label="rsl_chan_activate_lchan() re-invoked"];
|
||||
bts <= bsc [label="RSL Chan Activ"];
|
||||
--- [label="else (no dyn TS switchover)"];
|
||||
|
||||
bts <= bsc [label="RSL Chan Activ"];
|
||||
bsc -> bsc_gscon [label="bsc_handover_start_gscon() returns"];
|
||||
--- [label="IF lchan FSM decides that it is an lchan for speech"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_ENSURE_MGW_ENDPOINT"];
|
||||
--- [label="IF there is an MGW endpoint for the BTS already (conn->user_plane.fi_bts)"];
|
||||
bsc_gscon box bsc_gscon [label="handover_created_mgw_endpoint = false"];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
|
||||
--- [label="ELSE: no MGW endpoint for the BTS side yet"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_CRCX_BTS"];
|
||||
bsc_gscon box bsc_gscon [label="handover_created_mgw_endpoint = true"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_create()"];
|
||||
bsc_mgcp => mgw_msc [label="CRCX (for BTS)"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_CRCX_RESP (MGCP_MGW_TIMEOUT = 4s)"];
|
||||
bsc_gscon note bsc_mgcp [label="conn FSM relies on mgcp FSM timeout"];
|
||||
...;
|
||||
--- [label="On Timeout"];
|
||||
bsc_mgcp note bsc_mgcp [label="On timeout, the MGCP FSM will terminate, emitting the parent_term
|
||||
event set upon mgcp_conn_create():"];
|
||||
bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_FAIL_BTS"];
|
||||
bsc_gscon note bsc_gscon [label="GSCON_EV_MGW_FAIL_BTS is handled by the conn FSM allstate
|
||||
handler. It sets conn->user_plane.fi_bts = NULL."];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_ERROR"];
|
||||
bsc_lchan note bsc_gscon [label="conn FSM error handler exits and relies on the lchan FSM
|
||||
signalling error, which should actually happen immediately:"];
|
||||
bsc_gscon <- bsc_lchan [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_gscon box bsc_gscon [label="handover_end(fail)"];
|
||||
--- [label="IF handover_created_mgw_endpoint == true"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
|
||||
---;
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_HO_COMPL (no timeout, relies on T3103 below)"];
|
||||
ms note bsc_gscon [label="MS happily continues on the old lchan."];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
--- [label="END: 'On Timeout'"];
|
||||
...;
|
||||
|
||||
bsc_mgcp <= mgw_msc [label="CRCX OK (for BTS)"];
|
||||
bsc_mgcp box bsc_mgcp [label="libosmo-mgcp-client fsm_crcx_resp_cb()"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_READY"];
|
||||
bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_CRCX_RESP_BTS"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_LCHAN"];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
|
||||
--- [label="END: lchan FSM decides that it is an lchan for speech"];
|
||||
...;
|
||||
bts note bsc_gscon [linecolor="red",
|
||||
label="There seems to be no timer watching out for RSL Chan Activ ACK/NACK!"];
|
||||
...;
|
||||
bts => bsc [label="RSL Chan Activ ACK"];
|
||||
bsc box bsc [label="rsl_rx_chan_act_ack()"];
|
||||
bsc box bsc [label="Stop lchan->act_timer"];
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_ACTIVE"];
|
||||
bsc -> bsc [label="S_LCHAN_ACTIVATE_ACK"];
|
||||
bsc box bsc [label="handover_logic.c ho_logic_sig_cb()"];
|
||||
bsc box bsc [label="ho_chan_activ_ack()"];
|
||||
bsc note bsc [label="gsm48_send_ho_cmd()"];
|
||||
ms <= bsc [label="RR Handover Command"];
|
||||
bsc abox bsc [label="start T3103"];
|
||||
--- [label="is BTS using IPA Abis? (osmo-bts, ip.access)"];
|
||||
bts <= bsc [label="IPACC CRCX"];
|
||||
bsc -> bsc [label="ho_chan_activ_ack() returns"];
|
||||
bts note bsc [linecolor="red",
|
||||
label="There seems to be no timer watching over IPACC CRCX ACK/NACK!
|
||||
If no response is received, we simply ignore that fact and carry on as if
|
||||
everything was fine."];
|
||||
...;
|
||||
bts note bsc [label="The IPACC CRCX and MDCX ACKs may come back at any time:
|
||||
before or after the Handover Detect, before or after Handover Complete."];
|
||||
bts note bsc_mgcp [linecolor="red",
|
||||
label="The CRCX ACK contains vital information for routing the RTP stream.
|
||||
If the CRCX ACK were very slow, we would not know which RTP/RTPC ports
|
||||
to point the MGW at, below at mgcp_conn_modify()!
|
||||
Even though this being unrealistic, we must make sure to receive a CRCX ACK."];
|
||||
...;
|
||||
bsc box bsc [label="osmo_bsc_audio.c"];
|
||||
bts => bsc [label="IPACC CRCX ACK"];
|
||||
bts <= bsc [label="IPACC MDCX"];
|
||||
...;
|
||||
bts note bsc [linecolor="red",
|
||||
label="There seems to be no timer watching over IPACC MDCX ACK/NACK!
|
||||
If no response is received, we simply ignore that fact and carry on as if
|
||||
everything was fine."];
|
||||
...;
|
||||
bts => bsc [label="IPACC MDCX ACK"];
|
||||
bts note bsc [label="IPACC MDCX ACK triggers no events or actions"];
|
||||
---;
|
||||
|
||||
...;
|
||||
ms => bsc [label="RR Handover Detect"];
|
||||
bsc -> bsc [label="S_LCHAN_HANDOVER_DETECT"];
|
||||
bsc box bsc [label="ho_rsl_detect(): no action, only logging"];
|
||||
bsc note bsc_gscon [label="Handover Detect triggers no events or actions"];
|
||||
bsc note bsc_gscon [linecolor="red",
|
||||
label="upon Handover Detect, we should already start re-routing the RTP!
|
||||
Instead we wait for Handover Complete."];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ACTIVE"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_DETECT\nT3103"];
|
||||
bsc_gscon box bsc_gscon [label="gsm48_send_ho_cmd()"];
|
||||
ms <= bsc_gscon [label="RR Handover Command"];
|
||||
|
||||
...;
|
||||
ms => bsc [label="RR Handover Complete"];
|
||||
bsc -> bsc [label="S_LCHAN_HANDOVER_COMPL"];
|
||||
bsc box bsc [label="handover_logic.c ho_logic_sig_cb()"];
|
||||
bsc box bsc [label="ho_gsm48_ho_compl()"];
|
||||
bsc box bsc [label="stop T3103"];
|
||||
bts note bsc_gscon [label="If anything goes wrong from this point on, we will not move back
|
||||
to the old lchan: would be pointless after Handover Complete."];
|
||||
bsc note bsc [label="officially take over new lchan: conn->lchan = ho->new_lchan"];
|
||||
|
||||
--- [label="Release old lchan"];
|
||||
bsc box bsc [label="_lchan_handle_release(sacch_deact=0)"];
|
||||
bsc box bsc [label="rsl_release_sapis_from(start=1)"];
|
||||
bts <= bsc [label="RSL Release Request (Local End)..."];
|
||||
bts <= bsc [label="...for each SAPI except link_id=0"];
|
||||
bsc box bsc [label="rsl_release_request(link_id=0)"];
|
||||
bts <= bsc [label="RSL Release Request (Local End) for link_id=0"];
|
||||
bsc box bsc [label="_lchan_handle_release() returns here, the remaining release is asynchronous;
|
||||
see `End: 'Release old lchan'` below."];
|
||||
...;
|
||||
bts note bsc_gscon [linecolor="red",
|
||||
label="There seems to be no timer watching over RSL Release Request!"];
|
||||
...;
|
||||
bts => bsc [label="RSL Release Confirm..."];
|
||||
bts => bsc [label="...for each SAPI and link_id=0"];
|
||||
bsc abox bsc [label="start T3111"];
|
||||
...;
|
||||
bsc box bsc [label="T3111 expires"];
|
||||
bsc abox bsc [label="Start lchan->act_timer with lchan_deact_tmr_cb"];
|
||||
bts <= bsc [label="RSL RF Channel Release"];
|
||||
...;
|
||||
--- [label="On timeout"];
|
||||
bsc box bsc [label="lchan_deact_tmr_cb()"];
|
||||
bsc box bsc [label="rsl_lchan_mark_broken(): state=LCHAN_S_BROKEN"];
|
||||
bsc box bsc [label="lchan_free()"];
|
||||
bsc -> bsc [label="S_LCHAN_UNEXPECTED_RELEASE"];
|
||||
bsc box bsc [label="bsc_api.c handle_release()"];
|
||||
bsc box bsc [label="bsc->clear_request()"];
|
||||
bsc box bsc [label="bsc_clear_request encodes a BSSMAP Clear Request message and passes it on
|
||||
to the conn FSM as data argument via:"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_TX_SCCP"];
|
||||
bsc_gscon rbox bsc_gscon [label="BSSMAP Clear Request to MSC"];
|
||||
bsc note bsc_gscon [linecolor="red",
|
||||
label="During Handover, we actually release the entire conn just because we failed to
|
||||
gracefully release the old lchan. That is obviously nonsense."];
|
||||
bsc note bsc [label="Stop T3101 (but was not active in this code path)"];
|
||||
bsc -> bsc [label="S_CHALLOC_FREED"];
|
||||
--- [label="End: 'On timeout'"];
|
||||
...;
|
||||
bts => bsc [label="RSL RF Channel Release Ack"];
|
||||
bsc box bsc [label="Stop lchan->act_timer"];
|
||||
bsc box bsc [label="Stop lchan->T3111"];
|
||||
bsc_lchan <- bsc_gscon [label="NEW lchan: LCHAN_EV_RELEASE"];
|
||||
ms <=> bsc_lchan [label="release procedure (async)"];
|
||||
bsc_gscon box bsc_gscon [label="handover_end(fail)"];
|
||||
--- [label="IF handover_created_mgw_endpoint == true"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
|
||||
---;
|
||||
ms note bsc_gscon [label="MS happily continues on the old lchan."];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
--- [label="END: On timeout"];
|
||||
...;
|
||||
ms => bsc_gscon [label="RR Handover Detect"];
|
||||
|
||||
bsc box bsc [label="still in ho_gsm48_ho_compl()"];
|
||||
bsc note bsc [label="handover_free(), conn->ho = NULL"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_HO_COMPL"];
|
||||
bsc note bsc_gscon [linecolor="orange",
|
||||
label="Handover information is cleared before signalling the conn FSM.
|
||||
That means the conn FSM cannot possibly log sensible information about exactly
|
||||
which Handover has just completed."];
|
||||
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_MDCX_BTS_HO
|
||||
(MGCP_MGW_TIMEOUT=4s with MGCP_MGW_HO_TIMEOUT_TIMER_NR)"];
|
||||
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_MDCX_BTS\ncontinue T3103"];
|
||||
bsc_gscon -> bsc_lchan [label="OLD lchan: LCHAN_EV_RELEASE"];
|
||||
ms <=> bsc_lchan [label="release procedure (async)"];
|
||||
bsc_lchan note bsc_gscon [label="officially take over new lchan: conn->lchan = ho->new_lchan"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_modify()"];
|
||||
bsc_mgcp note bsc_mgcp [label="mgcp FSM that was established for old lchan, for BTS side"];
|
||||
bsc_mgcp => mgw [label="MDCX (for BTS)"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_MDCX_RESP"];
|
||||
bsc_mgcp => mgw_msc [label="MDCX (for BTS)"];
|
||||
...;
|
||||
bsc_gscon note mgw [
|
||||
label="If we get no MDCX ACK, the MGCP FSM terminates, and emits GSCON_EV_MGW_FAIL_BTS.
|
||||
Besides invalidating the MGCP FSM pointer, this event has no
|
||||
effect in ST_WAIT_MDCX_BTS_HO, and we rely on above conn FSM
|
||||
timeout instead."];
|
||||
bsc_gscon note bsc_gscon [linecolor="red",
|
||||
label="A timeout of ST_WAIT_MDCX_BTS_HO simply transitions back to ST_ACTIVE!
|
||||
Even though the MGW failed, we carry on as if everything were fine."];
|
||||
--- [label="Should the Handover Complete arrive early"];
|
||||
ms => bsc_gscon [label="RR Handover Complete"];
|
||||
bsc_gscon box bsc_gscon [label="handover_complete_received = true"];
|
||||
---;
|
||||
...;
|
||||
bsc_mgcp <= mgw [label="MDCX OK"];
|
||||
--- [label="On timeout of the mgcp FSM"];
|
||||
bsc_gscon note mgw_msc [label="MGCP FSM terminates"];
|
||||
bsc_gscon <- bsc_mgcp [label="GSCON_EV_MGW_FAIL_BTS"];
|
||||
bsc_lchan note bsc_gscon [label="The phone has already taken on the new lchan, but now we happen
|
||||
to not be able to use it. The only sensible thing is to end the conn."];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Clear Request\n(Equipment Failure)"];
|
||||
bsc_lchan <- bsc_gscon [label="NEW lchan: LCHAN_EV_RELEASE"];
|
||||
ms <=> bsc_lchan [label="release procedure (async)"];
|
||||
bsc_gscon -> bsc_mgcp [label="mgcp_conn_delete()"];
|
||||
...;
|
||||
bsc_mgcp <= mgw_msc [label="MDCX OK"];
|
||||
bsc_mgcp abox bsc_mgcp [label="ST_READY"];
|
||||
bsc_mgcp -> bsc_gscon [label="GSCON_EV_MGW_MDCX_RESP_BTS"];
|
||||
--- [label="IF !handover_complete_received"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_HANDOVER_\nWAIT_COMPLETE\ncontinue T3103"];
|
||||
--- [label="ELSE"];
|
||||
bsc_gscon -> bsc_gscon [label="gscon_handover_post_complete()"];
|
||||
---;
|
||||
...;
|
||||
ms => bsc_gscon [label="RR Handover Complete"];
|
||||
bsc_gscon box bsc_gscon [label="gscon_handover_post_complete()"];
|
||||
bsc_gscon note bsc_gscon [label="handover_end(success), conn->ho = NULL"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
digraph G {
|
||||
rankdir=TB;
|
||||
|
||||
invisible [style="invisible"]
|
||||
UNUSED [penwidth=3.0]
|
||||
WAIT_TS_READY
|
||||
WAIT_MGW_ENDPOINT_AVAILABLE
|
||||
WAIT_ACTIV_ACK
|
||||
WAIT_IPACC_CRCX_ACK
|
||||
WAIT_IPACC_MDCX_ACK
|
||||
WAIT_RLL_ESTABLISH
|
||||
ACTIVE [penwidth=3.0]
|
||||
WAIT_SAPIS_RELEASED
|
||||
WAIT_BEFORE_RF_RELEASE
|
||||
WAIT_RF_RELEASE_ACK
|
||||
WAIT_AFTER_ERROR
|
||||
BORKEN
|
||||
|
||||
ts [label="timeslot FSM",shape=box3d];
|
||||
gscon [label="conn FSM",shape=box3d];
|
||||
|
||||
UNUSED -> WAIT_TS_READY [label="lchan_allocate()"]
|
||||
WAIT_TS_READY -> WAIT_ACTIV_ACK
|
||||
WAIT_ACTIV_ACK -> WAIT_RLL_ESTABLISH
|
||||
WAIT_RLL_ESTABLISH -> WAIT_MGW_ENDPOINT_AVAILABLE [label="TCH"]
|
||||
WAIT_MGW_ENDPOINT_AVAILABLE -> WAIT_IPACC_CRCX_ACK [label="IPACC BTS"]
|
||||
WAIT_MGW_ENDPOINT_AVAILABLE -> ACTIVE
|
||||
WAIT_IPACC_CRCX_ACK -> WAIT_IPACC_MDCX_ACK
|
||||
WAIT_IPACC_MDCX_ACK -> ACTIVE
|
||||
WAIT_RLL_ESTABLISH -> ACTIVE [label="non-TCH"];
|
||||
WAIT_RLL_ESTABLISH -> WAIT_RF_RELEASE_ACK [label="timeout",style=dashed,constraint=false]
|
||||
|
||||
ACTIVE -> WAIT_SAPIS_RELEASED [label="LCHAN_EV_\nRELEASE"]
|
||||
WAIT_SAPIS_RELEASED -> WAIT_BEFORE_RF_RELEASE
|
||||
WAIT_SAPIS_RELEASED -> WAIT_RF_RELEASE_ACK [label="timeout",style=dashed,constraint=false]
|
||||
|
||||
WAIT_BEFORE_RF_RELEASE -> WAIT_RF_RELEASE_ACK [label="T3111"]
|
||||
WAIT_RF_RELEASE_ACK -> UNUSED
|
||||
WAIT_RF_RELEASE_ACK -> WAIT_AFTER_ERROR [label="release was\ndue to error"]
|
||||
WAIT_AFTER_ERROR -> UNUSED [label="T3111+2s"]
|
||||
|
||||
WAIT_TS_READY -> ts [label="TS_EV_\nLCHAN_\nREQUESTED",style=dotted,penwidth=3]
|
||||
UNUSED -> ts [label="TS_EV_\nLCHAN_\nUNUSED",style=dotted,penwidth=3]
|
||||
ts -> WAIT_TS_READY [label="LCHAN_EV_\nTS_READY",style=dotted]
|
||||
|
||||
WAIT_TS_READY -> UNUSED [label="error/timeout",style=dashed,constraint=false]
|
||||
{WAIT_ACTIV_ACK,WAIT_RF_RELEASE_ACK} -> BORKEN [label="error/timeout",style=dashed]
|
||||
{WAIT_MGW_ENDPOINT_AVAILABLE,WAIT_IPACC_CRCX_ACK,WAIT_IPACC_MDCX_ACK} -> WAIT_SAPIS_RELEASED [label=error,style=dashed]
|
||||
|
||||
WAIT_TS_READY -> gscon [label="GSCON_EV_\nENSURE_\nMGW_ENDPOINT",style=dotted]
|
||||
gscon -> WAIT_MGW_ENDPOINT_AVAILABLE [label="LCHAN_EV_\nMGW_ENDPOINT_\n{AVAILABLE,ERROR}",style=dotted]
|
||||
|
||||
}
|
|
@ -1,149 +1,83 @@
|
|||
msc {
|
||||
hscale=2;
|
||||
ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_gscon[label="BSC conn FSM"];
|
||||
ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_lchan[label="BSC lchan FSM"],
|
||||
bsc_gscon[label="BSC conn FSM"], msc_[label="MSC"];
|
||||
|
||||
ms note bsc_gscon [label="various lchan release scenarios"];
|
||||
|
||||
|
||||
ms rbox bsc_gscon [label="IF BSC releases, from BSSMAP Clear Request"];
|
||||
bsc note bsc [label="lchan_release() may be called with sacch_deact=true or false.
|
||||
Currently, the only time lchan_release(sacch_deact=true) is invoked is upon BSSMAP Clear
|
||||
Command, i.e. when the MSC instructs to stop using an active lchan.
|
||||
Some error handling code paths however directly invoke
|
||||
rsl_rf_chan_release(error=1, SACCH_DEACTIVATE)."];
|
||||
|
||||
---;
|
||||
bsc_gscon note bsc_gscon [label="Rx: BSSMAP Clear Request from MSC"];
|
||||
bsc <- bsc_gscon [label="gsm0808_clear()"];
|
||||
bsc box bsc [label="lchan_release(sacch_deact=1)"];
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_REL_REQ"];
|
||||
bsc box bsc [label="_lchan_handle_release(sacch_deact=1)"];
|
||||
bsc box bsc [label="rsl_release_sapis_from(start=1)"];
|
||||
bts <= bsc [label="RSL Release Request (Local End)..."];
|
||||
bts <= bsc [label="...for each SAPI, except link_id=0"];
|
||||
ms <= bsc [label="RR Channel Release"];
|
||||
ms note bsc [label="There is no ACK for RR Channel Release"];
|
||||
bsc box bsc [label="rsl_deact_sacch()"];
|
||||
bts <= bsc [label="RSL Deactivate SACCH"];
|
||||
bsc abox bsc [label="Start T3109 (net->T3109, t3109_expired())"];
|
||||
ms rbox msc_ [label="MSC releases"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_ACTIVE"];
|
||||
bsc_gscon <= msc_ [label="BSSMAP Clear Command"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_CLEARING"];
|
||||
bsc_gscon => msc_ [label="BSSMAP Clear Complete"];
|
||||
bsc_gscon -> bsc_lchan [label="LCHAN_EV_RELEASE"];
|
||||
--- [label="IF SAPIs besides SAPI[0] are active"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nSAPIS_RELEASED\nT3109"];
|
||||
bts <= bsc_lchan [label="RSL Release Request (Local End)..."];
|
||||
bts <= bsc_lchan [label="...for each SAPI, except link_id=0"];
|
||||
ms <= bsc_lchan [label="RR Channel Release"];
|
||||
bts <= bsc_lchan [label="RSL Deactivate SACCH",ID="if appropriate pchan"];
|
||||
...;
|
||||
--- [label="If T3109 expires"];
|
||||
bsc box bsc [label="t3109_expired()"];
|
||||
bsc box bsc [label="rsl_rf_chan_release(error=1)"];
|
||||
bts <= bsc [label="RSL Release Request (Local End)..."];
|
||||
bts <= bsc [label="...for each SAPI, except link_id=0"];
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_REL_REQ"];
|
||||
bts <= bsc [label="RSL RF Channel Release"];
|
||||
---;
|
||||
bts => bsc_lchan [label="RSL Release ACKs"];
|
||||
--- [label="END: SAPIs besides SAPI[0] are active"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nBEFORE_RF_RELEASE\nT3111"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_FORGET_LCHAN"];
|
||||
bsc_gscon note bsc_gscon [label="has already forgotten the lchan above."];
|
||||
...;
|
||||
bsc rbox bsc [label="continue in the 'Common' part"];
|
||||
--- [label="END: 'BSSMAP Clear Request'"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRF_RELEASE_ACK\n4s"];
|
||||
bts <= bsc_lchan [label="RSL RF Channel Release"];
|
||||
...;
|
||||
bts => bsc_lchan [label="RSL RF Channel Release ACK"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
|
||||
...;
|
||||
...;
|
||||
|
||||
ms rbox bsc_gscon [label="IF BSC releases, from implicitly unused lchan"];
|
||||
bsc note bsc [label="The BSC may release old unused lchans after Handover, or release lchans
|
||||
after some error condition."];
|
||||
bsc note bsc [label="BSC decides to release an unused lchan"];
|
||||
bsc box bsc [label="lchan_release(sacch_deact=0)"];
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_REL_REQ"];
|
||||
bsc box bsc [label="_lchan_handle_release(sacch_deact=0)"];
|
||||
bts <= bsc [label="RSL Release Request (Local End)..."];
|
||||
bts <= bsc [label="...for all SAPIs"];
|
||||
ms rbox msc_ [label="BSC releases, outside of conn FSM's flow"];
|
||||
bsc -> bsc_lchan [label="LCHAN_EV_RELEASE"];
|
||||
--- [label="IF SAPIs besides SAPI[0] are active"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nSAPIS_RELEASED\nT3109"];
|
||||
bts <= bsc_lchan [label="RSL Release Request (Local End)..."];
|
||||
bts <= bsc_lchan [label="...for each SAPI, except link_id=0"];
|
||||
ms <= bsc_lchan [label="RR Channel Release",ID="if conn is present"];
|
||||
bts <= bsc_lchan [label="RSL Deactivate SACCH",ID="if appropriate pchan"];
|
||||
...;
|
||||
bts note bsc_gscon [linecolor="red",
|
||||
label="There seems to be no timer watching over RSL Release Request!"];
|
||||
bts => bsc_lchan [label="RSL Release ACKs"];
|
||||
--- [label="END: SAPIs besides SAPI[0] are active"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nBEFORE_RF_RELEASE\nT3111"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_FORGET_LCHAN"];
|
||||
bsc_gscon note bsc_gscon [label="conn FSM notices that its primary lchan is gone"];
|
||||
bsc_gscon => msc_ [label="BSSMAP Clear Request"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
|
||||
...;
|
||||
bts => bsc [label="RSL Release Confirm..."];
|
||||
bts => bsc [label="...for all SAPIs"];
|
||||
bsc rbox bsc [label="continue in the 'Common' part"];
|
||||
---;
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRF_RELEASE_ACK\n4s"];
|
||||
bts <= bsc_lchan [label="RSL RF Channel Release"];
|
||||
...;
|
||||
bts => bsc_lchan [label="RSL RF Channel Release ACK"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
|
||||
...;
|
||||
bsc_gscon <= msc_ [label="BSSMAP Clear Command"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_CLEARING"];
|
||||
bsc_gscon => msc_ [label="BSSMAP Clear Complete"];
|
||||
...;
|
||||
...;
|
||||
|
||||
ms rbox bsc_gscon [label="IF MS releases"];
|
||||
ms rbox msc_ [label="MS releases"];
|
||||
ms => bts [label="DISC"];
|
||||
bts => bsc [label="RLL Release Ind..."];
|
||||
bts => bsc [label="...for each SAPI"];
|
||||
bsc rbox bsc [label="continue in the 'Common' part"];
|
||||
---;
|
||||
bts => bsc_lchan [label="RLL Release Ind..."];
|
||||
bts => bsc_lchan [label="...for each SAPI"];
|
||||
bsc_lchan note bsc_lchan [label="The lchan FSM notices when all SAPIs have been released"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nBEFORE_RF_RELEASE\nT3111"];
|
||||
...;
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRF_RELEASE_ACK\n4s"];
|
||||
bts <= bsc_lchan [label="RSL RF Channel Release"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_FORGET_LCHAN"];
|
||||
bsc_gscon note bsc_gscon [label="conn FSM notices that its primary lchan is gone"];
|
||||
bsc_gscon => msc_ [label="BSSMAP Clear Request"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_CLEAR_CMD"];
|
||||
...;
|
||||
ms rbox bsc_gscon [label="Common"];
|
||||
--- [label="for each SAPI (?)"];
|
||||
bts => bsc [label="RLL Release Confirm / RLL Release Ind"];
|
||||
bsc box bsc [label="abis_rsl_rx_rll()"];
|
||||
bsc box bsc [label="mark lchan->sapis[link_id] = LCHAN_SAPI_UNUSED"];
|
||||
bsc box bsc [label="rll_indication()"];
|
||||
bsc box bsc [label="for each bsc_rll_req matching this link_id:
|
||||
disable timer, call cb(BSC_RLLR_IND_REL_IND)"];
|
||||
bsc box bsc [label="rsl_handle_release()"];
|
||||
--- [label="IF all SAPIs are unused"];
|
||||
bsc box bsc [label="Stop T3109"];
|
||||
bsc note bsc [label="T3109 was started if the MSC requested the release"];
|
||||
bsc abox bsc [label="Start T3111 (net->T3111 value, t3111_expired())"];
|
||||
--- [label="END: all SAPIs are unused"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_RLL_REL_IND (only if RLL Release Ind)"];
|
||||
--- [label="END: for each SAPI"];
|
||||
|
||||
bts => bsc_lchan [label="RSL RF Channel Release ACK"];
|
||||
...;
|
||||
bsc box bsc [label="T3111 expires"];
|
||||
bsc box bsc [label="rsl_rf_chan_release()"];
|
||||
bsc box bsc [label="Stop T3109"];
|
||||
bsc note bsc [label="[If lchan->state is LCHAN_S_REL_ERR, don't do anything]"];
|
||||
bsc abox bsc [label="Start lchan->act_timer (4s, lchan_deact_tmr_cb())"];
|
||||
bts <= bsc [label="RSL RF Channel Release"];
|
||||
|
||||
...;
|
||||
--- [label="IF lchan->act_timer expires"];
|
||||
bsc box bsc [label="lchan_deact_tmr_cb()"];
|
||||
bsc box bsc [label="rsl_lchan_mark_broken(): lchan->state = LCHAN_S_BROKEN"];
|
||||
bsc box bsc [label="lchan_free() (see below)"];
|
||||
--- [label="END: 'lchan->act_timer expires'"];
|
||||
...;
|
||||
|
||||
bts => bsc [label="RSL RF Channel Release ACK"];
|
||||
bsc box bsc [label="rsl_rx_rf_chan_rel_ack()"];
|
||||
bsc box bsc [label="Stop lchan->act_timer"];
|
||||
bsc box bsc [label="Stop T3111"];
|
||||
|
||||
--- [label="IF lchan->state == LCHAN_S_BROKEN"];
|
||||
bsc note bsc [label="If an ACK comes in late, for specific BTS models, we may choose to 'repair'
|
||||
the lchan so that it is usable again, by calling do_lchan_free() directly (see below)."];
|
||||
bsc box bsc [label="rsl_rx_rf_chan_rel_ack() exits here and none of below actions happen.
|
||||
The lchan remains LCHAN_S_BROKEN indefinitely."];
|
||||
--- [label="END: lchan->state == LCHAN_S_BROKEN"];
|
||||
bsc box bsc [label="do_lchan_free()"];
|
||||
--- [label="IF lchan->state == LCHAN_S_REL_ERR"];
|
||||
bsc note bsc [label="If release failed, we take the lchan back into operation after due
|
||||
timeout"];
|
||||
bsc abox bsc [label="Start lchan->error_timer (T3111+2, error_timeout_cb())"];
|
||||
bsc note bsc [label="do_lchan_free() continues, async:"];
|
||||
...;
|
||||
bsc box bsc [label="error_timeout_cb()"];
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_NONE"];
|
||||
bsc box bsc [label="dyn TS: activate PDCH..."];
|
||||
--- [label="ELSE"];
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_NONE"];
|
||||
--- [label="END: lchan->state == LCHAN_S_REL_ERR"];
|
||||
bsc box bsc [label="lchan_free()"];
|
||||
--- [label="IF conn is still associated (and not dyn TS in switchover)"];
|
||||
bsc -> bsc [label="S_LCHAN_UNEXPECTED_RELEASE"];
|
||||
bsc box bsc [label="handle_release()"];
|
||||
bsc box bsc [label="Stop T10"];
|
||||
bsc note bsc [linecolor=orange,label="conn->T10 is actually dead code, it is never started.
|
||||
Instead, the conn FSM starts ST_WAIT_ASS_COMPL with a T10 value."];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_RR_ASS_FAIL"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_TX_SCCP: BSSMAP Clear Request"];
|
||||
bsc box bsc [label="bsc_clear_handover()"];
|
||||
bsc box bsc [label="Stop T3103"];
|
||||
bsc box bsc [label="free handover struct"];
|
||||
bsc box bsc [label="lchan->conn = NULL"];
|
||||
--- [label="END: 'conn is still associated'"];
|
||||
bsc box bsc [label="Stop T3101"];
|
||||
bsc note bsc [label="T3101 is started when sending an RR Immediate Assignment"];
|
||||
bsc -> bsc [label="S_CHALLOC_FREED"];
|
||||
bsc -> bsc [label="rll_lchan_signal()"];
|
||||
bsc box bsc [label="for each bsc_rll_req matching this lchan:
|
||||
disable timer, call cb(BSC_RLLR_IND_REL_IND)"];
|
||||
bsc_gscon <= msc_ [label="BSSMAP Clear Command"];
|
||||
bsc_gscon => msc_ [label="BSSMAP Clear Complete"];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
msc {
|
||||
hscale=2;
|
||||
bts [label="MS/BTS"], bsc[label="BSC"], bsc_ts [label="BSC timeslot FSM"],
|
||||
bsc_lchan[label="BSC lchan FSM"], bsc_gscon[label="BSC conn FSM"],
|
||||
mgw_msc[label="MGW/MSC"];
|
||||
|
||||
bts box mgw_msc [label="lchan allocation sequence"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
|
||||
|
||||
bts rbox mgw_msc [label="Channel Request from MS"];
|
||||
bts => bsc [label="RSL Channel Request"];
|
||||
bsc box bsc [label="lchan_select_by_type(chan_type)"];
|
||||
bsc -> bsc_lchan [label="lchan_activate(lchan, FOR_MS_CHANNEL_REQUEST)"];
|
||||
bsc_lchan rbox bsc_lchan [label="Continue at\nlchan_activate()\n"];
|
||||
|||;
|
||||
|||;
|
||||
|
||||
bts rbox mgw_msc [label="Channel Request from BSSMAP Assignment"];
|
||||
bsc_gscon <= mgw_msc [label="BSSMAP Assignment request"];
|
||||
bsc_gscon box bsc_gscon [label="lchan_select_by_chan_mode(chan_mode)"];
|
||||
bsc_lchan <- bsc_gscon [label="lchan_activate(lchan, FOR_ASSIGNMENT)"];
|
||||
bsc_lchan rbox bsc_lchan [label="Continue at\nlchan_activate()\n"];
|
||||
|||;
|
||||
|||;
|
||||
|
||||
bts rbox mgw_msc [label="Channel Request from Handover Decision"];
|
||||
bsc note bsc [label="target lchan typically already chosen by Handover Decision"];
|
||||
bsc -> bsc_gscon [label="GSCON_EV_HO_START (intra-BSC)"];
|
||||
bsc_lchan <- bsc_gscon [label="lchan_activate(lchan, FOR_HANDOVER)"];
|
||||
bsc_lchan rbox bsc_lchan [label="Continue at\nlchan_activate()\n"];
|
||||
|||;
|
||||
|||;
|
||||
|
||||
bts rbox mgw_msc [label="Channel Request from intra-BSC-MT-Handover"];
|
||||
bsc_gscon <- mgw_msc [label="BSSMAP Handover Request"];
|
||||
bsc_gscon box bsc_gscon [label="lchan_select_by_chan_mode(chan_mode)"];
|
||||
bsc box bsc [label="lchan_activate(lchan, FOR_HANDOVER)"];
|
||||
bsc_lchan rbox bsc_lchan [label="Continue at\nlchan_activate()\n"];
|
||||
|||;
|
||||
|||;
|
||||
bts rbox mgw_msc [label="lchan_activate()"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_\nWAIT_TS_READY\n(timeout: ? s, Tnnnn)"];
|
||||
|||;
|
||||
|||;
|
||||
--- [label="TCH?"];
|
||||
bsc_lchan note bsc_gscon [label="This is skipped when FOR_MS_CHANNEL_REQUEST. If the MS requests
|
||||
a TCH lchan, and we end up actually giving it a TCH because no SDCCH are available, we
|
||||
can not set up an RTP stream because there is not even an L3 conn yet."];
|
||||
bsc_lchan note bsc_gscon [label="The lchan FSM asks the conn FSM to have an MGW endpoint ready as
|
||||
early as possible. Either the conn already has such MGW endpoint from a previous lchan,
|
||||
in which case it immediately replies, or it requests one from the MGW, in which case we
|
||||
wait for a response in 'TCH? (2)' below."];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_ENSURE_MGW_ENDPOINT"];
|
||||
--- [label="IF conn has user_plane.fi_bts in state ST_READY"];
|
||||
bsc_lchan <- bsc_gscon [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
|
||||
bsc_lchan box bsc_lchan [label="mgw_endpoint_available = true"];
|
||||
bsc_lchan note bsc_lchan [label="lchan_activate() continues"];
|
||||
--- [label="ELSE (no MGW endpoint available yet)"];
|
||||
bsc_gscon => mgw_msc [label="CRCX (for BTS) via mgcp_conn_create()"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_CRCX_BTS\n(timeout: ? s, Tnnnn)"];
|
||||
bsc_lchan <- bsc_gscon [label="(event dispatch returns)"];
|
||||
bsc_lchan note bsc_lchan [label="lchan_activate() continues"];
|
||||
...;
|
||||
bsc_gscon note bsc_gscon [label="async:"];
|
||||
bsc_gscon <= mgw_msc [label="CRCX OK (for BTS)"];
|
||||
bsc_lchan <- bsc_gscon [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
|
||||
bsc_lchan box bsc_lchan [label="mgw_endpoint_available = true"];
|
||||
bsc_lchan note bsc_lchan [label="As soon as we reach LCHAN_ST_WAIT_MGW_ENDPOINT_AVAILABLE, this triggers
|
||||
immedate action (s.b.), but until then, only the flag gets set to true."];
|
||||
...;
|
||||
--- [label="CRCX timeout"];
|
||||
bsc_gscon note bsc_gscon [label="conn FSM should fire on CRCX timeout"];
|
||||
bsc_lchan <- bsc_gscon [label="LCHAN_EV_MGW_ENDPOINT_ERROR"];
|
||||
bsc_gscon note bsc_gscon [label="conn FSM should not assume anything and wait for
|
||||
GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_lchan rbox bsc_lchan [label="Do 'On any error'"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED"];
|
||||
--- [label="END: 'TCH?'"];
|
||||
|||;
|
||||
|||;
|
||||
|
||||
bsc_lchan box bsc_lchan [label="lchan_activate() exits"];
|
||||
bsc_lchan note bsc_lchan [label="still in\nlchan_request()\nLCHAN_ST_WAIT_\nTS_READY"];
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_REQUESTED"];
|
||||
...;
|
||||
--- [label="on error from TS or timeout:"];
|
||||
bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_ERROR"];
|
||||
bsc_lchan rbox bsc_lchan [label="Do 'On any error'"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED"];
|
||||
---;
|
||||
...;
|
||||
bsc_ts abox bsc_ts [label="TS_ST_IN_USE"];
|
||||
bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_READY"];
|
||||
bsc_lchan box bsc_lchan [label="lchan_fsm_\npre_lchan_activ()"];
|
||||
|
||||
|||;
|
||||
|||;
|
||||
bts rbox mgw_msc [label="mode FOR_MS_CHANNEL_REQUEST"];
|
||||
bts note bsc_lchan [label="This is the simple case where the MS requested a channel, and there is no
|
||||
L3 conn to the MSC; no matter if this is SDDCH or a TCH channel type, we will not prepare
|
||||
an RTP stream."];
|
||||
|
||||
bsc_lchan note bsc_lchan [label="still in lchan_fsm_\npre_lchan_activ()"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nACTIV_ACK\n(timeout: ? s, Tnnnn)"];
|
||||
bts <= bsc_lchan [label="RSL Chan Activ (RSL_ACT_INTRA_IMM_ASS)"];
|
||||
bts note bsc_lchan [label="If any errors occur from now on, we don't want to send an RR Immediate
|
||||
Assignment Reject anymore."];
|
||||
bsc_lchan box bsc_lchan [label="sent_chan_activ = true"];
|
||||
...;
|
||||
--- [label="on timeout"];
|
||||
bsc_lchan rbox bsc_lchan [label="Continue at: 'On any error', 'unrecoverable'"];
|
||||
---;
|
||||
...;
|
||||
bts => bsc_lchan [label="RSL Chan Activ ACK"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRLL_ESTABLISH\nT3101"];
|
||||
bsc_lchan note bsc_lchan [label="Now the lchan is assigned, but has no L3 conn yet. On errors,
|
||||
this will either go into graceful release or into broken state, but will not trigger any
|
||||
events to a (non-existing) conn."];
|
||||
...;
|
||||
--- [label="on timeout"];
|
||||
bts <= bsc_lchan [label="RSL RF Channel Release"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_RF_RELEASE_ACK\n(T?, 4s)"];
|
||||
---;
|
||||
...;
|
||||
bts => bsc_lchan [label="RLL Establish Ind"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
|
||||
|||;
|
||||
|||;
|
||||
bts rbox mgw_msc [label="modes FOR_ASSIGNMENT and FOR_HANDOVER"];
|
||||
|
||||
bsc_lchan note bsc_lchan [label="still in lchan_fsm_\npre_lchan_activ()"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nACTIV_ACK\n(timeout: ? s, Tnnnn)"];
|
||||
bts <= bsc_lchan [label="RSL Chan Activ (RSL_ACT_INTRA_NORM_ASS)",ID=FOR_ASSIGNMENT];
|
||||
bts <= bsc_lchan [label="RSL Chan Activ (RSL_ACT_INTER_ASYNC)",ID=FOR_HANDOVER];
|
||||
...;
|
||||
--- [label="on timeout"];
|
||||
bsc_lchan rbox bsc_lchan [label="Continue at: 'On any error', 'unrecoverable'"];
|
||||
---;
|
||||
bts => bsc_lchan [label="RSL Chan Activ ACK"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRLL_ESTABLISH\nT3101"];
|
||||
...;
|
||||
--- [label="on timeout"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_lchan -> bsc_lchan [label="lchan_fsm_pre_rf_release()"];
|
||||
---;
|
||||
...;
|
||||
bts => bsc_lchan [label="RLL Establish Indication"];
|
||||
|||;
|
||||
|
||||
--- [label="TCH? (2)"];
|
||||
--- [label="mgw_endpoint_available == false?"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nMGW_ENDPOINT_\nAVAILABLE"];
|
||||
bsc_lchan note bsc_lchan [label="rely on conn FSM timeout; apply only a long sanity timeout."];
|
||||
...;
|
||||
bsc_gscon <= mgw_msc [label="CRCX OK (for BTS)"];
|
||||
bsc_lchan <- bsc_gscon [label="LCHAN_EV_MGW_ENDPOINT_AVAILABLE"];
|
||||
bsc_lchan box bsc_lchan [label="mgw_endpoint_available = true"];
|
||||
bsc_lchan <- bsc_lchan [label="re-invoke lchan_fsm_pre_lchan_activ()"];
|
||||
--- [label="END: 'TCH? (2)'"];
|
||||
|||;
|
||||
|
||||
--- [label="is BTS using IPA Abis? (osmo-bts, ip.access)"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nIPACC_CRCX_ACK\n(timeout: ? s, Tnnnn)"];
|
||||
bts <= bsc_lchan [label="IPACC CRCX"];
|
||||
...;
|
||||
--- [label="on timeout"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_lchan -> bsc_lchan [label="lchan_graceful_release()"];
|
||||
---;
|
||||
...;
|
||||
bts => bsc_lchan [label="IPACC CRCX ACK"];
|
||||
bts note bsc_lchan [label="The IPACC CRCX ACK tells us what port the IPA Abis based BTS has
|
||||
assigned to this lchan. AoIP: we need to forward this to the MGW (BTS side) with an MDCX;
|
||||
SCCPlite: we forward this to the MSC during BSSMAP Assignment Complete (TODO: is this
|
||||
correct??)"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nIPACC_MDCX_ACK\n(timeout: ? s, Tnnnn)"];
|
||||
bts <= bsc_lchan [label="IPACC MDCX"];
|
||||
bts note bsc_lchan [label="The IPACC MDCX tells IPA Abis based BTSes the IP address and RTP port
|
||||
assigned by the BTS side of the MGW. AoIP: the MGW CRCX (BTS) must thus happen before
|
||||
this; SCCPlite: the RTP port is already known from the timeslot+multiplex information."];
|
||||
...;
|
||||
--- [label="on timeout"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_lchan -> bsc_lchan [label="lchan_graceful_release()"];
|
||||
---;
|
||||
...;
|
||||
bts => bsc_lchan [label="IPACC MDCX ACK"];
|
||||
--- [label="END: is BTS using IPA Abis? (osmo-bts, ip.access)"];
|
||||
|||;
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
|
||||
bsc_lchan box bsc_lchan [label="lchan_fsm_post_lchan_activ()"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ACTIVE"];
|
||||
bts <= bsc_gscon [label="RR Assignment",ID="BSSMAP Assignment Request"];
|
||||
bts <= bsc_gscon [label="RR Handover Command",ID="intra-BSC HO"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Handover\nRequest Acknowledge",ID="inter-BSC-MT HO"];
|
||||
...;
|
||||
---[label="On error"];
|
||||
bsc_lchan rbox bsc_lchan [label="Continue at 'When the lchan is no longer used'"];
|
||||
---;
|
||||
...;
|
||||
|
||||
bts => bsc_gscon [label="RR Assignment Complete",ID="BSSMAP Assignment Request"];
|
||||
bts => bsc_gscon [label="RR Handover Detect",ID="intra-BSC HO"];
|
||||
bts => bsc_gscon [label="RR Handover Accept",ID="inter-BSC-MT HO"];
|
||||
bsc_gscon note bsc_gscon [label="conn FSM takes care of MGW endpoints for BTS side (possibly
|
||||
redirect) and MSC side (possibly create). More information in e.g. assignment.msc and
|
||||
handover.msc"];
|
||||
|
||||
...;
|
||||
...;
|
||||
...;
|
||||
|
||||
bts rbox mgw_msc [label="When the lchan is no longer used"];
|
||||
--- [label="IF the MS or BTS release the lchan"];
|
||||
bts -> bsc_lchan [label="RLL Release Ind for SAPI=0"];
|
||||
--- [label="IF the BSC other than the conn FSM decides to release"];
|
||||
bsc -> bsc_lchan [label="LCHAN_EV_RELEASE"];
|
||||
--- [label="IF the MSC or conn FSM release the lchan"];
|
||||
bsc_lchan <- bsc_gscon [label="LCHAN_EV_RELEASE"];
|
||||
---;
|
||||
bsc note bsc_gscon [label="The LCHAN_EV_RELEASE's data pointer possibly indicates an error
|
||||
cause"];
|
||||
bsc_lchan note bsc_gscon [label="If the conn FSM requested a release, it probably has already
|
||||
forgotten about this lchan. However, if the MS/BTS initiated the release, make sure the conn FSM
|
||||
is informed:"];
|
||||
bsc_lchan box bsc_lchan [label="lchan_graceful_release()"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nSAPIS_RELEASED\nT3109"];
|
||||
--- [label="TCH and got as far as Chan Activ Ack?"];
|
||||
bts <= bsc_lchan [label="RSL Deactivate SACCH"];
|
||||
---;
|
||||
bts <= bsc_lchan [label="RLL Release Request (Local End)..."];
|
||||
bts <= bsc_lchan [label="...for all SAPIs except [0]"];
|
||||
|||;
|
||||
--- [label="SAPI[0] in use?"];
|
||||
bsc_lchan note bsc_lchan [label="for bts->nokia.no_loc_rel_cnf we do not expect Release Confirm
|
||||
messages and this state immediately advances to lchan_fsm_pre_rf_release()"];
|
||||
...;
|
||||
--- [label="on timeout"];
|
||||
bsc_lchan box bsc_lchan [label="Anyway try RF Channel Release, continue
|
||||
with lchan_fsm_wait_before_rf_release()"];
|
||||
---;
|
||||
...;
|
||||
bts => bsc_lchan [label="RLL Release Confirm..."];
|
||||
bts => bsc_lchan [label="...for each SAPI except [0]"];
|
||||
bsc_lchan box bsc_lchan [label="Stay in\nLCHAN_ST_WAIT_\nSAPIS_RELEASED\nuntil only SAPI[0] remains active"];
|
||||
--- [label="END: 'SAPI[0] in use?'"];
|
||||
|||;
|
||||
|
||||
bsc_lchan box bsc_lchan [label="lchan_fsm_wait_before_rf_release()"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nBEFORE_RF_RELEASE\nT3111"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_FORGET_LCHAN (data=lchan)"];
|
||||
bsc_gscon note bsc_gscon [label="conn FSM immediately forgets about the lchan"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP Clear Request?"];
|
||||
...;
|
||||
bsc_lchan box bsc_lchan [label="T3111 expires"];
|
||||
bsc_lchan box bsc_lchan [label="lchan_fsm_pre_rf_release()"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRF_RELEASE_ACK\nT3111"];
|
||||
bsc_lchan box bsc_lchan [label="for each bsc_rll_req matching this lchan: disable timer, call
|
||||
cb(BSC_RLLR_IND_REL_IND)"];
|
||||
bts <= bsc_lchan [label="RSL RF Channel Release"];
|
||||
...;
|
||||
--- [label="on timeout"];
|
||||
bsc_lchan rbox bsc_lchan [label="Continue at: 'On any error', 'unrecoverable'"];
|
||||
---;
|
||||
...;
|
||||
bts => bsc_lchan [label="RSL RF Channel Release Ack"];
|
||||
|
||||
bsc_lchan box bsc_lchan [label="lchan_fsm_post_rf_release()"];
|
||||
|||;
|
||||
--- [label="IF an error cause was indicated on LCHAN_EV_RELEASE"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nAFTER_ERROR\n(timeout: T3111+2 s, T?)"];
|
||||
...;
|
||||
bsc_lchan box bsc_lchan [label="timer expires"];
|
||||
--- [label="END: 'an error cause was indicated on LCHAN_EV_RELEASE'"];
|
||||
|||;
|
||||
bsc_lchan box bsc_lchan [label="lchan_fsm_release_complete()"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED"];
|
||||
bsc_ts abox bsc_ts [label="TS_ST_UNUSED"];
|
||||
|||;
|
||||
|||;
|
||||
|
||||
bts rbox mgw_msc [label="On any error"];
|
||||
|||;
|
||||
--- [label="IF FOR_MS_CHANNEL_REQUEST && !sent_chan_activ"];
|
||||
bts <= bsc_lchan [label="RR Immediate Assign Reject"];
|
||||
|||;
|
||||
--- [label="IF FOR_ASSIGNMENT or FOR_HANDOVER"];
|
||||
bsc_lchan -> bsc_gscon [label="GSCON_EV_LCHAN_ALLOC_ERROR"];
|
||||
bsc_gscon note bsc_gscon [label="conn FSM shall immediately 'forget' the lchan"];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP\nAssignment Failure",ID=FOR_ASSIGNMENT];
|
||||
bsc_gscon => mgw_msc [label="BSSMAP\nHandover Failure",ID="inter-BSC-MT HO"];
|
||||
---;
|
||||
|||;
|
||||
--- [label="IF unrecoverable error"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_BORKEN"];
|
||||
bsc_lchan note bsc_lchan [label="The broken state usually stays around
|
||||
until the BTS disconnects."];
|
||||
...;
|
||||
bts note bsc_lchan [label="If an ACK comes in late, for specific BTS models, we may choose to
|
||||
'repair' the lchan so that it is usable again."];
|
||||
bts -> bsc_lchan [label="Chan Release ACK"];
|
||||
bsc_lchan -> bsc_lchan [label="lchan_fsm_post_rf_release()"];
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
msc {
|
||||
hscale=3;
|
||||
ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_gscon[label="BSC conn FSM"];
|
||||
hscale=2;
|
||||
ms [label="MS"], bts [label="BTS"], bsc[label="BSC"], bsc_lchan[label="BSC lchan FSM"];
|
||||
|
||||
ms note bsc_gscon [label="lchan allocation sequence for RSL Channel Request"];
|
||||
ms note bsc_lchan [label="lchan allocation sequence for RSL Channel Request"];
|
||||
|
||||
ms => bts [label="RR Channel Request"];
|
||||
bts => bsc [label="RSL Channel Request"];
|
||||
|
@ -13,51 +13,47 @@ msc {
|
|||
longer concerned (rsl_rx_pchan_rqd())."];
|
||||
bsc note bsc [label="Always try to allocate an SDCCH regardless of the requested type, only if no
|
||||
SDCCH is available, look for the actually requested channel type."];
|
||||
bsc box bsc [label="lchan_alloc(SDCCH, allow_bigger=0)"];
|
||||
bsc box bsc [label="lchan_select_by_type(SDCCH)"];
|
||||
|
||||
--- [label="IF no lchan is available (neither SDCCH nor requested type)"];
|
||||
bsc note bsc [label="Figure out T3122 value from bts->T3122, network->T3122 or
|
||||
GSM_T3122_DEFAULT"];
|
||||
bsc box bsc [label="rsl_send_imm_ass_rej()"];
|
||||
bsc box bsc [label="rsl_send_imm_ass_rej(wait_ind=T3122)"];
|
||||
bsc note bsc [label="..."];
|
||||
bts <= bsc [label="RR Immediate Assign Reject"];
|
||||
ms <= bts [label="RR Immediate Assign Reject (possibly grouped with up to 4 others)"];
|
||||
bsc note bsc [label="rsl_rx_pchan_rqd() exits, no channel is allocated."];
|
||||
---;
|
||||
--- [label="END: no lchan is available"];
|
||||
|
||||
bsc box bsc [label="Store RACH data in lchan->rqd_ref, rqd_ta"];
|
||||
bsc abox bsc [label="Start lchan->act_timer (4s, lchan_act_tmr_cb())"];
|
||||
|
||||
bsc box bsc [label="rsl_chan_activate_lchan(RSL_ACT_INTRA_IMM_ASS)"];
|
||||
--- [label="is the chosen lchan on dynamic timeslot that is currently used as PDCH?"];
|
||||
bsc box bsc [linecolor=red,label="Osmocom style dyn TS use the lchan->act_timer for an RSL RF
|
||||
Channel Release, to release PDCH mode. This will actually overwrite above act_timer!"];
|
||||
bts <= bsc [label="i) RSL RF Chan Release of PDCH (Osmocom dyn TS)"];
|
||||
bts <= bsc [label="OR ii) RSL PDCH Deact (ip.access dyn TS)"];
|
||||
bsc -> bsc_gscon [label="gsm0808_assign_req() returns early"];
|
||||
bsc_gscon abox bsc_gscon [label="ST_WAIT_ASS_COMPL (GSM0808_T10_VALUE=6s)"];
|
||||
bsc -> bsc_lchan [label="lchan_allocate(FOR_MS_CHANNEL_REQUEST)"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_ACTIV_ACK\nT3103"];
|
||||
bsc_lchan note bsc_lchan [label="The lchan FSM knows that FOR_MS_CHANNEL_REQUEST is about
|
||||
Immediate Assignment."];
|
||||
bts <= bsc_lchan [label="RSL Chan Activ (Immediate Assignment)"];
|
||||
...;
|
||||
bts note bsc_gscon [linecolor="red",
|
||||
label="Osmocom style dyn TS use lchan->act_timer to watch over RF Chan Release, but there
|
||||
seems to be no timer watching over PDCH Deact!"];
|
||||
...;
|
||||
bts => bsc [label="i) RSL RF Chan Release ACK (Osmocom dyn TS)"];
|
||||
bts => bsc [label="OR ii) RSL PDCH Deact ACK (ip.access dyn TS)"];
|
||||
bsc box bsc [label="rsl_chan_activate_lchan() re-invoked"];
|
||||
--- [label="on any error"];
|
||||
bts <= bsc_lchan [label="RR Immediate Assign Reject"];
|
||||
ms <= bts [label="RR Immediate Assign Reject (possibly grouped with up to 4 others)"];
|
||||
---;
|
||||
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_ACT_REQ"];
|
||||
bts <= bsc [label="RSL Chan Activ: Immediate Assignment"];
|
||||
...;
|
||||
bsc note bsc [label="Timeout of lchan->act_timer causes the
|
||||
lchan->state to go to LCHAN_S_BROKEN, but no events or actions
|
||||
are triggered."];
|
||||
bts => bsc_lchan [label="RSL Chan Activ ACK"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_\nRLL_ESTABLISH\ncontinue T3103"];
|
||||
...;
|
||||
bts => bsc [label="RSL Chan Activ ACK"];
|
||||
bsc box bsc [label="rsl_rx_chan_act_ack()"];
|
||||
bsc box bsc [label="Stop lchan->act_timer"];
|
||||
bsc box bsc [label="lchan->state = LCHAN_S_ACTIVE"];
|
||||
bsc -> bsc [label="S_LCHAN_ACTIVATE_ACK (has no effect)"];
|
||||
bsc note bsc [label="Since this was an Immediate Assignment, no further action is required on
|
||||
behalf of the BSC. The MS is now free to use the lchan."];
|
||||
--- [label="on timeout"];
|
||||
bsc_lchan box bsc_lchan [label="lchan_error_release(deact_sacch=true)"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_RF_RELEASE_ACK"];
|
||||
bts <= bsc_lchan [label="RLL Release Request (Local End)..."];
|
||||
bts <= bsc_lchan [label="...for all SAPIs including [0]"];
|
||||
bts <= bsc_lchan [label="RSL Deactivate SACCH"];
|
||||
bts <= bsc_lchan [label="RSL RF Channel Release"];
|
||||
...;
|
||||
bts => bsc_lchan [label="RSL RF Channel Release ACK"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_WAIT_AFTER_ERROR"];
|
||||
...;
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
|
||||
---;
|
||||
ms => bsc_lchan [label="RLL Establish Ind"];
|
||||
bsc_lchan box bsc_lchan [label="associate lchan FSM with new conn FSM"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
digraph G {
|
||||
rankdir=TB;
|
||||
|
||||
invisible [style="invisible"]
|
||||
invisible2 [style="invisible"]
|
||||
NOT_INITIALIZED
|
||||
lchan [label="lchan FSM",shape=box3d];
|
||||
UNUSED
|
||||
IN_USE
|
||||
BORKEN
|
||||
PDCH
|
||||
WAIT_PDCH_ACT
|
||||
WAIT_PDCH_DEACT
|
||||
|
||||
invisible -> NOT_INITIALIZED [label="OML\nOpstart ACK",style=dotted]
|
||||
invisible2 -> NOT_INITIALIZED [label="RSL\nbootstrapped",style=dotted]
|
||||
|
||||
NOT_INITIALIZED -> UNUSED [label="OML+RSL ready"]
|
||||
|
||||
UNUSED -> IN_USE [label="first\nlchan\nrequested\nby lchan\nFSM"]
|
||||
IN_USE -> UNUSED [label="last lchan\nunused"]
|
||||
|
||||
UNUSED -> PDCH [label="onenter:\ndedicated PDCH\nand GPRS\nis enabled"]
|
||||
UNUSED -> WAIT_PDCH_ACT [label="onenter:\ndyn TS\nand GPRS\nis enabled"]
|
||||
WAIT_PDCH_ACT -> PDCH [label="dyn TS:\nPDCH activated"]
|
||||
|
||||
PDCH -> WAIT_PDCH_DEACT [label="dyn TS:\nlchan of specific\npchan requested"]
|
||||
WAIT_PDCH_DEACT -> UNUSED [label="lchan\nunused\n(e.g. error)",style=dashed]
|
||||
WAIT_PDCH_DEACT -> IN_USE [label="dyn TS:\nPDCH released"]
|
||||
|
||||
lchan -> {UNUSED} [label="TS_EV_LCHAN_\nREQUESTED",style=dotted]
|
||||
{IN_USE} -> lchan [label="LCHAN_EV_\nTS_READY",style=dotted]
|
||||
lchan -> IN_USE [label="TS_EV_LCHAN_\nUNUSED",style=dotted]
|
||||
|
||||
{WAIT_PDCH_ACT,WAIT_PDCH_DEACT} -> BORKEN [label=timeout,style=dashed]
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
msc {
|
||||
hscale=2;
|
||||
bts [label="MS/BTS"], bsc[label="BSC"], bsc_ts[label="BSC timeslot FSM"], bsc_lchan[label="BSC lchan FSM"];
|
||||
|
||||
bsc_ts abox bsc_ts [label="NOT_INITIALIZED (no timeout)"];
|
||||
|
||||
...;
|
||||
bsc note bsc_ts [label="OML and RSL may be established in any order"];
|
||||
bts => bsc_ts [label="OML: Channel OPSTART ACK"];
|
||||
bsc -> bsc_ts [label="RSL bootstrapped"];
|
||||
bsc_ts abox bsc_ts [label="UNUSED (no timeout)"];
|
||||
|
||||
|||;
|
||||
bts rbox bsc_lchan [label="UNUSED, onenter"];
|
||||
bsc_ts abox bsc_ts [label="UNUSED"];
|
||||
--- [label="GPRS enabled?"];
|
||||
--- [label="IF: dedicated PDCH?"];
|
||||
bsc_ts abox bsc_ts [label="PDCH (no timeout)"];
|
||||
|
||||
|||;
|
||||
--- [label="IF: dynamic timeslot"];
|
||||
bsc_ts abox bsc_ts [label="WAIT_PDCH_ACT (?s, Tnnnn)"];
|
||||
bts <= bsc_ts [label="RSL Chan Activ of PDCH",ID="Osmocom style"];
|
||||
bts <= bsc_ts [label="RSL PDCH Act",ID="ip.access style"];
|
||||
...;
|
||||
--- [label="timeout:"];
|
||||
bsc_ts abox bsc_ts [label="BORKEN"];
|
||||
---;
|
||||
...;
|
||||
bts => bsc_ts [label="RSL RF Chan Activ ACK",ID="Osmocom style"];
|
||||
bts => bsc_ts [label="RSL PDCH Act ACK",ID="ip.access style"];
|
||||
bsc_ts abox bsc_ts [label="PDCH (no timeout)"];
|
||||
|
||||
--- [label="END: GPRS enabled?"];
|
||||
...;
|
||||
...;
|
||||
|
||||
bts rbox bsc_lchan [label="UNUSED, on event"];
|
||||
bsc_ts abox bsc_ts [label="UNUSED"];
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_REQUESTED (data=lchan)"];
|
||||
bsc_ts abox bsc_ts [label="IN_USE"];
|
||||
bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_READY"];
|
||||
bts <= bsc_lchan [label="RSL Chan Activ (and so on)"];
|
||||
...;
|
||||
bts rbox bsc_lchan [label="IN_USE, second lchan"];
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_REQUESTED (data=lchan)"];
|
||||
bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_READY"];
|
||||
bts <= bsc_lchan [label="RSL Chan Activ (and so on)"];
|
||||
...;
|
||||
...;
|
||||
bts rbox bsc_lchan [label="IN_USE, when lchan FSM releases (both regularly, or due to error)"];
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED (data=lchan)"];
|
||||
--- [label="IF all lchan->fi->state == LCHAN_ST_UNUSED"];
|
||||
bsc_ts abox bsc_ts [label="UNUSED"];
|
||||
---;
|
||||
...;
|
||||
...;
|
||||
|
||||
|
||||
bts rbox bsc_lchan [label="PDCH on lchan request"];
|
||||
bsc_ts note bsc_lchan [label="TS_EV_LCHAN_REQUESTED should only come in on
|
||||
lchans where it makes sense, both from TS kind as well as not
|
||||
conflicting with other users of the lchan."];
|
||||
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_REQUESTED"];
|
||||
bsc_ts abox bsc_ts [label="WAIT_PDCH_DEACT (?s, Tnnnn)"];
|
||||
bts <= bsc_ts [label="RSL RF Chan Release of PDCH",ID="Osmocom style"];
|
||||
bts <= bsc_ts [label="RSL PDCH Deact",ID="ip.access style"];
|
||||
...;
|
||||
--- [label="timeout:"];
|
||||
bsc_ts abox bsc_ts [label="BORKEN"];
|
||||
bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_ERROR"];
|
||||
---;
|
||||
...;
|
||||
bts => bsc_ts [label="RSL RF Chan Release ACK",ID="Osmocom style"];
|
||||
bts => bsc_ts [label="RSL PDCH Deact ACK",ID="ip.access style"];
|
||||
--- [label="IF all lchan->fi->state == LCHAN_ST_UNUSED"];
|
||||
bsc_ts note bsc_lchan [label="If the lchan FSM decided to give up in the
|
||||
meantime, nr of active lchans might have dropped back to zero."];
|
||||
bsc_ts abox bsc_ts [label="UNUSED"];
|
||||
bsc_ts note bsc_ts [label="onenter at UNUSED state will trigger back to
|
||||
PDCH mode"];
|
||||
|||;
|
||||
--- [label="IF at least one lchan->state != LCHAN_ST_UNUSED"];
|
||||
bsc_ts abox bsc_ts [label="IN_USE"];
|
||||
bsc_ts rbox bsc_ts [label="Continue at 'IN_USE' above"];
|
||||
...;
|
||||
...;
|
||||
|
||||
bts rbox bsc_lchan [label="on erratic event"];
|
||||
bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_ERROR"];
|
||||
bsc_lchan box bsc_lchan [label="release lchan"];
|
||||
...;
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED"];
|
||||
bsc_ts note bsc_ts [label="log error but ignore"];
|
||||
...;
|
||||
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
msc {
|
||||
hscale=2;
|
||||
bts [label="MS/BTS"], bsc[label="BSC"], bsc_ts[label="BSC timeslot FSM"], bsc_lchan[label="BSC lchan FSM"];
|
||||
|
||||
bsc box bsc [label="gsm_bts_alloc()"];
|
||||
bsc box bsc [label="bts->c0 = gsm_bts_trx_alloc()"];
|
||||
bsc -> bsc_ts;
|
||||
bsc_ts box bsc_ts [label="trx->ts[*].fi = osmo_fsm_inst_alloc(timeslot_fsm)"];
|
||||
bsc_ts abox bsc_ts [label="TS_ST_NOT_INITIALIZED"];
|
||||
bsc -> bsc_lchan;
|
||||
bsc_lchan box bsc_lchan [label="ts->lchan[*].ts = ts;\nts->lchan[*].nr = i;"];
|
||||
bsc_lchan box bsc_lchan [label="ts->lchan[*].fi = NULL"];
|
||||
bsc_ts note bsc_lchan [label="lchan_select() will only pick lchans from initialized timeslots of
|
||||
the right pchan kind. lchan_select() shall OSMO_ASSERT(lchan->fi)."];
|
||||
...;
|
||||
...;
|
||||
|
||||
bts rbox bsc_lchan [label="reading config file"];
|
||||
...;
|
||||
bsc box bsc [label="timeslot N"];
|
||||
bsc box bsc [label="phys_chan_config X"];
|
||||
bsc_ts box bsc_ts [label="ts->pchan_from_config = X"];
|
||||
bsc_ts note bsc_ts [label="still TS_ST_NOT_INITIALIZED"];
|
||||
...;
|
||||
bsc box bsc [label="trx 1..*"];
|
||||
bsc box bsc [label="bts->trx_list add gsm_bts_trx_alloc()"];
|
||||
bsc_ts rbox bsc_lchan [label="same as for c0 above"];
|
||||
...;
|
||||
...;
|
||||
bts rbox bsc_lchan [label="Starting Operation"];
|
||||
bts => bsc_ts [label="OML Channel OPSTART ACK"];
|
||||
bsc_ts box bsc_ts [label="ts_on_oml_opstart()"];
|
||||
bsc_ts box bsc_ts [label="ts->pchan_on_init = pchan_from_config"];
|
||||
--- [label="IF dedicated TS"];
|
||||
bsc_ts box bsc_ts [label="ts->pchan = ts->pchan_on_init"];
|
||||
--- [label="ELSE: dyn TS"];
|
||||
bsc_ts box bsc_ts [label="ts->pchan = NONE"];
|
||||
--- [label="END: dyn TS"];
|
||||
bsc_ts note bsc_lchan [label="Normally, the lchan FSM never terminates. Logic dictates that
|
||||
the lchan is a child of the timeslot FSM, but it's not actually of functional importance
|
||||
beyond basic sanity. Parent term event: TS_EV_LCHAN_UNUSED"];
|
||||
bsc_ts box bsc_ts [label="Determine N = maximum number of lchans applicable to pchan_on_init"];
|
||||
bsc_ts -> bsc_lchan;
|
||||
bsc_lchan box bsc_lchan [label="ts->lchan[all N].type = osmo_fsm_inst_alloc(lchan_fsm)"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED\n(initial state)"];
|
||||
bsc_ts -> bsc_ts [label="ts_check_init()"];
|
||||
...;
|
||||
bsc -> bsc_ts [label="RSL bootstrapped"];
|
||||
bsc_ts -> bsc_ts [label="ts_check_init()"];
|
||||
...;
|
||||
bsc_ts box bsc_ts [label="ts_check_init()"];
|
||||
--- [label="as soon as both OML and RSL are ready:"];
|
||||
bsc_ts box bsc_ts [label="ts_on_init()"];
|
||||
bsc_ts abox bsc_ts [label="TS_ST_UNUSED"];
|
||||
--- [label="dyn TS"];
|
||||
bsc_ts box bsc_ts [label="onenter of TS_ST_UNUSED:"];
|
||||
bsc_ts abox bsc_ts [label="TS_ST_WAIT_PDCH_ACT"];
|
||||
...;
|
||||
bsc_ts abox bsc_ts [label="PDCH"];
|
||||
--- [label="END: dyn TS"];
|
||||
--- [label="END: OML and RSL ready"];
|
||||
...;
|
||||
bsc box bsc [label="lchan_select() picks an unused lchan"];
|
||||
bsc -> bsc_lchan [label="lchan_allocate()"];
|
||||
bsc_lchan -> bsc_ts [label="TS_EV_LCHAN_REQUESTED"];
|
||||
|
||||
--- [label="dyn TS"];
|
||||
bsc_ts note bsc_ts [label="possibly switch from PDCH...\n(see timeslot FSM)"];
|
||||
bsc_ts box bsc_ts [label="ts->pchan =\n requested GSM_PCHAN_XXX type"];
|
||||
---;
|
||||
|
||||
bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_READY"];
|
||||
bsc_lchan note bsc_lchan [label="RSL Chan Alloc and so fort..."];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_ACTIVE"];
|
||||
...;
|
||||
bsc -> bsc_lchan [label="LCHAN_EV_RELEASE"];
|
||||
bsc_lchan note bsc_lchan [label="...RSL RF Chan Release..."];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED"];
|
||||
bsc_ts abox bsc_ts [label="TS_ST_UNUSED"];
|
||||
--- [label="dyn TS"];
|
||||
bsc_ts note bsc_ts [label="possibly switch to PDCH"];
|
||||
---;
|
||||
...;
|
||||
...;
|
||||
bts rbox bsc_lchan [label="BTS RSL is dropped"];
|
||||
bsc box bsc [label="ipaccess_drop_rsl()"];
|
||||
bsc -> bsc_ts [label="ts[*]:"];
|
||||
bsc_ts abox bsc_ts [label="TS_ST_NOT_INITIALIZED"];
|
||||
bsc_ts note bsc_lchan [label="If it's just the RSL being dropped, transition lchan FSMs to
|
||||
LCHAN_ST_UNUSED, but keep them allocated. Unless OML is re-established, any vty pchan
|
||||
modifications must not take effect."];
|
||||
bsc_ts -> bsc_lchan [label="lchan[*]:"];
|
||||
bsc_lchan abox bsc_lchan [label="LCHAN_ST_UNUSED"];
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED (ignored)"];
|
||||
...;
|
||||
--- [label="when RSL comes back later:"];
|
||||
bsc -> bsc_ts [label="RSL bootstrapped"];
|
||||
bsc_ts box bsc_ts [label="ts_check_init()"];
|
||||
bsc_ts rbox bsc_ts [label="see ts_check_init() above"];
|
||||
...;
|
||||
...;
|
||||
bts rbox bsc_lchan [label="BTS OML is dropped"];
|
||||
bsc note bsc [label="As part of OML drop, RSL is also dropped:"];
|
||||
bsc box bsc [label="ipaccess_drop_rsl()"];
|
||||
bsc -> bsc_ts [label="ts[*]:"];
|
||||
bsc_ts abox bsc_ts [label="TS_ST_NOT_INITIALIZED"];
|
||||
bsc rbox bsc [label="see 'BTS RSL is dropped' above"];
|
||||
bsc -> bsc_ts [label="ts[*]:"];
|
||||
bsc_ts -> bsc_lchan [label="lchan[*]:"];
|
||||
bsc_lchan box bsc_lchan [label="osmo_fsm_inst_term()"];
|
||||
bsc_ts <- bsc_lchan [label="TS_EV_LCHAN_UNUSED (ignored)"];
|
||||
bsc_lchan box bsc_lchan [label="lchan->fi = NULL"];
|
||||
bsc rbox bsc [label="Continue at 'Starting Operation'"];
|
||||
|
||||
}
|
Loading…
Reference in New Issue