Add new BSC RLL layer of code

A caller can call rll_establish(lchan, link_id) and a callback to the GSM RLL
code.  He will get called back if the RLL link is established or receives some
error message, or the establishment times out.

We need this for proper SMS implementation, where we need to restablish a SAPI3
RLL link before transmitting the actual CP-DATA messages.
This commit is contained in:
Harald Welte 2009-08-09 13:47:35 +02:00
parent 42b4557fca
commit edcc527371
6 changed files with 155 additions and 2 deletions

View File

@ -2,4 +2,5 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \
gsm_subscriber.h linuxlist.h msgb.h select.h tlv.h gsm_04_11.h \
timer.h misdn.h chan_alloc.h telnet_interface.h paging.h \
subchan_demux.h trau_frame.h e1_input.h trau_mux.h signal.h \
gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h
gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \
bsc_rll.h

View File

@ -476,6 +476,7 @@ int rsl_paging_cmd_subscr(struct gsm_bts *bts, u_int8_t chan_needed,
int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val);
int rsl_data_request(struct msgb *msg, u_int8_t link_id);
int rsl_establish_request(struct gsm_lchan *lchan, u_int8_t link_id);
int rsl_relase_request(struct gsm_lchan *lchan, u_int8_t link_id);
/* ip.access specfic RSL extensions */

View File

@ -0,0 +1,19 @@
#ifndef _BSC_RLL_H
#define _BSC_RLL_H
#include <openbsc/gsm_data.h>
enum bsc_rllr_ind {
BSC_RLLR_IND_EST_CONF,
BSC_RLLR_IND_REL_IND,
BSC_RLLR_IND_ERR_IND,
BSC_RLLR_IND_TIMEOUT,
};
int rll_establish(struct gsm_lchan *lchan, u_int8_t link_id,
void (*cb)(struct gsm_lchan *, u_int8_t, void *,
enum bsc_rllr_ind),
void *data);
void rll_indication(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t type);
#endif /* _BSC_RLL_H */

View File

@ -10,7 +10,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_04_08.c gsm_data.c mncc.c \
gsm_04_11.c telnet_interface.c subchan_demux.c \
trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \
input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \
transaction.c rtp_proxy.c
transaction.c rtp_proxy.c bsc_rll.c
libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c

View File

@ -32,6 +32,7 @@
#include <openbsc/gsm_04_08.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_rll.h>
#include <openbsc/debug.h>
#include <openbsc/tlv.h>
#include <openbsc/paging.h>
@ -840,6 +841,24 @@ int rsl_data_request(struct msgb *msg, u_int8_t link_id)
return abis_rsl_sendmsg(msg);
}
/* Send "ESTABLISH REQUEST" message with given L3 Info payload */
/* Chapter 8.3.1 */
int rsl_establish_request(struct gsm_lchan *lchan, u_int8_t link_id)
{
struct msgb *msg = rsl_msgb_alloc();
struct abis_rsl_rll_hdr *rh;
rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
init_llm_hdr(rh, RSL_MT_REL_REQ);
//rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP;
rh->chan_nr = lchan2chan_nr(lchan);
rh->link_id = link_id;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
/* Chapter 8.3.7 Request the release of multiframe mode of RLL connection.
This is what higher layers should call. The BTS then responds with
RELEASE CONFIRM, which we in turn use to trigger RSL CHANNEL RELEASE,
@ -1212,6 +1231,8 @@ static int rsl_rx_rll_err_ind(struct msgb *msg)
u_int8_t *rlm_cause = rllh->data;
DEBUGPC(DRLL, "ERROR INDICATION cause=0x%02x\n", rlm_cause[1]);
rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND);
if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED)
return rsl_chan_release(msg->lchan);
@ -1254,9 +1275,16 @@ static int abis_rsl_rx_rll(struct msgb *msg)
return gsm0408_rcvmsg(msg);
}
break;
case RSL_MT_EST_CONF:
DEBUGPC(DRLL, "ESTABLISH CONFIRMATION\n");
rll_indication(msg->lchan, rllh->link_id,
BSC_RLLR_IND_EST_CONF);
break;
case RSL_MT_REL_IND:
/* BTS informs us of having received DISC from MS */
DEBUGPC(DRLL, "RELEASE INDICATION\n");
rll_indication(msg->lchan, rllh->link_id,
BSC_RLLR_IND_REL_IND);
/* we can now releae the channel on the BTS/Abis side */
rsl_chan_release(msg->lchan);
break;

104
openbsc/src/bsc_rll.c Normal file
View File

@ -0,0 +1,104 @@
/* GSM BSC Radio Link Layer API
* 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
* 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.
*
*/
#include <errno.h>
#include <openbsc/debug.h>
#include <openbsc/talloc.h>
#include <openbsc/timer.h>
#include <openbsc/linuxlist.h>
#include <openbsc/bsc_rll.h>
#include <openbsc/gsm_data.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/abis_rsl.h>
struct bsc_rll_req {
struct llist_head list;
struct timer_list timer;
struct gsm_lchan *lchan;
u_int8_t link_id;
void (*cb)(struct gsm_lchan *lchan, u_int8_t link_id,
void *data, enum bsc_rllr_ind);
void *data;
};
/* we only compare C1, C2 and SAPI */
#define LINKID_MASK 0xC7
static LLIST_HEAD(bsc_rll_reqs);
static void complete_rllr(struct bsc_rll_req *rllr, enum bsc_rllr_ind type)
{
llist_del(&rllr->list);
put_lchan(rllr->lchan);
rllr->cb(rllr->lchan, rllr->link_id, rllr->data, type);
talloc_free(rllr);
}
static void timer_cb(void *_rllr)
{
struct bsc_rll_req *rllr = _rllr;
complete_rllr(rllr, BSC_RLLR_IND_TIMEOUT);
}
/* establish a RLL connection with given SAPI / priority */
int rll_establish(struct gsm_lchan *lchan, u_int8_t link_id,
void (*cb)(struct gsm_lchan *, u_int8_t, void *,
enum bsc_rllr_ind),
void *data)
{
struct bsc_rll_req *rllr = talloc_zero(tall_bsc_ctx, struct bsc_rll_req);
if (!rllr)
return -ENOMEM;
use_lchan(lchan);
rllr->lchan = lchan;
rllr->link_id = link_id;
rllr->cb = cb;
rllr->data = data;
rllr->timer.cb = &timer_cb;
/* start some timer? */
bsc_schedule_timer(&rllr->timer, 10, 0);
/* send the RSL RLL ESTablish REQuest */
return rsl_establish_request(rllr->lchan, rllr->link_id);
}
/* Called from RSL code in case we have received an indication regarding
* any RLL link */
void rll_indication(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t type)
{
struct bsc_rll_req *rllr, *rllr2;
llist_for_each_entry_safe(rllr, rllr2, &bsc_rll_reqs, list) {
if (rllr->lchan == lchan &&
(rllr->link_id & LINKID_MASK) == (link_id & LINKID_MASK)) {
complete_rllr(rllr, type);
return;
}
}
}