690 lines
19 KiB
C
690 lines
19 KiB
C
/* ITU-T Q.77x TCAP / CSL - Component Sub-Layer */
|
|
|
|
/* (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 <errno.h>
|
|
#include <netinet/in.h>
|
|
|
|
#include <osmocore/talloc.h>
|
|
#include <osmocore/msgb.h>
|
|
|
|
#include <asn1c/OBJECT_IDENTIFIER.h>
|
|
|
|
#include <osmocom/tcap/TCMessage.h>
|
|
#include <osmocom/tcap/ExternalPDU.h>
|
|
#include <osmocom/tcap/DialoguePDU.h>
|
|
#include <osmocom/tcap/UniDialoguePDU.h>
|
|
#include <osmocom/tcap/DialoguePortion.h>
|
|
|
|
#include "tcap.h"
|
|
|
|
static uint8_t _dial_version1 = 0x80;
|
|
|
|
static BIT_STRING_t dial_version1 = {
|
|
.buf = &_dial_version1,
|
|
.size = 1,
|
|
.bits_unused = 7,
|
|
};
|
|
|
|
/* Extract the Application Context Name and User Info from a DialoguePDU */
|
|
static int extract_appctx_uinfo(OBJECT_IDENTIFIER_t **app_ctx_name, struct user_information **user_info,
|
|
struct DialoguePDU *dial_pdu)
|
|
{
|
|
switch (dial_pdu->present) {
|
|
case DialoguePDU_PR_dialogueRequest:
|
|
*app_ctx_name = &dial_pdu->choice.dialogueRequest.application_context_name;
|
|
*user_info = dial_pdu->choice.dialogueRequest.user_information;
|
|
break;
|
|
case DialoguePDU_PR_dialogueResponse:
|
|
*app_ctx_name = &dial_pdu->choice.dialogueResponse.application_context_name;
|
|
*user_info = dial_pdu->choice.dialogueResponse.user_information;
|
|
break;
|
|
case DialoguePDU_PR_dialogueAbort:
|
|
*app_ctx_name = NULL;
|
|
*user_info = dial_pdu->choice.dialogueAbort.user_information;
|
|
break;
|
|
default:
|
|
*app_ctx_name = NULL;
|
|
*user_info = NULL;
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* TC-UNI.req from TCU */
|
|
int tcap_csl_tc_uni_req(struct tcap_dialogue *td, OBJECT_IDENTIFIER_t *app_ctx, struct user_information *user_info)
|
|
{
|
|
struct TCMessage *tcm;
|
|
ExternalPDU_t *ext;
|
|
UniDialoguePDU_t *dial;
|
|
ANY_t *any;
|
|
ComponentPortion_t *pend_comp;
|
|
int rc;
|
|
|
|
tcm = talloc_zero(td, struct TCMessage);
|
|
tcm->present = TCMessage_PR_unidirectional;
|
|
|
|
if (app_ctx) {
|
|
AUDT_apdu_t *audt;
|
|
/* build AUDT apdu */
|
|
|
|
any = talloc_zero(tcm, ANY_t);
|
|
ext = talloc_zero(any, ExternalPDU_t);
|
|
dial = talloc_zero(td, UniDialoguePDU_t);
|
|
dial->present = UniDialoguePDU_PR_unidialoguePDU;
|
|
audt = &dial->choice.unidialoguePDU;
|
|
if (user_info)
|
|
audt->user_information = user_info;
|
|
memcpy(&audt->application_context_name, app_ctx, sizeof(audt->application_context_name));
|
|
audt->protocol_version = &dial_version1;
|
|
|
|
fprintf(stdout, "\nTC-UNI.req Dialogue portion:\n");
|
|
xer_fprint(stdout, &asn_DEF_UniDialoguePDU, dial);
|
|
|
|
ANY_fromType((ANY_t *) &ext->dialog, &asn_DEF_UniDialoguePDU, dial);
|
|
|
|
ANY_fromType(any, &asn_DEF_ExternalPDU, ext);
|
|
tcm->choice.unidirectional.dialoguePortion = (OCTET_STRING_t *) any;
|
|
}
|
|
/* Request components to CHA */
|
|
pend_comp = tcap_cha_req_components(td);
|
|
/* Process components */
|
|
memcpy(&tcm->choice.unidirectional.components, pend_comp, sizeof(*pend_comp));
|
|
talloc_free(pend_comp);
|
|
/* Assemble TSL user data */
|
|
|
|
/* TR-UNI-REQ to TSL */
|
|
rc = tcap_tco_tr_uni_req(&td->trans, tcm);
|
|
/* Dialogue terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
/* Free Dialogue ID */
|
|
tcap_dialg_free(td);
|
|
|
|
asn_DEF_TCMessage.free_struct(&asn_DEF_TCMessage, tcm, 0);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* TC-BEGIN.req from TCU */
|
|
int tcap_csl_tc_begin_req(struct tcap_dialogue *td, OBJECT_IDENTIFIER_t *app_ctx, struct user_information *user_info)
|
|
{
|
|
struct TCMessage *tcm;
|
|
ExternalPDU_t *ext;
|
|
DialoguePDU_t *dial;
|
|
struct tcap_invocation *ti;
|
|
uint32_t trans_id;
|
|
int rc;
|
|
|
|
tcm = talloc_zero(td, struct TCMessage);
|
|
tcm->present = TCMessage_PR_begin;
|
|
|
|
if (app_ctx) {
|
|
AARQ_apdu_t *aarq;
|
|
ANY_t *any;
|
|
/* Build AARQ apdu */
|
|
|
|
any = talloc_zero(tcm, ANY_t);
|
|
ext = talloc_zero(any, ExternalPDU_t);
|
|
dial = talloc_zero(ext, DialoguePDU_t);
|
|
dial->present = DialoguePDU_PR_dialogueRequest;
|
|
|
|
aarq = &dial->choice.dialogueRequest;
|
|
if (user_info)
|
|
aarq->user_information = user_info;
|
|
/* Set Application context mode */
|
|
td->app_ctx_mode = 1;
|
|
memcpy(&aarq->application_context_name, app_ctx, sizeof(aarq->application_context_name));
|
|
/* Set protocol_version = 1 */
|
|
aarq->protocol_version = &dial_version1;
|
|
|
|
fprintf(stdout, "\nTC-BEGIN.req Dialogue portion:\n");
|
|
xer_fprint(stdout, &asn_DEF_DialoguePDU, dial);
|
|
|
|
ANY_fromType((ANY_t *) &ext->dialog, &asn_DEF_DialoguePDU, dial);
|
|
|
|
ANY_fromType(any, &asn_DEF_ExternalPDU, ext);
|
|
tcm->choice.begin.dialoguePortion = (OCTET_STRING_t *) any;
|
|
}
|
|
/* Request components to CHA */
|
|
/* Process components */
|
|
/* Assemble TSL user data */
|
|
tcm->choice.begin.components = tcap_cha_req_components(td);
|
|
|
|
/* Assign local transaction ID */
|
|
trans_id = htonl(td->trans.tid_local);
|
|
OCTET_STRING_fromBuf(&tcm->choice.begin.otid,
|
|
(const char *) &trans_id, sizeof(trans_id));
|
|
|
|
/* TR-BEGIN-REQ to TSL */
|
|
rc = tcap_tco_tr_begin_req(&td->trans, tcm);
|
|
|
|
tcap_trans_set_state(&td->trans, TCAP_TS_INIT_SENT);
|
|
|
|
asn_DEF_TCMessage.free_struct(&asn_DEF_TCMessage, tcm, 0);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* Exteract and BER-decode the DialoguePDU contained in the ExternalPDU */
|
|
static struct DialoguePDU *unwrap_ext_dialg_pdu(DialoguePortion_t *dialg_por)
|
|
{
|
|
struct DialoguePDU *dial_pdu = NULL;
|
|
struct ExternalPDU *ext_pdu = NULL;
|
|
asn_dec_rval_t adr;
|
|
|
|
/* extract dialogue portion */
|
|
adr = ber_decode(NULL, &asn_DEF_ExternalPDU, (void **) &ext_pdu, dialg_por->buf,
|
|
dialg_por->size);
|
|
if (adr.code != RC_OK) {
|
|
fprintf(stderr, "Error parsing ExternalPDU in Dialogue Portion\n");
|
|
return NULL;
|
|
}
|
|
adr = ber_decode(NULL, &asn_DEF_DialoguePDU, (void **) &dial_pdu,
|
|
ext_pdu->dialog.buf, ext_pdu->dialog.size);
|
|
if (adr.code != RC_OK) {
|
|
fprintf(stderr, "Error parsing DialoguePDU in ExternalPDU\n");
|
|
return NULL;
|
|
}
|
|
/* Release the External part */
|
|
asn_DEF_ExternalPDU.free_struct(&asn_DEF_ExternalPDU, ext_pdu, 0);
|
|
|
|
return dial_pdu;
|
|
}
|
|
|
|
/* TR-UNI.ind from TSL */
|
|
int tcap_csl_tr_uni_ind(struct tcap_transaction *tt, struct TCMessage *tcmsg, struct msgb *msg)
|
|
{
|
|
struct tcap_dialogue *td = dialg_by_trans(tt);
|
|
struct Unidirectional *unimsg = &tcmsg->choice.unidirectional;
|
|
struct DialoguePDU *dial_pdu = NULL;
|
|
OBJECT_IDENTIFIER_t *app_ctx_name = NULL;
|
|
struct user_information *user_info = NULL;
|
|
int rc = 0;
|
|
|
|
if (unimsg->dialoguePortion) {
|
|
/* extract dialogue portion */
|
|
dial_pdu = unwrap_ext_dialg_pdu(unimsg->dialoguePortion);
|
|
/* Check for correctness */
|
|
if (!dial_pdu) {
|
|
/* FIXME */
|
|
}
|
|
/* Check version 1 */
|
|
extract_appctx_uinfo(&app_ctx_name, &user_info, dial_pdu);
|
|
}
|
|
/* Assign Dialogue ID */
|
|
td->dialogue_id = tcap_dialg_id_alloc();
|
|
/* TC-UNI.ind to TCU */
|
|
rc = tcap_tcu_uni_ind(td, app_ctx_name, user_info, 1);
|
|
/* Components to CHA */
|
|
rc = tcap_cha_proc_components(td, &unimsg->components);
|
|
/* Dialogue Terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
/* Free Dialogue ID */
|
|
tcap_dialg_free(td);
|
|
|
|
if (unimsg->dialoguePortion && dial_pdu) {
|
|
/* Release resources of the ber_decode */
|
|
asn_DEF_DialoguePDU.free_struct(&asn_DEF_DialoguePDU, dial_pdu, 0);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* TR-BEGIN.ind from TSL(TSM) -> CSL(DHA) */
|
|
int tcap_csl_tr_begin_ind(struct tcap_transaction *tt, struct TCMessage *tcmsg, struct msgb *msg)
|
|
{
|
|
struct tcap_dialogue *td = dialg_by_trans(tt);
|
|
struct Begin *bgmsg = &tcmsg->choice.begin;
|
|
struct DialoguePDU *dial_pdu = NULL;
|
|
OBJECT_IDENTIFIER_t *app_ctx_name = NULL;
|
|
struct user_information *user_info = NULL;
|
|
int rc = 0;
|
|
|
|
if (bgmsg->dialoguePortion) {
|
|
struct AARQ_apdu *aarq;
|
|
/* extract dialogue portion */
|
|
dial_pdu = unwrap_ext_dialg_pdu(bgmsg->dialoguePortion);
|
|
if (!dial_pdu) {
|
|
fprintf(stderr, "TC-BEGIN.ind Error parsing Dialogue portion\n");
|
|
/* Build ABORT apdu */
|
|
/* Discard components */
|
|
/* TR-U-ABPRT.req to TSL */
|
|
rc = tcap_tco_tr_u_abort_req(tt, tcmsg);
|
|
/* Dalogue terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
|
|
return rc;
|
|
}
|
|
|
|
fprintf(stdout, "\nTC-BEGIN.ind Dialogue portion:\n");
|
|
xer_fprint(stdout, &asn_DEF_DialoguePDU, dial_pdu);
|
|
|
|
aarq = &dial_pdu->choice.dialogueRequest;
|
|
if (aarq->protocol_version && 0/* Check version 1 */) {
|
|
/* Build AARE apdu */
|
|
/* Discard components */
|
|
/* TR-P-ABPRT.req to TSL */
|
|
/* Dalogue terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
}
|
|
/* Set application context mode */
|
|
td->app_ctx_mode = 1;
|
|
extract_appctx_uinfo(&app_ctx_name, &user_info, dial_pdu);
|
|
}
|
|
/* Assign Dialogue ID */
|
|
td->dialogue_id = tcap_dialg_id_alloc();
|
|
|
|
tcap_trans_set_state(tt, TCAP_TS_INIT_RECV);
|
|
|
|
/* TC-BEGIN.ind to TCU */
|
|
rc = tcap_tcu_begin_ind(td, app_ctx_name, user_info, bgmsg->components ? 1 : 0);
|
|
if (bgmsg->components) {
|
|
/* Components to CHA */
|
|
rc = tcap_cha_proc_components(td, bgmsg->components);
|
|
}
|
|
|
|
if (bgmsg->dialoguePortion && dial_pdu) {
|
|
/* Release resources of the ber_decode */
|
|
asn_DEF_DialoguePDU.free_struct(&asn_DEF_DialoguePDU, dial_pdu, 0);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static ANY_t *gen_ext_AARE(struct tcap_dialogue *td, OBJECT_IDENTIFIER_t *app_ctx,
|
|
struct user_information *user_info)
|
|
{
|
|
ANY_t *any;
|
|
ExternalPDU_t *ext;
|
|
DialoguePDU_t *dial;
|
|
AARE_apdu_t *aare;
|
|
int rc;
|
|
|
|
any = talloc_zero(td, ANY_t);
|
|
ext = talloc_zero(any, ExternalPDU_t);
|
|
dial = talloc_zero(ext, DialoguePDU_t);
|
|
|
|
dial->present = DialoguePDU_PR_dialogueResponse;
|
|
aare = &dial->choice.dialogueResponse;
|
|
/* Set protocol version 1 */
|
|
aare->protocol_version = &dial_version1;
|
|
/* Build AARE-apdu (accepted) */
|
|
memcpy(&aare->application_context_name, app_ctx, sizeof(aare->application_context_name));
|
|
asn_long2INTEGER(&aare->result, Associate_result_accepted);
|
|
aare->user_information = user_info;
|
|
aare->result_source_diagnostic.present = Associate_source_diagnostic_PR_dialogue_service_user;
|
|
asn_long2INTEGER(&aare->result_source_diagnostic.choice.dialogue_service_user,
|
|
dialogue_service_user_no_reason_given);
|
|
/* Link Dialogue into External PDU */
|
|
printf("calling ANY_fromType(%p, %p, %p)\n", &ext->dialog, &asn_DEF_DialoguePDU, dial);
|
|
rc = ANY_fromType((ANY_t *) &ext->dialog, &asn_DEF_DialoguePDU, dial);
|
|
if (rc < 0) {
|
|
fprintf(stderr, "Error generating ExternalPDU from DialoguePDU\n");
|
|
return NULL;
|
|
}
|
|
/* Link External PDU into Dialogue Portion */
|
|
rc = ANY_fromType(any, &asn_DEF_ExternalPDU, ext);
|
|
if (rc < 0) {
|
|
fprintf(stderr, "Error generating ANY_t from ExternalPDU\n");
|
|
return NULL;
|
|
}
|
|
|
|
xer_fprint(stdout, &asn_DEF_DialoguePDU, dial);
|
|
|
|
return any;
|
|
}
|
|
|
|
/* TC-CONTINUE.req from TCU */
|
|
int tcap_csl_tc_cont_req(struct tcap_dialogue *td, OBJECT_IDENTIFIER_t *app_ctx, struct user_information *user_info)
|
|
{
|
|
struct TCMessage tcm;
|
|
ANY_t *any;
|
|
uint32_t trans_id;
|
|
int rc = 0;
|
|
|
|
memset(&tcm, 0, sizeof(tcm));
|
|
tcm.present = TCMessage_PR_continue;
|
|
|
|
switch (td->trans.state) {
|
|
case TCAP_TS_INIT_RECV:
|
|
if (app_ctx) {
|
|
fprintf(stdout, "\nTC-CONTINUE.req Dialogue portion:\n");
|
|
any = gen_ext_AARE(td, app_ctx, user_info);
|
|
tcm.choice.Continue.dialoguePortion = (OCTET_STRING_t *) any;
|
|
}
|
|
break;
|
|
case TCAP_TS_ACTIVE:
|
|
break;
|
|
default:
|
|
fprintf(stderr, "TC-CONTNUE.req in invalid state %s\n",
|
|
tcap_trans_state_name(td->trans.state));
|
|
return -EINVAL;
|
|
}
|
|
/* Request components to CHA */
|
|
/* Process components */
|
|
/* Assemble TSL user data */
|
|
tcm.choice.Continue.components = tcap_cha_req_components(td);
|
|
|
|
/* Assign local transaction ID */
|
|
trans_id = htonl(td->trans.tid_local);
|
|
OCTET_STRING_fromBuf(&tcm.choice.Continue.otid,
|
|
(const char *) &trans_id, sizeof(trans_id));
|
|
|
|
/* Assign remote transaction ID */
|
|
trans_id = htonl(td->trans.tid_remote);
|
|
OCTET_STRING_fromBuf(&tcm.choice.Continue.dtid,
|
|
(const char *) &trans_id, sizeof(trans_id));
|
|
|
|
|
|
/* TR-CONTINUE to TSL */
|
|
rc = tcap_tco_tr_continue_req(&td->trans, &tcm);
|
|
|
|
tcap_trans_set_state(&td->trans, TCAP_TS_ACTIVE);
|
|
|
|
asn_DEF_ANY.free_struct(&asn_DEF_ANY, any, 0);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* TC-END.req from TCU */
|
|
int tcap_csl_tc_end_req(struct tcap_dialogue *td, OBJECT_IDENTIFIER_t *app_ctx, struct user_information *user_info, int prearranged)
|
|
{
|
|
struct TCMessage tcm;
|
|
ANY_t *any;
|
|
int rc = 0;
|
|
|
|
memset(&tcm, 0, sizeof(tcm));
|
|
tcm.present = TCMessage_PR_end;
|
|
|
|
switch (td->trans.state) {
|
|
case TCAP_TS_INIT_RECV:
|
|
case TCAP_TS_ACTIVE:
|
|
break;
|
|
case TCAP_TS_INIT_SENT:
|
|
/* TR-END.req to TSL */
|
|
rc = tcap_tco_tr_end_req(&td->trans, &tcm);
|
|
/* Dialogue terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
return rc;
|
|
default:
|
|
fprintf(stderr, "TC-END.req in invalid state %s\n",
|
|
tcap_trans_state_name(td->trans.state));
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (prearranged) {
|
|
/* TR-END.req to TSL */
|
|
rc = tcap_tco_tr_end_req(&td->trans, &tcm);
|
|
/* Dialogue terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
/* Free Dialogue ID */
|
|
tcap_dialg_free(td);
|
|
return rc;
|
|
}
|
|
if (td->trans.state == TCAP_TS_INIT_RECV && (app_ctx && user_info)) {
|
|
fprintf(stdout, "\nTC-END.req Dialogue portion:\n");
|
|
any = gen_ext_AARE(td, app_ctx, user_info);
|
|
tcm.choice.end.dialoguePortion = (OCTET_STRING_t *) any;
|
|
}
|
|
/* Request component to CHA */
|
|
/* Process components */
|
|
/* Assemble TLS user data */
|
|
tcm.choice.end.components = tcap_cha_req_components(td);
|
|
/* TR-END.req to TSL */
|
|
rc = tcap_tco_tr_end_req(&td->trans, &tcm);
|
|
/* Dialogue terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
/* Free Dialogue ID */
|
|
tcap_dialg_free(td);
|
|
|
|
asn_DEF_ANY.free_struct(&asn_DEF_ANY, any, 0);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* TC-U-APORT.req from TCU */
|
|
int tcap_csl_tc_u_abort_req(struct tcap_dialogue *td, uint32_t *abrt_reason,
|
|
OBJECT_IDENTIFIER_t *app_ctx, struct user_information *user_info)
|
|
{
|
|
struct tcap_transaction *tt = &td->trans;
|
|
void *app_ctx_mode;
|
|
|
|
switch (tt->state) {
|
|
case TCAP_TS_INIT_RECV:
|
|
case TCAP_TS_ACTIVE:
|
|
break;
|
|
case TCAP_TS_INIT_SENT:
|
|
app_ctx_mode = NULL;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "TC-U-ABORT.req in invalid state %s\n",
|
|
tcap_trans_state_name(td->trans.state));
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (app_ctx_mode) {
|
|
if (tt->state != TCAP_TS_ACTIVE && 0 /* Abort reason present && AC-name not supported || dialogure refused */) {
|
|
/* Set protocol version 1 */
|
|
/* Build AARE apdu (rejected) */
|
|
} else {
|
|
/* Build ABRT apdu (source = dialogue-service-user) */
|
|
}
|
|
}
|
|
/* FIXME: TR-U-ABORT.req to TSL */
|
|
//tcap_tco_tr_u_abort_req(tt, tcmsg);
|
|
/* Dialogue terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
/* Free Dialogue ID */
|
|
tcap_dialg_free(td);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* TR-END.ind from TSL */
|
|
int tcap_csl_tr_end_ind(struct tcap_transaction *tt, struct TCMessage *tcmsg, struct msgb *msg)
|
|
{
|
|
struct tcap_dialogue *td = dialg_by_trans(tt);
|
|
struct End *endmsg = &tcmsg->choice.end;
|
|
struct DialoguePDU *dial_pdu;
|
|
OBJECT_IDENTIFIER_t *app_ctx_name = NULL;
|
|
struct user_information *user_info = NULL;
|
|
int rc = 0;
|
|
|
|
switch (td->trans.state) {
|
|
case TCAP_TS_ACTIVE:
|
|
if (endmsg->dialoguePortion) {
|
|
/* FIXME: Discard components */
|
|
/* TC-P-ABORT.ind to TCU */
|
|
//rc = tcap_tcu_abort_ind(td, app_ctx_name, user_info);
|
|
} else {
|
|
/* TC-END.ind to TCU */
|
|
rc = tcap_tcu_end_ind(td, NULL, NULL, endmsg->components ? 1 : 0);
|
|
if (endmsg->components) {
|
|
/* Components to CHA */
|
|
rc = tcap_cha_proc_components(td, endmsg->components);
|
|
}
|
|
}
|
|
break;
|
|
case TCAP_TS_INIT_SENT:
|
|
if (endmsg->dialoguePortion) {
|
|
if (td->app_ctx_mode) {
|
|
/* Extract dialogue portion */
|
|
dial_pdu = unwrap_ext_dialg_pdu(endmsg->dialoguePortion);
|
|
/* Is dialogue portion corect? */
|
|
if (0 /*!correct */) {
|
|
/* TC-P-ABORT.ind to TCU */
|
|
rc = tcap_tcu_abort_ind(td, app_ctx_name, user_info);
|
|
}
|
|
extract_appctx_uinfo(&app_ctx_name, &user_info, dial_pdu);
|
|
/* TC-END.ind to TCU */
|
|
rc = tcap_tcu_end_ind(td, app_ctx_name, user_info, endmsg->components ? 1 : 0);
|
|
if (endmsg->components) {
|
|
/* Components to CHA */
|
|
rc = tcap_cha_proc_components(td, endmsg->components);
|
|
}
|
|
}
|
|
} else {
|
|
if (td->app_ctx_mode) {
|
|
/* Discard components */
|
|
/* TC-P-ABORT.ind to TCU */
|
|
rc = tcap_tcu_abort_ind(td, app_ctx_name, user_info);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Dialogue terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
/* Free Dialogue ID */
|
|
tcap_dialg_free(td);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* TR-NOTICE.ind from TSL */
|
|
int tcap_csl_tr_notice_ind(struct tcap_transaction *tt)
|
|
{
|
|
struct tcap_dialogue *td = dialg_by_trans(tt);
|
|
uint32_t cause = 0;
|
|
|
|
switch (tt->state) {
|
|
case TCAP_TS_INIT_SENT:
|
|
case TCAP_TS_ACTIVE:
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* TR-NOTICE.ind to TCU */
|
|
return tcap_tcu_notice_ind(td, cause);
|
|
}
|
|
|
|
/* TR-CONTINUE.ind from TSL */
|
|
int tcap_csl_tr_continue_ind(struct tcap_transaction *tt, struct TCMessage *tcmsg, struct msgb *msg)
|
|
{
|
|
struct tcap_dialogue *td = dialg_by_trans(tt);
|
|
struct Continue *ctmsg = &tcmsg->choice.Continue;
|
|
struct DialoguePDU *dial_pdu = NULL;
|
|
OBJECT_IDENTIFIER_t *app_ctx_name = NULL;
|
|
struct user_information *user_info = NULL;
|
|
int rc = 0;
|
|
|
|
switch (tt->state) {
|
|
case TCAP_TS_INIT_SENT:
|
|
if (ctmsg->dialoguePortion) {
|
|
if (td->app_ctx_mode) {
|
|
/* Extract dialogue portion */
|
|
dial_pdu = unwrap_ext_dialg_pdu(ctmsg->dialoguePortion);
|
|
if (!dial_pdu /*!correct*/) {
|
|
err_discard:
|
|
/* FIXME Discard components */
|
|
/* TC-P-ABORT.ind to TCU */
|
|
rc = tcap_tcu_abort_ind(td, app_ctx_name, user_info);
|
|
/* FIXME Build ABRT apdu */
|
|
/* TR-U-ABORT.req to TSL */
|
|
rc = tcap_tco_tr_u_abort_req(tt, tcmsg);
|
|
/* Dialogue terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
/* Free Dialogue ID */
|
|
tcap_dialg_free(td);
|
|
return rc;
|
|
}
|
|
fprintf(stdout, "\nTC-CONTINUE.ind Dialogue portion:\n");
|
|
xer_fprint(stdout, &asn_DEF_DialoguePDU, dial_pdu);
|
|
extract_appctx_uinfo(&app_ctx_name, &user_info, dial_pdu);
|
|
} else
|
|
goto err_discard;
|
|
} else {
|
|
if (td->app_ctx_mode)
|
|
goto err_discard;
|
|
}
|
|
break;
|
|
case TCAP_TS_ACTIVE:
|
|
if (ctmsg->dialoguePortion) {
|
|
/* FIXME: Is abstract syntax = dialoguePDU-AS ?? */
|
|
if (!td->app_ctx_mode)
|
|
goto err_discard;
|
|
}
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
tcap_trans_set_state(tt, TCAP_TS_ACTIVE);
|
|
|
|
/* TC-CONTINUE.ind to TCU */
|
|
rc = tcap_tcu_cont_ind(td, app_ctx_name, user_info, ctmsg->components ? 1 : 0);
|
|
if (rc < 0)
|
|
return rc;
|
|
if (ctmsg->components) {
|
|
/* Components to CHA */
|
|
rc = tcap_cha_proc_components(td, ctmsg->components);
|
|
if (rc < 0)
|
|
return rc;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/* TR-U-ABORT.ind from TSL */
|
|
int tcap_csl_tr_u_abort_ind(struct tcap_transaction *tt, struct TCMessage *tcmsg, struct msgb *msg)
|
|
{
|
|
struct tcap_dialogue *td = dialg_by_trans(tt);
|
|
|
|
switch (tt->state) {
|
|
case TCAP_TS_INIT_SENT:
|
|
break;
|
|
/* FIXME: TCAP_TS_ACTIVE */
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* FIXME */
|
|
}
|
|
|
|
/* TR-P-ABORT.ind from TSL */
|
|
int tcap_csl_tr_p_abort_ind(struct tcap_transaction *tt)
|
|
{
|
|
struct tcap_dialogue *td = dialg_by_trans(tt);
|
|
OBJECT_IDENTIFIER_t *app_ctx_name = NULL;
|
|
struct user_information *user_data = NULL;
|
|
int rc;
|
|
|
|
switch (tt->state) {
|
|
case TCAP_TS_INIT_SENT:
|
|
case TCAP_TS_ACTIVE:
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* TC-P-ABORT.ind to TCU */
|
|
rc = tcap_tcu_abort_ind(td, app_ctx_name, user_data);
|
|
/* Dialog terminated to CHA */
|
|
tcap_cha_dialg_term(td);
|
|
/* Free Dialogue ID */
|
|
tcap_dialg_free(td);
|
|
|
|
return rc;
|
|
}
|
|
|