switch to new 'pass by value' at the TCAP-User boundary

this will enable the TCAP-User to queue primitives at will, since they
don't hold references to any data inside the TCAP-layer
This commit is contained in:
Harald Welte 2010-07-18 23:39:22 +02:00
parent c671dff577
commit 5a7afc24a7
3 changed files with 154 additions and 55 deletions

View File

@ -38,14 +38,20 @@ static struct {
uint32_t dialg_id;
} test_state;
static int send_continue(uint32_t dialg_id, void *app_ctx, void *user_info)
static int send_continue(uint32_t dialg_id, struct tcap_obj_ident *app_ctx, struct tcap_user_info *user_info)
{
struct tcap_dialg_ind tcdi;
memset(&tcdi, 0, sizeof(tcdi));
tcdi.dialg_id = dialg_id;
tcdi.app_ctx_name = app_ctx;
tcdi.user_info = user_info;
if (app_ctx) {
memcpy(&tcdi.app_ctx_name, app_ctx, sizeof(tcdi.app_ctx_name));
tcdi.app_ctx_present = 1;
}
if (user_info) {
memcpy(&tcdi.user_info, user_info, sizeof(tcdi.user_info));
tcdi.user_info_present = 1;
}
return tcap_user_req_dialg(TCAP_PR_TC_CONTINUE, &tcdi);
}
@ -56,8 +62,10 @@ static void tcap_gen_oper_local(struct OPERATION *op, uint32_t local_value)
}
/* UpdateGprsLocationArg */
static const int gprsLocationUpdateContext_v3[] = { 0, 4, 0, 0, 1, 0, 32, 3 };
static OBJECT_IDENTIFIER_t gprs_loc_upd_ctx_v3_oid;
static struct tcap_obj_ident gprsLocationUpdateContext_v3 = {
.arc = { 0, 4, 0, 0, 1, 0, 32, 3 },
.num_arcs = 8,
};
static uint8_t gprs_loc_upd_param[] = {
0x30, 0x1d, 0x04, 0x0f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x31, 0x32,
@ -83,13 +91,16 @@ static int send_invoke(uint32_t dialg_id, int8_t invoke_id, uint8_t *param, uint
return tcap_user_req_comp(TCAP_PR_TC_INVOKE, &tcci);
}
static int send_begin(uint32_t dialg_id, OBJECT_IDENTIFIER_t *app_ctx)
static int send_begin(uint32_t dialg_id, struct tcap_obj_ident *app_ctx)
{
struct tcap_dialg_ind tcdi;
memset(&tcdi, 0, sizeof(tcdi));
tcdi.dialg_id = dialg_id;
tcdi.app_ctx_name = app_ctx;
if (app_ctx) {
memcpy(&tcdi.app_ctx_name, app_ctx, sizeof(tcdi.app_ctx_name));
tcdi.app_ctx_present = 1;
}
tcdi.transp_ent = test_state.tte;
return tcap_user_req_dialg(TCAP_PR_TC_BEGIN, &tcdi);
@ -126,7 +137,7 @@ int tcap_user_ind_comp(enum tcap_primitive prim, struct tcap_component_ind *tcci
/* actually process the invoke */
send_invoke(test_state.dialg_id, 0, NULL, 0);
if (tcci->last_component)
send_continue(test_state.dialg_id, &gprs_loc_upd_ctx_v3_oid, NULL);
send_continue(test_state.dialg_id, &gprsLocationUpdateContext_v3, NULL);
break;
default:
break;
@ -135,13 +146,6 @@ int tcap_user_ind_comp(enum tcap_primitive prim, struct tcap_component_ind *tcci
return 0;
}
static void initialize(void)
{
OBJECT_IDENTIFIER_set_arcs(&gprs_loc_upd_ctx_v3_oid, &gprsLocationUpdateContext_v3,
sizeof(gprsLocationUpdateContext_v3[0]),
ARRAY_SIZE(gprsLocationUpdateContext_v3));
}
static void signal_handler(int signal)
{
switch (signal) {
@ -149,6 +153,10 @@ static void signal_handler(int signal)
talloc_report_full(NULL, stderr);
exit(0);
break;
case SIGSEGV:
case SIGABRT:
talloc_report_full(NULL, stderr);
break;
default:
break;
}
@ -161,8 +169,8 @@ int main(int argc, char **argv)
talloc_enable_leak_report_full();
signal(SIGINT, &signal_handler);
initialize();
signal(SIGSEGV, &signal_handler);
signal(SIGABRT, &signal_handler);
ss.ss_family = AF_INET;
sin->sin_addr.s_addr = INADDR_ANY;
@ -180,7 +188,7 @@ int main(int argc, char **argv)
send_invoke(0x1234, 0, gprs_loc_upd_param, sizeof(gprs_loc_upd_param));
send_invoke(0x1234, 1, NULL, 0);
send_invoke(0x1234, -1, NULL, 0);
send_begin(0x1234, &gprs_loc_upd_ctx_v3_oid);
send_begin(0x1234, &gprsLocationUpdateContext_v3);
while (1) {
bsc_select_main(0);

View File

@ -57,20 +57,40 @@ struct tcap_transport_entity {
};
};
struct tcap_obj_ident {
uint32_t arc[16];
unsigned int num_arcs;
};
struct tcap_user_info {
/* 272 bytes is the MTU of classic SS7 links */
uint8_t data[272];
uint32_t data_len;
};
extern struct tcap_transport_entity *tcap_transp_udp_create(struct sockaddr_storage *local_addr);
/* Call-back to user from other points in the stack */
/* metadata associated with a dialogue indication primitive */
struct tcap_dialg_ind {
/* Dummy list head structure for the user. libosmo-tcap doesn't use it */
struct llist_head list;
/* Dialogue ID to which this primitive relates */
uint32_t dialg_id;
/* Reference to the user-provided TCAP transport entity */
struct tcap_transport_entity *transp_ent;
OBJECT_IDENTIFIER_t *app_ctx_name;
struct user_information *user_info;
int components_present:1;
int prearranged_end:1;
uint32_t components_present:1,
prearranged_end:1,
app_ctx_present:1,
user_info_present:1;
/* Reason/Cause in case of some error */
uint32_t reason;
void *qos;
/* Application Context Name as OID */
struct tcap_obj_ident app_ctx_name;
/* User information (application dialogue data) */
struct tcap_user_info user_info;
};
/* metadata associated with a component indication primitive */

135
src/tcu.c
View File

@ -24,12 +24,22 @@
#include <osmocore/msgb.h>
#include <osmocore/utils.h>
#include <osmocore/talloc.h>
#include <osmocom/tcap/Parameter.h>
#include "tcap.h"
#include "tcap_user.h"
void *tcap_dialg_ind_ctx;
static struct tcap_dialg_ind *tcap_dialg_ind_alloc(void)
{
struct tcap_dialg_ind *tcdi = talloc_zero(tcap_dialg_ind_ctx,
struct tcap_dialg_ind);
return tcdi;
}
static const struct value_string tcap_prim_names[] = {
/* dialogue handling */
{ TCAP_PR_TC_UNI, "TC-UNI" },
@ -86,52 +96,84 @@ int tcap_tcu_tc_r_rej_ind(struct tcap_invocation *ti, int8_t *invoke_id, uint32_
}
/* fill the application context and user information part of 'tcap_dialg_ind' */
static int fill_tcap_dialg_ind(struct tcap_dialg_ind *tcdi,
OBJECT_IDENTIFIER_t *app_ctx_name,
struct user_information *user_info)
{
int rc;
if (app_ctx_name) {
/* Parse the Application Context from an OID into our array of ARCs */
rc = OBJECT_IDENTIFIER_get_arcs(app_ctx_name, &tcdi->app_ctx_name.arc,
sizeof(tcdi->app_ctx_name.arc[0]),
ARRAY_SIZE(tcdi->app_ctx_name.arc));
if (rc < 0)
return rc;
tcdi->app_ctx_name.num_arcs = rc;
tcdi->app_ctx_present = 1;
}
/* copy the user_info */
if (user_info) {
EXTERNAL_t *ext;
if (user_info->list.count != 1)
return -EIO;
ext = user_info->list.array[0];
if (ext->size > sizeof(tcdi->user_info.data))
return -EIO;
memcpy(tcdi->user_info.data, ext->buf, ext->size);
tcdi->user_info.data_len = ext->size;
}
return 0;
}
/* Take any TC-Dialogue.ind from the stack and pass it to the user */
static int _tcap_tcu_dialg_ind(enum tcap_primitive prim, struct tcap_dialogue *td,
OBJECT_IDENTIFIER_t *app_ctx_name,
struct user_information *user_info, int comp_present)
{
struct tcap_dialg_ind *tcdi = tcap_dialg_ind_alloc();
int rc;
if (!tcdi)
return -ENOMEM;
tcdi->dialg_id = td->dialogue_id;
rc = fill_tcap_dialg_ind(tcdi, app_ctx_name, user_info);
if (rc < 0) {
/* FIXME: reject the dialogue */
return rc;
}
if (comp_present)
tcdi->components_present = 1;
return tcap_user_ind_dialg(prim, tcdi);
}
/* TC-BEGIN.ind from DHA */
int tcap_tcu_begin_ind(struct tcap_dialogue *td, void *app_ctx_name, void *user_info, int comp_present)
{
struct tcap_dialg_ind tcdi;
memset(&tcdi, 0, sizeof(tcdi));
tcdi.dialg_id = td->dialogue_id;
tcdi.app_ctx_name = app_ctx_name;
tcdi.user_info = user_info;
tcdi.components_present = comp_present;
return tcap_user_ind_dialg(TCAP_PR_TC_BEGIN, &tcdi);
return _tcap_tcu_dialg_ind(TCAP_PR_TC_BEGIN, td, app_ctx_name, user_info, comp_present);
}
/* TC-UNI.ind from DHA */
int tcap_tcu_uni_ind(struct tcap_dialogue *td, void *app_ctx_name, void *user_info, int comp_present)
{
return _tcap_tcu_dialg_ind(TCAP_PR_TC_UNI, td, app_ctx_name, user_info, comp_present);
}
/* TC-CONT.ind from DHA */
int tcap_tcu_cont_ind(struct tcap_dialogue *td, void *app_ctx_name, void *user_info, int comp_present)
{
struct tcap_dialg_ind tcdi;
memset(&tcdi, 0, sizeof(tcdi));
tcdi.dialg_id = td->dialogue_id;
tcdi.app_ctx_name;
tcdi.user_info;
tcdi.components_present = comp_present;
return tcap_user_ind_dialg(TCAP_PR_TC_CONTINUE, &tcdi);
return _tcap_tcu_dialg_ind(TCAP_PR_TC_CONTINUE, td, app_ctx_name, user_info, comp_present);
}
/* TC-END.ind from DHA */
int tcap_tcu_end_ind(struct tcap_dialogue *td, void *app_ctx_name, void *user_info, int comp_present)
{
struct tcap_dialg_ind tcdi;
memset(&tcdi, 0, sizeof(tcdi));
tcdi.dialg_id = td->dialogue_id;
tcdi.app_ctx_name;
tcdi.user_info;
tcdi.components_present = comp_present;
return tcap_user_ind_dialg(TCAP_PR_TC_END, &tcdi);
return _tcap_tcu_dialg_ind(TCAP_PR_TC_END, td, app_ctx_name, user_info, comp_present);
}
/* TC-ABORT.ind from DHA */
@ -159,6 +201,8 @@ LIB_EXPORTED int tcap_user_req_comp(enum tcap_primitive prim, struct tcap_compon
struct tcap_dialogue *td;
int rc = 0;
fprintf(stdout, "<- USER_REQ_COMP(%s)\n", tcap_prim_name(prim));
/* Resolve (or allocate) the dialogue/transaction state */
td = tcap_dialg_by_dialg_id(tcci->dialg_id);
if (!td) {
@ -194,11 +238,20 @@ LIB_EXPORTED int tcap_user_req_comp(enum tcap_primitive prim, struct tcap_compon
return rc;
}
/* DIALOGUE primitive received from TC-User */
LIB_EXPORTED int tcap_user_req_dialg(enum tcap_primitive prim, struct tcap_dialg_ind *tcdi)
{
/* Allocate some structures on the stack */
OBJECT_IDENTIFIER_t _app_ctx;
OBJECT_IDENTIFIER_t *app_ctx = NULL;
EXTERNAL_t ext;
struct user_information _user_info;
struct user_information *user_info = NULL;
struct tcap_dialogue *td;
int rc = 0;
fprintf(stdout, "<- USER_REQ_DIALG(%s)\n", tcap_prim_name(prim));
/* Resolve (or allocate) the dialogue/transaction state */
td = tcap_dialg_by_dialg_id(tcdi->dialg_id);
if (!td) {
@ -213,17 +266,35 @@ LIB_EXPORTED int tcap_user_req_dialg(enum tcap_primitive prim, struct tcap_dialg
}
}
/* Parse the tcap_dialg_ind into something that the asn1c code understands */
if (tcdi->app_ctx_present) {
app_ctx = &_app_ctx;
memset(app_ctx, 0, sizeof(&app_ctx));
OBJECT_IDENTIFIER_set_arcs(app_ctx, &tcdi->app_ctx_name.arc,
sizeof(tcdi->app_ctx_name.arc[0]),
tcdi->app_ctx_name.num_arcs);
}
/* Parse the tcap_dialg_ind into something that the asn1c code understands */
if (tcdi->user_info_present) {
user_info = &_user_info;
memset(&ext, 0, sizeof(ext));
memset(user_info, 0, sizeof(*user_info));
ext.buf = tcdi->user_info.data;
ext.size = tcdi->user_info.data_len;
ASN_SEQUENCE_ADD(&user_info->list, &ext);
}
switch (prim) {
case TCAP_PR_TC_BEGIN:
td->transp_ent = tcdi->transp_ent;
rc = tcap_csl_tc_begin_req(td, tcdi->app_ctx_name, tcdi->user_info);
rc = tcap_csl_tc_begin_req(td, app_ctx, user_info);
break;
case TCAP_PR_TC_CONTINUE:
fprintf(stdout, "TC-CONTINUE.req\n");
rc = tcap_csl_tc_cont_req(td, tcdi->app_ctx_name, tcdi->user_info);
rc = tcap_csl_tc_cont_req(td, app_ctx, user_info);
break;
case TCAP_PR_TC_END:
rc = tcap_csl_tc_end_req(td, tcdi->app_ctx_name, tcdi->user_info, tcdi->prearranged_end);
rc = tcap_csl_tc_end_req(td, app_ctx, user_info, tcdi->prearranged_end);
break;
default:
fprintf(stderr, "unsupported component primitive %s\n", tcap_prim_name(prim));