osmo-bts/src/common/rsl.c

788 lines
21 KiB
C
Raw Normal View History

/*
* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
/*
* Radio Link Layer Messages
*/
#include <stdio.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <osmocore/msgb.h>
#include <osmocore/rsl.h>
#include <osmocore/protocol/gsm_12_21.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/osmocom_data.h>
#include <osmocom/bb/bts/abis.h>
#include <osmocom/bb/bts/rtp.h>
#include <osmocom/bb/bts/bts.h>
#include <osmocom/bb/bts/rsl.h>
#include <osmocom/bb/bts/oml.h>
#include <osmocom/bb/bts/support.h>
static int rsl_tx_error_report(struct osmobts_trx *trx, uint8_t cause);
/*
* support
*/
static uint8_t bts_si_list[BTS_SI_NUM] = BTS_SI_LIST;
struct osmobts_lchan *rsl_get_chan(struct osmobts_trx *trx, uint8_t chan_nr)
{
uint8_t ts_nr = chan_nr & 0x07;
uint8_t cbits = chan_nr >> 3;
struct bts_support *sup = &bts_support;
struct osmobts_slot *slot = &trx->slot[ts_nr];
struct osmobts_lchan *lchan = NULL;
if (!slot->tx_ms) {
LOGP(DRSL, LOGL_NOTICE, "Given slot not available: %d\n", ts_nr);
return NULL;
}
if (cbits == 0x01) {
/* TCH/F */
if (!sup->chan_comb[NM_CHANC_TCHFull]) {
LOGP(DRSL, LOGL_NOTICE, "TCH/F not not supported on slot: %d\n", ts_nr);
return NULL;
}
if (slot->chan_comb != NM_CHANC_TCHFull) {
LOGP(DRSL, LOGL_NOTICE, "Given channel type not TCH/F: %d\n", ts_nr);
return NULL;
}
lchan = slot->lchan[0];
} else if ((cbits & 0x1e) == 0x02) {
/* TCH/H */
if (!sup->chan_comb[NM_CHANC_TCHHalf]) {
LOGP(DRSL, LOGL_NOTICE, "TCH/H not not supported on slot: %d\n", ts_nr);
return NULL;
}
if (slot->chan_comb != NM_CHANC_TCHHalf) {
LOGP(DRSL, LOGL_NOTICE, "Given channel type not TCH/H: %d\n", ts_nr);
return NULL;
}
lchan = slot->lchan[cbits & 0x01];;
} else if ((cbits & 0x1c) == 0x04) {
/* BCCH+SDCCH4 */
if (!sup->chan_comb[NM_CHANC_BCCHComb]) {
LOGP(DRSL, LOGL_NOTICE, "Combined BCCH+SDCCH/4 not not supported on slot: %d\n", ts_nr);
return NULL;
}
if (slot->chan_comb != NM_CHANC_BCCHComb) {
LOGP(DRSL, LOGL_NOTICE, "Given channel type not Combined BCCH+SDCCH/4: %d\n", ts_nr);
return NULL;
}
lchan = slot->lchan[cbits & 0x03];;
} else if ((cbits & 0x18) == 0x08) {
/* SDCCH8 */
if (!sup->chan_comb[NM_CHANC_SDCCH]) {
LOGP(DRSL, LOGL_NOTICE, "SDCCH/8 not not supported on slot: %d\n", ts_nr);
return NULL;
}
if (slot->chan_comb != NM_CHANC_SDCCH) {
LOGP(DRSL, LOGL_NOTICE, "Given channel type not SDCCH/8: %d\n", ts_nr);
return NULL;
}
lchan = slot->lchan[cbits & 0x07];
} else {
LOGP(DRSL, LOGL_NOTICE, "Given chan_nr unknown: %d\n", chan_nr);
return NULL;
}
if (!lchan)
LOGP(DRSL, LOGL_ERROR, "Lchan not created.\n");
return lchan;
}
static struct msgb *rsl_msgb_alloc(int hdr_size)
{
struct msgb *nmsg;
nmsg = abis_msgb_alloc(hdr_size);
if (!nmsg)
return NULL;
nmsg->l3h = nmsg->data;
return nmsg;
}
static void rsl_trx_push_hdr(struct msgb *msg, uint8_t msg_type)
{
struct abis_rsl_common_hdr *th;
th = (struct abis_rsl_common_hdr *) msgb_push(msg, sizeof(*th));
th->msg_discr = ABIS_RSL_MDISC_TRX;
th->msg_type = msg_type;
}
static void rsl_cch_push_hdr(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr)
{
struct abis_rsl_cchan_hdr *cch;
cch = (struct abis_rsl_cchan_hdr *) msgb_push(msg, sizeof(*cch));
cch->c.msg_discr = ABIS_RSL_MDISC_COM_CHAN;
cch->c.msg_type = msg_type;
cch->chan_nr = chan_nr;
}
static void rsl_dch_push_hdr(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr)
{
struct abis_rsl_dchan_hdr *dch;
dch = (struct abis_rsl_dchan_hdr *) msgb_push(msg, sizeof(*dch));
dch->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
dch->c.msg_type = msg_type;
dch->chan_nr = chan_nr;
}
/*
* TRX related messages
*/
/* 8.6.4 sending ERROR REPORT */
static int rsl_tx_error_report(struct osmobts_trx *trx, uint8_t cause)
{
struct msgb *nmsg;
uint8_t *ie;
LOGP(DRSL, LOGL_NOTICE, "Sending Error Report: cause = 0x%02x\n", cause);
nmsg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
if (!nmsg)
return -ENOMEM;
ie = msgb_put(nmsg, 3);
ie[0] = RSL_IE_CAUSE;
ie[1] = 1;
ie[2] = cause;
rsl_trx_push_hdr(nmsg, RSL_MT_ERROR_REPORT);
abis_push_ipa(nmsg, IPA_PROTO_RSL);
return abis_tx(&trx->link, nmsg);
}
/* 8.6.1 sending RF RESOURCE INDICATION */
int rsl_tx_rf_res(struct osmobts_trx *trx)
{
struct msgb *nmsg;
LOGP(DRSL, LOGL_INFO, "Sending RF RESource INDication\n");
nmsg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
if (!nmsg)
return -ENOMEM;
// FIXME: add interference levels of TRX
rsl_trx_push_hdr(nmsg, RSL_MT_RF_RES_IND);
abis_push_ipa(nmsg, IPA_PROTO_RSL);
return abis_tx(&trx->link, nmsg);
}
/*
* common channel releated messages
*/
/* 8.5.1 BCCH INFOrmation is received */
static int rsl_rx_bcch_info(struct osmobts_trx *trx, struct msgb *msg)
{
struct tlv_parsed tp;
uint8_t si;
int i;
LOGP(DRSL, LOGL_INFO, "RSL BCCH Information:\n");
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
/* 9.3.30 System Info Type */
if (!TLVP_PRESENT(&tp, RSL_IE_SYSINFO_TYPE)) {
return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR);
}
si = *TLVP_VAL(&tp, RSL_IE_SYSINFO_TYPE);
i = 0;
while(i < BTS_SI_NUM) {
if (bts_si_list[i] == si)
break;
i++;
}
if (i == BTS_SI_NUM) {
LOGP(DRSL, LOGL_NOTICE, " SI 0x%02x not supported.\n", si);
return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT);
}
/* 9.3.39 Full BCCH Information */
if (TLVP_PRESENT(&tp, RSL_IE_FULL_BCCH_INFO)) {
trx->si.flags[i] |= BTS_SI_USE;
memcpy(trx->si.si[i], TLVP_VAL(&tp, RSL_IE_FULL_BCCH_INFO), 23);
LOGP(DRSL, LOGL_INFO, " Got new SYSTEM INFORMATION 0x%02x.\n",si);
} else if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) {
trx->si.flags[i] |= BTS_SI_USE;
memcpy(trx->si.si[i], TLVP_VAL(&tp, RSL_IE_L3_INFO), 23);
LOGP(DRSL, LOGL_INFO, " Got new SYSTEM INFORMATION 0x%02x.\n",si);
} else {
trx->si.flags[i] &= ~BTS_SI_USE;
LOGP(DRSL, LOGL_INFO, " Removing SYSTEM INFORMATION 0x%02x.\n",si);
}
trx->si.flags[i] |= BTS_SI_NEW;
bts_new_si(trx);
return 0;
}
/* 8.5.6 IMMEDIATE ASSIGN COMMAND is received */
static int rsl_rx_imm_ass(struct osmobts_trx *trx, struct msgb *msg)
{
struct tlv_parsed tp;
uint8_t *data;
LOGP(DRSL, LOGL_INFO, "Immidiate Assignment Command:\n");
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
/* 9.3.30 System Info Type */
if (!TLVP_PRESENT(&tp, RSL_IE_FULL_IMM_ASS_INFO)) {
return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR);
}
data = (uint8_t *) TLVP_VAL(&tp, RSL_IE_FULL_IMM_ASS_INFO);
LOGP(DRSL, LOGL_INFO, " length = %d\n", data[-1]);
#warning HACK
{
struct msgb *nmsg = rsl_msgb_alloc(64);
struct l1ctl_info_dl *dl;
uint8_t lupd[23] = {0x01,0x03f,0x3d,
0x05,0x08,0x12,0x62,0xf2,0x10,0x31,0x04,0x33,0x05,0xf4,0x87,0x16,0xb3,0xf0,
0x2b, 0x2b, 0x2b, 0x2b, 0x2b};
memcpy(msgb_put(nmsg, sizeof(lupd)), lupd, sizeof(lupd));
nmsg->l3h = nmsg->data;
dl = (struct l1ctl_info_dl *)(nmsg->l1h = msgb_push(nmsg, sizeof(*dl)));
dl->chan_nr = trx->slot[2].lchan[0]->chan_nr;
dl->link_id = 0x00;
msgb_push(nmsg, sizeof(struct l1ctl_hdr));
printf("%p '%s'\n", trx->slot[2].tx_ms, trx->slot[2].tx_ms->ms.name);
rx_ph_data_ind(&trx->slot[2].tx_ms->ms, nmsg);
}
return 0;
}
/*
* dedicated channel related messages
*/
/* 8.4.19 sebdubg RF CHANnel RELease ACKnowledge */
static int rsl_tx_rf_rel_ack(struct osmobts_trx *trx, struct msgb *msg, uint8_t t1, uint8_t t2, uint8_t t3)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
uint8_t chan_nr = dch->chan_nr;
LOGP(DRSL, LOGL_NOTICE, "Sending Channel Release ACK\n");
msg->len = 0;
msg->data = msg->tail = msg->l3h;
rsl_dch_push_hdr(msg, RSL_MT_RF_CHAN_REL_ACK, chan_nr);
abis_push_ipa(msg, IPA_PROTO_RSL);
return abis_tx(&trx->link, msg);
}
/* 8.4.2 sending CHANnel ACTIVation ACKnowledge */
static int rsl_tx_chan_ack(struct osmobts_trx *trx, struct msgb *msg, uint8_t t1, uint8_t t2, uint8_t t3)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
uint8_t *ie;
uint8_t chan_nr = dch->chan_nr;
LOGP(DRSL, LOGL_NOTICE, "Sending Channel Activated ACK\n");
msg->len = 0;
msg->data = msg->tail = msg->l3h;
ie = msgb_put(msg, 3);
ie[0] = RSL_IE_FRAME_NUMBER;
ie[1] = (t1 << 3) | (t3 >> 3);
ie[2] = (t3 & 0x07) | (t2 & 0x1f);
rsl_dch_push_hdr(msg, RSL_MT_CHAN_ACTIV_ACK, chan_nr);
abis_push_ipa(msg, IPA_PROTO_RSL);
return abis_tx(&trx->link, msg);
}
/* 8.4.3 sending CHANnel ACTIVation Negative ACK */
static int rsl_tx_chan_nack(struct osmobts_trx *trx, struct msgb *msg, uint8_t cause)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
uint8_t *ie;
uint8_t chan_nr = dch->chan_nr;
LOGP(DRSL, LOGL_NOTICE, "Sending Channel Activated NACK: cause = 0x%02x\n", cause);
msg->len = 0;
msg->data = msg->tail = msg->l3h;
ie = msgb_put(msg, 3);
/* 9.3.26 Cause */
ie[0] = RSL_IE_CAUSE;
ie[1] = 1;
ie[2] = cause;
rsl_dch_push_hdr(msg, RSL_MT_CHAN_ACTIV_NACK, chan_nr);
abis_push_ipa(msg, IPA_PROTO_RSL);
return abis_tx(&trx->link, msg);
}
/* 8.5.3 sending CHANnel ReQuireD */
int rsl_tx_chan_rqd(struct osmobts_trx *trx)
{
struct msgb *nmsg;
uint8_t *ie;
LOGP(DRSL, LOGL_NOTICE, "Sending Channel Required\n");
nmsg = rsl_msgb_alloc(sizeof(struct abis_rsl_cchan_hdr));
if (!nmsg)
return -ENOMEM;
ie = msgb_put(nmsg, 4);
/* 9.3.19 Request Reference */
ie[0] = RSL_IE_REQ_REFERENCE;
ie[1] = 0xe0; // FIXME
ie[2] = 0x00;
ie[3] = 0x00;
/* 9.3.17 Access Delay */
ie = msgb_put(nmsg, 2);
ie[0] = RSL_IE_ACCESS_DELAY;
ie[1] = 0x00; // FIXME
rsl_cch_push_hdr(nmsg, RSL_MT_CHAN_RQD, 0x88); // FIXME
abis_push_ipa(nmsg, IPA_PROTO_RSL);
return abis_tx(&trx->link, nmsg);
}
/* 8.4.1 CHANnel ACTIVation is received */
static int rsl_rx_chan_activ(struct osmobts_trx *trx, struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct tlv_parsed tp;
uint8_t type, mode;
struct osmobts_lchan *lchan;
LOGP(DRSL, LOGL_INFO, "Channel Activation:\n");
lchan = rsl_get_chan(trx, dch->chan_nr);
if (!lchan)
return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
/* 9.3.3 Activation Type */
if (!TLVP_PRESENT(&tp, RSL_IE_ACT_TYPE)) {
LOGP(DRSL, LOGL_NOTICE, "missing Activation Type\n");
msgb_free(msg);
return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
}
type = *TLVP_VAL(&tp, RSL_IE_ACT_TYPE);
/* 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_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
}
mode = *TLVP_VAL(&tp, RSL_IE_CHAN_MODE);
LOGP(DRSL, LOGL_INFO, " chan_nr=0x%02x type=0x%02x mode=0x%02x\n", dch->chan_nr, type, mode);
return rsl_tx_chan_ack(trx, msg, 0, 0, 0);
}
/* 8.4.14 RF CHANnel RELease is received */
static int rsl_rx_rf_chan_rel(struct osmobts_trx *trx, struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct osmobts_lchan *lchan;
int rc;
LOGP(DRSL, LOGL_INFO, "Channel Release:\n");
lchan = rsl_get_chan(trx, dch->chan_nr);
if (!lchan)
return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
LOGP(DRSL, LOGL_INFO, " chan_nr=0x%02x\n", dch->chan_nr);
lapdm_reset(&lchan->l2_entity.lapdm_dcch);
lapdm_reset(&lchan->l2_entity.lapdm_acch);
rc = rsl_tx_rf_rel_ack(trx, msg, 0, 0, 0);
if (lchan->rtp.socket_created)
rsl_tx_ipac_dlcx_ind(lchan, RSL_ERR_NORMAL_UNSPEC);
return rc;
}
/*
* ip.access related messages
*/
int rsl_tx_ipac_dlcx_ind(struct osmobts_lchan *lchan, uint8_t cause)
{
struct msgb *nmsg;
struct osmobts_trx *trx = lchan->slot->trx;
uint8_t *ie;
LOGP(DRSL, LOGL_NOTICE, "Sending RTP delete indication: cause=%d\n", cause);
nmsg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
if (!nmsg)
return -ENOMEM;
ie = msgb_put(nmsg, 3);
ie[0] = RSL_IE_CAUSE;
ie[1] = 1;
ie[2] = cause;
rsl_trx_push_hdr(nmsg, RSL_MT_IPAC_DLCX_IND);
abis_push_ipa(nmsg, IPA_PROTO_RSL);
return abis_tx(&trx->link, nmsg);
}
static int rsl_tx_ipac_cx_ack(struct osmobts_trx *trx, struct msgb *msg, uint32_t ip, uint16_t port, uint16_t *conn_id)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
uint8_t chan_nr = dch->chan_nr;
uint8_t msg_type = dch->c.msg_type;
uint8_t *ie;
LOGP(DRSL, LOGL_NOTICE, "Sending RTP connection request ACK\n");
msg->len = 0;
msg->data = msg->tail = msg->l3h;
if (conn_id)
msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, htons(*conn_id));
ie = msgb_put(msg, 5);
ie[0] = RSL_IE_IPAC_LOCAL_IP;
*((uint32_t *)(ie + 1)) = htonl(ip);
msgb_tv16_put(msg, RSL_IE_IPAC_LOCAL_PORT, htons(port));
rsl_dch_push_hdr(msg, msg_type + 1, chan_nr);
abis_push_ipa(msg, IPA_PROTO_RSL);
return abis_tx(&trx->link, msg);
}
static int rsl_tx_ipac_cx_nack(struct osmobts_trx *trx, struct msgb *msg, uint8_t cause)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
uint8_t chan_nr = dch->chan_nr;
uint8_t msg_type = dch->c.msg_type;
uint8_t *ie;
LOGP(DRSL, LOGL_NOTICE, "Sending RTP connection request NACK: cause=%d\n", cause);
msg->len = 0;
msg->data = msg->tail = msg->l3h;
ie = msgb_put(msg, 3);
/* 9.3.26 Cause */
ie[0] = RSL_IE_CAUSE;
ie[1] = 1;
ie[2] = cause;
rsl_dch_push_hdr(msg, msg_type + 2, chan_nr);
abis_push_ipa(msg, IPA_PROTO_RSL);
return abis_tx(&trx->link, msg);
}
static int rsl_rx_ipac_crcx_mdcx(struct osmobts_trx *trx, struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct tlv_parsed tp;
struct osmobts_lchan *lchan;
uint32_t *ip = NULL;
uint16_t *port = NULL;
uint8_t *speech_mode = NULL, *payload_type = NULL;
uint16_t conn_id;
int rc;
if (dch->c.msg_type == RSL_MT_IPAC_CRCX)
LOGP(DRSL, LOGL_INFO, "Request of creating RTP connection:\n");
else
LOGP(DRSL, LOGL_INFO, "Request of modding RTP connection:\n");
lchan = rsl_get_chan(trx, dch->chan_nr);
if (!lchan)
return rsl_tx_ipac_cx_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
if (TLVP_PRESENT(&tp, RSL_IE_IPAC_SPEECH_MODE)) {
speech_mode = (uint8_t *) TLVP_VAL(&tp, RSL_IE_IPAC_SPEECH_MODE);
}
if (TLVP_PRESENT(&tp, RSL_IE_IPAC_RTP_PAYLOAD)) {
payload_type = (uint8_t *) TLVP_VAL(&tp, RSL_IE_IPAC_RTP_PAYLOAD);
}
if (TLVP_PRESENT(&tp, RSL_IE_IPAC_REMOTE_IP)) {
ip = (uint32_t *) TLVP_VAL(&tp, RSL_IE_IPAC_REMOTE_IP);
}
if (TLVP_PRESENT(&tp, RSL_IE_IPAC_REMOTE_PORT)) {
port = (uint16_t *) TLVP_VAL(&tp, RSL_IE_IPAC_REMOTE_PORT);
}
if (!lchan->rtp.socket_created) {
if (dch->c.msg_type == RSL_MT_IPAC_CRCX && !payload_type) {
LOGP(DRSL, LOGL_ERROR, "Missing payload type IE.\n");
return rsl_tx_ipac_cx_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
}
rc = rtp_create_socket(lchan, &lchan->rtp);
if (rc < 0) {
LOGP(DRSL, LOGL_ERROR, "Failed to create RTP/RTCP sockets.\n");
return rsl_tx_ipac_cx_nack(trx, msg, RSL_ERR_RES_UNAVAIL);
}
rc = rtp_bind_socket(&lchan->rtp);
if (rc < 0) {
LOGP(DRSL, LOGL_ERROR, "Failed to bind RTP/RTCP sockets.\n");
rtp_close_socket(&lchan->rtp);
return rsl_tx_ipac_cx_nack(trx, msg, RSL_ERR_RES_UNAVAIL);
}
}
if (payload_type)
lchan->rtp.payload_type = *payload_type;
if (ip && port) {
rc = rtp_connect_socket(&lchan->rtp, ntohl(*ip), ntohs(*port));
if (rc < 0) {
LOGP(DRSL, LOGL_ERROR, "Failed to connect RTP/RTCP sockets.\n");
rtp_close_socket(&lchan->rtp);
return rsl_tx_ipac_cx_nack(trx, msg, RSL_ERR_RES_UNAVAIL);
}
}
conn_id = 0; // FIXME: what the hack is conn_id for?
return rsl_tx_ipac_cx_ack(trx, msg, ntohl(lchan->rtp.rtp_udp.sin_local.sin_addr.s_addr), ntohs(lchan->rtp.rtp_udp.sin_local.sin_port), &conn_id);
}
static int rsl_rx_ipac_dlcx(struct osmobts_trx *trx, struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct tlv_parsed tp;
struct osmobts_lchan *lchan;
LOGP(DRSL, LOGL_INFO, "Request of deleting RTP connection:\n");
lchan = rsl_get_chan(trx, dch->chan_nr);
if (!lchan)
return rsl_tx_ipac_cx_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
rtp_close_socket(&lchan->rtp);
return rsl_tx_ipac_cx_ack(trx, msg, ntohl(lchan->rtp.rtp_udp.sin_local.sin_addr.s_addr), ntohs(lchan->rtp.rtp_udp.sin_local.sin_port), NULL);
}
/*
* selecting message
*/
static int rsl_rx_rll(struct osmobts_trx *trx, struct msgb *msg)
{
struct abis_rsl_rll_hdr *rh = msgb_l2(msg);
struct osmobts_lchan *lchan;
if (msgb_l2len(msg) < sizeof(*rh)) {
LOGP(DRSL, LOGL_NOTICE, "RSL Radio Link Layer message too short\n");
msgb_free(msg);
return -EIO;
}
msg->l3h = (unsigned char *)rh + sizeof(*rh);
lchan = rsl_get_chan(trx, rh->chan_nr);
if (!lchan)
return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
return rslms_recvmsg(msg, &lchan->l2_entity);
}
int rsl_tx_rll(struct msgb *msg, struct osmol2_entity *l2_entity)
{
struct osmobts_lchan *lchan = container_of(l2_entity, struct osmobts_lchan, l2_entity);
struct abis_rsl_common_hdr *rh = msgb_l2(msg);
LOGP(DRSL, LOGL_INFO, "Got '%s' message from L2.\n", get_rsl_name(rh->msg_type));
abis_push_ipa(msg, IPA_PROTO_RSL);
return abis_tx(&lchan->slot->trx->link, msg);
}
static int rsl_rx_cchan(struct osmobts_trx *trx, struct msgb *msg)
{
struct abis_rsl_cchan_hdr *cch = msgb_l2(msg);
int ret = 0;
if (msgb_l2len(msg) < sizeof(*cch)) {
LOGP(DRSL, LOGL_NOTICE, "RSL Common Channel Management message too short\n");
msgb_free(msg);
return -EIO;
}
msg->l3h = (unsigned char *)cch + sizeof(*cch);
switch (cch->c.msg_type) {
case RSL_MT_BCCH_INFO:
ret = rsl_rx_bcch_info(trx, msg);
break;
case RSL_MT_IMMEDIATE_ASSIGN_CMD:
ret = rsl_rx_imm_ass(trx, msg);
break;
default:
LOGP(DRSL, LOGL_NOTICE, "unsupported RSL cchan msg_type 0x%02x\n",
cch->c.msg_type);
ret = -EINVAL;
}
msgb_free(msg);
return ret;
}
static int rsl_rx_dchan(struct osmobts_trx *trx, struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
int ret = 0;
if (msgb_l2len(msg) < sizeof(*dch)) {
LOGP(DRSL, LOGL_NOTICE, "RSL Dedicated Channel Management message too short\n");
msgb_free(msg);
return -EIO;
}
msg->l3h = (unsigned char *)dch + sizeof(*dch);
switch (dch->c.msg_type) {
case RSL_MT_CHAN_ACTIV:
return rsl_rx_chan_activ(trx, msg);
case RSL_MT_RF_CHAN_REL:
return rsl_rx_rf_chan_rel(trx, msg);
default:
LOGP(DRSL, LOGL_NOTICE, "unsupported RSL dchan msg_type 0x%02x\n",
dch->c.msg_type);
ret = -EINVAL;
}
msgb_free(msg);
return ret;
}
static int rsl_rx_trx(struct osmobts_trx *trx, struct msgb *msg)
{
struct abis_rsl_common_hdr *th = msgb_l2(msg);
int ret = 0;
if (msgb_l2len(msg) < sizeof(*th)) {
LOGP(DRSL, LOGL_NOTICE, "RSL TRX message too short\n");
msgb_free(msg);
return -EIO;
}
msg->l3h = (unsigned char *)th + sizeof(*th);
switch (th->msg_type) {
case RSL_MT_SACCH_FILL:
ret = rsl_rx_bcch_info(trx, msg);
break;
default:
LOGP(DRSL, LOGL_NOTICE, "unsupported RSL TRX msg_type 0x%02x\n",
th->msg_type);
ret = -EINVAL;
}
msgb_free(msg);
return ret;
}
static int rsl_rx_ipaccess(struct osmobts_trx *trx, struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
int ret = 0;
if (msgb_l2len(msg) < sizeof(*dch)) {
LOGP(DRSL, LOGL_NOTICE, "RSL ip.access message too short\n");
msgb_free(msg);
return -EIO;
}
msg->l3h = (unsigned char *)dch + sizeof(*dch);
switch (dch->c.msg_type) {
case RSL_MT_IPAC_CRCX:
case RSL_MT_IPAC_MDCX:
return rsl_rx_ipac_crcx_mdcx(trx, msg);
case RSL_MT_IPAC_DLCX:
return rsl_rx_ipac_dlcx(trx, msg);
default:
LOGP(DRSL, LOGL_NOTICE, "unsupported RSL ip.access msg_type 0x%02x\n",
dch->c.msg_type);
ret = -EINVAL;
}
msgb_free(msg);
return ret;
}
int down_rsl(struct osmobts_trx *trx, struct msgb *msg)
{
struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
int ret = 0;
if (msgb_l2len(msg) < sizeof(*rslh)) {
LOGP(DRSL, LOGL_NOTICE, "RSL message too short\n");
msgb_free(msg);
return -EIO;
}
switch (rslh->msg_discr & 0xfe) {
case ABIS_RSL_MDISC_RLL:
ret = rsl_rx_rll(trx, msg);
break;
case ABIS_RSL_MDISC_COM_CHAN:
ret = rsl_rx_cchan(trx, msg);
break;
case ABIS_RSL_MDISC_DED_CHAN:
ret = rsl_rx_dchan(trx, msg);
break;
case ABIS_RSL_MDISC_TRX:
ret = rsl_rx_trx(trx, msg);
break;
case ABIS_RSL_MDISC_IPACCESS:
ret = rsl_rx_ipaccess(trx, msg);
break;
default:
LOGP(DRSL, LOGL_NOTICE, "unknown RSL msg_discr 0x%02x\n",
rslh->msg_discr);
msgb_free(msg);
ret = -EINVAL;
}
return ret;
}