/* Handover FSM API for intra-BSC and inter-BSC Handover. */ #pragma once #include #include const char *handover_status(struct gsm_subscriber_connection *conn); /* This macro automatically includes a final \n, if omitted. */ #define LOG_HO(conn, level, fmt, args...) do { \ if (conn->ho.fi) \ LOGPFSML(conn->ho.fi, level, "%s: " fmt, \ handover_status(conn), ## args); \ else \ LOGP(DHODEC, level, "%s: " fmt, \ handover_status(conn), ## args); \ } while(0) /* Terminology: * Intra-Cell: stays within one BTS, this should actually be an Assignment. * Intra-BSC: stays within one BSC, but moves between BTSes. * Inter-BSC: moves between BSCs. * Inter-BSC Out: move away from this BSC to another one. * Inter-BSC In: move from another BSC to this one. */ enum handover_fsm_state { HO_ST_NOT_STARTED, HO_ST_WAIT_LCHAN_ACTIVE, HO_ST_WAIT_RR_HO_DETECT, HO_ST_WAIT_RR_HO_COMPLETE, HO_ST_WAIT_LCHAN_ESTABLISHED, HO_ST_WAIT_MGW_ENDPOINT_TO_MSC, /* The inter-BSC Outgoing Handover FSM has completely separate states, but since it makes sense for it * to also live in conn->ho.fi, it should share the same event enum. From there it is merely * cosmetic to just include the separate fairly trivial states in the same FSM definition. * An inter-BSC Outgoing FSM is almost unnecessary. The sole reason is to wait whether the MSC * indeed clears the conn, and if not to log and count a failed handover attempt. */ HO_OUT_ST_WAIT_HO_COMMAND, HO_OUT_ST_WAIT_CLEAR, }; enum handover_fsm_event { HO_EV_LCHAN_ACTIVE, HO_EV_LCHAN_ESTABLISHED, HO_EV_LCHAN_ERROR, HO_EV_RR_HO_DETECT, HO_EV_RR_HO_COMPLETE, HO_EV_RR_HO_FAIL, HO_EV_MSC_MGW_OK, HO_EV_MSC_MGW_FAIL, HO_EV_CONN_RELEASING, HO_OUT_EV_BSSMAP_HO_COMMAND, }; struct ho_out_rx_bssmap_ho_command { const uint8_t *l3_info; const uint8_t l3_info_len; }; /* To be sent along with the HO_EV_RR_HO_DETECT */ struct handover_rr_detect_data { struct msgb *msg; const uint8_t *access_delay; }; void handover_fsm_init(); void handover_request(struct handover_out_req *req); void handover_start(struct handover_out_req *req); void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn, struct msgb *ho_request_msg); void handover_end(struct gsm_subscriber_connection *conn, enum handover_result result); const char *handover_status(struct gsm_subscriber_connection *conn); bool handover_is_sane(struct gsm_subscriber_connection *conn, struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan);