Don't use stack-based libasn1c objects for component primitives
In order for the recursive free-ing of libasn1c data structures to work, we cannot have some of them stack-allocated.
This commit is contained in:
parent
a7c47009c9
commit
57058f3600
|
@ -71,6 +71,11 @@ static Parameter_t *gen_param(const void *ctx, uint8_t *param, uint32_t param_le
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TC-INVOKE.req (TCU -> CHA) */
|
/* 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,
|
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,
|
int8_t *linked_id, struct OPERATION *op,
|
||||||
uint8_t *param, uint32_t param_len, uint32_t timeout)
|
uint8_t *param, uint32_t param_len, uint32_t timeout)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
@ -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);
|
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 */
|
/* UpdateGprsLocationArg */
|
||||||
static struct tcap_obj_ident gprsLocationUpdateContext_v3 = {
|
static struct tcap_obj_ident gprsLocationUpdateContext_v3 = {
|
||||||
.arc = { 0, 4, 0, 0, 1, 0, 32, 3 },
|
.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.dialg_id = dialg_id;
|
||||||
tcci.invoke_id = invoke_id;
|
tcci.invoke_id = invoke_id;
|
||||||
tcci.linked_id = NULL;
|
tcci.linked_id = NULL;
|
||||||
tcap_gen_oper_local(&tcci.operation, 1);
|
tcci.operation.local = 1;
|
||||||
tcci.timeout_secs = 10;
|
tcci.timeout_secs = 10;
|
||||||
tcci.op_class = 1;
|
tcci.op_class = 1;
|
||||||
|
|
||||||
tcci.parameter.buf = param;
|
if (param_len > sizeof(tcci.parameter.data))
|
||||||
tcci.parameter.size = param_len;
|
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);
|
return tcap_user_req_comp(TCAP_PR_TC_INVOKE, &tcci);
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,12 +95,22 @@ struct tcap_dialg_ind {
|
||||||
|
|
||||||
/* metadata associated with a component indication primitive */
|
/* metadata associated with a component indication primitive */
|
||||||
struct tcap_component_ind {
|
struct tcap_component_ind {
|
||||||
|
/* Dummy list head structure for the user. libosmo-tcap doesn't use it */
|
||||||
|
struct llist_head list;
|
||||||
/* public */
|
/* public */
|
||||||
uint32_t dialg_id; /* Dialogue ID */
|
uint32_t dialg_id; /* Dialogue ID */
|
||||||
int8_t invoke_id; /* Invoke ID */
|
int8_t invoke_id; /* Invoke ID */
|
||||||
int8_t *linked_id; /* Linked ID */
|
int8_t *linked_id; /* Linked ID */
|
||||||
struct OPERATION operation; /* Operation Code */
|
struct {
|
||||||
Parameter_t parameter; /* ANY_t */
|
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? */
|
int last_component; /* is this the last component in the msg? */
|
||||||
uint32_t timeout_secs; /* Timeout in seconds */
|
uint32_t timeout_secs; /* Timeout in seconds */
|
||||||
uint32_t error;
|
uint32_t error;
|
||||||
|
|
122
src/tcu.c
122
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 <laforge@gnumonks.org>
|
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
||||||
* (C) 2010 by On-Waves
|
* (C) 2010 by On-Waves
|
||||||
|
@ -27,18 +27,12 @@
|
||||||
#include <osmocore/talloc.h>
|
#include <osmocore/talloc.h>
|
||||||
|
|
||||||
#include <osmocom/tcap/Parameter.h>
|
#include <osmocom/tcap/Parameter.h>
|
||||||
|
#include <osmocom/tcap/OPERATION.h>
|
||||||
|
|
||||||
#include "tcap.h"
|
#include "tcap.h"
|
||||||
#include "tcap_user.h"
|
#include "tcap_user.h"
|
||||||
|
|
||||||
void *tcap_dialg_ind_ctx;
|
void *tcap_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[] = {
|
static const struct value_string tcap_prim_names[] = {
|
||||||
/* dialogue handling */
|
/* 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' */
|
/* fill the application context and user information part of 'tcap_dialg_ind' */
|
||||||
static int fill_tcap_dialg_ind(struct tcap_dialg_ind *tcdi,
|
static int fill_tcap_dialg_ind(struct tcap_dialg_ind *tcdi,
|
||||||
OBJECT_IDENTIFIER_t *app_ctx_name,
|
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 */
|
/* 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,
|
static int _tcu_comp_ind(enum tcap_primitive prim, struct tcap_invocation *ti, struct OPERATION *oper,
|
||||||
Parameter_t *param, int last)
|
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.dialg_id = ti->dialogue->dialogue_id;
|
tcci->invoke_id = ti->invoke_id;
|
||||||
tcci.invoke_id = ti->invoke_id;
|
|
||||||
if (ti->linked_id) {
|
if (ti->linked_id) {
|
||||||
tcci._linked_id = ti->_linked_id;
|
tcci->_linked_id = ti->_linked_id;
|
||||||
tcci.linked_id = &tcci._linked_id;
|
tcci->linked_id = &tcci->_linked_id;
|
||||||
}
|
}
|
||||||
memcpy(&tcci.operation, oper, sizeof(tcci.operation));
|
if (oper && oper->present != OPERATION_PR_NOTHING) {
|
||||||
tcci.last_component = last;
|
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 */
|
/* 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);
|
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)
|
LIB_EXPORTED int tcap_user_req_comp(enum tcap_primitive prim, struct tcap_component_ind *tcci)
|
||||||
{
|
{
|
||||||
struct tcap_dialogue *td;
|
struct tcap_dialogue *td;
|
||||||
|
OPERATION_t *op = NULL;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
fprintf(stdout, "<- USER_REQ_COMP(%s)\n", tcap_prim_name(prim));
|
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 */
|
/* Actually dispatch the primitive */
|
||||||
switch (prim) {
|
switch (prim) {
|
||||||
case TCAP_PR_TC_INVOKE:
|
case TCAP_PR_TC_INVOKE:
|
||||||
rc = tcap_cha_tc_invoke_req(td, tcci->op_class, tcci->invoke_id, tcci->linked_id, &tcci->operation,
|
op = generate_op(td, tcci);
|
||||||
tcci->parameter.buf, tcci->parameter.size, tcci->timeout_secs);
|
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;
|
break;
|
||||||
case TCAP_PR_TC_RESULT_L:
|
case TCAP_PR_TC_RESULT_L:
|
||||||
rc = tcap_cha_tc_result_req(td, tcci->invoke_id, 1, &tcci->operation, &tcci->parameter.buf,
|
op = generate_op(td, tcci);
|
||||||
tcci->parameter.buf);
|
rc = tcap_cha_tc_result_req(td, tcci->invoke_id, 1, op,
|
||||||
|
&tcci->parameter.data, tcci->parameter.data_len);
|
||||||
break;
|
break;
|
||||||
case TCAP_PR_TC_RESULT_NL:
|
case TCAP_PR_TC_RESULT_NL:
|
||||||
rc = tcap_cha_tc_result_req(td, tcci->invoke_id, 0, &tcci->operation, tcci->parameter.buf,
|
op = generate_op(td, tcci);
|
||||||
tcci->parameter.buf);
|
rc = tcap_cha_tc_result_req(td, tcci->invoke_id, 0, op,
|
||||||
|
tcci->parameter.data, tcci->parameter.data_len);
|
||||||
break;
|
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:
|
default:
|
||||||
fprintf(stderr, "unsupported dialogue primitive %s\n", tcap_prim_name(prim));
|
fprintf(stderr, "unsupported dialogue primitive %s\n", tcap_prim_name(prim));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
talloc_free(op);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue