diff options
Diffstat (limited to 'sys/netatm/uni/unisig_decode.c')
-rw-r--r-- | sys/netatm/uni/unisig_decode.c | 2474 |
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); +} |