summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-07-22 22:22:17 +0200
committerHarald Welte <laforge@gnumonks.org>2010-07-22 22:22:17 +0200
commit537e110011473aaf4234910f787fa2e0235e4aba (patch)
tree456c947fff8c2c7edfca760570d4b25c42671c94
parentd6f49749dc82b23415adace2dd5d2d3c77020049 (diff)
Introduce new (unfinished) application support layer
This will be what applicaitons like the MSC or SGSN actually use to invoke MAP operations.
-rw-r--r--src/app_support.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/app_support.c b/src/app_support.c
new file mode 100644
index 0000000..bf2cab8
--- /dev/null
+++ b/src/app_support.c
@@ -0,0 +1,286 @@
+/* TCAP/MAP application support code */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by On-Waves
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <libosmocore/linuxlist.h>
+#include <libosmocore/msgb.h>
+
+#include "tcap_user.h"
+
+static LLIST_HEAD(map_app_list);
+
+/* One suppoerted application context */
+struct map_supp_app_ctx {
+ struct tcap_obj_ident obj_id;
+};
+
+struct map_op_type_info {
+ /* The localValue of the Operation */
+ uint32_t local_op_code;
+ /* ASN type descriptor for the user_data argument of INVOKE */
+ asn_TYPE_descriptor_t *inv_type;
+ /* ASN type descriptor for the user_data argument of RESULT */
+ asn_TYPE_descriptor_t *res_type;
+};
+
+/* Structure that an application can register */
+struct map_app_reg_info {
+ struct llist_head list;
+
+ struct map_supp_ap_ctx *supp_app_ctx;
+ unsigned int num_supp_app_ctx;
+
+ struct map_op_type_info *op_type_info;
+ unsigned int num_op_type_info;
+
+ /* queue for incoming (received) primitives from the network */
+ struct llist_head prim_upqueue;
+
+ /* callbcak for COMPONENT related primitives (indication) */
+ //int (*comp_ind_cb)(
+};
+
+/* local opCode, pointer to parsed asn1C structure, tcap indication, private ptr */
+typedef void map_cbfn(long opcode, void *parsed, struct tcap_component_ind *tcci, void *priv);
+
+struct map_op_callback {
+ void *priv;
+ /* call-back function to be called once the operation completes/fails/time-outs*/
+ map_cbfn *cb;
+};
+
+int map_call(long opcode, void *parsed, void *priv, map_cbfn *cb);
+
+/* FIXME: auto-generate this from the ASN.1 specs */
+extern const struct map_op_type_info map_std_op_info[] = {
+ { 2, &asn_DEF_UpdateGprsLocationArg, &asn_DEF_UpdateGprsLocationRes },
+ { 3, &asn_DEF_CancelLocationArg, &asn_DEF_CancelLocationRes },
+ { 23, &asn_DEF_UpdateGprsLocationArg, &asn_DEF_UpdateGprsLocationRes },
+ { 7, &asn_DEF_InsertSubscriberDataArg, &asn_DEF_InsertSubscriberDataRes },
+ { 8, &asn_DEF_DeleteSubscriberDataArg, &asn_DEF_DeleteSubscriberDataRes },
+ { 56, &asn_DEF_SendAuthenticationInfoArg, &asn_DEF_SendAuthenticationInfoRes },
+ /* FIXME: complete this! */
+};
+
+static const struct map_op_type_info *
+get_op_type_info(struct map_app_reg_info *app, uint32_t local_op)
+{
+ unsigned int i;
+ struct map_op_type_info *optinf;
+
+ for (i = 0; i < app->num_op_type_info; i++) {
+ optinf = &app->op_type_info[i];
+ if (optinf->local_op_code == local_op)
+ return optinf;
+ }
+
+ return NULL;
+}
+
+int map_app_register(struct map_app_reg_info *mi)
+{
+ llist_add(&mi->list, &map_app_list);
+}
+
+/* The User Application is initiating a new MAP operation */
+int map_op_invoke(long opcode, void *parsed, struct map_op_callback *cb,
+ uint32_t timeout_sec, uint32_t dialogue_id, uint8_t *linked_id)
+{
+ struct map_op_type_info *optinf;
+ struct tcap_prim_buf *tcpb = &_tcpb;
+ struct tcap_component_ind *tcci = &tcpb->comp;
+
+ memset(&_tcpb, 0, sizeof(_tcpb));
+
+ optinf = get_op_type_info(app, opcode);
+ if (!optinf)
+ return -EINVAL;
+
+ tcpb->prim = TCAP_PR_TC_INVOKE;
+ tcpb->user_ref = (unsigned long) cb;
+ tcci->op_class = 1; /* do we need other types in MAP? */
+ tcci->dialg_id = dialogue_id;
+ /* we currently only do one invocation per dialogue */
+ tcci->invoke_id = 1;
+ if (linked_id) {
+ tcci->_linked_id = *linked_id;
+ tcci->linked_id = &tcci->_linked_id;
+ }
+ tcci->operation.local = opcode;
+
+ if (parsed) {
+ asn_enc_rval_t er;
+ er = der_encode_to_buffer(optinf->inv_type, parsed,
+ tcci->parameter.data,
+ tcci->parameter.data_len);
+ if (er.encoded < 0)
+ return -EINVAL;
+ }
+
+ return tcap_user_req(tcpb);
+}
+
+/* process an incoming TCAP component indication from the TCAP stack */
+static int process_tcap_comp_ind(struct tcap_prim_buf *tcpb)
+{
+ /* component primitives */
+ struct tcap_component_ind *tcci = &tcpb->comp;
+ struct map_op_type_info *optinf;
+ void *parsed = NULL;
+ asn_dec_rval_t rv;
+ int rc = 0;
+
+ /* We only support local operation codes for now! */
+ if (tcci->operation.is_global)
+ goto out_reject;
+
+ /* find out which ASN.1 types to expect in the component parameter */
+ optinf = get_op_type_info(app, tcci->operation.local);
+ if (!optinf)
+ goto out_reject;
+
+ switch (tcpb->prim) {
+ case TC_PR_TC_INVOKE:
+ /* parse user information */
+ rv = ber_decode(NULL, optinf->inv_type, &parsed,
+ tcci->parameter.data,
+ tcci->parameter.data_len);
+ if (rv.code != RC_OK) {
+ rc = -EIO;
+ goto out_reject;
+ }
+ rc = send_map_primitive(MAP_PR_COMPONENT, tcpb);
+ break;
+ case TC_RR_TC_RESULT_L:
+ case TC_RR_TC_RESULT_NL:
+ /* parse user information */
+ rv = ber_decode(NULL, optinf->res_type, &parsed,
+ tcci->parameter.data,
+ tcci->parameter.data_len);
+ if (rv.code != RC_OK) {
+ rc = -EIO;
+ goto out_reject;
+ }
+ /* Resolve and call the invocation specific completion
+ * callback */
+ if (!tcci->user_ref) {
+ rc = -EIO;
+ goto out_reject;
+ }
+ cb = (struct map_op_callback *) tcci->user_ref;
+ if (!cb->cbfn) {
+ rc = -EIO;
+ goto out_reject;
+ }
+ cb->cbfn(FIXME, parsed, tcpb, priv);
+ break;
+ case TCAP_PR_TC_U_ERROR:
+ case TCAP_PR_TC_U_REJECT:
+ case TCAP_PR_TC_L_REJECT:
+ case TCAP_PR_TC_R_REJECT:
+ case TCAP_PR_TC_P_ABORT:
+ /* FIXME */
+ default:
+ fprintf(stderr, "Unsupported/Unknown TCAP Component Primitive %s\n",
+ tcap_prim_name(tcpb->prim));
+ }
+
+ /* Free the parsed information */
+ talloc_free(parsed);
+
+ /* check if this was the last component and generate
+ * MAP-DELIMITER.ind */
+ if (tcpb->comp.last_component)
+ rc = send_map_primitive(MAP_PR_DELIMITER_IND, );
+
+ return rc;
+
+out_reject:
+ /* Free the parsed information */
+ talloc_free(parsed);
+
+ /* FIXME */
+
+ return rc;
+}
+
+
+/* Process an incoming Dialogue indication from TCAP stack */
+static int process_tcap_dialg_ind(struct tcap_prim_buf *tcpb)
+{
+ struct tcap_dialogue_ind *tcdi = &tcpb->dialg;
+ int rc;
+
+ switch (tcpb->prim) {
+ case TCAP_PR_TC_BEGIN:
+ /* FIXME: parse asn_DEF_MAP_OpenInfo */
+ rc = send_map_primitive(MAP_PR_OPEN_IND, );
+ break;
+ case TCAP_PR_TC_CONTINUE:
+ if (tcdi->app_ctx_present) {
+ /* FIXME: parse asn_DEF_MAP_OpenInfo */
+ send_map_primitive(MAP_PR_OPEN_RESP, );
+ }
+ break;
+ case TCAP_PR_TC_END:
+ send_map_primitive(MAP_PR_CLOSE_IND, );
+ break;
+ case TCAP_PR_TC_U_ABORT:
+ case TCAP_PR_TC_NOTICE:
+ default:
+ fprintf(stderr, "Unsupported/Unknown TCAP Dialogue Primitive %s\n",
+ tcap_prim_name(tcpb->prim));
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+/* Process an incoming TCAP primitive from TCAP stack */
+static int process_tcap_ind(struct tcap_prim_buf *tcpb)
+{
+ int rc;
+ struct map_op_callback *cb;
+
+ /* Hand it off to the respective sub-function
+ * for dialogue or component indications */
+ if (tcpb->prim > _TCAP_PR_COMP_BASE)
+ rc = process_tcap_comp_ind(tcpb);
+ else
+ rc = process_tcap_dialg_ind(tcpb);
+
+ /* Free the TCAP primitive */
+ talloc_free(tcpb);
+
+ return rc;
+}
+
+/* callback for incoming primitives form TCAP */
+int tcap_user_ind_cb(struct tcap_prim_buf *tcpb)
+{
+ /* FIXME: Later we may want to simply enqueue the tcpb
+ * and have multiple threads pull from that queue */
+
+ return process_tcap_ind(tcpb);
+}