diff options
Diffstat (limited to 'sys/netatm/uni/unisig_encode.c')
-rw-r--r-- | sys/netatm/uni/unisig_encode.c | 1681 |
1 files changed, 1681 insertions, 0 deletions
diff --git a/sys/netatm/uni/unisig_encode.c b/sys/netatm/uni/unisig_encode.c new file mode 100644 index 000000000000..0920accf8122 --- /dev/null +++ b/sys/netatm/uni/unisig_encode.c @@ -0,0 +1,1681 @@ +/* + * + * =================================== + * 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_encode.c,v 1.11 1998/08/26 23:29:21 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message formatting module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_encode.c,v 1.11 1998/08/26 23:29:21 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> + + +/* + * Local functions + */ +static int usf_enc_ie __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_aalp __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_clrt __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_bbcp __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_bhli __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_blli __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_clst __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_cdad __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_cdsa __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_cgad __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_cgsa __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_caus __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_cnid __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_qosp __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_brpi __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_rsti __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_bsdc __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_trnt __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_uimp __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_ident __P((struct usfmt *, struct ie_generic *, + struct ie_decode_tbl *)); +static int usf_enc_atm_addr __P((struct usfmt *, Atm_addr *)); + + +/* + * Local variables + */ +static struct { + u_char ident; /* IE identifier */ + int (*encode) __P((struct usfmt *, struct ie_generic *)); + /* Encoding function */ +} ie_table[] = { + { UNI_IE_AALP, usf_enc_ie_aalp }, + { UNI_IE_CLRT, usf_enc_ie_clrt }, + { UNI_IE_BBCP, usf_enc_ie_bbcp }, + { UNI_IE_BHLI, usf_enc_ie_bhli }, + { UNI_IE_BLLI, usf_enc_ie_blli }, + { UNI_IE_CLST, usf_enc_ie_clst }, + { UNI_IE_CDAD, usf_enc_ie_cdad }, + { UNI_IE_CDSA, usf_enc_ie_cdsa }, + { UNI_IE_CGAD, usf_enc_ie_cgad }, + { UNI_IE_CGSA, usf_enc_ie_cgsa }, + { UNI_IE_CAUS, usf_enc_ie_caus }, + { UNI_IE_CNID, usf_enc_ie_cnid }, + { UNI_IE_QOSP, usf_enc_ie_qosp }, + { UNI_IE_BRPI, usf_enc_ie_brpi }, + { UNI_IE_RSTI, usf_enc_ie_rsti }, + { UNI_IE_BLSH, usf_enc_ie_uimp }, + { UNI_IE_BNSH, usf_enc_ie_uimp }, + { UNI_IE_BSDC, usf_enc_ie_bsdc }, + { UNI_IE_TRNT, usf_enc_ie_trnt }, + { UNI_IE_EPRF, usf_enc_ie_uimp }, + { UNI_IE_EPST, usf_enc_ie_uimp }, + { 0, 0 } +}; + +extern struct ie_decode_tbl ie_aal1_tbl[]; +extern struct ie_decode_tbl ie_aal4_tbl_30[]; +extern struct ie_decode_tbl ie_aal4_tbl_31[]; +extern struct ie_decode_tbl ie_aal5_tbl_30[]; +extern struct ie_decode_tbl ie_aal5_tbl_31[]; +extern struct ie_decode_tbl ie_clrt_tbl[]; + + +/* + * Encode 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_enc_msg(usf, msg) + struct usfmt *usf; + struct unisig_msg *msg; +{ + int i, len, rc; + u_char c; + u_char *lp0, *lp1; + struct ie_generic *ie; + + union { + short s; + u_char sb[sizeof(short)]; + } su; + + ATM_DEBUG2("usf_enc_msg: usf=0x%x, msg=0x%x\n", + (int)usf, (int)msg); + + /* + * Encode the protocol discriminator + */ + c = UNI_MSG_DISC_Q93B; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the call reference length + */ + c = 3; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the call reference + */ + rc = usf_int3(usf, &msg->msg_call_ref); + if (rc) + return(rc); + + /* + * Encode the message type + */ + rc = usf_byte(usf, &msg->msg_type); + if (rc) + return(rc); + + /* + * Encode the message type extension + */ + c = ((msg->msg_type_flag & UNI_MSG_TYPE_FLAG_MASK) << + UNI_MSG_TYPE_FLAG_SHIFT) + + (msg->msg_type_action & UNI_MSG_TYPE_ACT_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Save the location of the message length and encode a length + * of zero for now. We'll fix the length up at the end. + */ + su.s = 0; + rc = usf_byte_mark(usf, &su.sb[sizeof(short)-2], &lp0); + if (rc) + return(rc); + rc = usf_byte_mark(usf, &su.sb[sizeof(short)-1], &lp1); + if (rc) + return(rc); + + /* + * Process information elements + */ + len = 0; + for (i=0; i<UNI_MSG_IE_CNT; i++) { + ie = msg->msg_ie_vec[i]; + while (ie) { + rc = usf_enc_ie(usf, ie); + if (rc) + return(rc); + len += (ie->ie_length + UNI_IE_HDR_LEN); + ie = ie->ie_next; + } + } + + /* + * Fix the message length in the encoded message + */ + su.s = htons((u_short)len); + *lp0 = su.sb[sizeof(short)-2]; + *lp1 = su.sb[sizeof(short)-1]; + + return(0); +} + + +/* + * Encode an information element + * + * 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_enc_ie(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + u_char c; + u_char *lp0, *lp1; + + union { + short s; + u_char sb[sizeof(short)]; + } su; + + ATM_DEBUG2("usf_enc_ie: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the IE identifier + */ + rc = usf_byte(usf, &ie->ie_ident); + if (rc) + return(rc); + + /* + * Encode the extended type + */ + c = ((ie->ie_coding & UNI_IE_CODE_MASK) << UNI_IE_CODE_SHIFT) + + ((ie->ie_flag & UNI_IE_FLAG_MASK) << + UNI_IE_FLAG_SHIFT) + + (ie->ie_action & UNI_IE_ACT_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Mark the current location in the output stream. Encode a + * length of zero for now; we'll come back and fix it up at + * the end. + */ + su.s = 0; + rc = usf_byte_mark(usf, &su.sb[sizeof(short)-2], &lp0); + if (rc) + return(rc); + rc = usf_byte_mark(usf, &su.sb[sizeof(short)-1], &lp1); + if (rc) + return(rc); + + /* + * Look up the information element in the table + */ + for (i=0; (ie->ie_ident != ie_table[i].ident) && + (ie_table[i].encode != NULL); i++) { + } + if (ie_table[i].encode == NULL) { + /* + * Unrecognized IE + */ + return(EINVAL); + } + + /* + * Process the IE by calling the function indicated + * in the IE table + */ + rc = ie_table[i].encode(usf, ie); + if (rc) + return(rc); + + /* + * Set the length in the output stream + */ + su.s = htons((u_short)ie->ie_length); + *lp0 = su.sb[sizeof(short)-2]; + *lp1 = su.sb[sizeof(short)-1]; + + return(0); +} + + +/* + * Encode 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_enc_ie_aalp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc = 0; + + ATM_DEBUG2("usf_enc_ie_aalp: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + ie->ie_length = 0; + + /* + * Encode the AAL type + */ + if (ie->ie_aalp_aal_type == T_ATM_ABSENT) + return(0); + rc = usf_byte(usf, &ie->ie_aalp_aal_type); + if (rc) + return(rc); + + /* + * Process based on AAL type + */ + switch (ie->ie_aalp_aal_type) { + case UNI_IE_AALP_AT_AAL1: + rc = usf_enc_ie_ident(usf, ie, ie_aal1_tbl); + break; + case UNI_IE_AALP_AT_AAL3: + if (usf->usf_sig->us_proto == ATM_SIG_UNI30) + rc = usf_enc_ie_ident(usf, ie, ie_aal4_tbl_30); + else + rc = usf_enc_ie_ident(usf, ie, ie_aal4_tbl_31); + break; + case UNI_IE_AALP_AT_AAL5: + if (usf->usf_sig->us_proto == ATM_SIG_UNI30) + rc = usf_enc_ie_ident(usf, ie, ie_aal5_tbl_30); + else + rc = usf_enc_ie_ident(usf, ie, ie_aal5_tbl_31); + break; + case UNI_IE_AALP_AT_AALU: + /* + * Encode the user data + */ + i = 0; + while (i < sizeof(ie->ie_aalp_user_info)) { + rc = usf_byte(usf, &ie->ie_aalp_user_info[i]); + if (rc) + break; + i++; + ie->ie_length++; + } + break; + default: + return(EINVAL); + } + + ie->ie_length++; + return(rc); +} + + +/* + * Encode a user cell rate information element + * + * This routine just encodes the parameters required for best + * effort service. + * + * 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_enc_ie_clrt(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + + ATM_DEBUG2("usf_enc_ie_clrt: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + +#ifdef NOTDEF + /* + * Encode Peak Cell Rate Forward CLP = 0 + 1 + */ + c = UNI_IE_CLRT_FWD_PEAK_01_ID; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + rc = usf_int3(usf, &ie->ie_clrt_fwd_peak_01); + if (rc) + return(rc); + + /* + * Encode Peak Cell Rate Backward CLP = 0 + 1 + */ + c = UNI_IE_CLRT_BKWD_PEAK_01_ID; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + rc = usf_int3(usf, &ie->ie_clrt_bkwd_peak_01); + if (rc) + return(rc); + + /* + * Encode Best Effort Flag + */ + c = UNI_IE_CLRT_BEST_EFFORT_ID; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Set IE length + */ + ie->ie_length = 9; +#endif + + /* + * Encode the user cell rate IE using the table + */ + ie->ie_length = 0; + rc = usf_enc_ie_ident(usf, ie, ie_clrt_tbl); + + return(rc); +} + + +/* + * Encode 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_enc_ie_bbcp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_bbcp: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + ie->ie_length = 0; + + /* + * Encode the broadband bearer class + */ + if (ie->ie_bbcp_bearer_class == T_ATM_ABSENT) + return(0); + c = ie->ie_bbcp_bearer_class & UNI_IE_BBCP_BC_MASK; + 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_length++; + + /* + * 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 = ((ie->ie_bbcp_traffic_type & UNI_IE_BBCP_TT_MASK) << + UNI_IE_BBCP_TT_SHIFT) + + (ie->ie_bbcp_timing_req & + UNI_IE_BBCP_TR_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + + /* + * Encode the clipping and user plane connection configuration + */ + c = ((ie->ie_bbcp_clipping & UNI_IE_BBCP_SC_MASK) << + UNI_IE_BBCP_SC_SHIFT) + + (ie->ie_bbcp_conn_config & + UNI_IE_BBCP_CC_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + return(0); +} + + +/* + * Encode 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_enc_ie_bhli(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + u_int type; + + ATM_DEBUG2("usf_enc_ie_bhli: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + ie->ie_length = 0; + + /* + * Encode the high layer information type + */ + if (ie->ie_bhli_type == T_ATM_ABSENT) + return(0); + type = ie->ie_bhli_type | UNI_IE_EXT_BIT; + rc = usf_ext(usf, &type); + if (rc) + return(rc); + ie->ie_length++; + + /* + * 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); + ie->ie_length++; + } + 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) + return (EINVAL); + for (i=0; i<UNI_IE_BHLI_HLP_LEN; i++) { + rc = usf_byte(usf, &ie->ie_bhli_info[i]); + if (rc) + return(rc); + ie->ie_length++; + } + break; + case UNI_IE_BHLI_TYPE_VSA: + /* + * Make sure the IE is long enough for the vendor- + * specific application information, then get it + */ + for (i=0; i<UNI_IE_BHLI_VSA_LEN; i++) { + rc = usf_byte(usf, &ie->ie_bhli_info[i]); + if (rc) + return(rc); + ie->ie_length++; + } + break; + default: + return(EINVAL); + } + + return(0); +} + + +/* + * Encode 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_enc_ie_blli(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + int rc; + u_int ipi; + + ATM_DEBUG2("usf_enc_ie_blli: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + ie->ie_length = 0; + + /* + * Encode paramteters for whichever protocol layers the + * user specified + */ + + /* + * Layer 1 information + */ + if (ie->ie_blli_l1_id && ie->ie_blli_l1_id != T_ATM_ABSENT) { + c = (UNI_IE_BLLI_L1_ID << UNI_IE_BLLI_LID_SHIFT) + + (ie->ie_blli_l1_id & + UNI_IE_BLLI_LP_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + + /* + * Layer 2 information + */ + if (ie->ie_blli_l2_id && ie->ie_blli_l2_id != T_ATM_ABSENT) { + c = (UNI_IE_BLLI_L2_ID << UNI_IE_BLLI_LID_SHIFT) + + (ie->ie_blli_l2_id & + UNI_IE_BLLI_LP_MASK); + + 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: + /* + * Write the Layer 2 type + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode the Layer 2 mode + */ + if (ie->ie_blli_l2_mode) { + c = (ie->ie_blli_l2_mode & + UNI_IE_BLLI_L2MODE_MASK) << + UNI_IE_BLLI_L2MODE_SHIFT; + if (!ie->ie_blli_l2_window) + c |= UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + + /* + * Encode the Layer 2 window size + */ + if (ie->ie_blli_l2_window) { + c = (ie->ie_blli_l2_window & + UNI_IE_EXT_MASK) + + UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + break; + case UNI_IE_BLLI_L2P_USER: + /* + * Write the Layer 2 type + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode the user-specified layer 2 info + */ + c = (ie->ie_blli_l2_user_proto & + UNI_IE_EXT_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + break; + default: + /* + * Write the Layer 2 type + */ + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + break; + } + } + + /* + * Layer 3 information + */ + if (ie->ie_blli_l3_id && ie->ie_blli_l3_id != T_ATM_ABSENT) { + /* + * Encode the layer 3 protocol ID + */ + c = (UNI_IE_BLLI_L3_ID << UNI_IE_BLLI_LID_SHIFT) + + (ie->ie_blli_l3_id & + UNI_IE_BLLI_LP_MASK); + + /* + * Process other fields based on protocol ID + */ + switch(ie->ie_blli_l3_id) { + case UNI_IE_BLLI_L3P_X25: + case UNI_IE_BLLI_L3P_ISO8208: + case UNI_IE_BLLI_L3P_ISO8878: + /* + * Write the protocol ID + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + if (ie->ie_blli_l3_mode || + ie->ie_blli_l3_packet_size || + ie->ie_blli_l3_window) { + c = (ie->ie_blli_l3_mode & + UNI_IE_BLLI_L3MODE_MASK) << + UNI_IE_BLLI_L3MODE_SHIFT; + if (!ie->ie_blli_l3_packet_size && + !ie->ie_blli_l3_window) + c |= UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + + if (ie->ie_blli_l3_packet_size || + ie->ie_blli_l3_window) { + c = ie->ie_blli_l3_packet_size & + UNI_IE_BLLI_L3PS_MASK; + if (!ie->ie_blli_l3_window) + c |= UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + + if (ie->ie_blli_l3_window) { + c = (ie->ie_blli_l3_window & + UNI_IE_EXT_MASK) + + UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + break; + case UNI_IE_BLLI_L3P_USER: + /* + * Write the protocol ID + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode the user-specified protocol info + */ + c = (ie->ie_blli_l3_user_proto & + UNI_IE_EXT_MASK) + + UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + break; + case UNI_IE_BLLI_L3P_ISO9577: + /* + * Write the protocol ID + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode the IPI + */ + ipi = ie->ie_blli_l3_ipi << + UNI_IE_BLLI_L3IPI_SHIFT; + rc = usf_ext(usf, &ipi); + if (rc) + return(rc); + ie->ie_length += 2; + + if (ie->ie_blli_l3_ipi == + UNI_IE_BLLI_L3IPI_SNAP) { + c = UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + 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); + + ie->ie_length += 6; + } + break; + default: + /* + * Write the layer 3 protocol ID + */ + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + break; + } + } + + return(0); +} + + +/* + * Encode 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_enc_ie_clst(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_clst: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + c = ie->ie_clst_state & UNI_IE_CLST_STATE_MASK; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length = 1; + + return(0); +} + + +/* + * Encode 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_enc_ie_cdad(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + int rc; + + ATM_DEBUG2("usf_enc_ie_cdad: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the numbering plan + */ + switch(ie->ie_cdad_addr.address_format) { + case T_ATM_E164_ADDR: + c = UNI_IE_CDAD_PLAN_E164 + + (UNI_IE_CDAD_TYPE_INTL + << UNI_IE_CDAD_TYPE_SHIFT); + ie->ie_length = sizeof(Atm_addr_e164) + 1; + break; + case T_ATM_ENDSYS_ADDR: + c = UNI_IE_CDAD_PLAN_NSAP + + (UNI_IE_CDAD_TYPE_UNK + << UNI_IE_CDAD_TYPE_SHIFT); + ie->ie_length = sizeof(Atm_addr_nsap) + 1; + break; + default: + return(EINVAL); + } + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the ATM address + */ + rc = usf_enc_atm_addr(usf, &ie->ie_cdad_addr); + + return(rc); +} + + +/* + * Encode 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_enc_ie_cdsa(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + int rc; + + /* + * Encode the subaddress type + */ + switch(ie->ie_cdsa_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + c = UNI_IE_CDSA_TYPE_AESA << UNI_IE_CDSA_TYPE_SHIFT; + ie->ie_length = sizeof(Atm_addr_nsap) + 1; + break; + default: + return(EINVAL); + } + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the ATM address + */ + rc = usf_enc_atm_addr(usf, &ie->ie_cdsa_addr); + + return(rc); +} + + +/* + * Encode 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_enc_ie_cgad(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + int rc; + + ATM_DEBUG2("usf_enc_ie_cgad: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the numbering plan + */ + switch(ie->ie_cgad_addr.address_format) { + case T_ATM_E164_ADDR: + c = UNI_IE_CGAD_PLAN_E164 + + (UNI_IE_CGAD_TYPE_INTL + << UNI_IE_CGAD_TYPE_SHIFT) + + UNI_IE_EXT_BIT; + ie->ie_length = sizeof(Atm_addr_e164) + 1; + break; + case T_ATM_ENDSYS_ADDR: + c = UNI_IE_CGAD_PLAN_NSAP + + (UNI_IE_CGAD_TYPE_UNK + << UNI_IE_CGAD_TYPE_SHIFT) + + UNI_IE_EXT_BIT; + ie->ie_length = sizeof(Atm_addr_nsap) + 1; + break; + default: + return(EINVAL); + } + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the presentation and screening indicators + */ +#ifdef NOTDEF + c = ((ie->ie_cgad_pres_ind & UNI_IE_CGAD_PRES_MASK) + << UNI_IE_CGAD_PRES_SHIFT) + + (ie->ie_cgad_screen_ind & + UNI_IE_CGAD_SCR_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); +#endif + + + /* + * Encode the ATM address + */ + rc = usf_enc_atm_addr(usf, &ie->ie_cgad_addr); + + return(rc); +} + + +/* + * Encode 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_enc_ie_cgsa(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + int rc; + + /* + * Encode the subaddress type + */ + switch(ie->ie_cgsa_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + c = UNI_IE_CGSA_TYPE_AESA << UNI_IE_CGSA_TYPE_SHIFT; + ie->ie_length = sizeof(Atm_addr_nsap) + 1; + break; + default: + return(EINVAL); + } + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the ATM address + */ + rc = usf_enc_atm_addr(usf, &ie->ie_cgsa_addr); + + return(rc); +} + + +/* + * Encode 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_enc_ie_caus(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_caus: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + ie->ie_length = 0; + + /* + * Encode the cause location + */ + c = (ie->ie_caus_loc & UNI_IE_CAUS_LOC_MASK) | UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode the cause value + */ + c = ie->ie_caus_cause | UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode any included diagnostics + */ + for (i = 0; i < ie->ie_caus_diag_len && + i < sizeof(ie->ie_caus_diagnostic); + i++) { + rc = usf_byte(usf, &ie->ie_caus_diagnostic[i]); + if (rc) + return(rc); + ie->ie_length++; + } + + return(0); +} + + +/* + * Encode 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_enc_ie_cnid(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_cnid: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + c = ((ie->ie_cnid_vp_sig & UNI_IE_CNID_VPSIG_MASK) + << UNI_IE_CNID_VPSIG_SHIFT) + + (ie->ie_cnid_pref_excl & UNI_IE_CNID_PREX_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + rc = usf_short(usf, &ie->ie_cnid_vpci); + if (rc) + return(rc); + rc = usf_short(usf, &ie->ie_cnid_vci); + if (rc) + return(rc); + + ie->ie_length = 5; + return(0); +} + + +/* + * Encode 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_enc_ie_qosp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + + ATM_DEBUG2("usf_enc_ie_qosp: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode forward QoS class + */ + if (ie->ie_qosp_fwd_class == T_ATM_ABSENT || + ie->ie_qosp_bkwd_class == T_ATM_ABSENT) + return(0); + rc = usf_byte(usf, &ie->ie_qosp_fwd_class); + if (rc) + return(rc); + + /* + * Encode backward QoS class + */ + rc = usf_byte(usf, &ie->ie_qosp_bkwd_class); + + ie->ie_length = 2; + return(rc); +} + + +/* + * Encode 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_enc_ie_brpi(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_brpi: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the repeat indicator + */ + c = ie->ie_brpi_ind + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + + return(rc); +} + + +/* + * Encode 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_enc_ie_rsti(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_rsti: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the restart class + */ + c = (ie->ie_rsti_class & UNI_IE_RSTI_CLASS_MASK) | + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + ie->ie_length = 1; + + return(rc); +} + + +/* + * Encode 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_enc_ie_bsdc(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_bsdc: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the sending complete indicator + */ + c = UNI_IE_BSDC_IND | UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + ie->ie_length = 1; + + return(rc); +} + + +/* + * Encode a transit network selection information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a transit network selection rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_trnt(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_trnt: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the sending complete indicator + */ + c = ((ie->ie_trnt_id_type & UNI_IE_TRNT_IDT_MASK) << + UNI_IE_TRNT_IDT_SHIFT) + + (ie->ie_trnt_id_plan & UNI_IE_TRNT_IDP_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length = 1; + + /* + * Encode the network identification + */ + for (i=0; i<ie->ie_trnt_id_len; i++) { + rc = usf_byte(usf, &ie->ie_trnt_id[i]); + if (rc) + return(rc); + ie->ie_length++; + } + + return(rc); +} + + +/* + * Encode an unsupported IE type + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to an IE structure + * + * Returns: + * 0 success + * + */ +static int +usf_enc_ie_uimp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + return(0); +} + + +/* + * Encode 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 + * encodes these IEs by using a table which relates the field + * identifiers with the fields in the appropriate IE structure. + * + * 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_enc_ie_ident(usf, ie, tbl) + struct usfmt *usf; + struct ie_generic *ie; + struct ie_decode_tbl *tbl; +{ + int i, len, rc; + char *cp; + u_int8_t cv; + u_int16_t sv; + u_int32_t iv; + + ATM_DEBUG3("usf_enc_ie_ident: usf=0x%x, ie=0x%x, tbl=0x%x\n", + (int)usf, (int)ie, (int)tbl); + + /* + * Scan through the IE table + */ + len = 0; + for (i=0; tbl[i].ident; i++) { + /* + * Check whether to send the field + */ + cp = (char *) ((int)ie + tbl[i].f_offs); + if (tbl[i].len == 0) { + if ((*cp == T_NO || *cp == T_ATM_ABSENT)) + continue; + } else { + switch (tbl[i].f_size) { + case 1: + if (*(int8_t *)cp == T_ATM_ABSENT) + continue; + break; + case 2: + if (*(int16_t *)cp == T_ATM_ABSENT) + continue; + break; + case 4: + if (*(int32_t *)cp == T_ATM_ABSENT) + continue; + break; + default: +badtbl: + log(LOG_ERR, + "uni encode: id=%d,len=%d,off=%d,size=%d\n", + tbl[i].ident, tbl[i].len, + tbl[i].f_offs, tbl[i].f_size); + return (EFAULT); + } + } + + /* + * Encode the field identifier + */ + rc = usf_byte(usf, &tbl[i].ident); + if (rc) + return(rc); + len++; + + /* + * Encode the field value + */ + switch (tbl[i].len) { + case 0: + break; + case 1: + switch (tbl[i].f_size) { + case 1: + cv = *(u_int8_t *)cp; + break; + case 2: + cv = *(u_int16_t *)cp; + break; + case 4: + cv = *(u_int32_t *)cp; + break; + default: + goto badtbl; + } + rc = usf_byte(usf, &cv); + break; + + case 2: + switch (tbl[i].f_size) { + case 2: + sv = *(u_int16_t *)cp; + break; + case 4: + sv = *(u_int32_t *)cp; + break; + default: + goto badtbl; + } + rc = usf_short(usf, &sv); + break; + + case 3: + switch (tbl[i].f_size) { + case 4: + iv = *(u_int32_t *)cp; + break; + default: + goto badtbl; + } + rc = usf_int3(usf, &iv); + break; + + case 4: + switch (tbl[i].f_size) { + case 4: + iv = *(u_int32_t *)cp; + break; + default: + goto badtbl; + } + rc = usf_int(usf, &iv); + break; + + default: + goto badtbl; + } + + len += tbl[i].len; + + if (rc) + return(rc); + } + + ie->ie_length = len; + return(0); +} + + +/* + * Encode an ATM address + * + * Arguments: + * usf pointer to a unisig formatting structure + * addr pointer to an ATM address structure. The address + * type must already be set correctly. + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_atm_addr(usf, addr) + struct usfmt *usf; + Atm_addr *addr; +{ + int len, rc; + u_char *cp; + + /* + * Check the address type + */ + switch (addr->address_format) { + case T_ATM_E164_ADDR: + cp = (u_char *) addr->address; + len = sizeof(Atm_addr_e164); + break; + case T_ATM_ENDSYS_ADDR: + cp = (u_char *) addr->address; + len = sizeof(Atm_addr_nsap); + break; + default: + return(EINVAL); + } + + /* + * Get the address bytes + */ + while (len) { + rc = usf_byte(usf, cp); + if (rc) + return(rc); + len--; + cp++; + } + + return(0); +} |