1701 lines
32 KiB
C
1701 lines
32 KiB
C
/*
|
|
*
|
|
* ===================================
|
|
* HARP | Host ATM Research Platform
|
|
* ===================================
|
|
*
|
|
*
|
|
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
|
* made available by Network Computing Services, Inc. ("NetworkCS")
|
|
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
|
* support of any kind.
|
|
*
|
|
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
|
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
|
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
|
* In no event shall NetworkCS be responsible for any damages, including
|
|
* but not limited to consequential damages, arising from or relating to
|
|
* any use of the Software or related support.
|
|
*
|
|
* Copyright 1994-1998 Network Computing Services, Inc.
|
|
*
|
|
* Copies of this Software may be made, however, the above copyright
|
|
* notice must be reproduced on all copies.
|
|
*
|
|
* @(#) $FreeBSD$
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* ATM Forum UNI 3.0/3.1 Signalling Manager
|
|
* ----------------------------------------
|
|
*
|
|
* Message formatting module
|
|
*
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/types.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/time.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/socketvar.h>
|
|
#include <sys/syslog.h>
|
|
#include <net/if.h>
|
|
#include <netatm/port.h>
|
|
#include <netatm/queue.h>
|
|
#include <netatm/atm.h>
|
|
#include <netatm/atm_sys.h>
|
|
#include <netatm/atm_sap.h>
|
|
#include <netatm/atm_cm.h>
|
|
#include <netatm/atm_if.h>
|
|
#include <netatm/atm_vc.h>
|
|
#include <netatm/atm_sigmgr.h>
|
|
#include <netatm/atm_stack.h>
|
|
#include <netatm/atm_pcb.h>
|
|
#include <netatm/atm_var.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>
|
|
|
|
#ifndef lint
|
|
__RCSID("@(#) $FreeBSD$");
|
|
#endif
|
|
|
|
|
|
/*
|
|
* 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=%p, msg=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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=%p, ie=%p\n",
|
|
usf, 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 preceding 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=%p, ie=%p, tbl=%p\n",
|
|
usf, ie, 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);
|
|
}
|