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:
parent
c671dff577
commit
5a7afc24a7
|
@ -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);
|
||||
|
|
|
@ -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
135
src/tcu.c
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue