summaryrefslogtreecommitdiffstats
path: root/sys/netatm/uni/unisig_decode.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/uni/unisig_decode.c')
-rw-r--r--sys/netatm/uni/unisig_decode.c2474
1 files changed, 2474 insertions, 0 deletions
diff --git a/sys/netatm/uni/unisig_decode.c b/sys/netatm/uni/unisig_decode.c
new file mode 100644
index 0000000..98f5dfd
--- /dev/null
+++ b/sys/netatm/uni/unisig_decode.c
@@ -0,0 +1,2474 @@
+/*
+ *
+ * ===================================
+ * 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.
+ *
+ * @(#) $Id: unisig_decode.c,v 1.13 1998/08/26 23:29:20 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Message formatting module
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_decode.c,v 1.13 1998/08/26 23:29:20 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+#include <netatm/uni/unisig_mbuf.h>
+#include <netatm/uni/unisig_decode.h>
+
+#define ALLOC_IE(ie) \
+ (ie) = (struct ie_generic *) atm_allocate(&unisig_iepool); \
+ if (!ie) \
+ return(ENOMEM);
+
+
+/*
+ * Local functions
+ */
+static int usf_dec_ie __P((struct usfmt *, struct unisig_msg *, struct ie_generic *));
+static int usf_dec_ie_hdr __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_aalp __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_clrt __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_bbcp __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_bhli __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_blli __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_clst __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_cdad __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_cdsa __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_cgad __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_cgsa __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_caus __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_cnid __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_qosp __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_brpi __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_rsti __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_bsdc __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_trnt __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_uimp __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_ident __P((struct usfmt *, struct ie_generic *,
+ struct ie_decode_tbl *));
+static int usf_dec_atm_addr __P((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=0x%x, msg=0x%x\n", (int) usf,
+ (int) 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; i<UNI_MSG_IE_CNT-1; i++) {
+ switch(ie_tbl[i]) {
+ case IE_MAND:
+ if (!msg->msg_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; i<ie->ie_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; i<ie->ie_length &&
+ i<UNI_IE_BHLI_HLP_LEN; i++) {
+ rc = usf_byte(usf, &ie->ie_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; i<ie->ie_length &&
+ i<UNI_IE_BHLI_VSA_LEN; i++) {
+ rc = usf_byte(usf, &ie->ie_bhli_info[i]);
+ if (rc)
+ return(rc);
+ }
+ break;
+ default:
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ for (i=0; i<ie->ie_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; i<ie->ie_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; i<len; i++) {
+ if (i<sizeof(ie->ie_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; i<ie->ie_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 preceeding 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);
+}
OpenPOWER on IntegriCloud