/************************************************************************/ /* SISCO SOFTWARE MODULE HEADER *****************************************/ /************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 1997-2002, All Rights Reserved */ /* */ /* PROPRIETARY AND CONFIDENTIAL */ /* */ /* MODULE NAME : copp_dec.c */ /* PRODUCT(S) : MOSI Stack (over TP4) */ /* */ /* MODULE DESCRIPTION : */ /* This file implements decoding of most confirm/indication*/ /* functions. */ /* */ /* For information see the: */ /* ISO 8822 "Information processing systems - Open Systems */ /* Interconnection - Connection oriented presentation service */ /* definition. */ /* ISO 8823 "Information processing systems - Open Systems */ /* Interconnection - Connection oriented presentation protocol */ /* specification. */ /* */ /* */ /* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ /* */ /* u_cosp_bind_cnf */ /* u_cosp_unbind_cnf */ /* */ /* u_cosp_rel_cnf_pos */ /* u_cosp_rel_ind */ /* u_cosp_p_abort_ind */ /* u_cosp_data_ind */ /* */ /* */ /* MODIFICATION LOG : */ /* Date Who Rev Comments */ /* -------- --- ------ ------------------------------------------- */ /* 02/26/09 JRB 12 Fix to handle PDV len=0 or User-data len=0. */ /* 04/28/08 GLB 11 Removed CALLED_ONLY and CALLING_ONLY */ /* 01/02/02 JRB 10 Converted to use ASN1R (re-entrant ASN1) */ /* 04/24/01 JRB 09 Allow octet-aligned PDV. Don't think it's */ /* legal but some stacks (ONE?) may use it. */ /* 02/21/01 JRB 08 Fix previous change. Was checking wrong byte */ /* in PDU for Indef Len. Use global flag instead*/ /* 12/20/00 JRB 07 asn1_skip_elmnt doesn't work for indef len */ /* encoding. Use "parse_next" instead. */ /* 08/13/98 JRB 06 Lint cleanup. */ /* 03/18/98 JRB 05 Use defines (not variables) for ASN1 errors. */ /* 02/20/98 JRB 04 Chg abort_reason & event_id to ST_INT8. */ /* 12/22/97 JRB 03 Use ST_INT8. */ /* 05/27/97 JRB 7.00 MMSEASE 7.0 release. */ /* 03/19/97 JRB 02 Add "CALLING" support. General cleanup. */ /* 02/27/97 JRB 01 Created */ /************************************************************************/ #ifdef DEBUG_SISCO static char *thisFileName = __FILE__; #endif #include "glbtypes.h" #include "sysincs.h" #include "mem_chk.h" #include "asn1defs.h" #include "acse2.h" #include "copp.h" #include "cosp_usr.h" /* START_p_user_data used by everyone, so proto in include */ /* START_pdv_list used by everyone, so proto in include */ static ST_VOID decode_pdv_tsn (ASN1_DEC_CTXT *aCtx); static ST_VOID decode_pdv_pci (ASN1_DEC_CTXT *aCtx); static ST_VOID START_pdv (ASN1_DEC_CTXT *aCtx); static ST_VOID parse_next_done (ASN1_DEC_CTXT *aCtx); static ST_VOID END_pdv (ASN1_DEC_CTXT *aCtx); static ST_VOID END_pdv_list (ASN1_DEC_CTXT *aCtx); static ST_VOID END_p_user_data (ASN1_DEC_CTXT *aCtx); /************************************************************************/ /* Global Variables */ /************************************************************************/ ST_CHAR expected_pdv_pci; ST_UCHAR *pdv_data_ptr; ST_INT pdv_data_len; ST_BOOLEAN p_user_data_is_outer; /* Is P-User-data outermost constr?*/ /* SD_TRUE or SD_FALSE */ /************************************************************************/ /* u_cosp_bind_cnf */ /************************************************************************/ ST_VOID u_cosp_bind_cnf (ST_LONG user_bind_id, ST_LONG cosp_bind_id, ST_RET result) { COPP_LOG_DEC3 ("P-BIND.cnf: copp_user_bind_id =0x%08X copp_bind_id =%9ld result =%d", user_bind_id, cosp_bind_id, result); u_copp_bind_cnf (user_bind_id, cosp_bind_id, result); } /************************************************************************/ /* u_cosp_unbind_cnf */ /************************************************************************/ ST_VOID u_cosp_unbind_cnf (ST_LONG user_bind_id) { COPP_LOG_DEC1 ("P-UNBIND.cnf: copp_user_bind_id =0x%08X", user_bind_id); u_copp_unbind_cnf (user_bind_id); } /* See "coppdcp.c" for "u_cosp_con_cnf_pos" function. */ /* See "coppdcpr.c" for "u_cosp_con_cnf_neg" function. */ /************************************************************************/ /* u_cosp_rel_cnf_pos */ /*----------------------------------------------------------------------*/ /* This USER function is called by the SS-Provider to indicate positive */ /* result of the release operation. */ /* */ /* Parameters: */ /* acse_conn Pointer to connection info */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID u_cosp_rel_cnf_pos (ACSE_CONN *acse_conn) { ST_INT8 abort_reason; ASN1_DEC_CTXT localDecCtx; /* For readability, use "aCtx" to access this.*/ ASN1_DEC_CTXT *aCtx = &localDecCtx; memset (aCtx, 0, sizeof (ASN1_DEC_CTXT)); /* CRITICAL: start clean */ if (acse_conn->copp_state != COPP_STATE_CONNECTED) { COPP_LOG_ERR1 ("COPP-ERROR: Cannot process S-RELEASE.cnf+ (Illegal state=%d)", acse_conn->copp_state); return; } aCtx->asn1r_decode_method = ASN1_TAG_METHOD; /* Use asn1_tag method for decoding. */ aCtx->asn1r_decode_done_fun = asn1r_done_err; /* done function = error fun */ aCtx->asn1r_err_fun = NULL; /* set up error detected fun */ /* Clean out old stuff from structure. */ decode_acse_conn = acse_conn; /* Save in global so asn1r_decode_asn1 (aCtx, */ /* can fill it in. */ /* Set the PCI to be used during P-User-Data decode. */ expected_pdv_pci = decode_acse_conn->pciacse; p_user_data_is_outer = SD_TRUE; /* P-User-data IS outermost constr. */ /* CRITICAL: Init APDU ptr & len. Changed only if APDU found in msg. */ acse_conn->apdu_ptr = NULL; acse_conn->apdu_len = 0; /* CRITICAL: Init global PDV ptr & len. Changed only if PDV found in msg.*/ pdv_data_ptr = NULL; pdv_data_len = 0; /* Call 'asn1r_decode_asn1 (aCtx,' to parse the message. */ ASN1R_TAG_ADD (aCtx, APP|CONSTR,1,START_p_user_data); asn1r_decode_asn1 (aCtx, acse_conn->ppdu_ptr,acse_conn->ppdu_len); if (aCtx->asn1r_pdu_dec_err != NO_DECODE_ERR) { COPP_LOG_ERR1 ("COPP-ERROR: ASN.1 decode of S-Release.cnf failed, err=%d", aCtx->asn1r_pdu_dec_err); abort_reason = 1; /* unrecognized-ppdu */ /* Don't send ARP PPDU. COSP already thinks we're released. */ /* Pass P-P-Abort.ind to COPP-user. */ u_copp_p_abort_ind (acse_conn, abort_reason); } else { COPP_LOG_DEC2 ("P-RELEASE.cnf+: acse_conn_id =0x%08X user_conn_id =%4ld", acse_conn, acse_conn->user_conn_id); COPP_LOG_DECC1 ("User data length: %d", acse_conn->apdu_len); COPP_LOG_DECH (acse_conn->apdu_len, acse_conn->apdu_ptr); if (acse_conn->cr) { acse_conn->cr = SD_FALSE; acse_conn->rl = SD_FALSE; /* and stay in COPP_STATE_CONNECTED */ } else acse_conn->copp_state = COPP_STATE_IDLE; u_copp_rel_cnf_pos (acse_conn); } } /* See "coppdcp.c" for "u_cosp_con_ind" function. */ /************************************************************************/ /* u_cosp_rel_ind */ /*----------------------------------------------------------------------*/ /* This USER function is called by the SS-Provider to indicate that a */ /* remote node wishes to release a connection. */ /* */ /* Parameters: */ /* ACSE_CONN *acse_conn Pointer to connection info */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID u_cosp_rel_ind (ACSE_CONN *acse_conn) { ST_INT8 abort_reason; ST_INT8 event_id; ASN1_DEC_CTXT localDecCtx; /* For readability, use "aCtx" to access this.*/ ASN1_DEC_CTXT *aCtx = &localDecCtx; memset (aCtx, 0, sizeof (ASN1_DEC_CTXT)); /* CRITICAL: start clean */ if (acse_conn->copp_state != COPP_STATE_CONNECTED) { COPP_LOG_ERR1 ("COPP-ERROR: Cannot process S-RELEASE.ind (Illegal state=%d)", acse_conn->copp_state); return; } /* Set release collision flags. */ if (acse_conn->rl) acse_conn->cr = SD_TRUE; acse_conn->rl = SD_TRUE; aCtx->asn1r_decode_method = ASN1_TAG_METHOD; /* Use asn1_tag method for decoding. */ aCtx->asn1r_decode_done_fun = asn1r_done_err; /* done function = error fun */ aCtx->asn1r_err_fun = NULL; /* set up error detected fun */ /* Clean out old stuff from structure. */ decode_acse_conn = acse_conn; /* Save in global so asn1r_decode_asn1 (aCtx, */ /* can fill it in. */ /* Set the PCI to be used during P-User-Data decode. */ expected_pdv_pci = decode_acse_conn->pciacse; p_user_data_is_outer = SD_TRUE; /* P-User-data IS outermost constr. */ /* CRITICAL: Init APDU ptr & len. Changed only if APDU found in msg. */ acse_conn->apdu_ptr = NULL; acse_conn->apdu_len = 0; /* CRITICAL: Init global PDV ptr & len. Changed only if PDV found in msg.*/ pdv_data_ptr = NULL; pdv_data_len = 0; /* Call 'asn1r_decode_asn1 (aCtx,' to parse the message. */ ASN1R_TAG_ADD (aCtx, APP|CONSTR,1,START_p_user_data); asn1r_decode_asn1 (aCtx, acse_conn->ppdu_ptr,acse_conn->ppdu_len); if (aCtx->asn1r_pdu_dec_err != NO_DECODE_ERR) { COPP_LOG_ERR1 ("COPP-ERROR: ASN.1 decode of S-Release.ind failed, err=%d", aCtx->asn1r_pdu_dec_err); acse_conn->copp_state = COPP_STATE_IDLE; abort_reason = 1; /* unrecognized-ppdu */ event_id = 14; /* s-release-indication */ /* Encode and send ARP PPDU. */ copp_p_abort_req (acse_conn, abort_reason, event_id); /* Pass P-P-Abort.ind to COPP-user. */ u_copp_p_abort_ind (acse_conn, abort_reason); } else { COPP_LOG_DEC2 ("P-RELEASE.ind: acse_conn_id =0x%08X user_conn_id =%4ld", acse_conn, acse_conn->user_conn_id); COPP_LOG_DECC1 ("User data length: %d", acse_conn->apdu_len); COPP_LOG_DECH (acse_conn->apdu_len, acse_conn->apdu_ptr); u_copp_rel_ind (acse_conn); } } /************************************************************************/ /* u_cosp_p_abort_ind */ /*----------------------------------------------------------------------*/ /* This USER function is called by the SS-Provider to indicate that a */ /* connection has been aborted by SS-provider (local or remote). */ /* */ /* Parameters: */ /* ACSE_CONN *acse_con Pointer to connection info */ /* ST_INT reason see def reasons COSP_P_AB_IND_... above */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID u_cosp_p_abort_ind (ACSE_CONN *acse_conn, ST_INT reason) { if (acse_conn->copp_state == COPP_STATE_IDLE) { COPP_LOG_ERR1 ("COPP-ERROR: Cannot process S-P-ABORT.ind (Illegal state=%d)", acse_conn->copp_state); return; } COPP_LOG_DEC3 ("P-P-ABORT.ind: acse_conn_id =0x%08X user_conn_id =%4ld reason =%d", acse_conn, acse_conn->user_conn_id, reason + 0x100); acse_conn->copp_state = COPP_STATE_IDLE; u_copp_p_abort_ind (acse_conn, reason + 0x100); } /************************************************************************/ /* u_cosp_data_ind */ /*----------------------------------------------------------------------*/ /* This USER function is called by the SS-Provider to indicate that a */ /* data SPDU has been received. */ /* */ /* Parameters: */ /* ACSE_CONN *acse_conn Pointer to connection info */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID u_cosp_data_ind (ACSE_CONN *acse_conn) { ST_INT8 abort_reason; ST_INT8 event_id; ASN1_DEC_CTXT localDecCtx; /* For readability, use "aCtx" to access this.*/ ASN1_DEC_CTXT *aCtx = &localDecCtx; memset (aCtx, 0, sizeof (ASN1_DEC_CTXT)); /* CRITICAL: start clean */ if (acse_conn->copp_state != COPP_STATE_CONNECTED) { COPP_LOG_ERR1 ("COPP-ERROR: Cannot process S-DATA.ind (Illegal state=%d)", acse_conn->copp_state); return; } aCtx->asn1r_decode_method = ASN1_TAG_METHOD; /* Use asn1_tag method for decoding. */ aCtx->asn1r_decode_done_fun = asn1r_done_err; /* done function = error fun */ aCtx->asn1r_err_fun = NULL; /* set up error detected fun */ /* Clean out old stuff from structure. */ decode_acse_conn = acse_conn; /* Save in global so asn1r_decode_asn1 (aCtx, */ /* can fill it in. */ /* Set the PCI to be used during P-User-Data decode. */ expected_pdv_pci = decode_acse_conn->pcimms; p_user_data_is_outer = SD_TRUE; /* P-User-data IS outermost constr. */ /* CRITICAL: Init APDU ptr & len. Changed only if APDU found in msg. */ acse_conn->apdu_ptr = NULL; acse_conn->apdu_len = 0; /* CRITICAL: Init global PDV ptr & len. Changed only if PDV found in msg.*/ pdv_data_ptr = NULL; pdv_data_len = 0; /* Call 'asn1r_decode_asn1 (aCtx,' to parse the message. */ ASN1R_TAG_ADD (aCtx, APP|CONSTR,1,START_p_user_data); asn1r_decode_asn1 (aCtx, acse_conn->ppdu_ptr,acse_conn->ppdu_len); if (aCtx->asn1r_pdu_dec_err != NO_DECODE_ERR) { COPP_LOG_ERR1 ("COPP-ERROR: ASN.1 decode of S-Data.ind failed, err=%d", aCtx->asn1r_pdu_dec_err); abort_reason = 1; /* unrecognized-ppdu */ event_id = -1; /* Unlisted */ /* Encode and send ARP PPDU. */ copp_p_abort_req (acse_conn, abort_reason, event_id); /* Pass P-P-Abort.ind to COPP-user. */ u_copp_p_abort_ind (acse_conn, abort_reason); } else { COPP_LOG_DEC2 ("P-DATA.ind: acse_conn_id =0x%08X user_conn_id =%4ld", acse_conn, acse_conn->user_conn_id); COPP_LOG_DECC1 ("User data length: %d", acse_conn->apdu_len); COPP_LOG_DECH (acse_conn->apdu_len, acse_conn->apdu_ptr); u_copp_data_ind (acse_conn); } } /*======================================================*/ /* ASN.1 DECODE FUNCTIONS FOR P-USER-DATA */ /* */ /* Used for CP, CPA, CPR, ARU, DT, or REL decode. */ /*======================================================*/ /************************************************************************/ /* START_p_user_data */ /************************************************************************/ ST_VOID START_p_user_data (ASN1_DEC_CTXT *aCtx) { ASN1R_TAG_ADD (aCtx, UNI|CONSTR,SEQ_CODE,START_pdv_list); aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = END_p_user_data; } /************************************************************************/ /* START_pdv_list */ /* ACSE also uses this function to decode "EXTERNAL". Although defined */ /* independently, it's encoding is same as "PDV-list". */ /************************************************************************/ ST_VOID START_pdv_list (ASN1_DEC_CTXT *aCtx) { ASN1R_TAG_ADD (aCtx, UNI,OBJ_ID_CODE,decode_pdv_tsn); ASN1R_TAG_ADD (aCtx, UNI,INT_CODE,decode_pdv_pci); aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = END_pdv_list; } /************************************************************************/ /* decode_pdv_tsn */ /************************************************************************/ static ST_VOID decode_pdv_tsn (ASN1_DEC_CTXT *aCtx) { MMS_OBJ_ID tsn; if (asn1r_get_objid (aCtx, tsn.comps,&tsn.num_comps)) { asn1r_set_dec_err (aCtx, ASN1E_INVALID_BOOLEAN); return; } if (asn1_objidcmp (&tsn, &asn1_obj_id) != 0) { /* TSN better be ASN1 */ asn1r_set_dec_err (aCtx, ASN1E_INVALID_BITSTR); return; } ASN1R_TAG_ADD (aCtx, UNI,INT_CODE,decode_pdv_pci); } /************************************************************************/ /* decode_pdv_pci */ /************************************************************************/ static ST_VOID decode_pdv_pci (ASN1_DEC_CTXT *aCtx) { ST_INT8 pci; if (asn1r_get_i8 (aCtx, &pci)) { asn1r_set_dec_err (aCtx, ASN1E_INVALID_BOOLEAN); return; } if (pci != expected_pdv_pci) { /* Not the pci we're expecting. */ asn1r_set_dec_err (aCtx, ASN1E_INVALID_BITSTR); return; } ASN1R_TAG_ADD (aCtx, CTX|CONSTR,0,START_pdv); /* Must be single-ASN1-type */ /* Octet-aligned doesn't appear to be legal, but some stacks (ONE?) */ /* may use it. To be friendly, let's accept it. */ ASN1R_TAG_ADD (aCtx, CTX,1,START_pdv); /* Allow octet-aligned */ } /************************************************************************/ /* START_pdv */ /************************************************************************/ static ST_VOID START_pdv (ASN1_DEC_CTXT *aCtx) { /* Should now point to PDV data. Save until decode done. */ pdv_data_ptr = aCtx->asn1r_field_ptr; /* If this is indefinite length encoding, use "asn1r_parse_next (aCtx,". */ /* If "normal" encoding, use "asn1_skip_elmnt" (faster). */ if (aCtx->asn1r_indef_flag) { /* indefinite length encoding */ aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = END_pdv; asn1r_parse_next (aCtx, parse_next_done); } else { /* "normal" encoding */ pdv_data_len = aCtx->asn1r_elmnt_len; asn1_skip_elmnt (aCtx); /* Done decoding PPDU. Let ACSE decode rest. */ } } /************************************************************************/ /* parse_next_done */ /* Only used for indefinite length encoding. */ /************************************************************************/ static ST_VOID parse_next_done (ASN1_DEC_CTXT *aCtx) { /* called when "asn1r_parse_next (aCtx," is done */ } /************************************************************************/ /* END_pdv */ /* Only used for indefinite length encoding. */ /************************************************************************/ static ST_VOID END_pdv (ASN1_DEC_CTXT *aCtx) { pdv_data_len = aCtx->asn1r_field_ptr - pdv_data_ptr - 2; /* -2 strips 00 00*/ } /************************************************************************/ /* END_pdv_list */ /************************************************************************/ static ST_VOID END_pdv_list (ASN1_DEC_CTXT *aCtx) { } /************************************************************************/ /* END_p_user_data */ /************************************************************************/ static ST_VOID END_p_user_data (ASN1_DEC_CTXT *aCtx) { decode_acse_conn->apdu_ptr = pdv_data_ptr; decode_acse_conn->apdu_len = pdv_data_len; if (p_user_data_is_outer) /* Is P-User-data outermost constr? */ aCtx->asn1r_decode_done_fun = NULL; /* done decoding */ }