/* * * =================================== * HARP | Host ATM Research Platform * =================================== * * * This Host ATM Research Platform ("HARP") file (the "Software") is * made available by Network Computing Services, Inc. ("NetworkCS") * "AS IS". NetworkCS does not provide maintenance, improvements or * support of any kind. * * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. * In no event shall NetworkCS be responsible for any damages, including * but not limited to consequential damages, arising from or relating to * any use of the Software or related support. * * Copyright 1994-1998 Network Computing Services, Inc. * * Copies of this Software may be made, however, the above copyright * notice must be reproduced on all copies. * * @(#) $FreeBSD$ * */ /* * ATM Forum UNI 3.0/3.1 Signalling Manager * ---------------------------------------- * * Message formatting module * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef lint __RCSID("@(#) $FreeBSD$"); #endif #define ALLOC_IE(ie) \ (ie) = (struct ie_generic *) atm_allocate(&unisig_iepool); \ if (!ie) \ return(ENOMEM); /* * Local functions */ static int usf_dec_ie(struct usfmt *, struct unisig_msg *, struct ie_generic *); static int usf_dec_ie_hdr(struct usfmt *, struct ie_generic *); static int usf_dec_ie_aalp(struct usfmt *, struct ie_generic *); static int usf_dec_ie_clrt(struct usfmt *, struct ie_generic *); static int usf_dec_ie_bbcp(struct usfmt *, struct ie_generic *); static int usf_dec_ie_bhli(struct usfmt *, struct ie_generic *); static int usf_dec_ie_blli(struct usfmt *, struct ie_generic *); static int usf_dec_ie_clst(struct usfmt *, struct ie_generic *); static int usf_dec_ie_cdad(struct usfmt *, struct ie_generic *); static int usf_dec_ie_cdsa(struct usfmt *, struct ie_generic *); static int usf_dec_ie_cgad(struct usfmt *, struct ie_generic *); static int usf_dec_ie_cgsa(struct usfmt *, struct ie_generic *); static int usf_dec_ie_caus(struct usfmt *, struct ie_generic *); static int usf_dec_ie_cnid(struct usfmt *, struct ie_generic *); static int usf_dec_ie_qosp(struct usfmt *, struct ie_generic *); static int usf_dec_ie_brpi(struct usfmt *, struct ie_generic *); static int usf_dec_ie_rsti(struct usfmt *, struct ie_generic *); static int usf_dec_ie_bsdc(struct usfmt *, struct ie_generic *); static int usf_dec_ie_trnt(struct usfmt *, struct ie_generic *); static int usf_dec_ie_uimp(struct usfmt *, struct ie_generic *); static int usf_dec_ie_ident(struct usfmt *, struct ie_generic *, struct ie_decode_tbl *); static int usf_dec_atm_addr(struct usfmt *, Atm_addr *, int); /* * Table associating IE type with IE vector index */ u_char unisig_ie_ident_vec[] = { UNI_IE_AALP, UNI_IE_CLRT, UNI_IE_BBCP, UNI_IE_BHLI, UNI_IE_BLLI, UNI_IE_CLST, UNI_IE_CDAD, UNI_IE_CDSA, UNI_IE_CGAD, UNI_IE_CGSA, UNI_IE_CAUS, UNI_IE_CNID, UNI_IE_QOSP, UNI_IE_BRPI, UNI_IE_RSTI, UNI_IE_BLSH, UNI_IE_BNSH, UNI_IE_BSDC, UNI_IE_TRNT, UNI_IE_EPRF, UNI_IE_EPST }; /* * Tables specifying which IEs are mandatory, optional, and * not allowed for each Q.2931 message type */ static u_char uni_calp_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_NA, /* Cause */ IE_OPT, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_OPT, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_conn_ie_tbl[] = { IE_OPT, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_OPT, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_NA, /* Cause */ IE_OPT, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_OPT, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_cack_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_NA, /* Cause */ IE_NA, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_NA, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_setu_ie_tbl[] = { IE_MAND, /* ATM AAL Parameters (not required by UNI 3.0) */ IE_MAND, /* ATM User Cell Rate */ IE_MAND, /* Broadband Bearer Capability */ IE_OPT, /* Broadband High Layer Information */ IE_MAND, /* Broadband Low Layer Information (not required by UNI 3.0 */ IE_NA, /* Call State */ IE_MAND, /* Called Party Number */ IE_OPT, /* Called Party Subaddress */ IE_OPT, /* Calling Party Number */ IE_OPT, /* Calling Party Subaddress */ IE_NA, /* Cause */ IE_MAND, /* Connection Identifier */ IE_MAND, /* Quality of Service Parameters */ IE_OPT, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_OPT, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_OPT, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_rlse_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_MAND, /* Cause */ IE_NA, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_NA, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_rlsc_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_MAND, /* Cause */ IE_NA, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_NA, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_rstr_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_NA, /* Cause */ IE_OPT, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_MAND, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_NA, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_rsta_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_NA, /* Cause */ IE_OPT, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_MAND, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_NA, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_stat_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_MAND, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_MAND, /* Cause */ IE_NA, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_OPT, /* Endpoint Reference */ IE_OPT /* Endpoint State */ }; static u_char uni_senq_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_NA, /* Cause */ IE_NA, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_OPT, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_addp_ie_tbl[] = { IE_OPT, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_OPT, /* Broadband High Layer Information */ IE_OPT, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_MAND, /* Called Party Number */ IE_OPT, /* Called Party Subaddress */ IE_OPT, /* Calling Party Number */ IE_OPT, /* Calling Party Subaddress */ IE_NA, /* Cause */ IE_NA, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_OPT, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_MAND, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_adpa_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_NA, /* Cause */ IE_NA, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_MAND, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_adpr_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_MAND, /* Cause */ IE_NA, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_MAND, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_drpp_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_MAND, /* Cause */ IE_NA, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_MAND, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; static u_char uni_drpa_ie_tbl[] = { IE_NA, /* ATM AAL Parameters */ IE_NA, /* ATM User Cell Rate */ IE_NA, /* Broadband Bearer Capability */ IE_NA, /* Broadband High Layer Information */ IE_NA, /* Broadband Low Layer Information */ IE_NA, /* Call State */ IE_NA, /* Called Party Number */ IE_NA, /* Called Party Subaddress */ IE_NA, /* Calling Party Number */ IE_NA, /* Calling Party Subaddress */ IE_OPT, /* Cause */ IE_NA, /* Connection Identifier */ IE_NA, /* Quality of Service Parameters */ IE_NA, /* Broadband Repeat Indicator */ IE_NA, /* Restart Indicator */ IE_NA, /* Broadband Locking Shift */ IE_NA, /* Broadband Non-locking Shift */ IE_NA, /* Broadband Sending Complete */ IE_NA, /* Transit Net */ IE_MAND, /* Endpoint Reference */ IE_NA /* Endpoint State */ }; /* * Table of Q.2931 message types */ static struct { u_char msg_type; u_char *msg_ie_tbl; } uni_msg_types[] = { { UNI_MSG_CALP, uni_calp_ie_tbl }, { UNI_MSG_CONN, uni_conn_ie_tbl }, { UNI_MSG_CACK, uni_cack_ie_tbl }, { UNI_MSG_SETU, uni_setu_ie_tbl }, { UNI_MSG_RLSE, uni_rlse_ie_tbl }, { UNI_MSG_RLSC, uni_rlsc_ie_tbl }, { UNI_MSG_RSTR, uni_rstr_ie_tbl }, { UNI_MSG_RSTA, uni_rsta_ie_tbl }, { UNI_MSG_STAT, uni_stat_ie_tbl }, { UNI_MSG_SENQ, uni_senq_ie_tbl }, { UNI_MSG_ADDP, uni_addp_ie_tbl }, { UNI_MSG_ADPA, uni_adpa_ie_tbl }, { UNI_MSG_ADPR, uni_adpr_ie_tbl }, { UNI_MSG_DRPP, uni_drpp_ie_tbl }, { UNI_MSG_DRPA, uni_drpa_ie_tbl }, }; /* * Table of information elements */ static struct ie_ent ie_table[] = { { UNI_IE_AALP, 5, 16, UNI_MSG_IE_AALP, usf_dec_ie_aalp }, { UNI_IE_CLRT, 0, 26, UNI_MSG_IE_CLRT, usf_dec_ie_clrt }, { UNI_IE_BBCP, 2, 3, UNI_MSG_IE_BBCP, usf_dec_ie_bbcp }, { UNI_IE_BHLI, 1, 9, UNI_MSG_IE_BHLI, usf_dec_ie_bhli }, { UNI_IE_BLLI, 0, 13, UNI_MSG_IE_BLLI, usf_dec_ie_blli }, { UNI_IE_CLST, 1, 1, UNI_MSG_IE_CLST, usf_dec_ie_clst }, { UNI_IE_CDAD, 1, 21, UNI_MSG_IE_CDAD, usf_dec_ie_cdad }, { UNI_IE_CDSA, 1, 21, UNI_MSG_IE_CDSA, usf_dec_ie_cdsa }, { UNI_IE_CGAD, 1, 22, UNI_MSG_IE_CGAD, usf_dec_ie_cgad }, { UNI_IE_CGSA, 1, 21, UNI_MSG_IE_CGSA, usf_dec_ie_cgsa }, { UNI_IE_CAUS, 2, 30, UNI_MSG_IE_CAUS, usf_dec_ie_caus }, { UNI_IE_CNID, 5, 5, UNI_MSG_IE_CNID, usf_dec_ie_cnid }, { UNI_IE_QOSP, 2, 2, UNI_MSG_IE_QOSP, usf_dec_ie_qosp }, { UNI_IE_BRPI, 1, 1, UNI_MSG_IE_BRPI, usf_dec_ie_brpi }, { UNI_IE_RSTI, 1, 1, UNI_MSG_IE_RSTI, usf_dec_ie_rsti }, { UNI_IE_BLSH, 1, 1, UNI_MSG_IE_ERR, usf_dec_ie_uimp }, { UNI_IE_BNSH, 1, 1, UNI_MSG_IE_ERR, usf_dec_ie_uimp }, { UNI_IE_BSDC, 1, 1, UNI_MSG_IE_BSDC, usf_dec_ie_bsdc }, { UNI_IE_TRNT, 1, 5, UNI_MSG_IE_TRNT, usf_dec_ie_trnt }, { UNI_IE_EPRF, 3, 3, UNI_MSG_IE_ERR, usf_dec_ie_uimp }, { UNI_IE_EPST, 1, 1, UNI_MSG_IE_ERR, usf_dec_ie_uimp }, { 0, 0, 0, 0, 0 } }; /* * Decoding table for AAL 1 */ struct ie_decode_tbl ie_aal1_tbl[] = { { 133, 1, IE_OFF_SIZE(ie_aalp_1_subtype) }, { 134, 1, IE_OFF_SIZE(ie_aalp_1_cbr_rate) }, { 135, 2, IE_OFF_SIZE(ie_aalp_1_multiplier) }, { 136, 1, IE_OFF_SIZE(ie_aalp_1_clock_recovery) }, { 137, 1, IE_OFF_SIZE(ie_aalp_1_error_correction) }, { 138, 1, IE_OFF_SIZE(ie_aalp_1_struct_data_tran) }, { 139, 1, IE_OFF_SIZE(ie_aalp_1_partial_cells) }, { 0, 0, 0, 0 } }; /* * Decoding table for AAL 3/4 */ struct ie_decode_tbl ie_aal4_tbl_30[] = { { 140, 2, IE_OFF_SIZE(ie_aalp_4_fwd_max_sdu) }, { 129, 2, IE_OFF_SIZE(ie_aalp_4_bkwd_max_sdu) }, { 130, 2, IE_OFF_SIZE(ie_aalp_4_mid_range) }, { 131, 1, IE_OFF_SIZE(ie_aalp_4_mode) }, { 132, 1, IE_OFF_SIZE(ie_aalp_4_sscs_type) }, { 0, 0, 0, 0 } }; struct ie_decode_tbl ie_aal4_tbl_31[] = { { 140, 2, IE_OFF_SIZE(ie_aalp_4_fwd_max_sdu) }, { 129, 2, IE_OFF_SIZE(ie_aalp_4_bkwd_max_sdu) }, { 130, 4, IE_OFF_SIZE(ie_aalp_4_mid_range) }, { 132, 1, IE_OFF_SIZE(ie_aalp_4_sscs_type) }, { 0, 0, 0, 0 } }; /* * Decoding table for AAL 5 */ struct ie_decode_tbl ie_aal5_tbl_30[] = { { 140, 2, IE_OFF_SIZE(ie_aalp_5_fwd_max_sdu) }, { 129, 2, IE_OFF_SIZE(ie_aalp_5_bkwd_max_sdu) }, { 131, 1, IE_OFF_SIZE(ie_aalp_5_mode) }, { 132, 1, IE_OFF_SIZE(ie_aalp_5_sscs_type) }, { 0, 0, 0, 0 } }; struct ie_decode_tbl ie_aal5_tbl_31[] = { { 140, 2, IE_OFF_SIZE(ie_aalp_5_fwd_max_sdu) }, { 129, 2, IE_OFF_SIZE(ie_aalp_5_bkwd_max_sdu) }, { 132, 1, IE_OFF_SIZE(ie_aalp_5_sscs_type) }, { 0, 0, 0, 0 } }; /* * Decoding table for ATM user cell rate */ struct ie_decode_tbl ie_clrt_tbl[] = { {UNI_IE_CLRT_FWD_PEAK_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_peak)}, {UNI_IE_CLRT_BKWD_PEAK_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_peak)}, {UNI_IE_CLRT_FWD_PEAK_01_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_peak_01)}, {UNI_IE_CLRT_BKWD_PEAK_01_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_peak_01)}, {UNI_IE_CLRT_FWD_SUST_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_sust)}, {UNI_IE_CLRT_BKWD_SUST_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_sust)}, {UNI_IE_CLRT_FWD_SUST_01_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_sust_01)}, {UNI_IE_CLRT_BKWD_SUST_01_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_sust_01)}, {UNI_IE_CLRT_FWD_BURST_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_burst)}, {UNI_IE_CLRT_BKWD_BURST_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_burst)}, {UNI_IE_CLRT_FWD_BURST_01_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_burst_01)}, {UNI_IE_CLRT_BKWD_BURST_01_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_burst_01)}, {UNI_IE_CLRT_BEST_EFFORT_ID, 0, IE_OFF_SIZE(ie_clrt_best_effort)}, {UNI_IE_CLRT_TM_OPTIONS_ID, 1, IE_OFF_SIZE(ie_clrt_tm_options)}, {0, 0, 0, 0 } }; /* * IEs initialized to empty values */ struct ie_aalp ie_aalp_absent = { T_ATM_ABSENT }; struct ie_clrt ie_clrt_absent = { T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT }; struct ie_bbcp ie_bbcp_absent = { T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT }; struct ie_bhli ie_bhli_absent = { T_ATM_ABSENT, { 0, 0, 0, 0, 0, 0, 0, 0 } }; struct ie_blli ie_blli_absent = { T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, { 0, 0, 0 }, { 0, 0 } }; struct ie_clst ie_clst_absent = { T_ATM_ABSENT }; struct ie_cdad ie_cdad_absent = { T_ATM_ABSENT, T_ATM_ABSENT, { T_ATM_ABSENT, 0 } }; struct ie_cdsa ie_cdsa_absent = { { T_ATM_ABSENT, 0 } }; struct ie_cgad ie_cgad_absent = { T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, { T_ATM_ABSENT, 0 } }; struct ie_cgsa ie_cgsa_absent = { { T_ATM_ABSENT, 0 } }; struct ie_caus ie_caus_absent = { T_ATM_ABSENT, T_ATM_ABSENT, 0 }; struct ie_cnid ie_cnid_absent = { T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT, T_ATM_ABSENT }; struct ie_qosp ie_qosp_absent = { T_ATM_ABSENT, T_ATM_ABSENT }; struct ie_brpi ie_brpi_absent = { T_ATM_ABSENT }; struct ie_rsti ie_rsti_absent = { T_ATM_ABSENT }; struct ie_blsh ie_blsh_absent = { T_ATM_ABSENT }; struct ie_bnsh ie_bnsh_absent = { T_ATM_ABSENT }; struct ie_bsdc ie_bsdc_absent = { T_ATM_ABSENT }; struct ie_trnt ie_trnt_absent = { T_ATM_ABSENT, T_ATM_ABSENT, 0 }; struct ie_eprf ie_eprf_absent = { T_ATM_ABSENT, T_ATM_ABSENT }; struct ie_epst ie_epst_absent = { T_ATM_ABSENT }; /* * Decode a UNI signalling message * * Arguments: * usf pointer to a unisig formatting structure * msg pointer to a signalling message structure * * Returns: * 0 success * errno error encountered * */ int usf_dec_msg(usf, msg) struct usfmt *usf; struct unisig_msg *msg; { int i, len, rc; short s; u_char c, *ie_tbl; struct ie_generic *ie; ATM_DEBUG2("usf_dec_msg: usf=%p, msg=%p\n", usf, msg); /* * Check the total message length */ if (usf_count(usf) < UNI_MSG_MIN_LEN) { return(EIO); } /* * Get and check the protocol discriminator */ rc = usf_byte(usf, &c); if (rc) return(rc); if (c != UNI_MSG_DISC_Q93B) return(EIO); /* * Get and check the call reference length */ rc = usf_byte(usf, &c); if (rc) return(rc); if (c != 3) return(EIO); /* * Get the call reference */ rc = usf_int3(usf, &msg->msg_call_ref); if (rc) return(rc); /* * Get the message type */ rc = usf_byte(usf, &msg->msg_type); if (rc) return(rc); /* * Get the message type extension */ rc = usf_byte(usf, &c); if (rc) return(rc); msg->msg_type_flag = (c >> UNI_MSG_TYPE_FLAG_SHIFT) & UNI_MSG_TYPE_FLAG_MASK; msg->msg_type_action = c & UNI_MSG_TYPE_ACT_MASK; /* * Get the message length and make sure we actually have * enough data for the whole message */ rc = usf_short(usf, &s); if (rc) return(rc); msg->msg_length = s; if (usf_count(usf) != msg->msg_length) { return(EMSGSIZE); } /* * Process information elements */ len = msg->msg_length; while (len) { ALLOC_IE(ie); rc = usf_dec_ie(usf, msg, ie); if (rc) { atm_free(ie); return(rc); } len -= (ie->ie_length + UNI_IE_HDR_LEN); } /* * Make sure that mandatory IEs are included and * unwanted ones aren't */ for (i=0; msg->msg_type!=uni_msg_types[i].msg_type && uni_msg_types[i].msg_type!=0; i++) { } if (!uni_msg_types[i].msg_ie_tbl) goto done; /* * If the message type is in the table, check the IEs. * If it isn't, the receive routine will catch the error. */ ie_tbl = uni_msg_types[i].msg_ie_tbl; for (i=0; imsg_ie_vec[i]) { /* * Mandatory IE missing */ ALLOC_IE(ie); ie->ie_ident = unisig_ie_ident_vec[i]; ie->ie_err_cause = UNI_IE_CAUS_MISSING; MSG_IE_ADD(msg, ie, UNI_MSG_IE_ERR); } break; case IE_NA: if (msg->msg_ie_vec[i]) { /* * Disallowed IE present */ ie = msg->msg_ie_vec[i]; msg->msg_ie_vec[i] = (struct ie_generic *) 0; MSG_IE_ADD(msg, ie, UNI_MSG_IE_ERR); while (ie) { ie->ie_err_cause = UNI_IE_CAUS_IEEXIST; ie = ie->ie_next; } } break; case IE_OPT: break; } } done: return(0); } /* * Decode an information element * * This routine will be called repeatedly as long as there are * information elements left to be decoded. It will decode the * first part of the IE, look its type up in a table, and call * the appropriate routine to decode the rest. After an IE is * successfully decoded, it is linked into the UNI signalling * message structure. If an error is discovered, the IE is linked * into the IE error chain and an error cause is set in the header. * * Arguments: * usf pointer to a UNISIG formatting structure * msg pointer to a UNISIG message structure * ie pointer to a generic IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie(usf, msg, ie) struct usfmt *usf; struct unisig_msg *msg; struct ie_generic *ie; { int i, ie_index, rc; /* * Decode the IE header (identifier, instruction field, * and length) */ rc = usf_dec_ie_hdr(usf, ie); if (rc) return(rc); /* * Ignore the IE if it is of zero length. */ if (!ie->ie_length) { atm_free(ie); return(0); } /* * Look up the information element in the table */ for (i=0; (ie->ie_ident != ie_table[i].ident) && (ie_table[i].decode != NULL); i++) { } if (ie_table[i].decode == NULL) { /* * Unrecognized IE */ ie_index = UNI_MSG_IE_ERR; } else { ie_index = ie_table[i].p_idx; } /* * Check for unimplemented or unrecognized IEs */ if (ie_index == UNI_MSG_IE_ERR) { ie->ie_err_cause = UNI_IE_CAUS_IEEXIST; /* * Skip over the invalid IE */ rc = usf_dec_ie_uimp(usf, ie); if (rc) return(rc); goto done; } /* * Check the length against the IE table */ if (ie->ie_length < ie_table[i].min_len || ie->ie_length > ie_table[i].max_len) { ie_index = UNI_MSG_IE_ERR; ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; /* * Skip over the invalid IE */ rc = usf_dec_ie_uimp(usf, ie); if (rc) return(rc); goto done; } /* * Process the IE by calling the function indicated * in the IE table */ rc = ie_table[i].decode(usf, ie); if (rc) return(rc); /* * Link the IE into the signalling message */ done: if (ie->ie_err_cause) { ie_index = UNI_MSG_IE_ERR; } MSG_IE_ADD(msg, ie, ie_index); return(0); } /* * Decode an information element header * * Arguments: * usf pointer to a UNISIG formatting structure * ie pointer to a generic IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_hdr(usf, ie) struct usfmt *usf; struct ie_generic *ie; { u_char c; short s; int rc; /* * Get the IE identifier */ rc = usf_byte(usf, &ie->ie_ident); if (rc) return(rc); /* * Get the extended type */ rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_coding = (c >> UNI_IE_CODE_SHIFT) & UNI_IE_CODE_MASK; ie->ie_flag = (c >> UNI_IE_FLAG_SHIFT) & UNI_IE_FLAG_MASK; ie->ie_action = c & UNI_IE_ACT_MASK; /* * Get the length. */ rc = usf_short(usf, &s); if (rc) return(rc); ie->ie_length = s; return(0); } /* * Decode an AAL parameters information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to an AAL parms IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_aalp(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int i, rc = 0; /* * Clear the IE */ KM_COPY(&ie_aalp_absent, &ie->ie_u.ie_aalp, sizeof(ie_aalp_absent)); /* * Get the AAL type */ rc = usf_byte(usf, &ie->ie_aalp_aal_type); if (rc) return(rc); /* * Subtract the length of the AAL type from the total. * It will be readjusted after usf_dec_ie_ident is finished. */ ie->ie_length--; /* * Process based on AAL type */ switch (ie->ie_aalp_aal_type) { case UNI_IE_AALP_AT_AAL1: /* * Clear the AAL 1 subparameters */ ie->ie_aalp_1_subtype = T_ATM_ABSENT; ie->ie_aalp_1_cbr_rate = T_ATM_ABSENT; ie->ie_aalp_1_multiplier = T_ATM_ABSENT; ie->ie_aalp_1_clock_recovery = T_ATM_ABSENT; ie->ie_aalp_1_error_correction = T_ATM_ABSENT; ie->ie_aalp_1_struct_data_tran = T_ATM_ABSENT; ie->ie_aalp_1_partial_cells = T_ATM_ABSENT; /* * Parse the AAL fields based on their IDs */ rc = usf_dec_ie_ident(usf, ie, ie_aal1_tbl); break; case UNI_IE_AALP_AT_AAL3: /* * Clear the AAL 3/4 subparameters */ ie->ie_aalp_4_fwd_max_sdu = T_ATM_ABSENT; ie->ie_aalp_4_bkwd_max_sdu = T_ATM_ABSENT; ie->ie_aalp_4_mid_range = T_ATM_ABSENT; ie->ie_aalp_4_mode = T_ATM_ABSENT; ie->ie_aalp_4_sscs_type = T_ATM_ABSENT; /* * Parse the AAL fields based on their IDs */ if (usf->usf_sig->us_proto == ATM_SIG_UNI30) rc = usf_dec_ie_ident(usf, ie, ie_aal4_tbl_30); else rc = usf_dec_ie_ident(usf, ie, ie_aal4_tbl_31); /* * If either forward or backward maximum SDU * size is specified, the other must also be * specified. */ if ((ie->ie_aalp_4_fwd_max_sdu != T_ATM_ABSENT && ie->ie_aalp_4_bkwd_max_sdu == T_ATM_ABSENT) || (ie->ie_aalp_4_fwd_max_sdu == T_ATM_ABSENT && ie->ie_aalp_4_bkwd_max_sdu != T_ATM_ABSENT)) { ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; } break; case UNI_IE_AALP_AT_AAL5: /* * Clear the AAL 5 subparameters */ ie->ie_aalp_5_fwd_max_sdu = T_ATM_ABSENT; ie->ie_aalp_5_bkwd_max_sdu = T_ATM_ABSENT; ie->ie_aalp_5_mode = T_ATM_ABSENT; ie->ie_aalp_5_sscs_type = T_ATM_ABSENT; /* * Parse the AAL fields based on their IDs */ if (usf->usf_sig->us_proto == ATM_SIG_UNI30) rc = usf_dec_ie_ident(usf, ie, ie_aal5_tbl_30); else rc = usf_dec_ie_ident(usf, ie, ie_aal5_tbl_31); /* * If either forward or backward maximum SDU * size is specified, the other must also be * specified. */ if ((ie->ie_aalp_5_fwd_max_sdu != T_ATM_ABSENT && ie->ie_aalp_5_bkwd_max_sdu == T_ATM_ABSENT) || (ie->ie_aalp_5_fwd_max_sdu == T_ATM_ABSENT && ie->ie_aalp_5_bkwd_max_sdu != T_ATM_ABSENT)) { ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; } break; case UNI_IE_AALP_AT_AALU: /* * Check user parameter length */ if (ie->ie_length > sizeof(ie->ie_aalp_user_info) + 1) { ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; } /* * Get the user data */ i = 0; while (i < ie->ie_length - 2) { rc = usf_byte(usf, &ie->ie_aalp_user_info[i]); if (rc) break; i++; } break; default: ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; } ie->ie_length++; return(rc); } /* * Decode a user cell rate information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_clrt(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int rc; /* * Clear the IE */ KM_COPY(&ie_clrt_absent, &ie->ie_u.ie_clrt, sizeof(ie_clrt_absent)); /* * Parse the IE using field identifiers */ rc = usf_dec_ie_ident(usf, ie, ie_clrt_tbl); return(rc); } /* * Decode a broadband bearer capability information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_bbcp(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_bbcp_absent, &ie->ie_u.ie_bbcp, sizeof(ie_bbcp_absent)); /* * Get the broadband bearer class */ rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_bbcp_bearer_class = c & UNI_IE_BBCP_BC_MASK; /* * If the broadband bearer class was X, the next * byte has the traffic type and timing requirements */ if (ie->ie_bbcp_bearer_class == UNI_IE_BBCP_BC_BCOB_X && !(c & UNI_IE_EXT_BIT)) { rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_bbcp_traffic_type = (c >> UNI_IE_BBCP_TT_SHIFT) & UNI_IE_BBCP_TT_MASK; ie->ie_bbcp_timing_req = c & UNI_IE_BBCP_TR_MASK; } /* * Get the clipping and user plane connection configuration */ if (c & UNI_IE_EXT_BIT) { rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_bbcp_clipping = (c >> UNI_IE_BBCP_SC_SHIFT) & UNI_IE_BBCP_SC_MASK; ie->ie_bbcp_conn_config = c & UNI_IE_BBCP_CC_MASK; } return(0); } /* * Decode a broadband high layer information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_bhli(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int i, rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_bhli_absent, &ie->ie_u.ie_bhli, sizeof(ie_bhli_absent)); /* * Get the high layer information type */ rc = usf_ext(usf, &i); ie->ie_bhli_type = i & UNI_IE_EXT_MASK; if (rc) return(rc); /* * What comes next depends on the type */ switch (ie->ie_bhli_type) { case UNI_IE_BHLI_TYPE_ISO: case UNI_IE_BHLI_TYPE_USER: /* * ISO or user-specified parameters -- take the * length of information from the IE length */ for (i=0; iie_length-1; i++) { rc = usf_byte(usf, &ie->ie_bhli_info[i]); if (rc) return(rc); } break; case UNI_IE_BHLI_TYPE_HLP: /* * Make sure the IE is long enough for the high * layer profile information, then get it */ if (usf->usf_sig->us_proto != ATM_SIG_UNI30) ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; if (ie->ie_length < UNI_IE_BHLI_HLP_LEN+1) ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; for (i=0; iie_length && iie_bhli_info[i]); if (rc) return(rc); } break; case UNI_IE_BHLI_TYPE_VSA: /* * Make sure the IE is long enough for the vendor- * specific application information, then get it */ if (ie->ie_length < UNI_IE_BHLI_VSA_LEN+1) ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; for (i=0; iie_length && iie_bhli_info[i]); if (rc) return(rc); } break; default: ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; for (i=0; iie_length; i++) { rc = usf_byte(usf, &c); if (rc) return(rc); } } return(0); } /* * Decode a broadband low layer information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_blli(usf, ie) struct usfmt *usf; struct ie_generic *ie; { u_char c, id; int bc, i, rc; u_int ipi; /* * Clear the IE */ KM_COPY(&ie_blli_absent, &ie->ie_u.ie_blli, sizeof(ie_blli_absent)); /* * Get paramteters for the protocol layers as long as * there is still information left in the IE */ bc = ie->ie_length; while (bc) { /* * Get the type and process based on what it is */ rc = usf_byte(usf, &id); if (rc) return(rc); switch (((id & UNI_IE_EXT_MASK) >> UNI_IE_BLLI_LID_SHIFT) & UNI_IE_BLLI_LID_MASK) { case UNI_IE_BLLI_L1_ID: /* * Layer 1 info */ ie->ie_blli_l1_id = id & UNI_IE_BLLI_LP_MASK; bc--; break; case UNI_IE_BLLI_L2_ID: /* * Layer 2 info--contents vary based on type */ ie->ie_blli_l2_id = id & UNI_IE_BLLI_LP_MASK; bc--; if (id & UNI_IE_EXT_BIT) break; switch (ie->ie_blli_l2_id) { case UNI_IE_BLLI_L2P_X25L: case UNI_IE_BLLI_L2P_X25M: case UNI_IE_BLLI_L2P_HDLC1: case UNI_IE_BLLI_L2P_HDLC2: case UNI_IE_BLLI_L2P_HDLC3: case UNI_IE_BLLI_L2P_Q922: case UNI_IE_BLLI_L2P_ISO7776: rc = usf_byte(usf, &c); if (rc) return(rc); bc--; ie->ie_blli_l2_mode = (c >> UNI_IE_BLLI_L2MODE_SHIFT) & UNI_IE_BLLI_L2MODE_MASK; if (!(c & UNI_IE_EXT_BIT)) break; rc = usf_byte(usf, &c); if (rc) return(rc); bc--; ie->ie_blli_l2_window = c & UNI_IE_EXT_MASK; break; case UNI_IE_BLLI_L2P_USER: rc = usf_byte(usf, &c); if (rc) return(rc); bc--; ie->ie_blli_l2_user_proto = c & UNI_IE_EXT_MASK; break; } break; case UNI_IE_BLLI_L3_ID: /* * Layer 3 info--contents vary based on type */ ie->ie_blli_l3_id = id & UNI_IE_BLLI_LP_MASK; bc--; switch (ie->ie_blli_l3_id) { case UNI_IE_BLLI_L3P_X25: case UNI_IE_BLLI_L3P_ISO8208: case UNI_IE_BLLI_L3P_ISO8878: rc = usf_byte(usf, &c); if (rc) return(rc); bc--; ie->ie_blli_l3_mode = (c >> UNI_IE_BLLI_L3MODE_SHIFT) & UNI_IE_BLLI_L3MODE_MASK; if (!(c & UNI_IE_EXT_BIT)) break; rc = usf_byte(usf, &c); if (rc) return(rc); bc--; ie->ie_blli_l3_packet_size = c & UNI_IE_BLLI_L3PS_MASK; if (!(c & UNI_IE_EXT_BIT)) break; rc = usf_byte(usf, &c); if (rc) return(rc); bc--; ie->ie_blli_l3_window = c & UNI_IE_EXT_MASK; break; case UNI_IE_BLLI_L3P_USER: rc = usf_byte(usf, &c); if (rc) return(rc); bc--; ie->ie_blli_l3_mode = c & UNI_IE_EXT_MASK; break; case UNI_IE_BLLI_L3P_ISO9577: rc = usf_ext(usf, &ipi); if (rc) return(rc); bc -= 2; ie->ie_blli_l3_ipi = ipi >> UNI_IE_BLLI_L3IPI_SHIFT; if (ie->ie_blli_l3_ipi != UNI_IE_BLLI_L3IPI_SNAP) break; rc = usf_byte(usf, &c); ie->ie_blli_l3_snap_id = c & UNI_IE_EXT_MASK; if (rc) return(rc); bc --; rc = usf_byte(usf, &ie->ie_blli_l3_oui[0]); if (rc) return(rc); rc = usf_byte(usf, &ie->ie_blli_l3_oui[1]); if (rc) return(rc); rc = usf_byte(usf, &ie->ie_blli_l3_oui[2]); if (rc) return(rc); rc = usf_byte(usf, &ie->ie_blli_l3_pid[0]); if (rc) return(rc); rc = usf_byte(usf, &ie->ie_blli_l3_pid[1]); if (rc) return(rc); bc -= 5; break; } break; default: ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; for (i=0; iie_length; i++) { rc = usf_byte(usf, &c); if (rc) return(rc); } } } return(0); } /* * Decode a call state information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_clst(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_clst_absent, &ie->ie_u.ie_clst, sizeof(ie_clst_absent)); rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_clst_state = c & UNI_IE_CLST_STATE_MASK; return(0); } /* * Decode a called party number information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_cdad(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int len, rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_cdad_absent, &ie->ie_u.ie_cdad, sizeof(ie_cdad_absent)); /* * Get and check the numbering plan */ rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_cdad_plan = c & UNI_IE_CDAD_PLAN_MASK; len = ie->ie_length - 1; switch (ie->ie_cdad_plan) { case UNI_IE_CDAD_PLAN_E164: ie->ie_cdad_addr.address_format = T_ATM_E164_ADDR; break; case UNI_IE_CDAD_PLAN_NSAP: ie->ie_cdad_addr.address_format = T_ATM_ENDSYS_ADDR; break; default: /* * Invalid numbering plan */ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; while (len) { rc = usf_byte(usf, &c); if (rc) return(rc); len--; } return(0); } /* * Get the ATM address */ rc = usf_dec_atm_addr(usf, &ie->ie_cdad_addr, len); if (rc == EINVAL) { ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; rc = 0; } return(rc); } /* * Decode a called party subaddress information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_cdsa(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int len, rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_cdsa_absent, &ie->ie_u.ie_cdsa, sizeof(ie_cdsa_absent)); /* * Get and check the subaddress type */ rc = usf_byte(usf, &c); if (rc) return(rc); len = ie->ie_length - 1; if (((c >> UNI_IE_CDSA_TYPE_SHIFT) & UNI_IE_CDSA_TYPE_MASK) != UNI_IE_CDSA_TYPE_AESA) { /* * Invalid subaddress type */ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; while (len) { rc = usf_byte(usf, &c); if (rc) return(rc); len--; } return(0); } /* * Get the ATM address */ ie->ie_cdsa_addr.address_format = T_ATM_ENDSYS_ADDR; rc = usf_dec_atm_addr(usf, &ie->ie_cdsa_addr, len); if (rc == EINVAL) { ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; rc = 0; } return(rc); } /* * Decode a calling party number information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_cgad(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int len, rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_cgad_absent, &ie->ie_u.ie_cgad, sizeof(ie_cgad_absent)); /* * Get and check the numbering plan */ len = ie->ie_length; rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_cgad_type = (c >> UNI_IE_CGAD_TYPE_SHIFT) & UNI_IE_CGAD_TYPE_MASK; ie->ie_cgad_plan = c & UNI_IE_CGAD_PLAN_MASK; len--; switch (ie->ie_cgad_plan) { case UNI_IE_CGAD_PLAN_E164: ie->ie_cgad_addr.address_format = T_ATM_E164_ADDR; break; case UNI_IE_CGAD_PLAN_NSAP: ie->ie_cgad_addr.address_format = T_ATM_ENDSYS_ADDR; break; default: ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; while (len) { rc = usf_byte(usf, &c); if (rc) return(rc); len--; } return(0); } /* * Get the presentation and screening indicators, if present */ if (!(c & UNI_IE_EXT_BIT)) { rc = usf_byte(usf, &c); if (rc) return(rc); len--; ie->ie_cgad_pres_ind = (c >> UNI_IE_CGAD_PRES_SHIFT) & UNI_IE_CGAD_PRES_MASK; ie->ie_cgad_screen_ind = c & UNI_IE_CGAD_SCR_MASK; } else { ie->ie_cgad_pres_ind = 0; ie->ie_cgad_screen_ind =0; } /* * Get the ATM address */ rc = usf_dec_atm_addr(usf, &ie->ie_cgad_addr, len); if (rc == EINVAL) { ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; rc = 0; } return(rc); } /* * Decode a calling party subaddress information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_cgsa(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int len, rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_cgsa_absent, &ie->ie_u.ie_cgsa, sizeof(ie_cgsa_absent)); /* * Get and check the subaddress type */ rc = usf_byte(usf, &c); if (rc) return(rc); len = ie->ie_length - 1; if (((c >> UNI_IE_CGSA_TYPE_SHIFT) & UNI_IE_CGSA_TYPE_MASK) != UNI_IE_CGSA_TYPE_AESA) { /* * Invalid subaddress type */ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; while (len) { rc = usf_byte(usf, &c); if (rc) return(rc); len--; } return(0); } /* * Get the ATM address */ ie->ie_cgsa_addr.address_format = T_ATM_ENDSYS_ADDR; rc = usf_dec_atm_addr(usf, &ie->ie_cgsa_addr, len); if (rc == EINVAL) { ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; rc = 0; } return(rc); } /* * Decode a cause information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_caus(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int i, len, rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_caus_absent, &ie->ie_u.ie_caus, sizeof(ie_caus_absent)); /* * Get the cause location */ rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_caus_loc = c & UNI_IE_CAUS_LOC_MASK; /* * Get the cause value */ rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_caus_cause = c & UNI_IE_EXT_MASK; /* * Get any included diagnostics */ len = ie->ie_length - 2; for (i = 0, ie->ie_caus_diag_len = 0; len && i < sizeof(ie->ie_caus_diagnostic); len--, i++, ie->ie_caus_diag_len++) { rc = usf_byte(usf, &ie->ie_caus_diagnostic[i]); if (rc) return(rc); } return(0); } /* * Decode a conection identifier information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_cnid(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int i, rc; /* * Clear the IE */ KM_COPY(&ie_cnid_absent, &ie->ie_u.ie_cnid, sizeof(ie_cnid_absent)); rc = usf_ext(usf, &i); if (rc) return(rc); ie->ie_cnid_vp_sig = (i >> UNI_IE_CNID_VPSIG_SHIFT) & UNI_IE_CNID_VPSIG_MASK; ie->ie_cnid_pref_excl = i & UNI_IE_CNID_PREX_MASK; rc = usf_short(usf, &ie->ie_cnid_vpci); if (rc) return(rc); rc = usf_short(usf, &ie->ie_cnid_vci); return(rc); } /* * Decode a quality of service parameters information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_qosp(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int rc; /* * Clear the IE */ KM_COPY(&ie_qosp_absent, &ie->ie_u.ie_qosp, sizeof(ie_qosp_absent)); /* * Get forward QoS class */ rc = usf_byte(usf, &ie->ie_qosp_fwd_class); if (rc) return(rc); /* * Get backward QoS class */ rc = usf_byte(usf, &ie->ie_qosp_bkwd_class); return(rc); } /* * Decode a broadband repeat indicator information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_brpi(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_brpi_absent, &ie->ie_u.ie_brpi, sizeof(ie_brpi_absent)); /* * Get the repeat indicator */ rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_brpi_ind = c & UNI_IE_BRPI_IND_MASK; return(0); } /* * Decode a restart indicator information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_rsti(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_rsti_absent, &ie->ie_u.ie_rsti, sizeof(ie_rsti_absent)); /* * Get the restart class */ rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_rsti_class = c & UNI_IE_RSTI_CLASS_MASK; return(0); } /* * Decode a broadband sending complete information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a broadband sending complete IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_bsdc(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_bsdc_absent, &ie->ie_u.ie_bsdc, sizeof(ie_bsdc_absent)); /* * Get the sending complete indicator */ rc = usf_byte(usf, &c); if (rc) return(rc); /* * Validate the indicator */ c &= UNI_IE_EXT_MASK; if (c != UNI_IE_BSDC_IND) ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; ie->ie_bsdc_ind = c; return(0); } /* * Decode a transit network selection information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a transit network selection IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_trnt(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int i, len, rc; u_char c; /* * Clear the IE */ KM_COPY(&ie_trnt_absent, &ie->ie_u.ie_trnt, sizeof(ie_trnt_absent)); /* * Get the network ID type and plan */ rc = usf_byte(usf, &c); if (rc) return(rc); ie->ie_trnt_id_type = (c >> UNI_IE_TRNT_IDT_SHIFT) & UNI_IE_TRNT_IDT_MASK; ie->ie_trnt_id_plan = c & UNI_IE_TRNT_IDP_MASK; /* * Get the length of the network ID */ len = ie->ie_length - 1; ie->ie_trnt_id_len = MIN(len, sizeof(ie->ie_trnt_id)); /* * Get the network ID */ for (i=0; iie_trnt_id)) rc = usf_byte(usf, &ie->ie_trnt_id[i]); else rc = usf_byte(usf, &c); if (rc) return(rc); } return(0); } /* * Decode an unimplemented information element * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_uimp(usf, ie) struct usfmt *usf; struct ie_generic *ie; { int i, rc; u_char c; /* * Skip over the IE contents */ for (i=0; iie_length; i++) { rc = usf_byte(usf, &c); if (rc) return(rc); } return(0); } /* * Decode an information element using field identifiers * * The AAL parameters and ATM user cell rate IEs are formatted * with a one-byte identifier preceding each field. The routine * parses these IEs by using a table which relates the field * identifiers with the fields in the appropriate IE structure. * Field order in the received message is immaterial. * * Arguments: * usf pointer to a unisig formatting structure * ie pointer to a cell rate IE structure * tbl pointer to an IE decoding table * * Returns: * 0 success * errno error encountered * */ static int usf_dec_ie_ident(usf, ie, tbl) struct usfmt *usf; struct ie_generic *ie; struct ie_decode_tbl *tbl; { int i, len, rc; u_char c; u_int8_t cv; u_int16_t sv; u_int32_t iv; void *dest; /* * Scan through the IE */ len = ie->ie_length; while (len) { /* * Get the field identifier */ rc = usf_byte(usf, &c); if (rc) return(rc); len--; /* * Look up the field in the table */ for (i=0; (tbl[i].ident != c) && tbl[i].len; i++) { } if (tbl[i].ident == 0) { /* * Bad subfield identifier -- flag an * error and skip over the rest of the IE */ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; while (len) { rc = usf_byte(usf, &c); if (rc) return(rc); } return(0); } /* * Save final destination address */ dest = (void *)((int)ie + tbl[i].f_offs); /* * Get the field value */ switch (tbl[i].len) { case 0: cv = 1; goto savec; case 1: rc = usf_byte(usf, &cv); if (rc) break; savec: /* * Save field value */ switch (tbl[i].f_size) { case 1: *(u_int8_t *)dest = cv; break; case 2: *(u_int16_t *)dest = cv; break; case 4: *(u_int32_t *)dest = cv; break; default: goto badtbl; } break; case 2: rc = usf_short(usf, &sv); if (rc) break; /* * Save field value */ switch (tbl[i].f_size) { case 2: *(u_int16_t *)dest = sv; break; case 4: *(u_int32_t *)dest = sv; break; default: goto badtbl; } break; case 3: rc = usf_int3(usf, &iv); goto savei; case 4: rc = usf_int(usf, &iv); savei: /* * Save field value */ if (rc) break; switch (tbl[i].f_size) { case 4: *(u_int32_t *)dest = iv; break; default: goto badtbl; } break; default: badtbl: log(LOG_ERR, "uni decode: id=%d,len=%d,off=%d,size=%d\n", tbl[i].ident, tbl[i].len, tbl[i].f_offs, tbl[i].f_size); rc = EFAULT; break; } if (rc) return(rc); len -= tbl[i].len; } return(0); } /* * Decode an ATM address * * Arguments: * usf pointer to a unisig formatting structure * addr pointer to an ATM address structure * len length of data remainig in the IE * * Returns: * 0 success * errno error encountered * */ static int usf_dec_atm_addr(usf, addr, len) struct usfmt *usf; Atm_addr *addr; int len; { int rc; u_char c, *cp; /* * Check the address type */ addr->address_length = len; switch (addr->address_format) { case T_ATM_E164_ADDR: if (len > sizeof(Atm_addr_e164)) { goto flush; } cp = (u_char *) addr->address; break; case T_ATM_ENDSYS_ADDR: if (len != sizeof(Atm_addr_nsap)) { goto flush; } cp = (u_char *) addr->address; break; default: /* Silence the compiler */ cp = NULL; } /* * Get the ATM address */ while (len) { rc = usf_byte(usf, cp); if (rc) return(rc); len--; cp++; } return(0); flush: while (len) { rc = usf_byte(usf, &c); if (rc) return(rc); len--; } return(EINVAL); }