189 lines
4.8 KiB
C
189 lines
4.8 KiB
C
|
|
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
|
* (C) 2010 by On-Waves
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdint.h>
|
|
#include <errno.h>
|
|
|
|
#include <osmocore/linuxlist.h>
|
|
#include <osmocore/talloc.h>
|
|
#include <osmocore/utils.h>
|
|
#include <osmocore/logging.h>
|
|
|
|
#include "tcap.h"
|
|
|
|
static LLIST_HEAD(tcap_dialogues);
|
|
|
|
static uint32_t dialg_id_ctr = 0x4000;
|
|
static uint32_t trans_id_ctr = 0x8000;
|
|
|
|
void *tall_tcap_dialg_ctx;
|
|
|
|
uint32_t tcap_dialg_id_alloc(void)
|
|
{
|
|
uint32_t dialg_id;
|
|
|
|
dialg_id = dialg_id_ctr++;
|
|
|
|
while (tcap_dialg_by_dialg_id(dialg_id))
|
|
dialg_id = dialg_id_ctr++;
|
|
|
|
printf("found free Dialogue ID 0x%08x\n", dialg_id);
|
|
return dialg_id;
|
|
}
|
|
|
|
struct tcap_dialogue *tcap_dialg_by_dialg_id(uint32_t dialogue_id)
|
|
{
|
|
struct tcap_dialogue *td;
|
|
llist_for_each_entry(td, &tcap_dialogues, list) {
|
|
if (td->dialogue_id == dialogue_id)
|
|
return td;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void _comp_seq_elem_free(Component_t *comp)
|
|
{
|
|
asn_DEF_Component.free_struct(&asn_DEF_Component, comp, 0);
|
|
}
|
|
|
|
|
|
/* Add a single component to the list of pending components of this dialogue */
|
|
int tcap_dialg_comp_add(struct tcap_dialogue *td, Component_t *comp)
|
|
{
|
|
if (!td->pend_comp) {
|
|
td->pend_comp = talloc_zero(td, struct ComponentPortion);
|
|
if (!td->pend_comp)
|
|
return -ENOMEM;
|
|
td->pend_comp->list.free = _comp_seq_elem_free;
|
|
}
|
|
ASN_SEQUENCE_ADD(&td->pend_comp->list, comp);
|
|
}
|
|
|
|
struct tcap_dialogue *tcap_dialg_alloc(uint32_t dialogue_id)
|
|
{
|
|
struct tcap_dialogue *td = talloc_zero(tall_tcap_dialg_ctx, struct tcap_dialogue);
|
|
if (!td)
|
|
return NULL;
|
|
|
|
td->dialogue_id = dialogue_id;
|
|
td->trans.state = TCAP_TS_IDLE;
|
|
td->trans.tid_local = tcap_trans_id_alloc();
|
|
INIT_LLIST_HEAD(&td->ism_list);
|
|
|
|
llist_add(&td->list, &tcap_dialogues);
|
|
|
|
printf("allocated Dialogue with ID 0x%08x\n", dialogue_id);
|
|
|
|
return td;
|
|
}
|
|
|
|
void tcap_dialg_free(struct tcap_dialogue *td)
|
|
{
|
|
printf("freeing Dialogue with ID 0x%08x\n", td->dialogue_id);
|
|
|
|
/* Delete from global list of all dialogues */
|
|
llist_del(&td->list);
|
|
/* No need to iterate over pending component list, talloc is hierarchical */
|
|
/* No need to iterate over ISM list, talloc is hierarchical */
|
|
talloc_free(td);
|
|
}
|
|
|
|
/* allocate a transaction (by allocating a dialogue) */
|
|
struct tcap_transaction *tcap_transaction_alloc(void)
|
|
{
|
|
uint32_t dialg_id = tcap_dialg_id_alloc();
|
|
struct tcap_dialogue *td = tcap_dialg_alloc(dialg_id);
|
|
return &td->trans;
|
|
}
|
|
|
|
struct tcap_transaction *tcap_transaction_by_remote_tid(uint32_t tid_remote)
|
|
{
|
|
struct tcap_dialogue *td;
|
|
|
|
llist_for_each_entry(td, &tcap_dialogues, list) {
|
|
if (td->trans.tid_remote == tid_remote)
|
|
return &td->trans;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct tcap_transaction *tcap_transaction_by_local_tid(uint32_t tid_local)
|
|
{
|
|
struct tcap_dialogue *td;
|
|
|
|
llist_for_each_entry(td, &tcap_dialogues, list) {
|
|
if (td->trans.tid_local == tid_local)
|
|
return &td->trans;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t tcap_trans_id_alloc(void)
|
|
{
|
|
uint32_t trans_id;
|
|
|
|
trans_id = trans_id_ctr++;
|
|
|
|
while (tcap_transaction_by_local_tid(trans_id))
|
|
trans_id = trans_id_ctr++;
|
|
|
|
return trans_id;
|
|
}
|
|
|
|
static const struct value_string trans_state_name[] = {
|
|
{ TCAP_TS_INVALID, "TS-Invalid" },
|
|
{ TCAP_TS_IDLE, "TS-Idle" },
|
|
{ TCAP_TS_INIT_RECV, "TS-Initiation-Received" },
|
|
{ TCAP_TS_INIT_SENT, "TS-Initiation-Sent" },
|
|
{ TCAP_TS_ACTIVE, "TS-Active" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const struct value_string inv_state_name[] = {
|
|
{ TCAP_IS_INVALID, "IS-Invalid" },
|
|
{ TCAP_IS_IDLE, "IS-Idle" },
|
|
{ TCAP_IS_OP_SENT_CL1, "IS-Operation-Sent-CL1" },
|
|
{ TCAP_IS_OP_SENT_CL2, "IS-Operation-Sent-CL2" },
|
|
{ TCAP_IS_OP_SENT_CL3, "IS-Operation-Sent-CL3" },
|
|
{ TCAP_IS_OP_SENT_CL4, "IS-Operation-Sent-CL4" },
|
|
{ TCAP_IS_WAIT_REJECT, "IS-Wait-Reject" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
const char *tcap_trans_state_name(enum tcap_transaction_state ts)
|
|
{
|
|
return get_value_string(trans_state_name, ts);
|
|
}
|
|
|
|
const char *tcap_inv_state_name(enum tcap_invocation_state is)
|
|
{
|
|
return get_value_string(inv_state_name, is);
|
|
}
|
|
|
|
void tcap_trans_set_state(struct tcap_transaction *tt, enum tcap_transaction_state st)
|
|
{
|
|
printf("Transaction 0x%08x old_state=%s, new_state=%s\n", tt->tid_local,
|
|
tcap_trans_state_name(tt->state), tcap_trans_state_name(st));
|
|
tt->state = st;
|
|
}
|