diff --git a/src/csl_cha_cco.c b/src/csl_cha_cco.c index e4f683c..c0005fc 100644 --- a/src/csl_cha_cco.c +++ b/src/csl_cha_cco.c @@ -71,6 +71,11 @@ static Parameter_t *gen_param(const void *ctx, uint8_t *param, uint32_t param_le }; /* TC-INVOKE.req (TCU -> CHA) */ +/* + * linked_id not referenced after call, caller needs to free it + * op not referenced after call, caller needs to free it + * param not referenced after call, caller needs to free it + */ int tcap_cha_tc_invoke_req(struct tcap_dialogue *td, uint8_t op_class, int8_t inv_id, int8_t *linked_id, struct OPERATION *op, uint8_t *param, uint32_t param_len, uint32_t timeout) diff --git a/src/tcap_test.c b/src/tcap_test.c index 3576dce..9311994 100644 --- a/src/tcap_test.c +++ b/src/tcap_test.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -56,12 +57,6 @@ static int send_continue(uint32_t dialg_id, struct tcap_obj_ident *app_ctx, stru return tcap_user_req_dialg(TCAP_PR_TC_CONTINUE, &tcdi); } -static void tcap_gen_oper_local(struct OPERATION *op, uint32_t local_value) -{ - op->present = OPERATION_PR_localValue; - asn_long2INTEGER(&op->choice.localValue, local_value); -} - /* UpdateGprsLocationArg */ static struct tcap_obj_ident gprsLocationUpdateContext_v3 = { .arc = { 0, 4, 0, 0, 1, 0, 32, 3 }, @@ -82,12 +77,14 @@ static int send_invoke(uint32_t dialg_id, int8_t invoke_id, uint8_t *param, uint tcci.dialg_id = dialg_id; tcci.invoke_id = invoke_id; tcci.linked_id = NULL; - tcap_gen_oper_local(&tcci.operation, 1); + tcci.operation.local = 1; tcci.timeout_secs = 10; tcci.op_class = 1; - tcci.parameter.buf = param; - tcci.parameter.size = param_len; + if (param_len > sizeof(tcci.parameter.data)) + return -EINVAL; + memcpy(&tcci.parameter.data, param, param_len); + tcci.parameter.data_len = param_len; return tcap_user_req_comp(TCAP_PR_TC_INVOKE, &tcci); } diff --git a/src/tcap_user.h b/src/tcap_user.h index df529bd..86d8237 100644 --- a/src/tcap_user.h +++ b/src/tcap_user.h @@ -95,12 +95,22 @@ struct tcap_dialg_ind { /* metadata associated with a component indication primitive */ struct tcap_component_ind { + /* Dummy list head structure for the user. libosmo-tcap doesn't use it */ + struct llist_head list; /* public */ uint32_t dialg_id; /* Dialogue ID */ int8_t invoke_id; /* Invoke ID */ int8_t *linked_id; /* Linked ID */ - struct OPERATION operation; /* Operation Code */ - Parameter_t parameter; /* ANY_t */ + struct { + int is_global:1; /* is it global (1) or local (0) */ + union { + /* Global Operation (OID) */ + struct tcap_obj_ident global; + /* Local Operation */ + long local; + }; + } operation; + struct tcap_user_info parameter; int last_component; /* is this the last component in the msg? */ uint32_t timeout_secs; /* Timeout in seconds */ uint32_t error; diff --git a/src/tcu.c b/src/tcu.c index 3871ea4..c4d8d74 100644 --- a/src/tcu.c +++ b/src/tcu.c @@ -1,4 +1,4 @@ -/* TC-User */ +/* TC-User API / Interface between TCAP protocol manager and User Application */ /* (C) 2010 by Harald Welte * (C) 2010 by On-Waves @@ -27,18 +27,12 @@ #include #include +#include #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; -} +void *tcap_ind_ctx; static const struct value_string tcap_prim_names[] = { /* dialogue handling */ @@ -67,9 +61,16 @@ LIB_EXPORTED const char *tcap_prim_name(enum tcap_primitive prim) } /***********************************************************************/ -/* Component Primitives */ +/* Dialogue Primitives */ /***********************************************************************/ +static struct tcap_dialg_ind *tcap_dialg_ind_alloc(void) +{ + struct tcap_dialg_ind *tcdi = talloc_zero(tcap_ind_ctx, + struct tcap_dialg_ind); + return tcdi; +} + /* 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, @@ -226,22 +227,58 @@ LIB_EXPORTED int tcap_user_req_dialg(enum tcap_primitive prim, struct tcap_dialg /* Component Primitives */ /***********************************************************************/ +static struct tcap_component_ind *tcap_comp_ind_alloc(void) +{ + struct tcap_component_ind *tcci = talloc_zero(tcap_ind_ctx, + struct tcap_component_ind); + return tcci; +} + static int _tcu_comp_ind(enum tcap_primitive prim, struct tcap_invocation *ti, struct OPERATION *oper, Parameter_t *param, int last) { - struct tcap_component_ind tcci; + struct tcap_component_ind *tcci = tcap_comp_ind_alloc(); + int rc; - memset(&tcci, 0, sizeof(tcci)); - tcci.dialg_id = ti->dialogue->dialogue_id; - tcci.invoke_id = ti->invoke_id; + tcci->dialg_id = ti->dialogue->dialogue_id; + tcci->invoke_id = ti->invoke_id; if (ti->linked_id) { - tcci._linked_id = ti->_linked_id; - tcci.linked_id = &tcci._linked_id; + tcci->_linked_id = ti->_linked_id; + tcci->linked_id = &tcci->_linked_id; } - memcpy(&tcci.operation, oper, sizeof(tcci.operation)); - tcci.last_component = last; + if (oper && oper->present != OPERATION_PR_NOTHING) { + switch (oper->present) { + case OPERATION_PR_localValue: + rc = asn_INTEGER2long(&oper->choice.localValue, &tcci->operation.local); + if (rc < 0) + goto out_free; + break; + case OPERATION_PR_globalValue: + rc = OBJECT_IDENTIFIER_get_arcs(&oper->choice.globalValue, + &tcci->operation.global.arc, + sizeof(tcci->operation.global.arc[0]), + ARRAY_SIZE(tcci->operation.global.arc)); + if (rc < 0) + goto out_free; + tcci->operation.global.num_arcs = rc; + break; + default: + break; + } + } + if (param) { + if (param->size > sizeof(tcci->parameter.data)) + goto out_free; + memcpy(tcci->parameter.data, param->buf, param->size); + tcci->parameter.data_len = param->size; + } + tcci->last_component = last; - return tcap_user_ind_comp(prim, &tcci); + return tcap_user_ind_comp(prim, tcci); + +out_free: + talloc_free(tcci); + return rc; } /* Table 10 / Q.771 : TC-INVOKE.ind */ @@ -274,9 +311,32 @@ int tcap_tcu_result_nl_ind(struct tcap_invocation *ti, struct OPERATION *oper, P return _tcu_comp_ind(TCAP_PR_TC_RESULT_NL, ti, oper, param, last); } +static OPERATION_t *generate_op(struct tcap_dialogue *td, struct tcap_component_ind *tcci) +{ + OPERATION_t *op; + + op = talloc_zero(td, OPERATION_t); + if (!op) + return NULL; + + if (tcci->operation.is_global) { + op->present = OPERATION_PR_globalValue; + OBJECT_IDENTIFIER_set_arcs(&op->choice.globalValue, + tcci->operation.global.arc, + sizeof(tcci->operation.global.arc[0]), + tcci->operation.global.num_arcs); + } else { + op->present = OPERATION_PR_localValue; + asn_long2INTEGER(&op->choice.localValue, tcci->operation.local); + } + + return op; +} + LIB_EXPORTED int tcap_user_req_comp(enum tcap_primitive prim, struct tcap_component_ind *tcci) { struct tcap_dialogue *td; + OPERATION_t *op = NULL; int rc = 0; fprintf(stdout, "<- USER_REQ_COMP(%s)\n", tcap_prim_name(prim)); @@ -297,23 +357,31 @@ LIB_EXPORTED int tcap_user_req_comp(enum tcap_primitive prim, struct tcap_compon /* Actually dispatch the primitive */ switch (prim) { case TCAP_PR_TC_INVOKE: - rc = tcap_cha_tc_invoke_req(td, tcci->op_class, tcci->invoke_id, tcci->linked_id, &tcci->operation, - tcci->parameter.buf, tcci->parameter.size, tcci->timeout_secs); + op = generate_op(td, tcci); + rc = tcap_cha_tc_invoke_req(td, tcci->op_class, tcci->invoke_id, + tcci->linked_id, op, tcci->parameter.data, + tcci->parameter.data_len, tcci->timeout_secs); break; case TCAP_PR_TC_RESULT_L: - rc = tcap_cha_tc_result_req(td, tcci->invoke_id, 1, &tcci->operation, &tcci->parameter.buf, - tcci->parameter.buf); + op = generate_op(td, tcci); + rc = tcap_cha_tc_result_req(td, tcci->invoke_id, 1, op, + &tcci->parameter.data, tcci->parameter.data_len); break; case TCAP_PR_TC_RESULT_NL: - rc = tcap_cha_tc_result_req(td, tcci->invoke_id, 0, &tcci->operation, tcci->parameter.buf, - tcci->parameter.buf); + op = generate_op(td, tcci); + rc = tcap_cha_tc_result_req(td, tcci->invoke_id, 0, op, + tcci->parameter.data, tcci->parameter.data_len); break; + case TCAP_PR_TC_U_ERROR: + case TCAP_PR_TC_U_REJECT: + case TCAP_PR_TC_CANCEL: + case TCAP_PR_TC_TIMER_RESET: default: fprintf(stderr, "unsupported dialogue primitive %s\n", tcap_prim_name(prim)); return -EINVAL; } + talloc_free(op); + return rc; } - -