diff options
-rw-r--r-- | openbsc/include/openbsc/osmo_bsc.h | 1 | ||||
-rw-r--r-- | openbsc/src/bsc/osmo_bsc_bssap.c | 178 |
2 files changed, 179 insertions, 0 deletions
diff --git a/openbsc/include/openbsc/osmo_bsc.h b/openbsc/include/openbsc/osmo_bsc.h index c4b241a24..8aa5ddce6 100644 --- a/openbsc/include/openbsc/osmo_bsc.h +++ b/openbsc/include/openbsc/osmo_bsc.h @@ -11,6 +11,7 @@ struct osmo_bsc_sccp_con { struct llist_head entry; int ciphering_handled; + int rtp_port; /* SCCP connection realted */ struct sccp_connection *sccp; diff --git a/openbsc/src/bsc/osmo_bsc_bssap.c b/openbsc/src/bsc/osmo_bsc_bssap.c index 533da77e1..97ce68a07 100644 --- a/openbsc/src/bsc/osmo_bsc_bssap.c +++ b/openbsc/src/bsc/osmo_bsc_bssap.c @@ -21,7 +21,9 @@ #include <openbsc/osmo_bsc.h> #include <openbsc/osmo_bsc_grace.h> +#include <openbsc/osmo_msc_data.h> #include <openbsc/debug.h> +#include <openbsc/mgcp.h> #include <osmocore/gsm0808.h> #include <osmocore/protocol/gsm_08_08.h> @@ -36,6 +38,65 @@ static uint16_t read_data16(const uint8_t *data) return res; } +/* + * helpers for the assignment command + */ +enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support *audio) +{ + if (audio->hr) { + switch (audio->ver) { + case 1: + return GSM0808_PERM_HR1; + break; + case 2: + return GSM0808_PERM_HR2; + break; + case 3: + return GSM0808_PERM_HR3; + break; + default: + LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", audio->ver); + return GSM0808_PERM_FR1; + } + } else { + switch (audio->ver) { + case 1: + return GSM0808_PERM_FR1; + break; + case 2: + return GSM0808_PERM_FR2; + break; + case 3: + return GSM0808_PERM_FR3; + break; + default: + LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", audio->ver); + return GSM0808_PERM_HR1; + } + } +} + +enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech) +{ + switch (speech) { + case GSM0808_PERM_HR1: + case GSM0808_PERM_FR1: + return GSM48_CMODE_SPEECH_V1; + break; + case GSM0808_PERM_HR2: + case GSM0808_PERM_FR2: + return GSM48_CMODE_SPEECH_EFR; + break; + case GSM0808_PERM_HR3: + case GSM0808_PERM_FR3: + return GSM48_CMODE_SPEECH_AMR; + break; + } + + LOGP(DMSC, LOGL_FATAL, "Should not be reached.\n"); + return GSM48_CMODE_SPEECH_AMR; +} + static int bssmap_handle_reset_ack(struct gsm_network *net, struct msgb *msg, unsigned int length) { @@ -215,6 +276,120 @@ reject: return -1; } +/* + * Handle the assignment request message. + * + * See ยง3.2.1.1 for the message type + */ +static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn, + struct msgb *msg, unsigned int length) +{ + struct msgb *resp; + struct gsm_network *network; + struct tlv_parsed tp; + uint8_t *data; + uint16_t cic; + uint8_t timeslot; + uint8_t multiplex; + enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN; + int i, supported, port, full_rate = -1; + + if (!conn->conn) { + LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n"); + return -1; + } + + network = conn->conn->bts->network; + tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0); + + if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)) { + LOGP(DMSC, LOGL_ERROR, "Mandantory channel type not present.\n"); + goto reject; + } + + if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) { + LOGP(DMSC, LOGL_ERROR, "Identity code missing. Audio routing will not work.\n"); + goto reject; + } + + cic = ntohs(read_data16(TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE))); + timeslot = cic & 0x1f; + multiplex = (cic & ~0x1f) >> 5; + + /* + * Currently we only support a limited subset of all + * possible channel types. The limitation ends by not using + * multi-slot, limiting the channel coding, speech... + */ + if (TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE) < 3) { + LOGP(DMSC, LOGL_ERROR, "ChannelType len !=3 not supported: %d\n", + TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE)); + goto reject; + } + + /* + * Try to figure out if we support the proposed speech codecs. For + * now we will always pick the full rate codecs. + */ + + data = (uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE); + if ((data[0] & 0xf) != 0x1) { + LOGP(DMSC, LOGL_ERROR, "ChannelType != speech: %d\n", data[0]); + goto reject; + } + + if (data[1] != GSM0808_SPEECH_FULL_PREF && data[1] != GSM0808_SPEECH_HALF_PREF) { + LOGP(DMSC, LOGL_ERROR, "ChannelType full not allowed: %d\n", data[1]); + goto reject; + } + + /* + * go through the list of preferred codecs of our gsm network + * and try to find it among the permitted codecs. If we found + * it we will send chan_mode to the right mode and break the + * inner loop. The outer loop will exit due chan_mode having + * the correct value. + */ + full_rate = 0; + for (supported = 0; + chan_mode == GSM48_CMODE_SIGN && supported < network->msc_data->audio_length; + ++supported) { + + int perm_val = audio_support_to_gsm88(network->msc_data->audio_support[supported]); + for (i = 2; i < TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE); ++i) { + if ((data[i] & 0x7f) == perm_val) { + chan_mode = gsm88_to_chan_mode(perm_val); + full_rate = (data[i] & 0x4) == 0; + break; + } else if ((data[i] & 0x80) == 0x00) { + break; + } + } + } + + if (chan_mode == GSM48_CMODE_SIGN) { + LOGP(DMSC, LOGL_ERROR, "No supported audio type found.\n"); + goto reject; + } + + /* map it to a MGCP Endpoint and a RTP port */ + port = mgcp_timeslot_to_endpoint(multiplex, timeslot); + conn->rtp_port = rtp_calculate_port(port, + network->msc_data->rtp_base); + + return gsm0808_assign_req(conn->conn, chan_mode, full_rate); + +reject: + resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL); + if (!resp) { + LOGP(DMSC, LOGL_ERROR, "Channel allocation failure.\n"); + return -1; + } + + bsc_queue_for_msc(conn, resp); + return -1; +} + static int bssmap_rcvmsg_udt(struct gsm_network *net, struct msgb *msg, unsigned int length) { @@ -255,6 +430,9 @@ static int bssmap_rcvmsg_dt1(struct osmo_bsc_sccp_con *conn, case BSS_MAP_MSG_CIPHER_MODE_CMD: ret = bssmap_handle_cipher_mode(conn, msg, length); break; + case BSS_MAP_MSG_ASSIGMENT_RQST: + ret = bssmap_handle_assignm_req(conn, msg, length); + break; default: LOGP(DMSC, LOGL_DEBUG, "Unimplemented msg type: %d\n", msg->l4h[0]); break; |