aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/osmo_bsc.h1
-rw-r--r--openbsc/src/bsc/osmo_bsc_bssap.c178
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;