aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/rsl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/rsl.c')
-rw-r--r--src/common/rsl.c206
1 files changed, 184 insertions, 22 deletions
diff --git a/src/common/rsl.c b/src/common/rsl.c
index 4b8798b9..59185124 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -30,7 +30,7 @@
#include <osmocom/gsm/rsl.h>
#include <osmocom/gsm/lapdm.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
-#include <osmocom/trau/rtp.h>
+#include <osmocom/trau/osmo_ortp.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/gsm_data.h>
@@ -68,6 +68,19 @@ int osmo_in_array(unsigned int search, const unsigned int *arr, unsigned int siz
}
#define OSMO_IN_ARRAY(search, arr) osmo_in_array(search, arr, ARRAY_SIZE(arr))
+int msgb_queue_flush(struct llist_head *list)
+{
+ struct msgb *msg, *msg2;
+ int count = 0;
+
+ llist_for_each_entry_safe(msg, msg2, list, list) {
+ msgb_free(msg);
+ count++;
+ }
+
+ return count;
+}
+
/* FIXME: move this to libosmocore */
void gsm48_gen_starting_time(uint8_t *out, struct gsm_time *gtime)
{
@@ -76,6 +89,32 @@ void gsm48_gen_starting_time(uint8_t *out, struct gsm_time *gtime)
out[1] = (gtime->t3 << 5) | gtime->t2;
}
+/* compute lchan->rsl_cmode and lchan->tch_mode from RSL CHAN MODE IE */
+static void lchan_tchmode_from_cmode(struct gsm_lchan *lchan,
+ struct rsl_ie_chan_mode *cm)
+{
+ lchan->rsl_cmode = cm->spd_ind;
+ switch (cm->chan_rate) {
+ case RSL_CMOD_SP_GSM1:
+ lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
+ break;
+ case RSL_CMOD_SP_GSM2:
+ lchan->tch_mode = GSM48_CMODE_SPEECH_EFR;
+ break;
+ case RSL_CMOD_SP_GSM3:
+ lchan->tch_mode = GSM48_CMODE_SPEECH_AMR;
+ break;
+ case RSL_CMOD_SP_NT_14k5:
+ lchan->tch_mode = GSM48_CMODE_DATA_14k5;
+ break;
+ case RSL_CMOD_SP_NT_12k0:
+ lchan->tch_mode = GSM48_CMODE_DATA_12k0;
+ break;
+ case RSL_CMOD_SP_NT_6k0:
+ lchan->tch_mode = GSM48_CMODE_DATA_6k0;
+ break;
+ }
+}
/*
@@ -547,8 +586,9 @@ static int rsl_rx_chan_activ(struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct gsm_lchan *lchan = msg->lchan;
+ struct rsl_ie_chan_mode *cm;
struct tlv_parsed tp;
- uint8_t type, mode;
+ uint8_t type;
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
@@ -566,7 +606,8 @@ static int rsl_rx_chan_activ(struct msgb *msg)
msgb_free(msg);
return rsl_tx_chan_nack(msg->trx, msg, RSL_ERR_MAND_IE_ERROR);
}
- mode = *TLVP_VAL(&tp, RSL_IE_CHAN_MODE);
+ cm = (struct rsl_ie_chan_mode *) TLVP_VAL(&tp, RSL_IE_CHAN_MODE);
+ lchan_tchmode_from_cmode(lchan, cm);
/* 9.3.7 Encryption Information */
if (TLVP_PRESENT(&tp, RSL_IE_ENCR_INFO)) {
@@ -635,10 +676,19 @@ static int rsl_rx_chan_activ(struct msgb *msg)
copy_sacch_si_to_lchan(lchan);
}
/* 9.3.52 MultiRate Configuration */
+ if (TLVP_PRESENT(&tp, RSL_IE_MR_CONFIG)) {
+ if (TLVP_LEN(&tp, RSL_IE_MR_CONFIG) > sizeof(lchan->mr_conf)) {
+ LOGP(DRSL, LOGL_ERROR, "Error parsing MultiRate conf IE\n");
+ return rsl_tx_error_report(msg->trx, RSL_ERR_IE_CONTENT);
+ }
+ memcpy(&lchan->mr_conf, TLVP_VAL(&tp, RSL_IE_MR_CONFIG),
+ TLVP_LEN(&tp, RSL_IE_MR_CONFIG));
+ }
/* 9.3.53 MultiRate Control */
/* 9.3.54 Supported Codec Types */
- LOGP(DRSL, LOGL_INFO, " chan_nr=0x%02x type=0x%02x mode=0x%02x\n", dch->chan_nr, type, mode);
+ LOGP(DRSL, LOGL_INFO, " chan_nr=0x%02x type=0x%02x mode=0x%02x\n",
+ dch->chan_nr, type, lchan->tch_mode);
/* actually activate the channel in the BTS */
return bts_model_rsl_chan_act(msg->lchan, &tp);
@@ -651,8 +701,9 @@ static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan)
if (lchan->abis_ip.rtp_socket) {
rsl_tx_ipac_dlcx_ind(lchan, RSL_ERR_NORMAL_UNSPEC);
- rtp_socket_free(lchan->abis_ip.rtp_socket);
+ osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
lchan->abis_ip.rtp_socket = NULL;
+ msgb_queue_flush(&lchan->dl_tch_queue);
}
rc = bts_model_rsl_chan_rel(lchan);
@@ -795,6 +846,90 @@ static int rsl_rx_encr_cmd(struct msgb *msg)
}
}
+/* 8.4.11 MODE MODIFY NEGATIVE ACKNOWLEDGE */
+static int rsl_tx_mode_modif_nack(struct gsm_lchan *lchan, uint8_t cause)
+{
+ struct msgb *msg = rsl_msgb_alloc(sizeof(struct abis_rsl_dchan_hdr));
+ uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+
+ LOGP(DRSL, LOGL_NOTICE, "%s Tx MODE MODIFY NACK (cause = 0x%02x)\n",
+ gsm_lchan_name(lchan), cause);
+
+ msg->len = 0;
+ msg->data = msg->tail = msg->l3h;
+
+ /* 9.3.26 Cause */
+ msgb_tlv_put(msg, RSL_IE_CAUSE, 1, &cause);
+ rsl_dch_push_hdr(msg, RSL_MT_MODE_MODIFY_NACK, chan_nr);
+ msg->lchan = lchan;
+
+ return abis_rsl_sendmsg(msg);
+}
+
+/* 8.4.10 MODE MODIFY ACK */
+static int rsl_tx_mode_modif_ack(struct gsm_lchan *lchan)
+{
+ struct msgb *msg = rsl_msgb_alloc(sizeof(struct abis_rsl_dchan_hdr));
+ uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+
+ LOGP(DRSL, LOGL_INFO, "%s Tx MODE MODIF ACK\n", gsm_lchan_name(lchan));
+
+ rsl_dch_push_hdr(msg, RSL_MT_MODE_MODIFY_ACK, chan_nr);
+ msg->trx = lchan->ts->trx;
+
+ return abis_rsl_sendmsg(msg);
+}
+
+/* 8.4.9 MODE MODIFY */
+static int rsl_rx_mode_modif(struct msgb *msg)
+{
+ struct gsm_lchan *lchan = msg->lchan;
+ struct rsl_ie_chan_mode *cm;
+ struct tlv_parsed tp;
+ int rc;
+
+ rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+
+ /* 9.3.6 Channel Mode */
+ if (!TLVP_PRESENT(&tp, RSL_IE_CHAN_MODE)) {
+ LOGP(DRSL, LOGL_NOTICE, "missing Channel Mode\n");
+ msgb_free(msg);
+ return rsl_tx_mode_modif_nack(lchan, RSL_ERR_MAND_IE_ERROR);
+ }
+ cm = (struct rsl_ie_chan_mode *) TLVP_VAL(&tp, RSL_IE_CHAN_MODE);
+ lchan_tchmode_from_cmode(lchan, cm);
+
+ /* 9.3.7 Encryption Information */
+ if (TLVP_PRESENT(&tp, RSL_IE_ENCR_INFO)) {
+ uint8_t len = TLVP_LEN(&tp, RSL_IE_ENCR_INFO);
+ const uint8_t *val = TLVP_VAL(&tp, RSL_IE_ENCR_INFO);
+
+ if (encr_info2lchan(lchan, val, len) < 0)
+ return rsl_tx_error_report(msg->trx, RSL_ERR_IE_CONTENT);
+ }
+
+ /* 9.3.45 Main channel reference */
+
+ /* 9.3.52 MultiRate Configuration */
+ if (TLVP_PRESENT(&tp, RSL_IE_MR_CONFIG)) {
+ if (TLVP_LEN(&tp, RSL_IE_MR_CONFIG) > sizeof(lchan->mr_conf)) {
+ LOGP(DRSL, LOGL_ERROR, "Error parsing MultiRate conf IE\n");
+ return rsl_tx_error_report(msg->trx, RSL_ERR_IE_CONTENT);
+ }
+ memcpy(&lchan->mr_conf, TLVP_VAL(&tp, RSL_IE_MR_CONFIG),
+ TLVP_LEN(&tp, RSL_IE_MR_CONFIG));
+ }
+ /* 9.3.53 MultiRate Control */
+ /* 9.3.54 Supported Codec Types */
+
+ rc = bts_model_rsl_mode_modify(msg->lchan);
+
+ /* FIXME: delay this until L1 says OK? */
+ rsl_tx_mode_modif_ack(msg->lchan);
+
+ return rc;
+}
+
/* 8.4.20 SACCH INFO MODify */
static int rsl_rx_sacch_inf_mod(struct msgb *msg)
{
@@ -884,10 +1019,10 @@ static int rsl_tx_ipac_XXcx_ack(struct gsm_lchan *lchan, int inc_pt2,
else
name = "MDCX";
- ia.s_addr = lchan->abis_ip.bound_ip;
+ ia.s_addr = htonl(lchan->abis_ip.bound_ip);
LOGP(DRSL, LOGL_INFO, "%s RSL Tx IPAC_%s_ACK (local %s:%u)\n",
gsm_lchan_name(lchan), name, inet_ntoa(ia),
- ntohs(lchan->abis_ip.bound_port));
+ lchan->abis_ip.bound_port);
/* Connection ID */
msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, htons(lchan->abis_ip.conn_id));
@@ -899,7 +1034,7 @@ static int rsl_tx_ipac_XXcx_ack(struct gsm_lchan *lchan, int inc_pt2,
/* locally bound port */
msgb_tv16_put(msg, RSL_IE_IPAC_LOCAL_PORT,
- htons(lchan->abis_ip.bound_port));
+ lchan->abis_ip.bound_port);
if (inc_pt2) {
/* RTP Payload Type 2 */
@@ -1035,7 +1170,7 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
}
/* FIXME: select default value depending on speech_mode */
//if (!payload_type)
- lchan->abis_ip.rtp_socket = rtp_socket_create(lchan->ts->trx);
+ lchan->abis_ip.rtp_socket = osmo_rtp_socket_create(lchan->ts->trx);
if (!lchan->abis_ip.rtp_socket) {
LOGP(DRSL, LOGL_ERROR,
"%s IPAC Failed to create RTP/RTCP sockets\n",
@@ -1043,49 +1178,73 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
inc_ip_port, dch->c.msg_type);
}
+ lchan->abis_ip.rtp_socket->priv = lchan;
+ lchan->abis_ip.rtp_socket->rx_cb = &bts_model_rtp_rx_cb;
- rc = rtp_socket_bind(lchan->abis_ip.rtp_socket, INADDR_ANY);
+#warning remove hard-coded IP address
+ rc = osmo_rtp_socket_bind(lchan->abis_ip.rtp_socket,
+ "192.168.100.239", -1);
if (rc < 0) {
LOGP(DRSL, LOGL_ERROR,
"%s IPAC Failed to bind RTP/RTCP sockets\n",
gsm_lchan_name(lchan));
- rtp_socket_free(lchan->abis_ip.rtp_socket);
+ osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
lchan->abis_ip.rtp_socket = NULL;
+ msgb_queue_flush(&lchan->dl_tch_queue);
return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
inc_ip_port, dch->c.msg_type);
}
+ rc = osmo_rtp_get_bound_ip_port(lchan->abis_ip.rtp_socket,
+ &lchan->abis_ip.bound_ip,
+ &lchan->abis_ip.bound_port);
+ if (rc < 0)
+ LOGP(DRSL, LOGL_ERROR, "%s IPAC cannot obtain "
+ "locally bound IP/port: %d\n",
+ gsm_lchan_name(lchan), rc);
/* FIXME: multiplex connection, BSC proxy */
} else {
/* MDCX */
if (!lchan->abis_ip.rtp_socket) {
LOGP(DRSL, LOGL_ERROR, "%s Rx RSL IPAC MDCX, "
- "but we have no RTP socket!\n");
+ "but we have no RTP socket!\n",
+ gsm_lchan_name(lchan));
return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
inc_ip_port, dch->c.msg_type);
}
}
if (connect_ip && connect_port) {
- rc = rtp_socket_connect(lchan->abis_ip.rtp_socket,
- ntohl(*connect_ip), ntohs(*connect_port));
+ struct in_addr ia;
+ ia.s_addr = *connect_ip;
+ rc = osmo_rtp_socket_connect(lchan->abis_ip.rtp_socket,
+ inet_ntoa(ia), ntohs(*connect_port));
if (rc < 0) {
LOGP(DRSL, LOGL_ERROR,
"%s Failed to connect RTP/RTCP sockets\n",
gsm_lchan_name(lchan));
- rtp_socket_free(lchan->abis_ip.rtp_socket);
+ osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
lchan->abis_ip.rtp_socket = NULL;
+ msgb_queue_flush(&lchan->dl_tch_queue);
return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
inc_ip_port, dch->c.msg_type);
}
/* save IP address and port number */
- lchan->abis_ip.connect_ip = *connect_ip;
- lchan->abis_ip.connect_port = *connect_port;
+ lchan->abis_ip.connect_ip = ntohl(*connect_ip);
+ lchan->abis_ip.connect_port = ntohs(*connect_port);
}
/* Everything has succeeded, we can store new values in lchan */
- if (payload_type)
+ if (payload_type) {
lchan->abis_ip.rtp_payload = *payload_type;
- if (payload_type2)
+ if (lchan->abis_ip.rtp_socket)
+ osmo_rtp_socket_set_pt(lchan->abis_ip.rtp_socket,
+ *payload_type);
+ }
+ if (payload_type2) {
lchan->abis_ip.rtp_payload2 = *payload_type2;
+ if (lchan->abis_ip.rtp_socket)
+ osmo_rtp_socket_set_pt(lchan->abis_ip.rtp_socket,
+ *payload_type2);
+ }
if (speech_mode)
lchan->abis_ip.speech_mode = *speech_mode;
@@ -1109,8 +1268,9 @@ static int rsl_rx_ipac_dlcx(struct msgb *msg)
if (TLVP_PRESENT(&tp, RSL_IE_IPAC_CONN_ID))
inc_conn_id = 1;
- rtp_socket_free(lchan->abis_ip.rtp_socket);
+ osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
lchan->abis_ip.rtp_socket = NULL;
+ msgb_queue_flush(&lchan->dl_tch_queue);
return rsl_tx_ipac_dlcx_ack(lchan, inc_conn_id);
}
@@ -1336,6 +1496,8 @@ static int rsl_rx_dchan(struct gsm_bts_trx *trx, struct msgb *msg)
ret = rsl_rx_encr_cmd(msg);
break;
case RSL_MT_MODE_MODIFY_REQ:
+ ret = rsl_rx_mode_modif(msg);
+ break;
case RSL_MT_PHY_CONTEXT_REQ:
case RSL_MT_PREPROC_CONFIG:
case RSL_MT_RTD_REP:
@@ -1404,8 +1566,8 @@ static int rsl_rx_ipaccess(struct gsm_bts_trx *trx, struct msgb *msg)
//return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
}
- LOGP(DRSL, LOGL_INFO, "%s Rx RSL IPA %s\n", gsm_lchan_name(msg->lchan),
- rsl_msg_name(dch->c.msg_type));
+ LOGP(DRSL, LOGL_INFO, "%s Rx RSL %s\n", gsm_lchan_name(msg->lchan),
+ rsl_ipac_msg_name(dch->c.msg_type));
switch (dch->c.msg_type) {
case RSL_MT_IPAC_CRCX: