aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2009-07-23 18:56:43 +0200
committerHarald Welte <laforge@gnumonks.org>2009-07-23 19:10:12 +0200
commitaa0b29c2650104b4cb06cd63f295af16fa3a3231 (patch)
tree502ff81ed73dff97c969d4e3a36f71213e95c461 /openbsc
parentf8d536def97a65f5a0f1dec7f38ee15030acae53 (diff)
gms_transactions data model reorganization
This changeset factors out gsm_transaction as something independent of call control in preparation to re-use the code from SMS. A transaction is uniquely identified by either its callref, or by a tuple of (transaction_id, protocol, subscriber).
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/include/openbsc/gsm_data.h34
-rw-r--r--openbsc/src/Makefile.am3
-rw-r--r--openbsc/src/gsm_04_08.c183
-rw-r--r--openbsc/src/gsm_subscriber.c1
4 files changed, 91 insertions, 130 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index de3f1f578..9bbc2921d 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -107,26 +107,36 @@ struct gsm_trans {
/* Network */
struct gsm_network *network;
+ /* The protocol within which we live */
+ u_int8_t protocol;
+
/* The current transaction ID */
u_int8_t transaction_id;
- /* The LCHAN that we're part of */
- struct gsm_lchan *lchan;
-
- /* To whom we are allocated at the moment */
+ /* To whom we belong, unique identifier of remote MM entity */
struct gsm_subscriber *subscr;
- /* reference */
+ /* The LCHAN that we're currently using to transmit messages */
+ struct gsm_lchan *lchan;
+
+ /* reference from MNCC or other application */
u_int32_t callref;
- /* current call state */
- int state;
+ union {
+ struct {
+
+ /* current call state */
+ int state;
- /* current timer and message queue */
- int Tcurrent; /* current CC timer */
- int T308_second; /* used to send release again */
- struct timer_list cc_timer;
- struct gsm_mncc cc_msg; /* stores setup/disconnect/release message */
+ /* current timer and message queue */
+ int Tcurrent; /* current CC timer */
+ int T308_second; /* used to send release again */
+ struct timer_list timer;
+ struct gsm_mncc msg; /* stores setup/disconnect/release message */
+ } cc;
+ struct {
+ } sms;
+ };
};
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index c0ac63cb1..c6e9dae53 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -9,7 +9,8 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_04_08.c gsm_data.c mncc.c \
gsm_subscriber.c msgb.c select.c chan_alloc.c timer.c debug.c db.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
+ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \
+ transaction.c
libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index df4d3c668..6f729e370 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -45,6 +45,7 @@
#include <openbsc/trau_frame.h>
#include <openbsc/trau_mux.h>
#include <openbsc/talloc.h>
+#include <openbsc/transaction.h>
#define GSM48_ALLOC_SIZE 1024
#define GSM48_ALLOC_HEADROOM 128
@@ -54,7 +55,6 @@
#define GSM_MAX_USERUSER 128
static void *tall_locop_ctx;
-static void *tall_trans_ctx;
static const struct tlv_definition rsl_att_tlvdef = {
.def = {
@@ -292,7 +292,6 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi);
static int gsm48_tx_simple(struct gsm_lchan *lchan,
u_int8_t pdisc, u_int8_t msg_type);
static void schedule_reject(struct gsm_lchan *lchan);
-void free_trans(struct gsm_trans *trans);
struct gsm_lai {
u_int16_t mcc;
@@ -392,9 +391,12 @@ static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
release_loc_updating_req(lchan);
/* Free all transactions that are associated with the released lchan */
+ /* FIXME: this is not neccessarily the right thing to do, we should
+ * only set trans->lchan to NULL and wait for another lchan to be
+ * established to the same MM entity (phone/subscriber) */
llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) {
if (trans->lchan == lchan)
- free_trans(trans);
+ trans_free(trans);
}
return 0;
@@ -1789,9 +1791,9 @@ static void new_cc_state(struct gsm_trans *trans, int state)
return;
DEBUGP(DCC, "new state %s -> %s\n",
- cc_state_names[trans->state], cc_state_names[state]);
+ cc_state_names[trans->cc.state], cc_state_names[state]);
- trans->state = state;
+ trans->cc.state = state;
}
static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg)
@@ -1831,10 +1833,10 @@ static int gsm48_tx_simple(struct gsm_lchan *lchan,
static void gsm48_stop_cc_timer(struct gsm_trans *trans)
{
- if (bsc_timer_pending(&trans->cc_timer)) {
- DEBUGP(DCC, "stopping pending timer T%x\n", trans->Tcurrent);
- bsc_del_timer(&trans->cc_timer);
- trans->Tcurrent = 0;
+ if (bsc_timer_pending(&trans->cc.timer)) {
+ DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
+ bsc_del_timer(&trans->cc.timer);
+ trans->cc.Tcurrent = 0;
}
}
@@ -1883,10 +1885,10 @@ int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans,
return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
}
-void free_trans(struct gsm_trans *trans)
+/* Call Control Specific transaction release.
+ * gets called by trans_free, DO NOT CALL YOURSELF! */
+void _gsm48_cc_trans_free(struct gsm_trans *trans)
{
- struct gsm_bts *bts;
-
gsm48_stop_cc_timer(trans);
/* send release to L4, if callref still exists */
@@ -1895,37 +1897,11 @@ void free_trans(struct gsm_trans *trans)
mncc_release_ind(trans->network, trans, trans->callref,
GSM48_CAUSE_LOC_PRN_S_LU,
GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
- if (trans->state != GSM_CSTATE_NULL)
- new_cc_state(trans, GSM_CSTATE_NULL);
- }
-
- if (!trans->lchan && trans->subscr && trans->subscr->net) {
- /* Stop paging on all bts' */
- bts = NULL;
- do {
- bts = gsm_bts_by_lac(trans->subscr->net,
- trans->subscr->lac, bts);
- if (!bts)
- break;
- /* Stop paging */
- paging_request_stop(bts, trans->subscr, NULL);
- } while (1);
- }
-
- if (trans->lchan) {
- trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
- put_lchan(trans->lchan);
}
-
- if (trans->subscr)
- subscr_put(trans->subscr);
-
- if (trans->state != GSM_CSTATE_NULL)
+ if (trans->cc.state != GSM_CSTATE_NULL)
new_cc_state(trans, GSM_CSTATE_NULL);
-
- llist_del(&trans->entry);
-
- talloc_free(trans);
+ if (trans->lchan)
+ trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
}
static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
@@ -1966,7 +1942,7 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
use_lchan(lchan);
}
/* send SETUP request to called party */
- gsm48_cc_tx_setup(transt, &transt->cc_msg);
+ gsm48_cc_tx_setup(transt, &transt->cc.msg);
if (is_ipaccess_bts(lchan->ts->trx->bts))
rsl_ipacc_bind(lchan);
break;
@@ -1978,7 +1954,7 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
GSM48_CAUSE_LOC_PRN_S_LU,
GSM48_CC_CAUSE_DEST_OOO);
transt->callref = 0;
- free_trans(transt);
+ trans_free(transt);
break;
}
}
@@ -2027,21 +2003,11 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
return 0;
}
-static struct gsm_trans *get_trans_ref(struct gsm_network *net, u_int32_t callref)
-{
- struct gsm_trans *trans;
- llist_for_each_entry(trans, &net->trans_list, entry) {
- if (trans->callref == callref)
- return trans;
- }
- return NULL;
-}
-
/* bridge channels of two transactions */
static int tch_bridge(struct gsm_network *net, u_int32_t *refs)
{
- struct gsm_trans *trans1 = get_trans_ref(net, refs[0]);
- struct gsm_trans *trans2 = get_trans_ref(net, refs[1]);
+ struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]);
+ struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]);
if (!trans1 || !trans2)
return -EIO;
@@ -2059,7 +2025,7 @@ static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable)
struct gsm_trans *trans;
/* Find callref */
- trans = get_trans_ref(net, data->callref);
+ trans = trans_find_by_callref(net, data->callref);
if (!trans)
return -EIO;
if (!trans->lchan)
@@ -2077,7 +2043,7 @@ static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame)
struct gsm_trans *trans;
/* Find callref */
- trans = get_trans_ref(net, frame->callref);
+ trans = trans_find_by_callref(net, frame->callref);
if (!trans)
return -EIO;
if (!trans->lchan)
@@ -2116,7 +2082,7 @@ static void gsm48_cc_timeout(void *arg)
memset(&l4_rel, 0, sizeof(struct gsm_mncc));
l4_rel.callref = trans->callref;
- switch(trans->Tcurrent) {
+ switch(trans->cc.Tcurrent) {
case 0x303:
release = 1;
l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
@@ -2134,21 +2100,21 @@ static void gsm48_cc_timeout(void *arg)
l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
break;
case 0x308:
- if (!trans->T308_second) {
+ if (!trans->cc.T308_second) {
/* restart T308 a second time */
- gsm48_cc_tx_release(trans, &trans->cc_msg);
- trans->T308_second = 1;
+ gsm48_cc_tx_release(trans, &trans->cc.msg);
+ trans->cc.T308_second = 1;
break; /* stay in release state */
}
- free_trans(trans);
+ trans_free(trans);
return;
// release = 1;
// l4_cause = 14;
// break;
case 0x306:
release = 1;
- mo_cause = trans->cc_msg.cause.value;
- mo_location = trans->cc_msg.cause.location;
+ mo_cause = trans->cc.msg.cause.value;
+ mo_location = trans->cc.msg.cause.location;
break;
case 0x323:
disconnect = 1;
@@ -2173,9 +2139,9 @@ static void gsm48_cc_timeout(void *arg)
/* process disconnect towards mobile station */
if (disconnect || release) {
mncc_set_cause(&mo_rel, mo_location, mo_cause);
- mo_rel.cause.diag[0] = ((trans->Tcurrent & 0xf00) >> 8) + '0';
- mo_rel.cause.diag[1] = ((trans->Tcurrent & 0x0f0) >> 4) + '0';
- mo_rel.cause.diag[2] = (trans->Tcurrent & 0x00f) + '0';
+ mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
+ mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
+ mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
mo_rel.cause.diag_len = 3;
if (disconnect)
@@ -2190,10 +2156,10 @@ static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
int sec, int micro)
{
DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
- trans->cc_timer.cb = gsm48_cc_timeout;
- trans->cc_timer.data = trans;
- bsc_schedule_timer(&trans->cc_timer, sec, micro);
- trans->Tcurrent = current;
+ trans->cc.timer.cb = gsm48_cc_timeout;
+ trans->cc.timer.data = trans;
+ bsc_schedule_timer(&trans->cc.timer, sec, micro);
+ trans->cc.Tcurrent = current;
}
static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
@@ -2293,7 +2259,7 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
GSM48_CAUSE_LOC_PRN_S_LU,
GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
trans->callref = 0;
- free_trans(trans);
+ trans_free(trans);
return rc;
}
@@ -2311,7 +2277,7 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
GSM48_CAUSE_LOC_PRN_S_LU,
GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
trans->callref = 0;
- free_trans(trans);
+ trans_free(trans);
return rc;
}
for (i = 0; i < 7; i++) {
@@ -2695,7 +2661,7 @@ static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
encode_useruser(msg, 0, &disc->useruser);
/* store disconnect cause for T306 expiry */
- memcpy(&trans->cc_msg, disc, sizeof(struct gsm_mncc));
+ memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
@@ -2740,7 +2706,7 @@ static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
}
- if (trans->state == GSM_CSTATE_RELEASE_REQ) {
+ if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
/* release collision 5.4.5 */
rc = mncc_recvmsg(trans->network, trans, MNCC_REL_CNF, &rel);
} else {
@@ -2752,7 +2718,7 @@ static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
new_cc_state(trans, GSM_CSTATE_NULL);
trans->callref = 0;
- free_trans(trans);
+ trans_free(trans);
return rc;
}
@@ -2782,10 +2748,10 @@ static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
if (rel->fields & MNCC_F_USERUSER)
encode_useruser(msg, 0, &rel->useruser);
- trans->T308_second = 0;
- memcpy(&trans->cc_msg, rel, sizeof(struct gsm_mncc));
+ trans->cc.T308_second = 0;
+ memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
- if (trans->state != GSM_CSTATE_RELEASE_REQ)
+ if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
return gsm48_sendmsg(msg);
@@ -2830,7 +2796,7 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
}
if (trans->callref) {
- switch (trans->state) {
+ switch (trans->cc.state) {
case GSM_CSTATE_CALL_PRESENT:
rc = mncc_recvmsg(trans->network, trans,
MNCC_REJ_IND, &rel);
@@ -2846,7 +2812,7 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
}
trans->callref = 0;
- free_trans(trans);
+ trans_free(trans);
return rc;
}
@@ -2875,7 +2841,7 @@ static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
if (rel->fields & MNCC_F_USERUSER)
encode_useruser(msg, 0, &rel->useruser);
- free_trans(trans);
+ trans_free(trans);
return gsm48_sendmsg(msg);
}
@@ -3385,7 +3351,7 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg)
rel.callref = data->callref;
/* Find callref */
- trans = get_trans_ref(net, data->callref);
+ trans = trans_find_by_callref(net, data->callref);
/* Callref unknown */
if (!trans) {
@@ -3437,7 +3403,8 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg)
GSM48_CC_CAUSE_DEST_OOO);
}
/* Create transaction */
- if (!(trans = talloc_zero(tall_trans_ctx, struct gsm_trans))) {
+ trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref);
+ if (!trans) {
DEBUGP(DCC, "No memory for trans.\n");
subscr_put(subscr);
/* Ressource unavailable */
@@ -3446,12 +3413,6 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg)
GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
return -ENOMEM;
}
- trans->callref = data->callref;
- trans->network = net;
- trans->transaction_id = 0xff; /* unassigned */
- llist_add_tail(&trans->entry, &net->trans_list);
- /* Assign subscriber to transaction */
- trans->subscr = subscr;
/* Find lchan */
for (i = 0; i < net->num_bts; i++) {
bts = gsm_bts_num(net, i);
@@ -3487,7 +3448,7 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg)
return 0;
}
/* store setup informations until paging was successfull */
- memcpy(&trans->cc_msg, data, sizeof(struct gsm_mncc));
+ memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
/* start paging subscriber on all BTS with her location */
subscr->net = net;
bts = NULL;
@@ -3525,7 +3486,7 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg)
else
rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel);
trans->callref = 0;
- free_trans(trans);
+ trans_free(trans);
return rc;
}
@@ -3534,13 +3495,13 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg)
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
trans->transaction_id,
(lchan->subscr)?(lchan->subscr->extension):"-",
- get_mncc_name(msg_type), trans->state,
- cc_state_names[trans->state]);
+ get_mncc_name(msg_type), trans->cc.state,
+ cc_state_names[trans->cc.state]);
/* Find function for current state and message */
for (i = 0; i < DOWNSLLEN; i++)
if ((msg_type == downstatelist[i].type)
- && ((1 << trans->state) & downstatelist[i].states))
+ && ((1 << trans->cc.state) & downstatelist[i].states))
break;
if (i == DOWNSLLEN) {
DEBUGP(DCC, "Message unhandled at this state.\n");
@@ -3613,8 +3574,7 @@ static int gsm0408_rcv_cc(struct msgb *msg)
u_int8_t msg_type = gh->msg_type & 0xbf;
u_int8_t transaction_id = (gh->proto_discr & 0xf0) ^ 0x80; /* flip */
struct gsm_lchan *lchan = msg->lchan;
- struct gsm_trans *trans = NULL, *transt;
- struct gsm_network *net = lchan->ts->trx->bts->network;
+ struct gsm_trans *trans = NULL;
int i, rc = 0;
if (msg_type & 0x80) {
@@ -3623,50 +3583,38 @@ static int gsm0408_rcv_cc(struct msgb *msg)
}
/* Find transaction */
- llist_for_each_entry(transt, &net->trans_list, entry) {
- /* Transaction of our lchan? */
- if (transt->lchan == lchan
- && transt->transaction_id == transaction_id) {
- trans = transt;
- }
- }
-
+ trans = trans_find_by_id(lchan, transaction_id);
+
DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
"Received '%s' from MS in state %d (%s)\n",
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
- cc_msg_names[msg_type], trans?(trans->state):0,
- cc_state_names[trans?(trans->state):0]);
+ cc_msg_names[msg_type], trans?(trans->cc.state):0,
+ cc_state_names[trans?(trans->cc.state):0]);
/* Create transaction */
if (!trans) {
DEBUGP(DCC, "Unknown transaction ID %02x, "
"creating new trans.\n", transaction_id);
/* Create transaction */
- if (!(trans = talloc_zero(tall_trans_ctx, struct gsm_trans))) {
+ trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
+ transaction_id, new_callref++);
+ if (!trans) {
DEBUGP(DCC, "No memory for trans.\n");
rc = gsm48_tx_simple(msg->lchan,
GSM48_PDISC_CC | transaction_id,
GSM48_MT_CC_RELEASE_COMPL);
return -ENOMEM;
}
- llist_add_tail(&trans->entry, &net->trans_list);
/* Assign transaction */
- trans->callref = new_callref++;
- trans->network = net;
- trans->transaction_id = transaction_id;
trans->lchan = lchan;
use_lchan(lchan);
- if (lchan->subscr) {
- trans->subscr = lchan->subscr;
- subscr_get(trans->subscr);
- }
}
/* find function for current state and message */
for (i = 0; i < DATASLLEN; i++)
if ((msg_type == datastatelist[i].type)
- && ((1 << trans->state) & datastatelist[i].states))
+ && ((1 << trans->cc.state) & datastatelist[i].states))
break;
if (i == DATASLLEN) {
DEBUGP(DCC, "Message unhandled at this state.\n");
@@ -3823,3 +3771,4 @@ int bsc_upqueue(struct gsm_network *net)
return work;
}
+
diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c
index a323d4e87..56f15951a 100644
--- a/openbsc/src/gsm_subscriber.c
+++ b/openbsc/src/gsm_subscriber.c
@@ -168,6 +168,7 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason)
/* FIXME: Migrate pending requests from one BSC to another */
switch (reason) {
case GSM_SUBSCRIBER_UPDATE_ATTACHED:
+ s->net = bts->network;
/* Indicate "attached to LAC" */
s->lac = bts->location_area_code;
break;