bsc: Implement the assignment command to the point of calling into the BSC API
This commit is contained in:
parent
fae3c65938
commit
50c579b8c5
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue