diff options
author | Neels Hofmeyr <neels@hofmeyr.de> | 2018-07-24 16:12:45 +0200 |
---|---|---|
committer | Neels Hofmeyr <neels@hofmeyr.de> | 2018-07-28 12:18:23 +0200 |
commit | 68455f30a0a8dbda230091c13adce00760b7a467 (patch) | |
tree | 71be6b1103d54a91d93d5c308e4c6310867e3138 /src/osmo-bsc | |
parent | 6242742d2022d5d27fa938409e89514cb548d0de (diff) |
cosmetic: move RR functions from bsc_api.c to gsm_04_08_rr.c
Rationale: bsc_api.c used to be a kind of kitchen sink for various
implementations, we want to dissolve it. Also, combining 0808 and 0408 in the
same c file causes "weird" linking dependencies for utility and test programs.
bsc_api.c will be completely dissolved in upcoming
Ib7ce026b52d4ba3e53a8b2824e74ea92432c48c5.
Change-Id: Ie8ee334145bf7bc3a601d395ea7ab9b2009b61c7
Diffstat (limited to 'src/osmo-bsc')
-rw-r--r-- | src/osmo-bsc/bsc_api.c | 306 | ||||
-rw-r--r-- | src/osmo-bsc/gsm_04_08_rr.c | 307 |
2 files changed, 307 insertions, 306 deletions
diff --git a/src/osmo-bsc/bsc_api.c b/src/osmo-bsc/bsc_api.c index 2ce8d3bad..92b64e4d0 100644 --- a/src/osmo-bsc/bsc_api.c +++ b/src/osmo-bsc/bsc_api.c @@ -195,312 +195,6 @@ int gsm0808_page(struct gsm_bts *bts, unsigned int page_group, unsigned int mi_l return rsl_paging_cmd(bts, page_group, mi_len, mi, chan_type, false); } -static void handle_ass_compl(struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - struct gsm48_hdr *gh = msgb_l3(msg); - enum gsm48_rr_cause cause; - - /* Expecting gsm48_hdr + cause value */ - if (msgb_l3len(msg) != sizeof(*gh) + 1) { - LOGPLCHAN(msg->lchan, DRR, LOGL_ERROR, - "RR Assignment Complete: length invalid: %u, expected %zu\n", - msgb_l3len(msg), sizeof(*gh) + 1); - return; - } - - cause = gh->data[0]; - - LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, "ASSIGNMENT COMPLETE cause = %s\n", - rr_cause_name(cause)); - - if (conn->ho) { - struct lchan_signal_data sig = { - .lchan = msg->lchan, - }; - osmo_signal_dispatch(SS_LCHAN, S_LCHAN_ASSIGNMENT_COMPL, &sig); - /* FIXME: release old channel */ - - /* send pending messages, if any */ - gscon_dtap_queue_flush(conn, 1); - - return; - } - - if (conn->secondary_lchan != msg->lchan) { - LOGPLCHAN(msg->lchan, DRR, LOGL_ERROR, - "RR Assignment Complete does not match conn's secondary lchan.\n"); - return; - } - - lchan_release(conn->lchan, 0, RSL_REL_LOCAL_END); - conn->lchan = conn->secondary_lchan; - conn->secondary_lchan = NULL; - - /* send pending messages, if any */ - gscon_dtap_queue_flush(conn, 1); - - if (is_ipaccess_bts(conn_get_bts(conn)) && conn->lchan->tch_mode != GSM48_CMODE_SIGN) - rsl_ipacc_crcx(conn->lchan); - - bsc_assign_compl(conn, cause); -} - -static void handle_ass_fail(struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - uint8_t *rr_failure; - struct gsm48_hdr *gh; - - if (conn->ho) { - struct lchan_signal_data sig; - struct gsm48_hdr *gh = msgb_l3(msg); - - LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, "ASSIGNMENT FAILED cause = %s\n", - rr_cause_name(gh->data[0])); - - sig.lchan = msg->lchan; - sig.mr = NULL; - osmo_signal_dispatch(SS_LCHAN, S_LCHAN_ASSIGNMENT_FAIL, &sig); - /* FIXME: release allocated new channel */ - - /* send pending messages, if any */ - gscon_dtap_queue_flush(conn, 1); - - return; - } - - if (conn->lchan != msg->lchan) { - LOGPLCHAN(msg->lchan, DMSC, LOGL_ERROR, - "Assignment failure should occur on primary lchan.\n"); - return; - } - - /* stop the timer and release it */ - if (conn->secondary_lchan) { - lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END); - conn->secondary_lchan = NULL; - } - - /* send pending messages, if any */ - gscon_dtap_queue_flush(conn, 1); - - gh = msgb_l3(msg); - if (msgb_l3len(msg) - sizeof(*gh) != 1) { - LOGPLCHAN(conn->lchan, DMSC, LOGL_ERROR, "assignment failure unhandled: %zu\n", - msgb_l3len(msg) - sizeof(*gh)); - rr_failure = NULL; - } else { - rr_failure = &gh->data[0]; - } - - bsc_assign_fail(conn, GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, rr_failure); -} - -static void handle_classmark_chg(struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - struct gsm48_hdr *gh = msgb_l3(msg); - unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); - uint8_t cm2_len, cm3_len = 0; - uint8_t *cm2, *cm3 = NULL; - - LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, "CLASSMARK CHANGE "); - - /* classmark 2 */ - cm2_len = gh->data[0]; - cm2 = &gh->data[1]; - DEBUGPC(DRR, "CM2(len=%u) ", cm2_len); - - if (payload_len > cm2_len + 1) { - /* we must have a classmark3 */ - if (gh->data[cm2_len+1] != 0x20) { - DEBUGPC(DRR, "ERR CM3 TAG\n"); - return; - } - if (cm2_len > 3) { - DEBUGPC(DRR, "CM2 too long!\n"); - return; - } - - cm3_len = gh->data[cm2_len+2]; - cm3 = &gh->data[cm2_len+3]; - if (cm3_len > 14) { - DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len); - return; - } - DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len); - } - bsc_cm_update(conn, cm2, cm2_len, cm3, cm3_len); -} - -/* Chapter 9.1.16 Handover complete */ -static void handle_rr_ho_compl(struct msgb *msg) -{ - struct lchan_signal_data sig; - struct gsm48_hdr *gh = msgb_l3(msg); - - LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, - "HANDOVER COMPLETE cause = %s\n", rr_cause_name(gh->data[0])); - - sig.lchan = msg->lchan; - sig.mr = NULL; - osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_COMPL, &sig); - /* FIXME: release old channel */ - - /* send pending messages, if any */ - gscon_dtap_queue_flush(msg->lchan->conn, 1); -} - -/* Chapter 9.1.17 Handover Failure */ -static void handle_rr_ho_fail(struct msgb *msg) -{ - struct lchan_signal_data sig; - struct gsm48_hdr *gh = msgb_l3(msg); - - /* Log on both RR and HO categories: it is an RR message, but is still quite important when - * filtering on HO. */ - LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, - "HANDOVER FAILED cause = %s\n", rr_cause_name(gh->data[0])); - LOGPLCHAN(msg->lchan, DHO, LOGL_DEBUG, - "HANDOVER FAILED cause = %s\n", rr_cause_name(gh->data[0])); - - sig.lchan = msg->lchan; - sig.mr = NULL; - osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_FAIL, &sig); - /* FIXME: release allocated new channel */ - - /* send pending messages, if any */ - gscon_dtap_queue_flush(msg->lchan->conn, 1); -} - - -static void dispatch_dtap(struct gsm_subscriber_connection *conn, - uint8_t link_id, struct msgb *msg) -{ - struct gsm48_hdr *gh; - uint8_t pdisc; - uint8_t msg_type; - int rc; - - if (msgb_l3len(msg) < sizeof(*gh)) { - LOGP(DMSC, LOGL_ERROR, "(%s) Message too short for a GSM48 header.\n", - bsc_subscr_name(conn->bsub)); - return; - } - - gh = msgb_l3(msg); - pdisc = gsm48_hdr_pdisc(gh); - msg_type = gsm48_hdr_msg_type(gh); - - /* the idea is to handle all RR messages here, and only hand - * MM/CC/SMS-CP/LCS up to the MSC. Some messages like PAGING - * RESPONSE or CM SERVICE REQUEST will not be covered here, as - * they are only possible in the first L3 message of each L2 - * channel, i.e. 'conn' will not exist and gsm0408_rcvmsg() - * will call api->compl_l3() for it */ - switch (pdisc) { - case GSM48_PDISC_RR: - switch (msg_type) { - case GSM48_MT_RR_GPRS_SUSP_REQ: - LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, - "%s\n", gsm48_rr_msg_name(GSM48_MT_RR_GPRS_SUSP_REQ)); - break; - case GSM48_MT_RR_STATUS: - LOGPLCHAN(msg->lchan, DRR, LOGL_NOTICE, - "%s (cause: %s)\n", gsm48_rr_msg_name(GSM48_MT_RR_STATUS), - rr_cause_name(gh->data[0])); - break; - case GSM48_MT_RR_MEAS_REP: - /* This shouldn't actually end up here, as RSL treats - * L3 Info of 08.58 MEASUREMENT REPORT different by calling - * directly into gsm48_parse_meas_rep */ - LOGPLCHAN(msg->lchan, DMEAS, LOGL_ERROR, - "DIRECT GSM48 MEASUREMENT REPORT ?!?\n"); - gsm48_tx_rr_status(conn, GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT); - break; - case GSM48_MT_RR_HANDO_COMPL: - handle_rr_ho_compl(msg); - break; - case GSM48_MT_RR_HANDO_FAIL: - handle_rr_ho_fail(msg); - break; - case GSM48_MT_RR_CIPH_M_COMPL: - bsc_cipher_mode_compl(conn, msg, conn->lchan->encr.alg_id); - break; - case GSM48_MT_RR_ASS_COMPL: - handle_ass_compl(conn, msg); - break; - case GSM48_MT_RR_ASS_FAIL: - handle_ass_fail(conn, msg); - break; - case GSM48_MT_RR_CHAN_MODE_MODIF_ACK: - rc = gsm48_rx_rr_modif_ack(msg); - if (rc < 0) - bsc_assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL); - else - bsc_assign_compl(conn, 0); - break; - case GSM48_MT_RR_CLSM_CHG: - handle_classmark_chg(conn, msg); - break; - case GSM48_MT_RR_APP_INFO: - /* Passing RR APP INFO to MSC, not quite - * according to spec */ - bsc_dtap(conn, link_id, msg); - break; - default: - /* Drop unknown RR message */ - LOGPLCHAN(msg->lchan, DRR, LOGL_NOTICE, - "Dropping %s 04.08 RR message\n", gsm48_rr_msg_name(msg_type)); - gsm48_tx_rr_status(conn, GSM48_RR_CAUSE_MSG_TYPE_N); - break; - } - break; - default: - bsc_dtap(conn, link_id, msg); - break; - } -} - -/*! \brief RSL has received a DATA INDICATION with L3 from MS */ -int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id) -{ - int rc; - struct gsm_lchan *lchan; - - lchan = msg->lchan; - if (lchan->state != LCHAN_S_ACTIVE) { - LOGPLCHAN(msg->lchan, DRSL, LOGL_INFO, "Got data in non active state, discarding.\n"); - return -1; - } - - - if (lchan->conn) { - /* if we already have a connection, forward via DTAP to - * MSC */ - dispatch_dtap(lchan->conn, link_id, msg); - } else { - /* allocate a new connection */ - rc = BSC_API_CONN_POL_REJECT; - lchan->conn = bsc_subscr_con_allocate(msg->lchan->ts->trx->bts->network); - if (!lchan->conn) { - lchan_release(lchan, 1, RSL_REL_NORMAL); - return -1; - } - lchan->conn->lchan = lchan; - - /* fwd via bsc_api to send COMPLETE L3 INFO to MSC */ - rc = bsc_compl_l3(lchan->conn, msg, 0); - - if (rc != BSC_API_CONN_POL_ACCEPT) { - //osmo_fsm_inst_dispatch(lchan->conn->fi, FIXME, NULL); - } - } - - return 0; -} - /*! \brief We received a GSM 08.08 CIPHER MODE from the MSC */ int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher, const uint8_t *key, int len, int include_imeisv) diff --git a/src/osmo-bsc/gsm_04_08_rr.c b/src/osmo-bsc/gsm_04_08_rr.c index 64eace7e3..e6b654ac1 100644 --- a/src/osmo-bsc/gsm_04_08_rr.c +++ b/src/osmo-bsc/gsm_04_08_rr.c @@ -36,6 +36,8 @@ #include <osmocom/bsc/signal.h> #include <osmocom/bsc/bsc_subscr_conn_fsm.h> #include <osmocom/bsc/gsm_04_08_rr.h> +#include <osmocom/bsc/chan_alloc.h> +#include <osmocom/bsc/bsc_api.h> /* should ip.access BTS use direct RTP streams between each other (1), * or should OpenBSC always act as RTP relay/proxy in between (0) ? */ @@ -716,3 +718,308 @@ uint64_t str_to_imsi(const char *imsi_str) return ret; } + +static void handle_ass_compl(struct gsm_subscriber_connection *conn, + struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + enum gsm48_rr_cause cause; + + /* Expecting gsm48_hdr + cause value */ + if (msgb_l3len(msg) != sizeof(*gh) + 1) { + LOGPLCHAN(msg->lchan, DRR, LOGL_ERROR, + "RR Assignment Complete: length invalid: %u, expected %zu\n", + msgb_l3len(msg), sizeof(*gh) + 1); + return; + } + + cause = gh->data[0]; + + LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, "ASSIGNMENT COMPLETE cause = %s\n", + rr_cause_name(cause)); + + if (conn->ho) { + struct lchan_signal_data sig = { + .lchan = msg->lchan, + }; + osmo_signal_dispatch(SS_LCHAN, S_LCHAN_ASSIGNMENT_COMPL, &sig); + /* FIXME: release old channel */ + + /* send pending messages, if any */ + gscon_dtap_queue_flush(conn, 1); + + return; + } + + if (conn->secondary_lchan != msg->lchan) { + LOGPLCHAN(msg->lchan, DRR, LOGL_ERROR, + "RR Assignment Complete does not match conn's secondary lchan.\n"); + return; + } + + lchan_release(conn->lchan, 0, RSL_REL_LOCAL_END); + conn->lchan = conn->secondary_lchan; + conn->secondary_lchan = NULL; + + /* send pending messages, if any */ + gscon_dtap_queue_flush(conn, 1); + + if (is_ipaccess_bts(conn_get_bts(conn)) && conn->lchan->tch_mode != GSM48_CMODE_SIGN) + rsl_ipacc_crcx(conn->lchan); + + bsc_assign_compl(conn, cause); +} + +static void handle_ass_fail(struct gsm_subscriber_connection *conn, + struct msgb *msg) +{ + uint8_t *rr_failure; + struct gsm48_hdr *gh; + + if (conn->ho) { + struct lchan_signal_data sig; + struct gsm48_hdr *gh = msgb_l3(msg); + + LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, "ASSIGNMENT FAILED cause = %s\n", + rr_cause_name(gh->data[0])); + + sig.lchan = msg->lchan; + sig.mr = NULL; + osmo_signal_dispatch(SS_LCHAN, S_LCHAN_ASSIGNMENT_FAIL, &sig); + /* FIXME: release allocated new channel */ + + /* send pending messages, if any */ + gscon_dtap_queue_flush(conn, 1); + + return; + } + + if (conn->lchan != msg->lchan) { + LOGPLCHAN(msg->lchan, DMSC, LOGL_ERROR, + "Assignment failure should occur on primary lchan.\n"); + return; + } + + /* stop the timer and release it */ + if (conn->secondary_lchan) { + lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END); + conn->secondary_lchan = NULL; + } + + /* send pending messages, if any */ + gscon_dtap_queue_flush(conn, 1); + + gh = msgb_l3(msg); + if (msgb_l3len(msg) - sizeof(*gh) != 1) { + LOGPLCHAN(conn->lchan, DMSC, LOGL_ERROR, "assignment failure unhandled: %zu\n", + msgb_l3len(msg) - sizeof(*gh)); + rr_failure = NULL; + } else { + rr_failure = &gh->data[0]; + } + + bsc_assign_fail(conn, GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, rr_failure); +} + +static void handle_classmark_chg(struct gsm_subscriber_connection *conn, + struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); + uint8_t cm2_len, cm3_len = 0; + uint8_t *cm2, *cm3 = NULL; + + LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, "CLASSMARK CHANGE "); + + /* classmark 2 */ + cm2_len = gh->data[0]; + cm2 = &gh->data[1]; + DEBUGPC(DRR, "CM2(len=%u) ", cm2_len); + + if (payload_len > cm2_len + 1) { + /* we must have a classmark3 */ + if (gh->data[cm2_len+1] != 0x20) { + DEBUGPC(DRR, "ERR CM3 TAG\n"); + return; + } + if (cm2_len > 3) { + DEBUGPC(DRR, "CM2 too long!\n"); + return; + } + + cm3_len = gh->data[cm2_len+2]; + cm3 = &gh->data[cm2_len+3]; + if (cm3_len > 14) { + DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len); + return; + } + DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len); + } + bsc_cm_update(conn, cm2, cm2_len, cm3, cm3_len); +} + +/* Chapter 9.1.16 Handover complete */ +static void handle_rr_ho_compl(struct msgb *msg) +{ + struct lchan_signal_data sig; + struct gsm48_hdr *gh = msgb_l3(msg); + + LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, + "HANDOVER COMPLETE cause = %s\n", rr_cause_name(gh->data[0])); + + sig.lchan = msg->lchan; + sig.mr = NULL; + osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_COMPL, &sig); + /* FIXME: release old channel */ + + /* send pending messages, if any */ + gscon_dtap_queue_flush(msg->lchan->conn, 1); +} + +/* Chapter 9.1.17 Handover Failure */ +static void handle_rr_ho_fail(struct msgb *msg) +{ + struct lchan_signal_data sig; + struct gsm48_hdr *gh = msgb_l3(msg); + + /* Log on both RR and HO categories: it is an RR message, but is still quite important when + * filtering on HO. */ + LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, + "HANDOVER FAILED cause = %s\n", rr_cause_name(gh->data[0])); + LOGPLCHAN(msg->lchan, DHO, LOGL_DEBUG, + "HANDOVER FAILED cause = %s\n", rr_cause_name(gh->data[0])); + + sig.lchan = msg->lchan; + sig.mr = NULL; + osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_FAIL, &sig); + /* FIXME: release allocated new channel */ + + /* send pending messages, if any */ + gscon_dtap_queue_flush(msg->lchan->conn, 1); +} + +static void dispatch_dtap(struct gsm_subscriber_connection *conn, + uint8_t link_id, struct msgb *msg) +{ + struct gsm48_hdr *gh; + uint8_t pdisc; + uint8_t msg_type; + int rc; + + if (msgb_l3len(msg) < sizeof(*gh)) { + LOGP(DMSC, LOGL_ERROR, "(%s) Message too short for a GSM48 header.\n", + bsc_subscr_name(conn->bsub)); + return; + } + + gh = msgb_l3(msg); + pdisc = gsm48_hdr_pdisc(gh); + msg_type = gsm48_hdr_msg_type(gh); + + /* the idea is to handle all RR messages here, and only hand + * MM/CC/SMS-CP/LCS up to the MSC. Some messages like PAGING + * RESPONSE or CM SERVICE REQUEST will not be covered here, as + * they are only possible in the first L3 message of each L2 + * channel, i.e. 'conn' will not exist and gsm0408_rcvmsg() + * will call api->compl_l3() for it */ + switch (pdisc) { + case GSM48_PDISC_RR: + switch (msg_type) { + case GSM48_MT_RR_GPRS_SUSP_REQ: + LOGPLCHAN(msg->lchan, DRR, LOGL_DEBUG, + "%s\n", gsm48_rr_msg_name(GSM48_MT_RR_GPRS_SUSP_REQ)); + break; + case GSM48_MT_RR_STATUS: + LOGPLCHAN(msg->lchan, DRR, LOGL_NOTICE, + "%s (cause: %s)\n", gsm48_rr_msg_name(GSM48_MT_RR_STATUS), + rr_cause_name(gh->data[0])); + break; + case GSM48_MT_RR_MEAS_REP: + /* This shouldn't actually end up here, as RSL treats + * L3 Info of 08.58 MEASUREMENT REPORT different by calling + * directly into gsm48_parse_meas_rep */ + LOGPLCHAN(msg->lchan, DMEAS, LOGL_ERROR, + "DIRECT GSM48 MEASUREMENT REPORT ?!?\n"); + gsm48_tx_rr_status(conn, GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT); + break; + case GSM48_MT_RR_HANDO_COMPL: + handle_rr_ho_compl(msg); + break; + case GSM48_MT_RR_HANDO_FAIL: + handle_rr_ho_fail(msg); + break; + case GSM48_MT_RR_CIPH_M_COMPL: + bsc_cipher_mode_compl(conn, msg, conn->lchan->encr.alg_id); + break; + case GSM48_MT_RR_ASS_COMPL: + handle_ass_compl(conn, msg); + break; + case GSM48_MT_RR_ASS_FAIL: + handle_ass_fail(conn, msg); + break; + case GSM48_MT_RR_CHAN_MODE_MODIF_ACK: + rc = gsm48_rx_rr_modif_ack(msg); + if (rc < 0) + bsc_assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL); + else + bsc_assign_compl(conn, 0); + break; + case GSM48_MT_RR_CLSM_CHG: + handle_classmark_chg(conn, msg); + break; + case GSM48_MT_RR_APP_INFO: + /* Passing RR APP INFO to MSC, not quite + * according to spec */ + bsc_dtap(conn, link_id, msg); + break; + default: + /* Drop unknown RR message */ + LOGPLCHAN(msg->lchan, DRR, LOGL_NOTICE, + "Dropping %s 04.08 RR message\n", gsm48_rr_msg_name(msg_type)); + gsm48_tx_rr_status(conn, GSM48_RR_CAUSE_MSG_TYPE_N); + break; + } + break; + default: + bsc_dtap(conn, link_id, msg); + break; + } +} + +/*! \brief RSL has received a DATA INDICATION with L3 from MS */ +int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id) +{ + int rc; + struct gsm_lchan *lchan; + + lchan = msg->lchan; + if (lchan->state != LCHAN_S_ACTIVE) { + LOGPLCHAN(msg->lchan, DRSL, LOGL_INFO, "Got data in non active state, discarding.\n"); + return -1; + } + + + if (lchan->conn) { + /* if we already have a connection, forward via DTAP to + * MSC */ + dispatch_dtap(lchan->conn, link_id, msg); + } else { + /* allocate a new connection */ + rc = BSC_API_CONN_POL_REJECT; + lchan->conn = bsc_subscr_con_allocate(msg->lchan->ts->trx->bts->network); + if (!lchan->conn) { + lchan_release(lchan, 1, RSL_REL_NORMAL); + return -1; + } + lchan->conn->lchan = lchan; + + /* fwd via bsc_api to send COMPLETE L3 INFO to MSC */ + rc = bsc_compl_l3(lchan->conn, msg, 0); + + if (rc != BSC_API_CONN_POL_ACCEPT) { + //osmo_fsm_inst_dispatch(lchan->conn->fi, FIXME, NULL); + } + } + + return 0; +} |