summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-07-19 18:33:53 +0200
committerHarald Welte <laforge@gnumonks.org>2010-07-19 18:33:53 +0200
commit57058f3600a98189d3855d5f594e073ade362a72 (patch)
treed528e652b0a5c7246dd967a172598c66312d9828
parenta7c47009c9d79c842b1e752f1f0672d78621d64b (diff)
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.
-rw-r--r--src/csl_cha_cco.c5
-rw-r--r--src/tcap_test.c15
-rw-r--r--src/tcap_user.h14
-rw-r--r--src/tcu.c122
4 files changed, 118 insertions, 38 deletions
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 <stdio.h>
#include <stdlib.h>
#include <signal.h>
+#include <errno.h>
#include <netinet/in.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);
}
-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 <laforge@gnumonks.org>
* (C) 2010 by On-Waves
@@ -27,18 +27,12 @@
#include <osmocore/talloc.h>
#include <osmocom/tcap/Parameter.h>
+#include <osmocom/tcap/OPERATION.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;
-}
+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;
}
-
-