diff options
Diffstat (limited to 'sys/netatm/uni')
51 files changed, 33369 insertions, 0 deletions
diff --git a/sys/netatm/uni/Makefile b/sys/netatm/uni/Makefile new file mode 100644 index 0000000..5b769b4 --- /dev/null +++ b/sys/netatm/uni/Makefile @@ -0,0 +1,93 @@ +# +# +# =================================== +# 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: Makefile,v 1.6 1998/08/26 23:29:17 mks Exp $ +# +# + +# +# ATM Forum UNI Support +# --------------------- +# +# Source directory Makefile +# +# + +DEFS= + +UNI_HDRS= uni.h +UNI_SRCS= uni_load.c +UNI_OBJS= uni_load.o + +SIG_HDRS= unisig.h unisig_decode.h unisig_mbuf.h \ + unisig_msg.h unisig_print.h unisig_var.h +SIG_SRCS= unisig_decode.c unisig_encode.c unisig_if.c \ + unisig_mbuf.c unisig_msg.c \ + unisig_print.c unisig_proto.c \ + unisig_sigmgr_state.c unisig_subr.c \ + unisig_util.c unisig_vc_state.c +SIG_OBJS= unisig_decode.o unisig_encode.o unisig_if.o \ + unisig_mbuf.o unisig_msg.o \ + unisig_print.o unisig_proto.o \ + unisig_sigmgr_state.o unisig_subr.o \ + unisig_util.o unisig_vc_state.o + +SAAL_HDRS= sscop.h sscop_misc.h sscop_pdu.h sscop_var.h \ + sscf_uni.h sscf_uni_var.h +SAAL_SRCS= sscop.c sscop_lower.c sscop_pdu.c sscop_sigaa.c \ + sscop_sigcpcs.c sscop_subr.c sscop_timer.c sscop_upper.c \ + qsaal1_sigaa.c qsaal1_sigcpcs.c qsaal1_subr.c \ + q2110_sigaa.c q2110_sigcpcs.c q2110_subr.c \ + sscf_uni.c sscf_uni_lower.c sscf_uni_upper.c +SAAL_OBJS= sscop.o sscop_lower.o sscop_pdu.o sscop_sigaa.o \ + sscop_sigcpcs.o sscop_subr.o sscop_timer.o sscop_upper.o \ + qsaal1_sigaa.o qsaal1_sigcpcs.o qsaal1_subr.o \ + q2110_sigaa.o q2110_sigcpcs.o q2110_subr.o \ + sscf_uni.o sscf_uni_lower.o sscf_uni_upper.o + +IP_HDRS= uniip_var.h +IP_SRCS= uniip.c uniarp.c uniarp_cache.c uniarp_input.c \ + uniarp_output.c uniarp_timer.c uniarp_vcm.c +IP_OBJS= uniip.o uniarp.o uniarp_cache.o uniarp_input.o \ + uniarp_output.o uniarp_timer.o uniarp_vcm.o + +HDRS= $(UNI_HDRS) $(SIG_HDRS) $(SAAL_HDRS) $(IP_HDRS) +SRCS= $(UNI_SRCS) $(SIG_SRCS) $(SAAL_SRCS) $(IP_SRCS) +OBJS= $(UNI_OBJS) $(SIG_OBJS) $(SAAL_OBJS) $(IP_OBJS) +MOD= uni_mod.o + +OBJDIR= ../../`../../config/mkobjname -d`/uni + +all $(OBJS) $(MOD) config install clean depend lint load unload: + @if [ -d $(OBJDIR) ]; then \ + echo "cd $(OBJDIR); $(MAKE) $@"; \ + cd $(OBJDIR); \ + $(MAKE) $(MFLAGS) DEFS='$(DEFS)' HDRS='$(HDRS)' SRCS='$(SRCS)' OBJS='$(OBJS)' $@; \ + exit $$?; \ + else \ + echo "Object directory \"$(OBJDIR)\" does not exist."; \ + exit 1; \ + fi + diff --git a/sys/netatm/uni/q2110_sigaa.c b/sys/netatm/uni/q2110_sigaa.c new file mode 100644 index 0000000..357df71 --- /dev/null +++ b/sys/netatm/uni/q2110_sigaa.c @@ -0,0 +1,516 @@ +/* + * + * =================================== + * 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: q2110_sigaa.c,v 1.6 1998/08/26 23:29:18 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.2110 - Process AA-signals (SAP_SSCOP) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: q2110_sigaa.c,v 1.6 1998/08/26 23:29:18 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_resreq_ready __P((struct sscop *, int, int)); +static void sscop_resrsp_inresyn __P((struct sscop *, int, int)); +static void sscop_recrsp_recovrsp __P((struct sscop *, int, int)); +static void sscop_recrsp_inrecov __P((struct sscop *, int, int)); + + +/* + * Stack command state lookup tables + */ +/* SSCOP_INIT */ +static void (*sscop_init_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + sscop_init_inst, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + NULL /* SOS_TERM */ +}; + +/* SSCOP_TERM */ +static void (*sscop_term_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + sscop_term_all, /* SOS_INST */ + sscop_term_all, /* SOS_IDLE */ + sscop_term_all, /* SOS_OUTCONN */ + sscop_term_all, /* SOS_INCONN */ + sscop_term_all, /* SOS_OUTDISC */ + sscop_term_all, /* SOS_OUTRESYN */ + sscop_term_all, /* SOS_INRESYN */ + sscop_term_all, /* SOS_OUTRECOV */ + sscop_term_all, /* SOS_RECOVRSP */ + sscop_term_all, /* SOS_INRECOV */ + sscop_term_all, /* SOS_READY */ + sscop_term_all /* SOS_TERM */ +}; + +/* SSCOP_ESTABLISH_REQ */ +static void (*sscop_estreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + sscop_estreq_idle, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + sscop_estreq_idle, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_ESTABLISH_RSP */ +static void (*sscop_estrsp_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + sscop_estrsp_inconn, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RELEASE_REQ */ +static void (*sscop_relreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + sscop_relreq_outconn, /* SOS_OUTCONN */ + sscop_relreq_inconn, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + sscop_relreq_outconn, /* SOS_OUTRESYN */ + sscop_relreq_outconn, /* SOS_INRESYN */ + sscop_relreq_ready, /* SOS_OUTRECOV */ + sscop_relreq_outconn, /* SOS_RECOVRSP */ + sscop_relreq_outconn, /* SOS_INRECOV */ + sscop_relreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_DATA_REQ */ +static void (*sscop_datreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + sscop_aa_noop_1, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + sscop_datreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RESYNC_REQ */ +static void (*sscop_resreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + sscop_resreq_ready, /* SOS_OUTRECOV */ + sscop_resreq_ready, /* SOS_RECOVRSP */ + sscop_resreq_ready, /* SOS_INRECOV */ + sscop_resreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RESYNC_RSP */ +static void (*sscop_resrsp_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + sscop_resrsp_inresyn, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + sscop_aa_noop_0 /* SOS_TERM */ +}; + +/* SSCOP_RECOVER_RSP */ +static void (*sscop_recrsp_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + sscop_recrsp_recovrsp, /* SOS_RECOVRSP */ + sscop_recrsp_inrecov, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + sscop_aa_noop_0 /* SOS_TERM */ +}; + +/* SSCOP_UNITDATA_REQ */ +static void (*sscop_udtreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + sscop_udtreq_all, /* SOS_IDLE */ + sscop_udtreq_all, /* SOS_OUTCONN */ + sscop_udtreq_all, /* SOS_INCONN */ + sscop_udtreq_all, /* SOS_OUTDISC */ + sscop_udtreq_all, /* SOS_OUTRESYN */ + sscop_udtreq_all, /* SOS_INRESYN */ + sscop_udtreq_all, /* SOS_OUTRECOV */ + sscop_udtreq_all, /* SOS_RECOVRSP */ + sscop_udtreq_all, /* SOS_INRECOV */ + sscop_udtreq_all, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RETRIEVE_REQ */ +static void (*sscop_retreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + NULL /* SOS_TERM */ +}; + + +/* + * Stack command lookup table + */ +void (*(*sscop_q2110_aatab[SSCOP_CMD_SIZE])) + __P((struct sscop *, int, int)) = { + NULL, + sscop_init_tab, + sscop_term_tab, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + sscop_estreq_tab, + NULL, + sscop_estrsp_tab, + NULL, + sscop_relreq_tab, + NULL, + NULL, + sscop_datreq_tab, + NULL, + sscop_resreq_tab, + NULL, + sscop_resrsp_tab, + NULL, + NULL, + sscop_recrsp_tab, + sscop_udtreq_tab, + NULL, + sscop_retreq_tab, + NULL, + NULL +}; + + +/* + * SSCOP_RESYNC_REQ / SOS_READY Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_resreq_ready(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize receiver window + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + /* + * Send first RS PDU + */ + sop->so_connctl = 1; + SEQ_INCR(sop->so_sendconn, 1); + (void) sscop_send_rs(sop); + + /* + * Drain transmit and receive queues + */ + sscop_xmit_drain(sop); + sscop_rcvr_drain(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for RSAK + */ + sop->so_state = SOS_OUTRESYN; + + return; +} + + +/* + * SSCOP_RESYNC_RSP / SOS_INRESYN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 unused + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_resrsp_inresyn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Clear transmitter buffers + */ + q2110_clear_xmit(sop); + + /* + * Initialize state variables + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + q2110_init_state(sop); + + /* + * Send RSAK PDU + */ + (void) sscop_send_rsak(sop); + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Back to data transfer state + */ + sop->so_state = SOS_READY; + + return; +} + + +/* + * SSCOP_RECOVER_RSP / SOS_RECOVRSP Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 unused + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_recrsp_recovrsp(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Clear transmitter buffers, if not done earlier + */ + if (sop->so_flags & SOF_NOCLRBUF) + q2110_clear_xmit(sop); + + /* + * Initialize state variables + */ + q2110_init_state(sop); + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Back to data transfer state + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * SSCOP_RECOVER_RSP / SOS_INRECOV Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 unused + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_recrsp_inrecov(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Clear transmitter buffers, if not done earlier + */ + if (sop->so_flags & SOF_NOCLRBUF) + q2110_clear_xmit(sop); + + /* + * Initialize state variables + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + q2110_init_state(sop); + + /* + * Send ERAK PDU + */ + (void) sscop_send_erak(sop); + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Back to data transfer state + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + diff --git a/sys/netatm/uni/q2110_sigcpcs.c b/sys/netatm/uni/q2110_sigcpcs.c new file mode 100644 index 0000000..0fa5555 --- /dev/null +++ b/sys/netatm/uni/q2110_sigcpcs.c @@ -0,0 +1,1760 @@ +/* + * + * =================================== + * 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: q2110_sigcpcs.c,v 1.7 1998/08/26 23:29:18 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.2110 - Process CPCS-signals (SSCOP PDUs) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: q2110_sigcpcs.c,v 1.7 1998/08/26 23:29:18 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_bgn_outconn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_bgn_inconn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_bgn_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_bgrej_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_end_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_end_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_endak_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_inresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_error __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_idle __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_recovrsp __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_inrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_erak_error __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_erak_idle __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_erak_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_sd_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_poll_ready __P((struct sscop *, KBuffer *, caddr_t)); + + +/* + * PDU type state lookup tables + */ +/* BGN PDU */ +static void (*sscop_bgn_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgn_idle, /* SOS_IDLE */ + sscop_bgn_outconn, /* SOS_OUTCONN */ + sscop_bgn_inconn, /* SOS_INCONN */ + sscop_bgn_outdisc, /* SOS_OUTDISC */ + sscop_bgn_outresyn, /* SOS_OUTRESYN */ + sscop_bgn_inresyn, /* SOS_INRESYN */ + sscop_bgn_inresyn, /* SOS_OUTRECOV */ + sscop_bgn_inresyn, /* SOS_RECOVRSP */ + sscop_bgn_inresyn, /* SOS_INRECOV */ + sscop_bgn_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* BGAK PDU */ +static void (*sscop_bgak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgak_idle, /* SOS_IDLE */ + sscop_bgak_outconn, /* SOS_OUTCONN */ + sscop_bgak_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_bgak_error, /* SOS_INRESYN */ + sscop_bgak_error, /* SOS_OUTRECOV */ + sscop_bgak_error, /* SOS_RECOVRSP */ + sscop_bgak_error, /* SOS_INRECOV */ + sscop_noop, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* BGREJ PDU */ +static void (*sscop_bgrej_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgrej_error, /* SOS_IDLE */ + sscop_bgrej_outconn, /* SOS_OUTCONN */ + sscop_bgrej_inconn, /* SOS_INCONN */ + sscop_endak_outdisc, /* SOS_OUTDISC */ + sscop_bgrej_outresyn, /* SOS_OUTRESYN */ + sscop_bgrej_inconn, /* SOS_INRESYN */ + sscop_bgrej_outrecov, /* SOS_OUTRECOV */ + sscop_bgrej_inconn, /* SOS_RECOVRSP */ + sscop_bgrej_inconn, /* SOS_INRECOV */ + sscop_bgrej_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* END PDU */ +static void (*sscop_end_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_end_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_end_inconn, /* SOS_INCONN */ + sscop_end_outdisc, /* SOS_OUTDISC */ + sscop_end_inconn, /* SOS_OUTRESYN */ + sscop_end_inconn, /* SOS_INRESYN */ + sscop_end_outrecov, /* SOS_OUTRECOV */ + sscop_end_inconn, /* SOS_RECOVRSP */ + sscop_end_inconn, /* SOS_INRECOV */ + sscop_end_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* ENDAK PDU */ +static void (*sscop_endak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_noop, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_endak_inconn, /* SOS_INCONN */ + sscop_endak_outdisc, /* SOS_OUTDISC */ + sscop_endak_inconn, /* SOS_OUTRESYN */ + sscop_endak_inconn, /* SOS_INRESYN */ + sscop_endak_outrecov, /* SOS_OUTRECOV */ + sscop_endak_inconn, /* SOS_RECOVRSP */ + sscop_endak_inconn, /* SOS_INRECOV */ + sscop_endak_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* RS PDU */ +static void (*sscop_rs_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_rs_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_rs_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_rs_outresyn, /* SOS_OUTRESYN */ + sscop_rs_inresyn, /* SOS_INRESYN */ + sscop_rs_outrecov, /* SOS_OUTRECOV */ + sscop_rs_outrecov, /* SOS_RECOVRSP */ + sscop_rs_outrecov, /* SOS_INRECOV */ + sscop_rs_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* RSAK PDU */ +static void (*sscop_rsak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_rsak_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_rsak_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_rsak_outresyn, /* SOS_OUTRESYN */ + sscop_rsak_error, /* SOS_INRESYN */ + sscop_rsak_error, /* SOS_OUTRECOV */ + sscop_rsak_error, /* SOS_RECOVRSP */ + sscop_rsak_error, /* SOS_INRECOV */ + sscop_noop, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* ER PDU */ +static void (*sscop_er_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_er_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_er_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_er_error, /* SOS_INRESYN */ + sscop_er_outrecov, /* SOS_OUTRECOV */ + sscop_er_recovrsp, /* SOS_RECOVRSP */ + sscop_er_inrecov, /* SOS_INRECOV */ + sscop_er_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* ERAK PDU */ +static void (*sscop_erak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_erak_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_erak_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_erak_error, /* SOS_INRESYN */ + sscop_erak_outrecov, /* SOS_OUTRECOV */ + sscop_noop, /* SOS_RECOVRSP */ + sscop_erak_error, /* SOS_INRECOV */ + sscop_noop, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* SD PDU */ +static void (*sscop_sd_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_sd_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_sd_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_sd_inconn, /* SOS_INRESYN */ + sscop_noop, /* SOS_OUTRECOV */ + sscop_noop, /* SOS_RECOVRSP */ + sscop_sd_inconn, /* SOS_INRECOV */ + sscop_sd_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* POLL PDU */ +static void (*sscop_poll_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_poll_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_poll_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_poll_inconn, /* SOS_INRESYN */ + sscop_noop, /* SOS_OUTRECOV */ + sscop_noop, /* SOS_RECOVRSP */ + sscop_poll_inconn, /* SOS_INRECOV */ + sscop_poll_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* STAT PDU */ +static void (*sscop_stat_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_stat_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_stat_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_stat_inconn, /* SOS_INRESYN */ + sscop_noop, /* SOS_OUTRECOV */ + sscop_stat_inconn, /* SOS_RECOVRSP */ + sscop_stat_inconn, /* SOS_INRECOV */ + sscop_stat_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* USTAT PDU */ +static void (*sscop_ustat_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_ustat_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_ustat_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_ustat_inconn, /* SOS_INRESYN */ + sscop_noop, /* SOS_OUTRECOV */ + sscop_ustat_inconn, /* SOS_RECOVRSP */ + sscop_ustat_inconn, /* SOS_INRECOV */ + sscop_ustat_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* UD PDU */ +static void (*sscop_ud_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_ud_all, /* SOS_IDLE */ + sscop_ud_all, /* SOS_OUTCONN */ + sscop_ud_all, /* SOS_INCONN */ + sscop_ud_all, /* SOS_OUTDISC */ + sscop_ud_all, /* SOS_OUTRESYN */ + sscop_ud_all, /* SOS_INRESYN */ + sscop_ud_all, /* SOS_OUTRECOV */ + sscop_ud_all, /* SOS_RECOVRSP */ + sscop_ud_all, /* SOS_INRECOV */ + sscop_ud_all, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* MD PDU */ +static void (*sscop_md_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_md_all, /* SOS_IDLE */ + sscop_md_all, /* SOS_OUTCONN */ + sscop_md_all, /* SOS_INCONN */ + sscop_md_all, /* SOS_OUTDISC */ + sscop_md_all, /* SOS_OUTRESYN */ + sscop_md_all, /* SOS_INRESYN */ + sscop_md_all, /* SOS_OUTRECOV */ + sscop_md_all, /* SOS_RECOVRSP */ + sscop_md_all, /* SOS_INRECOV */ + sscop_md_all, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + + +/* + * PDU type lookup table + */ +void (*(*sscop_q2110_pdutab[])) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, + sscop_bgn_tab, + sscop_bgak_tab, + sscop_end_tab, + sscop_endak_tab, + sscop_rs_tab, + sscop_rsak_tab, + sscop_bgrej_tab, + sscop_sd_tab, + sscop_er_tab, + sscop_poll_tab, + sscop_stat_tab, + sscop_ustat_tab, + sscop_ud_tab, + sscop_md_tab, + sscop_erak_tab +}; + + +/* + * BGN PDU / SOS_OUTCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_bgn_outconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err; + + /* + * If retransmitted BGN, ignore it + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize state variables + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + q2110_init_state(sop); + + /* + * Return an ACK to peer + */ + (void) sscop_send_bgak(sop); + + /* + * Notify user of connection establishment + */ + STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * OK, we're ready for data + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * BGN PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_bgn_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err; + + /* + * If retransmitted BGN, ignore it + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + return; + } + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + /* + * First, tell user current connection has been released + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Now, tell user of new connection establishment + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + return; +} + + +/* + * BGN PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_bgn_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err; + + /* + * If retransmitted BGN, just ACK it again + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + (void) sscop_send_bgak(sop); + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + + /* + * Tell user current connection has been released + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Tell user of incoming connection + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user's response + */ + sop->so_state = SOS_INCONN; + + return; +} + + +/* + * BGREJ PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_bgrej_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Report protocol error + */ + sscop_bgrej_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_end_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct end_pdu *ep = (struct end_pdu *)trlr; + int err, source; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Get Source value + */ + if (ep->end_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_end_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct end_pdu *ep = (struct end_pdu *)trlr; + int err, source; + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Get Source value + */ + if (ep->end_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * ENDAK PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_endak_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Report protocol error + */ + sscop_endak_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * RS PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct rs_pdu *rp = (struct rs_pdu *)trlr; + int err; + + /* + * If retransmitted RS, ignore it + */ + if (sscop_is_rexmit(sop, rp->rs_nsq)) { + KB_FREEALL(m); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize state variables + */ + SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr)); + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + q2110_init_state(sop); + + /* + * Free PDU buffers + */ + KB_FREEALL(m); + + /* + * Return an ACK to peer + */ + (void) sscop_send_rsak(sop); + + /* + * Notify user of connection resynchronization + */ + STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * OK, we're ready for data + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * RS PDU / SOS_INRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_inresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct rs_pdu *rp = (struct rs_pdu *)trlr; + + /* + * If retransmitted RS, ignore it + */ + if (sscop_is_rexmit(sop, rp->rs_nsq)) { + KB_FREEALL(m); + return; + } + + /* + * Report error condition + */ + sscop_rs_error(sop, m, trlr); + + return; +} + + +/* + * RS PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct rs_pdu *rp = (struct rs_pdu *)trlr; + int err; + + /* + * If retransmitted RS, report an error + */ + if (sscop_is_rexmit(sop, rp->rs_nsq)) { + sscop_rs_error(sop, m, trlr); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr)); + + /* + * Notify user of connection resynchronization + */ + STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Wait for user response + */ + sop->so_state = SOS_INRESYN; + + return; +} + + +/* + * RS PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct rs_pdu *rp = (struct rs_pdu *)trlr; + int err; + + /* + * If retransmitted RS, just ACK it + */ + if (sscop_is_rexmit(sop, rp->rs_nsq)) { + KB_FREEALL(m); + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + sscop_send_rsak(sop); + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr)); + + /* + * Notify user of connection resynchronization + */ + STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + + /* + * Wait for user response + */ + sop->so_state = SOS_INRESYN; + + return; +} + +/* + * ER PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'L'); + KB_FREEALL(m); + + return; +} + + +/* + * ER PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_er_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + return; +} + + +/* + * ER PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct er_pdu *ep = (struct er_pdu *)trlr; + int err; + + /* + * If retransmitted ER, report an error + */ + if (sscop_is_rexmit(sop, ep->er_nsq)) { + sscop_er_error(sop, m, trlr); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr)); + + /* + * Initialize receiver window + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + /* + * Free PDU buffers + */ + KB_FREEALL(m); + + /* + * Acknowledge ER + */ + (void) sscop_send_erak(sop); + + /* + * Deliver any outstanding data to user + */ + q2110_deliver_data(sop); + + /* + * Notify user of connection recovery + */ + STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user response + */ + sop->so_state = SOS_RECOVRSP; + + return; +} + + +/* + * ER PDU / SOS_RECOVRSP Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_recovrsp(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct er_pdu *ep = (struct er_pdu *)trlr; + + /* + * If retransmitted ER, just ACK it + */ + if (sscop_is_rexmit(sop, ep->er_nsq)) { + KB_FREEALL(m); + (void) sscop_send_erak(sop); + return; + } + + /* + * Report error condition + */ + sscop_er_error(sop, m, trlr); + + return; +} + + +/* + * ER PDU / SOS_INRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_inrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct er_pdu *ep = (struct er_pdu *)trlr; + + /* + * If retransmitted ER, just ignore it + */ + if (sscop_is_rexmit(sop, ep->er_nsq)) { + KB_FREEALL(m); + return; + } + + /* + * Report error condition + */ + sscop_er_error(sop, m, trlr); + + return; +} + + +/* + * ER PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct er_pdu *ep = (struct er_pdu *)trlr; + int err; + + /* + * If retransmitted ER, just ACK it + */ + if (sscop_is_rexmit(sop, ep->er_nsq)) { + KB_FREEALL(m); + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + sscop_send_erak(sop); + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr)); + + /* + * Free PDU buffers + */ + KB_FREEALL(m); + + /* + * Clear out appropriate queues + */ + q2110_prep_recovery(sop); + + /* + * Deliver any outstanding data to user + */ + q2110_deliver_data(sop); + + /* + * Notify user of connection recovery + */ + STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user response + */ + sop->so_state = SOS_INRECOV; + + return; +} + + +/* + * ERAK PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_erak_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'M'); + KB_FREEALL(m); + + return; +} + + +/* + * ERAK PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_erak_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_erak_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + return; +} + + +/* + * ERAK PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_erak_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct erak_pdu *ep = (struct erak_pdu *)trlr; + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(ep->erak_nmr)); + + /* + * Free PDU buffers + */ + KB_FREEALL(m); + + /* + * Deliver any outstanding data to user + */ + q2110_deliver_data(sop); + + /* + * Notify user of connection recovery + */ + STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user response + */ + sop->so_state = SOS_RECOVRSP; + + return; +} + + +/* + * SD PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_sd_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct sd_pdu *sp = (struct sd_pdu *)trlr; + struct pdu_hdr *php; + KBuffer *n; + sscop_seq ns; + int err, space; + + /* + * Get PDU sequence number + */ + SEQ_SET(ns, ntohl(sp->sd_ns)); + + /* + * Ensure that the sequence number fits within the window + */ + if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) { + /* + * It doesn't, drop received data + */ + KB_FREEALL(m); + + /* + * If next highest PDU hasn't reached window end yet, + * then send a USTAT to inform transmitter of this gap + */ + if (SEQ_LT(sop->so_rcvhigh, sop->so_rcvmax, sop->so_rcvnext)) { + (void) sscop_send_ustat(sop, sop->so_rcvmax); + sop->so_rcvhigh = sop->so_rcvmax; + } + return; + } + + /* + * If this is the next in-sequence PDU, hand it to user + */ + if (ns == sop->so_rcvnext) { + STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, ns, err); + if (err) { + KB_FREEALL(m); + return; + } + + /* + * Bump next expected sequence number + */ + SEQ_INCR(sop->so_rcvnext, 1); + + /* + * Slide receive window down + */ + SEQ_INCR(sop->so_rcvmax, 1); + + /* + * Is this the highest sequence PDU we've received?? + */ + if (ns == sop->so_rcvhigh) { + /* + * Yes, bump the limit and exit + */ + sop->so_rcvhigh = sop->so_rcvnext; + return; + } + + /* + * This is a retransmitted PDU, so see if we have + * more in-sequence PDUs already queued up + */ + while ((php = sop->so_recv_hd) && + (php->ph_ns == sop->so_rcvnext)) { + + /* + * Yup we do, so remove next PDU from queue and + * pass it up to the user as well + */ + sop->so_recv_hd = php->ph_recv_lk; + if (sop->so_recv_hd == NULL) + sop->so_recv_tl = NULL; + STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)php->ph_buf, php->ph_ns, + err); + if (err) { + /* + * Should never happen, but... + */ + KB_FREEALL(php->ph_buf); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Bump next expected sequence number + */ + SEQ_INCR(sop->so_rcvnext, 1); + + /* + * Slide receive window down + */ + SEQ_INCR(sop->so_rcvmax, 1); + } + + /* + * Finished with data delivery... + */ + return; + } + + /* + * We're gonna have to queue this PDU, so find space + * for the PDU header + */ + KB_HEADROOM(m, space); + + /* + * If there's not enough room in the received buffer, + * allocate & link a new buffer for the header + */ + if (space < sizeof(struct pdu_hdr)) { + + KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER); + if (n == NULL) { + KB_FREEALL(m); + return; + } + KB_HEADSET(n, sizeof(struct pdu_hdr)); + KB_LEN(n) = 0; + KB_LINKHEAD(n, m); + m = n; + } + + /* + * Build PDU header + * + * We can at least assume/require that the start of + * the user data is aligned. Also note that we don't + * include this header in the buffer len/offset fields. + */ + KB_DATASTART(m, php, struct pdu_hdr *); + php--; + php->ph_ns = ns; + php->ph_buf = m; + + /* + * Insert PDU into the receive queue + */ + if (sscop_recv_insert(sop, php)) { + /* + * Oops, a duplicate sequence number PDU is already on + * the queue, somethings wrong here. + */ + sscop_maa_error(sop, 'Q'); + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Go into recovery mode + */ + q2110_error_recovery(sop); + + return; + } + + /* + * Are we at the high-water mark?? + */ + if (ns == sop->so_rcvhigh) { + /* + * Yes, just bump the mark + */ + SEQ_INCR(sop->so_rcvhigh, 1); + + return; + } + + /* + * Are we beyond the high-water mark?? + */ + if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) { + /* + * Yes, then there's a missing PDU, so inform the transmitter + */ + (void) sscop_send_ustat(sop, ns); + + /* + * Update high-water mark + */ + sop->so_rcvhigh = SEQ_ADD(ns, 1); + } + + return; +} + + +/* + * POLL PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_poll_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct poll_pdu *pp = (struct poll_pdu *)trlr; + sscop_seq nps; + + NTOHL(pp->poll_ns); + + /* + * If the poll sequence number is less than highest number + * we've already seen, something's wrong + */ + if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) { + /* + * Record error condition + */ + sscop_maa_error(sop, 'Q'); + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Go into recovery mode + */ + q2110_error_recovery(sop); + + return; + } + + /* + * Set a new "next highest" sequence number expected + */ + if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext)) + SEQ_SET(sop->so_rcvhigh, pp->poll_ns); + else + sop->so_rcvhigh = sop->so_rcvmax; + + /* + * Return a STAT PDU to peer + */ + SEQ_SET(nps, ntohl(pp->poll_nps)); + KB_FREEALL(m); + (void) sscop_send_stat(sop, nps); + + return; +} + diff --git a/sys/netatm/uni/q2110_subr.c b/sys/netatm/uni/q2110_subr.c new file mode 100644 index 0000000..4c6036b --- /dev/null +++ b/sys/netatm/uni/q2110_subr.c @@ -0,0 +1,239 @@ +/* + * + * =================================== + * 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: q2110_subr.c,v 1.1 1998/04/07 23:15:20 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.2110 - Subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: q2110_subr.c,v 1.1 1998/04/07 23:15:20 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Conditionally Clear Transmission Queues + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_clear_xmit(sop) + struct sscop *sop; +{ + /* + * Only clear queues if 'Clear Buffers' == No + */ + if (sop->so_flags & SOF_NOCLRBUF) + sscop_xmit_drain(sop); +} + + +/* + * Initialize Data Transfer State Variables + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_init_state(sop) + struct sscop *sop; +{ + /* + * Initialize for entry into Data Transfer Ready state + */ + sop->so_send = 0; + sop->so_pollsend = 0; + sop->so_ack = 0; + sop->so_pollack = 1; + sop->so_polldata = 0; + sop->so_rcvhigh = 0; + sop->so_rcvnext = 0; +} + + +/* + * Prepare Queues for Data Retrieval + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_prep_retrieve(sop) + struct sscop *sop; +{ + /* + * If 'Clear Buffers' == No, just clear retransmit queue, + * else clear all transmission queues + */ + if (sop->so_flags & SOF_NOCLRBUF) { + sop->so_rexmit_hd = NULL; + sop->so_rexmit_tl = NULL; + } else + sscop_xmit_drain(sop); + + /* + * Clear receiver queue + */ + sscop_rcvr_drain(sop); +} + + +/* + * Prepare Queues for Error Recovery + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_prep_recovery(sop) + struct sscop *sop; +{ + /* + * If 'Clear Buffers' == No, just clear retransmit queue, + * else clear all transmission queues + */ + if (sop->so_flags & SOF_NOCLRBUF) { + sop->so_rexmit_hd = NULL; + sop->so_rexmit_tl = NULL; + } else + sscop_xmit_drain(sop); +} + + +/* + * Conditionally Deliver Received Data to User + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_deliver_data(sop) + struct sscop *sop; +{ + /* + * If 'Clear Buffers' == No, give data to user + */ + if (sop->so_flags & SOF_NOCLRBUF) { + /* + * We don't support 'Clear Buffers' == No, so don't bother + */ + } + + /* + * Clear receiver queue + */ + sscop_rcvr_drain(sop); +} + + +/* + * Enter Connection Recovery Mode + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_error_recovery(sop) + struct sscop *sop; +{ + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize receiver window + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + /* + * Send first ER PDU + */ + sop->so_connctl = 1; + SEQ_INCR(sop->so_sendconn, 1); + (void) sscop_send_er(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Clear out appropriate queues + */ + q2110_prep_recovery(sop); + + /* + * Wait for ERAK + */ + sop->so_state = SOS_OUTRECOV; + + return; +} + diff --git a/sys/netatm/uni/qsaal1_sigaa.c b/sys/netatm/uni/qsaal1_sigaa.c new file mode 100644 index 0000000..f3b0097 --- /dev/null +++ b/sys/netatm/uni/qsaal1_sigaa.c @@ -0,0 +1,518 @@ +/* + * + * =================================== + * 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: qsaal1_sigaa.c,v 1.7 1998/08/26 23:29:18 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.SAAL1 - Process AA-signals (SAP_SSCOP) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: qsaal1_sigaa.c,v 1.7 1998/08/26 23:29:18 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_estreq_ready __P((struct sscop *, int, int)); +static void sscop_datreq_outconn __P((struct sscop *, int, int)); +static void sscop_resreq_ready __P((struct sscop *, int, int)); +static void sscop_resrsp_inresyn __P((struct sscop *, int, int)); +static void sscop_resrsp_conresyn __P((struct sscop *, int, int)); + + +/* + * Stack command state lookup tables + */ +/* SSCOP_INIT */ +static void (*sscop_init_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + sscop_init_inst, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + NULL, /* SOS_READY */ + NULL /* SOS_TERM */ +}; + +/* SSCOP_TERM */ +static void (*sscop_term_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + sscop_term_all, /* SOS_INST */ + sscop_term_all, /* SOS_IDLE */ + sscop_term_all, /* SOS_OUTCONN */ + sscop_term_all, /* SOS_INCONN */ + sscop_term_all, /* SOS_OUTDISC */ + sscop_term_all, /* SOS_OUTRESYN */ + sscop_term_all, /* SOS_INRESYN */ + sscop_term_all, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_term_all, /* SOS_READY */ + sscop_term_all /* SOS_TERM */ +}; + +/* SSCOP_ESTABLISH_REQ */ +static void (*sscop_estreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + sscop_estreq_idle, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + sscop_estreq_ready, /* SOS_OUTDISC */ + sscop_estreq_ready, /* SOS_OUTRESYN */ + sscop_estreq_ready, /* SOS_INRESYN */ + sscop_estreq_ready, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_estreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_ESTABLISH_RSP */ +static void (*sscop_estrsp_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + sscop_estrsp_inconn, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_aa_noop_1, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RELEASE_REQ */ +static void (*sscop_relreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + sscop_relreq_outconn, /* SOS_OUTCONN */ + sscop_relreq_inconn, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + sscop_relreq_outconn, /* SOS_OUTRESYN */ + sscop_relreq_ready, /* SOS_INRESYN */ + sscop_relreq_outconn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_relreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_DATA_REQ */ +static void (*sscop_datreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + sscop_datreq_outconn, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + sscop_datreq_ready, /* SOS_INRESYN */ + NULL, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_datreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RESYNC_REQ */ +static void (*sscop_resreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_resreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RESYNC_RSP */ +static void (*sscop_resrsp_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + sscop_resrsp_inresyn, /* SOS_INRESYN */ + sscop_resrsp_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + NULL, /* SOS_READY */ + sscop_aa_noop_0 /* SOS_TERM */ +}; + +/* SSCOP_UNITDATA_REQ */ +static void (*sscop_udtreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + sscop_udtreq_all, /* SOS_IDLE */ + sscop_udtreq_all, /* SOS_OUTCONN */ + sscop_udtreq_all, /* SOS_INCONN */ + sscop_udtreq_all, /* SOS_OUTDISC */ + sscop_udtreq_all, /* SOS_OUTRESYN */ + sscop_udtreq_all, /* SOS_INRESYN */ + sscop_udtreq_all, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_udtreq_all, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + + +/* + * Stack command lookup table + */ +void (*(*sscop_qsaal_aatab[SSCOP_CMD_SIZE])) + __P((struct sscop *, int, int)) = { + NULL, + sscop_init_tab, + sscop_term_tab, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + sscop_estreq_tab, + NULL, + sscop_estrsp_tab, + NULL, + sscop_relreq_tab, + NULL, + NULL, + sscop_datreq_tab, + NULL, + sscop_resreq_tab, + NULL, + sscop_resrsp_tab, + NULL, + NULL, + NULL, + sscop_udtreq_tab, + NULL, + NULL, + NULL, + NULL +}; + + +/* + * SSCOP_ESTABLISH_REQ / SOS_READY Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 buffer release parameter + * + * Returns: + * none + * + */ +static void +sscop_estreq_ready(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * We currently only support BR=YES + */ + if (arg2 != SSCOP_BR_YES) { + sscop_abort(sop, "sscop: BR != YES\n"); + return; + } + + /* + * Stop poll timer + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Stop lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = 0; + + /* + * Initialize receiver window + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + /* + * Send first BGN PDU + */ + sop->so_connctl = 1; + (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER); + + /* + * Reset transmitter state + */ + qsaal1_reset_xmit(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for BGAK + */ + sop->so_state = SOS_OUTCONN; + + return; +} + + +/* + * SSCOP_DATA_REQ / SOS_OUTCONN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing assured user data + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_datreq_outconn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + KBuffer *m = (KBuffer *)arg1; + + /* + * We must have a buffer (even if it contains no data) + */ + if (m == NULL) { + sscop_abort(sop, "sscop_datreq_outconn: no buffer\n"); + return; + } + + /* + * Only accept data here if in the middle of an SSCOP-initiated + * session reestablishment + */ + if ((sop->so_flags & SOF_REESTAB) == 0) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_datreq_outconn: data not allowed\n"); + return; + } + + /* + * Place data at end of transmission queue + */ + KB_QNEXT(m) = NULL; + if (sop->so_xmit_hd == NULL) + sop->so_xmit_hd = m; + else + KB_QNEXT(sop->so_xmit_tl) = m; + sop->so_xmit_tl = m; + + /* + * Note that the transmit queues need to be serviced + */ + sop->so_flags |= SOF_XMITSRVC; + + return; +} + + +/* + * SSCOP_RESYNC_REQ / SOS_READY Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_resreq_ready(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Stop poll timer + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Stop lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = 0; + + /* + * Send first RS PDU + */ + sop->so_connctl = 1; + (void) sscop_send_rs(sop); + + /* + * Reset transmitter state + */ + qsaal1_reset_xmit(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for RSAK + */ + sop->so_state = SOS_OUTRESYN; + + return; +} + + +/* + * SSCOP_RESYNC_RSP / SOS_INRESYN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 unused + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_resrsp_inresyn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Send RSAK PDU + */ + (void) sscop_send_rsak(sop); + + /* + * Back to data transfer state + */ + sop->so_state = SOS_READY; + + return; +} + + +/* + * SSCOP_RESYNC_RSP / SOS_CONRESYN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 unused + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_resrsp_conresyn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Send RSAK PDU + */ + (void) sscop_send_rsak(sop); + + /* + * Back to waiting for peer's RSAK + */ + sop->so_state = SOS_OUTRESYN; + + return; +} + diff --git a/sys/netatm/uni/qsaal1_sigcpcs.c b/sys/netatm/uni/qsaal1_sigcpcs.c new file mode 100644 index 0000000..1d62165 --- /dev/null +++ b/sys/netatm/uni/qsaal1_sigcpcs.c @@ -0,0 +1,1545 @@ +/* + * + * =================================== + * 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: qsaal1_sigcpcs.c,v 1.7 1998/04/07 23:21:03 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.SAAL1 - Process CPCS-signals (SSCOP PDUs) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: qsaal1_sigcpcs.c,v 1.7 1998/04/07 23:21:03 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_bgn_outconn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_end_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_end_conresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_end_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_endak_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rsak_conresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_sd_inresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_sd_conresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_sd_process __P((struct sscop *, KBuffer *, caddr_t, int)); +static void sscop_sd_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_sdp_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_poll_inresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_poll_conresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_poll_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_stat_conresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_ustat_conresyn __P((struct sscop *, KBuffer *, caddr_t)); + + +/* + * PDU type state lookup tables + */ +/* BGN PDU */ +static void (*sscop_bgn_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgn_idle, /* SOS_IDLE */ + sscop_bgn_outconn, /* SOS_OUTCONN */ + sscop_noop, /* SOS_INCONN */ + sscop_bgn_outdisc, /* SOS_OUTDISC */ + sscop_bgn_outresyn, /* SOS_OUTRESYN */ + sscop_bgn_inresyn, /* SOS_INRESYN */ + sscop_bgn_outresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_bgn_inresyn, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* BGAK PDU */ +static void (*sscop_bgak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgak_idle, /* SOS_IDLE */ + sscop_bgak_outconn, /* SOS_OUTCONN */ + sscop_bgak_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_bgak_error, /* SOS_OUTRESYN */ + sscop_bgak_error, /* SOS_INRESYN */ + sscop_bgak_error, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_noop, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* BGREJ PDU */ +static void (*sscop_bgrej_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgrej_error, /* SOS_IDLE */ + sscop_bgrej_outconn, /* SOS_OUTCONN */ + sscop_bgrej_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_bgrej_outresyn, /* SOS_OUTRESYN */ + sscop_bgrej_ready, /* SOS_INRESYN */ + sscop_bgrej_outresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_bgrej_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* END PDU */ +static void (*sscop_end_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_end_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_end_inconn, /* SOS_INCONN */ + sscop_end_outdisc, /* SOS_OUTDISC */ + sscop_end_outresyn, /* SOS_OUTRESYN */ + sscop_end_ready, /* SOS_INRESYN */ + sscop_end_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_end_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* ENDAK PDU */ +static void (*sscop_endak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_noop, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_endak_inconn, /* SOS_INCONN */ + sscop_endak_outdisc, /* SOS_OUTDISC */ + sscop_endak_outresyn, /* SOS_OUTRESYN */ + sscop_endak_ready, /* SOS_INRESYN */ + sscop_endak_outresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_endak_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* RS PDU */ +static void (*sscop_rs_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_rs_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_rs_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_rs_outresyn, /* SOS_OUTRESYN */ + sscop_noop, /* SOS_INRESYN */ + sscop_noop, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_rs_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* RSAK PDU */ +static void (*sscop_rsak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_rsak_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_rsak_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_rsak_outresyn, /* SOS_OUTRESYN */ + sscop_rsak_error, /* SOS_INRESYN */ + sscop_rsak_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_rsak_error, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* SD PDU */ +static void (*sscop_sd_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_sd_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_sd_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_sd_ready, /* SOS_OUTRESYN */ + sscop_sd_inresyn, /* SOS_INRESYN */ + sscop_sd_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_sd_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* SDP PDU */ +static void (*sscop_sdp_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_sd_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_sd_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_sdp_ready, /* SOS_OUTRESYN */ + sscop_sd_inresyn, /* SOS_INRESYN */ + sscop_sd_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_sdp_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* POLL PDU */ +static void (*sscop_poll_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_poll_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_poll_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_poll_ready, /* SOS_OUTRESYN */ + sscop_poll_inresyn, /* SOS_INRESYN */ + sscop_poll_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_poll_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* STAT PDU */ +static void (*sscop_stat_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_stat_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_stat_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_stat_ready, /* SOS_INRESYN */ + sscop_stat_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_stat_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* USTAT PDU */ +static void (*sscop_ustat_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_ustat_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_ustat_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_ustat_ready, /* SOS_INRESYN */ + sscop_ustat_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_ustat_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* UD PDU */ +static void (*sscop_ud_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_ud_all, /* SOS_IDLE */ + sscop_ud_all, /* SOS_OUTCONN */ + sscop_ud_all, /* SOS_INCONN */ + sscop_ud_all, /* SOS_OUTDISC */ + sscop_ud_all, /* SOS_OUTRESYN */ + sscop_ud_all, /* SOS_INRESYN */ + sscop_ud_all, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_ud_all, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* MD PDU */ +static void (*sscop_md_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_md_all, /* SOS_IDLE */ + sscop_md_all, /* SOS_OUTCONN */ + sscop_md_all, /* SOS_INCONN */ + sscop_md_all, /* SOS_OUTDISC */ + sscop_md_all, /* SOS_OUTRESYN */ + sscop_md_all, /* SOS_INRESYN */ + sscop_md_all, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_md_all, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + + +/* + * PDU type lookup table + */ +void (*(*sscop_qsaal_pdutab[])) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, + sscop_bgn_tab, + sscop_bgak_tab, + sscop_end_tab, + sscop_endak_tab, + sscop_rs_tab, + sscop_rsak_tab, + sscop_bgrej_tab, + sscop_sd_tab, + sscop_sdp_tab, + sscop_poll_tab, + sscop_stat_tab, + sscop_ustat_tab, + sscop_ud_tab, + sscop_md_tab, + NULL +}; + + +/* + * BGN PDU / SOS_OUTCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_bgn_outconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + /* + * Notify user of connection establishment + */ + if (sop->so_flags & SOF_REESTAB) { + KB_FREEALL(m); + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_bgn_outconn: stack memory\n"); + return; + } + sop->so_flags &= ~SOF_REESTAB; + } else { + STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_bgn_outconn: stack memory\n"); + return; + } + } + + /* + * Return an ACK to peer + */ + (void) sscop_send_bgak(sop); + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Reset receiver variables + */ + qsaal1_reset_rcvr(sop); + + /* + * Start polling timer + */ + sscop_set_poll(sop); + + /* + * Start lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * OK, we're ready for data + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * END PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_end_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct end_pdu *ep = (struct end_pdu *)trlr; + int err, source; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Get Source value + */ + if (ep->end_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_end_outresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_end_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Free up buffers + */ + KB_FREEALL(m); + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_end_conresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_end_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct end_pdu *ep = (struct end_pdu *)trlr; + int err, source; + + /* + * Stop poll timer + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Stop lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = 0; + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Get Source value + */ + if (ep->end_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_end_ready: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * ENDAK PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_endak_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Report protocol error + */ + sscop_endak_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_endak_outresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * RS PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Notify user of resynchronization + */ + STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_rs_outresyn: stack memory\n"); + return; + } + + /* + * Reset receiver state variables + */ + qsaal1_reset_rcvr(sop); + + /* + * Wait for both peer and user responses + */ + sop->so_state = SOS_CONRESYN; + + return; +} + + +/* + * RS PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Notify user of resynchronization + */ + STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_rs_ready: stack memory\n"); + return; + } + + /* + * Reset receiver state variables + */ + qsaal1_reset_rcvr(sop); + + /* + * Wait for user response + */ + sop->so_state = SOS_INRESYN; + + return; +} + + +/* + * RSAK PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rsak_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Notify user of resynchronization completion + */ + STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "sscop_rsak_conresyn: stack memory\n"); + return; + } + + /* + * Start the polling timer + */ + sscop_set_poll(sop); + + /* + * Start lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Continue waiting for user response + */ + sop->so_state = SOS_INRESYN; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * SD PDU / SOS_INRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_sd_inresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop poll timer + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Stop lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = 0; + + /* + * Record error condition + */ + sscop_sd_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_sd_inresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * SD PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_sd_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Record error condition + */ + sscop_sd_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_sd_conresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * SD/SDP PDU Common Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU user data buffer chain + * trlr pointer to PDU trailer + * type PDU type (SD or SDP) + * + * Returns: + * none + * + */ +static void +sscop_sd_process(sop, m, trlr, type) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; + int type; +{ + struct sd_pdu *sp; + struct sdp_pdu *spp; + struct poll_pdu poll; + struct pdu_hdr *php; + KBuffer *n; + sscop_seq ns, nps; + int err, space; + + /* + * Get PDU sequence number(s) + */ + if (type == PT_SD) { + sp = (struct sd_pdu *)trlr; + SEQ_SET(ns, ntohl(sp->sd_ns)); + SEQ_SET(nps, 0); + } else { + spp = (struct sdp_pdu *)trlr; + SEQ_SET(ns, ntohl(spp->sdp_ns)); + SEQ_SET(nps, ntohl(spp->sdp_nps)); + } + + /* + * Ensure that the sequence number fits within the window + */ + if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) { + KB_FREEALL(m); + return; + } + + /* + * If this is the next in-sequence PDU, hand it to user + */ + if (ns == sop->so_rcvnext) { + STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, ns, err); + if (err) { + KB_FREEALL(m); + return; + } + + /* + * Bump next expected sequence number + */ + SEQ_INCR(sop->so_rcvnext, 1); + + /* + * Slide receive window down + */ + SEQ_INCR(sop->so_rcvmax, 1); + + /* + * Is this the highest sequence PDU we've received?? + */ + if (ns == sop->so_rcvhigh) { + /* + * Yes, bump the limit and exit + */ + sop->so_rcvhigh = sop->so_rcvnext; + if (type == PT_SDP) + goto dopoll; + return; + } + + /* + * This is a retransmitted PDU, so see if we have + * more in-sequence PDUs already queued up + */ + while ((php = sop->so_recv_hd) && + (php->ph_ns == sop->so_rcvnext)) { + + /* + * Yup we do, so remove next PDU from queue and + * pass it up to the user as well + */ + sop->so_recv_hd = php->ph_recv_lk; + if (sop->so_recv_hd == NULL) + sop->so_recv_tl = NULL; + STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)php->ph_buf, php->ph_ns, + err); + if (err) { + /* + * Should never happen, but... + */ + KB_FREEALL(php->ph_buf); + sscop_abort(sop, + "sscop_sd_process: stack memory\n"); + return; + } + + /* + * Bump next expected sequence number + */ + SEQ_INCR(sop->so_rcvnext, 1); + + /* + * Slide receive window down + */ + SEQ_INCR(sop->so_rcvmax, 1); + } + + /* + * Finished with data...see if we need to poll + */ + if (type == PT_SDP) + goto dopoll; + return; + } + + /* + * We're gonna have to queue this PDU, so find space + * for the PDU header + */ + KB_HEADROOM(m, space); + + /* + * If there's not enough room in the received buffer, + * allocate & link a new buffer for the header + */ + if (space < sizeof(struct pdu_hdr)) { + + KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER); + if (n == NULL) { + KB_FREEALL(m); + return; + } + KB_HEADSET(n, sizeof(struct pdu_hdr)); + KB_LEN(n) = 0; + KB_LINKHEAD(n, m); + m = n; + } + + /* + * Build PDU header + * + * We can at least assume/require that the start of + * the user data is aligned. Also note that we don't + * include this header in the buffer len/offset fields. + */ + KB_DATASTART(m, php, struct pdu_hdr *); + php--; + php->ph_ns = ns; + php->ph_buf = m; + + /* + * Insert PDU into the receive queue + */ + if (sscop_recv_insert(sop, php)) { + /* + * Oops, a duplicate sequence number PDU is already on + * the queue, somethings wrong here. + */ + sscop_maa_error(sop, 'Q'); + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Reestablish a new connection + */ + qsaal1_reestablish(sop); + + return; + } + + /* + * Are we at the high-water mark?? + */ + if (ns == sop->so_rcvhigh) { + /* + * Yes, just bump the mark + */ + SEQ_INCR(sop->so_rcvhigh, 1); + + if (type == PT_SDP) + goto dopoll; + return; + } + + /* + * Are we beyond the high-water mark?? + */ + if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) { + /* + * Yes, then there's a missing PDU, so inform the transmitter + */ + if (type == PT_SD) + (void) sscop_send_ustat(sop, ns); + + /* + * Update high-water mark + */ + sop->so_rcvhigh = SEQ_ADD(ns, 1); + } + + if (type == PT_SD) + return; + +dopoll: + /* + * Do the "poll" part of an SDP PDU + */ + poll.poll_nps = htonl(nps); + poll.poll_ns = htonl((PT_POLL << PT_TYPE_SHIFT) | ns); + sscop_poll_ready(sop, NULL, (caddr_t)&poll); + return; +} + + +/* + * SD PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_sd_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + /* + * Just call common SD/SDP processor + */ + sscop_sd_process(sop, m, trlr, PT_SD); + + return; +} + + +/* + * SDP PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_sdp_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + /* + * Just call common SD/SDP processor + */ + sscop_sd_process(sop, m, trlr, PT_SDP); + + return; +} + + +/* + * POLL PDU / SOS_INRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_poll_inresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop poll timer + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Stop lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = 0; + + /* + * Report protocol error + */ + sscop_poll_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_poll_inresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * POLL PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_poll_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Record error condition + */ + sscop_poll_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_poll_conresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * POLL PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_poll_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct poll_pdu *pp = (struct poll_pdu *)trlr; + sscop_seq nps; + + NTOHL(pp->poll_ns); + + /* + * If the poll sequence number is less than highest number + * we've already seen, something's wrong - so attempt to + * reestablish a new connection. + */ + if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) { + /* + * Record error condition + */ + sscop_maa_error(sop, 'Q'); + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Reestablish a new connection + */ + qsaal1_reestablish(sop); + + return; + } + + /* + * Set a new "next highest" sequence number expected + */ + if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext)) + SEQ_SET(sop->so_rcvhigh, pp->poll_ns); + else + sop->so_rcvhigh = sop->so_rcvmax; + + /* + * Return a STAT PDU to peer + */ + SEQ_SET(nps, ntohl(pp->poll_nps)); + KB_FREEALL(m); + (void) sscop_send_stat(sop, nps); + + return; +} + + +/* + * STAT PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_stat_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Record error condition + */ + sscop_stat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_stat_conresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * USTAT PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_ustat_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Record error condition + */ + sscop_ustat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_ustat_conresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + diff --git a/sys/netatm/uni/qsaal1_subr.c b/sys/netatm/uni/qsaal1_subr.c new file mode 100644 index 0000000..ed4b43c --- /dev/null +++ b/sys/netatm/uni/qsaal1_subr.c @@ -0,0 +1,206 @@ +/* + * + * =================================== + * 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: qsaal1_subr.c,v 1.6 1998/04/07 23:21:17 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.SAAL1 - Subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: qsaal1_subr.c,v 1.6 1998/04/07 23:21:17 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Re-establish a new SSCOP Connection + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +qsaal1_reestablish(sop) + struct sscop *sop; +{ + + /* + * Stop polling timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Note that we're reestablishing a connection + */ + sop->so_flags |= SOF_REESTAB; + + /* + * Send first BGN PDU + */ + sop->so_connctl = 1; + (void) sscop_send_bgn(sop, SSCOP_SOURCE_SSCOP); + + /* + * Reset transmit variables + */ + qsaal1_reset_xmit(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for BGAK + */ + sop->so_state = SOS_OUTCONN; + + return; +} + + +/* + * Reset connection's transmitter state + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +qsaal1_reset_xmit(sop) + struct sscop *sop; +{ + + /* + * Drain the transmission queues + */ + sscop_xmit_drain(sop); + + /* + * Reset transmit variables + */ + SEQ_SET(sop->so_send, 0); + SEQ_SET(sop->so_pollsend, 0); + SEQ_SET(sop->so_ack, 0); + SEQ_SET(sop->so_pollack, 0); + if (sop->so_state != SOS_INCONN) + SEQ_SET(sop->so_sendmax, 0); + sop->so_polldata = 0; + + return; +} + + +/* + * Reset connection's receiver state + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +qsaal1_reset_rcvr(sop) + struct sscop *sop; +{ + + /* + * Drain the receiver queues + */ + sscop_rcvr_drain(sop); + + /* + * Reset transmit variables + */ + SEQ_SET(sop->so_rcvnext, 0); + SEQ_SET(sop->so_rcvhigh, 0); + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + return; +} + + +/* + * Clear connection's connection data + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +qsaal1_clear_connection(sop) + struct sscop *sop; +{ + + /* + * Can we clear transmit buffers ?? + */ + if ((sop->so_flags & SOF_NOCLRBUF) == 0) { + /* + * Yes, drain the transmission queues + */ + sscop_xmit_drain(sop); + } + + /* + * Clear service required flag + */ + sop->so_flags &= ~SOF_XMITSRVC; + + /* + * Drain receive queue buffers + */ + sscop_rcvr_drain(sop); + + return; +} + diff --git a/sys/netatm/uni/sscf_uni.c b/sys/netatm/uni/sscf_uni.c new file mode 100644 index 0000000..b5fd7fb --- /dev/null +++ b/sys/netatm/uni/sscf_uni.c @@ -0,0 +1,317 @@ +/* + * + * =================================== + * 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: sscf_uni.c,v 1.6 1998/03/24 21:10:38 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * Signalling AAL SSCF at the UNI + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscf_uni.c,v 1.6 1998/03/24 21:10:38 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscf_uni.h> +#include <netatm/uni/sscf_uni_var.h> + + +/* + * Global variables + */ +int sscf_uni_vccnt = 0; + +/* + * Local functions + */ +static int sscf_uni_inst __P((struct stack_defn **, Atm_connvc *)); + +/* + * Local variables + */ +static struct sp_info sscf_uni_pool = { + "sscf uni pool", /* si_name */ + sizeof(struct univcc), /* si_blksiz */ + 5, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + +static struct stack_defn sscf_uni_service = { + NULL, + SAP_SSCF_UNI, + 0, + sscf_uni_inst, + sscf_uni_lower, + sscf_uni_upper, + 0 +}; + +static struct t_atm_cause sscf_uni_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_TEMPORARY_FAILURE, + {0, 0, 0, 0} +}; + + +/* + * Initialize SSCF UNI processing + * + * This will be called during module loading. We will register our stack + * service and wait for someone to talk to us. + * + * Arguments: + * none + * + * Returns: + * 0 initialization was successful + * errno initialization failed - reason indicated + * + */ +int +sscf_uni_start() +{ + int err = 0; + + /* + * Register stack service + */ + if (err = atm_stack_register(&sscf_uni_service)) + goto done; + +done: + return (err); +} + + +/* + * Terminate SSCF UNI processing + * + * This will be called just prior to unloading the module from memory. All + * signalling instances should have been terminated by now, so we just free + * up all of our resources. + * + * Called at splnet. + * + * Arguments: + * none + * + * Returns: + * 0 termination was successful + * errno termination failed - reason indicated + * + */ +int +sscf_uni_stop() +{ + /* + * Any connections still exist?? + */ + if (sscf_uni_vccnt) { + + /* + * Yes, can't stop yet + */ + return (EBUSY); + } + + /* + * Deregister the stack service + */ + (void) atm_stack_deregister(&sscf_uni_service); + + /* + * Free our storage pools + */ + atm_release_pool(&sscf_uni_pool); + + return (0); +} + + +/* + * SSCF_UNI Stack Instantiation + * + * Called at splnet. + * + * Arguments: + * ssp pointer to array of stack definition pointers for connection + * ssp[0] points to upper layer's stack service definition + * ssp[1] points to this layer's stack service definition + * ssp[2] points to lower layer's stack service definition + * cvp pointer to connection vcc for this stack + * + * Returns: + * 0 instantiation successful + * errno instantiation failed - reason indicated + * + */ +static int +sscf_uni_inst(ssp, cvp) + struct stack_defn **ssp; + Atm_connvc *cvp; +{ + struct stack_defn *sdp_up = ssp[0], + *sdp_me = ssp[1], + *sdp_low = ssp[2]; + struct univcc *uvp; + int err; + + ATM_DEBUG2("sscf_uni_inst: ssp=0x%x, cvp=0x%x\n", ssp, cvp); + + /* + * Validate lower SAP + */ + if (sdp_low->sd_sap != SAP_SSCOP) + return (EINVAL); + + /* + * Allocate our control block + */ + uvp = (struct univcc *)atm_allocate(&sscf_uni_pool); + if (uvp == NULL) + return (ENOMEM); + + uvp->uv_ustate = UVU_INST; + uvp->uv_lstate = UVL_INST; + uvp->uv_connvc = cvp; + uvp->uv_toku = sdp_up->sd_toku; + uvp->uv_upper = sdp_up->sd_upper; + sscf_uni_vccnt++; + + /* + * Store my token into service definition + */ + sdp_me->sd_toku = uvp; + + /* + * Update and save input buffer headroom + */ + HEADIN(cvp, 0, 0); + /* uvp->uv_headin = cvp->cvc_attr.headin; */ + + /* + * Pass instantiation down the stack + */ + err = sdp_low->sd_inst(ssp + 1, cvp); + if (err) { + /* + * Lower layer instantiation failed, free our resources + */ + atm_free((caddr_t)uvp); + sscf_uni_vccnt--; + return (err); + } + + /* + * Save and update output buffer headroom + */ + /* uvp->uv_headout = cvp->cvc_attr.headout; */ + HEADOUT(cvp, 0, 0); + + /* + * Save lower layer's interface info + */ + uvp->uv_lower = sdp_low->sd_lower; + uvp->uv_tokl = sdp_low->sd_toku; + + return (0); +} + + +/* + * Abort an SSCF_UNI connection + * + * Called when an unrecoverable or "should never happen" error occurs. + * We just log a message and request the signalling manager to abort the + * connection. + * + * Arguments: + * uvp pointer to univcc control block + * msg pointer to error message + * + * Returns: + * none + * + */ +void +sscf_uni_abort(uvp, msg) + struct univcc *uvp; + char *msg; +{ + /* + * Log error message + */ + log(LOG_ERR, msg); + + /* + * Set termination states + */ + uvp->uv_ustate = UVU_TERM; + uvp->uv_lstate = UVL_TERM; + + /* + * Tell Connection Manager to abort this connection + */ + (void) atm_cm_abort(uvp->uv_connvc, &sscf_uni_cause); +} + + +/* + * Print an SSCF PDU + * + * Arguments: + * uvp pointer to univcc control block + * m pointer to pdu buffer chain + * msg pointer to message string + * + * Returns: + * none + * + */ +void +sscf_uni_pdu_print(uvp, m, msg) + struct univcc *uvp; + KBuffer *m; + char *msg; +{ + char buf[128]; + struct vccb *vcp; + + vcp = uvp->uv_connvc->cvc_vcc; + sprintf(buf, "sscf_uni %s: vcc=(%d,%d)\n", + msg, vcp->vc_vpi, vcp->vc_vci); + atm_pdu_print(m, buf); +} + diff --git a/sys/netatm/uni/sscf_uni.h b/sys/netatm/uni/sscf_uni.h new file mode 100644 index 0000000..cf24446 --- /dev/null +++ b/sys/netatm/uni/sscf_uni.h @@ -0,0 +1,47 @@ +/* + * + * =================================== + * 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: sscf_uni.h,v 1.2 1997/05/06 22:19:34 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCF UNI protocol definitions + * + */ + +#ifndef _UNI_SSCF_UNI_H +#define _UNI_SSCF_UNI_H + +/* + * SSCF_UNI API definitions + */ +#define SSCF_UNI_ESTIND_YES 1 /* Allow new ESTABLISH_IND */ +#define SSCF_UNI_ESTIND_NO 2 /* Disallow new ESTABLISH_IND */ + +#endif /* _UNI_SSCF_UNI_H */ diff --git a/sys/netatm/uni/sscf_uni_lower.c b/sys/netatm/uni/sscf_uni_lower.c new file mode 100644 index 0000000..fe2d839 --- /dev/null +++ b/sys/netatm/uni/sscf_uni_lower.c @@ -0,0 +1,379 @@ +/* + * + * =================================== + * 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: sscf_uni_lower.c,v 1.6 1998/04/07 23:23:26 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCF UNI - SSCF_UNI SAP interface processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscf_uni_lower.c,v 1.6 1998/04/07 23:23:26 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscf_uni.h> +#include <netatm/uni/sscf_uni_var.h> + + +/* + * Local variables + */ +static struct sscop_parms sscf_uni_sscop_parms = { + 4096, /* sp_maxinfo */ + 4096, /* sp_maxuu */ + 4, /* sp_maxcc */ + 25, /* sp_maxpd */ + 1 * ATM_HZ, /* sp_timecc */ + 2 * ATM_HZ, /* sp_timekeep */ + 7 * ATM_HZ, /* sp_timeresp */ + 1 * ATM_HZ, /* sp_timepoll */ + 15 * ATM_HZ, /* sp_timeidle */ + 80 /* sp_rcvwin */ +}; + + +/* + * SSCF_UNI Lower Stack Command Handler + * + * This function will receive all of the stack commands issued from the + * layer above SSCF UNI (ie. Q.2931). + * + * Arguments: + * cmd stack command code + * tok session token + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscf_uni_lower(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + struct univcc *uvp = (struct univcc *)tok; + Atm_connvc *cvp = uvp->uv_connvc; + enum sscop_vers vers; + int err; + + ATM_DEBUG5("sscf_uni_lower: cmd=0x%x, uvp=0x%x, ustate=%d, arg1=0x%x, arg2=0x%x\n", + cmd, (int)uvp, uvp->uv_ustate, arg1, arg2); + + switch (cmd) { + + case SSCF_UNI_INIT: + /* + * Validate state + */ + if (uvp->uv_ustate != UVU_INST) { + log(LOG_ERR, "sscf_uni_lower: SSCF_INIT in ustate=%d\n", + uvp->uv_ustate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + break; + } + + /* + * Validate UNI version + */ + if ((enum uni_vers)arg1 == UNI_VERS_3_0) + vers = SSCOP_VERS_QSAAL; + else if ((enum uni_vers)arg1 == UNI_VERS_3_1) + vers = SSCOP_VERS_Q2110; + else { + sscf_uni_abort(uvp, "sscf_uni: bad version\n"); + break; + } + uvp->uv_vers = (enum uni_vers)arg1; + + /* + * Make ourselves ready and pass on the INIT + */ + uvp->uv_ustate = UVU_RELEASED; + uvp->uv_lstate = UVL_IDLE; + + STACK_CALL(SSCOP_INIT, uvp->uv_lower, uvp->uv_tokl, cvp, + (int)vers, (int)&sscf_uni_sscop_parms, err); + if (err) { + /* + * Should never happen + */ + sscf_uni_abort(uvp, "sscf_uni: INIT failure\n"); + } + break; + + case SSCF_UNI_TERM: + /* + * Set termination states + */ + uvp->uv_ustate = UVU_TERM; + uvp->uv_lstate = UVL_TERM; + + /* + * Pass the TERM down the stack + */ + STACK_CALL(SSCOP_TERM, uvp->uv_lower, uvp->uv_tokl, cvp, + 0, 0, err); + if (err) { + /* + * Should never happen + */ + sscf_uni_abort(uvp, "sscf_uni: TERM failure\n"); + return; + } + atm_free((caddr_t)uvp); + sscf_uni_vccnt--; + break; + + case SSCF_UNI_ESTABLISH_REQ: + /* + * Validation based on user state + */ + switch (uvp->uv_ustate) { + + case UVU_RELEASED: + case UVU_PRELEASE: + /* + * Establishing a new connection + */ + uvp->uv_ustate = UVU_PACTIVE; + uvp->uv_lstate = UVL_OUTCONN; + STACK_CALL(SSCOP_ESTABLISH_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, SSCOP_BR_YES, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_ACTIVE: + /* + * Resynchronizing a connection + */ + uvp->uv_ustate = UVU_PACTIVE; + if (uvp->uv_vers == UNI_VERS_3_0) { + uvp->uv_lstate = UVL_OUTCONN; + STACK_CALL(SSCOP_ESTABLISH_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, SSCOP_BR_YES, err); + } else { + uvp->uv_lstate = UVL_OUTRESYN; + STACK_CALL(SSCOP_RESYNC_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, 0, err); + } + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_TERM: + /* Ignore */ + break; + + case UVU_INST: + case UVU_PACTIVE: + default: + log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n", + cmd, uvp->uv_ustate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCF_UNI_RELEASE_REQ: + /* + * Validate re-establishment parameter + */ + switch (arg1) { + + case SSCF_UNI_ESTIND_YES: + uvp->uv_flags &= ~UVF_NOESTIND; + break; + + case SSCF_UNI_ESTIND_NO: + uvp->uv_flags |= UVF_NOESTIND; + break; + + default: + sscf_uni_abort(uvp, "sscf_uni: bad estind value\n"); + return; + } + + /* + * Validation based on user state + */ + switch (uvp->uv_ustate) { + + case UVU_RELEASED: + /* + * Releasing a non-existant connection + */ + STACK_CALL(SSCF_UNI_RELEASE_CNF, uvp->uv_upper, + uvp->uv_toku, cvp, + 0, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_PACTIVE: + case UVU_ACTIVE: + /* + * Releasing a connection + */ + uvp->uv_ustate = UVU_PRELEASE; + uvp->uv_lstate = UVL_OUTDISC; + STACK_CALL(SSCOP_RELEASE_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_TERM: + /* Ignore */ + break; + + case UVU_INST: + case UVU_PRELEASE: + default: + log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n", + cmd, uvp->uv_ustate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCF_UNI_DATA_REQ: +#ifdef notdef + sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "DATA_REQ"); +#endif + + /* + * Validation based on user state + */ + switch (uvp->uv_ustate) { + + case UVU_ACTIVE: + /* + * Send assured data on connection + */ + STACK_CALL(SSCOP_DATA_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + arg1, 0, err); + if (err) { + KB_FREEALL((KBuffer *)arg1); + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_RELEASED: + case UVU_TERM: + /* + * Release supplied buffers and ignore + */ + KB_FREEALL((KBuffer *)arg1); + break; + + case UVU_INST: + case UVU_PACTIVE: + case UVU_PRELEASE: + default: + KB_FREEALL((KBuffer *)arg1); + log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n", + cmd, uvp->uv_ustate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCF_UNI_UNITDATA_REQ: +#ifdef notdef + sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "UNITDATA_REQ"); +#endif + + /* + * Validation based on user state + */ + switch (uvp->uv_ustate) { + + case UVU_RELEASED: + case UVU_PACTIVE: + case UVU_PRELEASE: + case UVU_ACTIVE: + /* + * Send unassured data on connection + */ + STACK_CALL(SSCOP_UNITDATA_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + arg1, 0, err); + if (err) { + KB_FREEALL((KBuffer *)arg1); + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_TERM: + /* + * Release supplied buffers and ignore + */ + KB_FREEALL((KBuffer *)arg1); + break; + + case UVU_INST: + default: + KB_FREEALL((KBuffer *)arg1); + log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n", + cmd, uvp->uv_ustate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + default: + log(LOG_ERR, "sscf_uni_lower: unknown cmd 0x%x, uvp=0x%x\n", + cmd, (int)uvp); + } + + return; +} + diff --git a/sys/netatm/uni/sscf_uni_upper.c b/sys/netatm/uni/sscf_uni_upper.c new file mode 100644 index 0000000..2febb5c --- /dev/null +++ b/sys/netatm/uni/sscf_uni_upper.c @@ -0,0 +1,625 @@ +/* + * + * =================================== + * 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: sscf_uni_upper.c,v 1.7 1998/06/29 22:15:31 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCF UNI - SSCOP SAP interface processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscf_uni_upper.c,v 1.7 1998/06/29 22:15:31 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscf_uni.h> +#include <netatm/uni/sscf_uni_var.h> + + +/* + * SSCF_UNI Upper Stack Command Handler + * + * This function will receive all of the stack commands issued from the + * layer below SSCF UNI (ie. SSCOP). + * + * Arguments: + * cmd stack command code + * tok session token + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscf_uni_upper(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + struct univcc *uvp = (struct univcc *)tok; + Atm_connvc *cvp = uvp->uv_connvc; + int err; + + ATM_DEBUG5("sscf_uni_upper: cmd=0x%x, uvp=0x%x, lstate=%d, arg1=0x%x, arg2=0x%x\n", + cmd, (int)uvp, uvp->uv_lstate, arg1, arg2); + + switch (cmd) { + + case SSCOP_ESTABLISH_IND: + /* + * We don't support SSCOP User-to-User data, so just + * get rid of any supplied to us + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_READY: + if (uvp->uv_vers != UNI_VERS_3_0) { + goto seqerr; + } + goto doestind; + + case UVL_IDLE: + /* + * Incoming connection establishment request + */ + + /* + * If user doesn't want any more incoming sessions + * accepted, then refuse request + */ + if (uvp->uv_flags & UVF_NOESTIND) { + STACK_CALL(SSCOP_RELEASE_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, + "sscf_uni: stack memory\n"); + return; + } + break; + } + +doestind: + /* + * Tell sscop we've accepted the new connection + */ + uvp->uv_lstate = UVL_READY; + STACK_CALL(SSCOP_ESTABLISH_RSP, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, SSCOP_BR_YES, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + + /* + * Now notify the user of the new connection + */ + uvp->uv_ustate = UVU_ACTIVE; + STACK_CALL(SSCF_UNI_ESTABLISH_IND, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + default: +seqerr: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_ESTABLISH_CNF: + /* + * We don't support SSCOP User-to-User data, so just + * get rid of any supplied to us + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_OUTCONN: + /* + * Outgoing connection establishment completed + */ + + /* + * Tell the user that the connection is established + */ + uvp->uv_ustate = UVU_ACTIVE; + uvp->uv_lstate = UVL_READY; + STACK_CALL(SSCF_UNI_ESTABLISH_CNF, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + case UVL_READY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RELEASE_IND: + /* + * We don't support SSCOP User-to-User data, so just + * get rid of any supplied to us + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_OUTCONN: + case UVL_OUTRESYN: + case UVL_READY: + /* + * Peer requesting connection termination + */ + + /* + * Notify the user that the connection + * has been terminated + */ + uvp->uv_ustate = UVU_RELEASED; + uvp->uv_lstate = UVL_IDLE; + STACK_CALL(SSCF_UNI_RELEASE_IND, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_INRESYN: + case UVL_RECOVERY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RELEASE_CNF: + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_OUTDISC: + /* + * Peer acknowledging connection termination + */ + + /* + * Notify the user that the connection + * termination is completed + */ + uvp->uv_ustate = UVU_RELEASED; + uvp->uv_lstate = UVL_IDLE; + STACK_CALL(SSCF_UNI_RELEASE_CNF, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + case UVL_READY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_DATA_IND: +#ifdef notdef + sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "DATA_IND"); +#endif + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_READY: + /* + * Incoming assured data from peer + */ + + /* + * Pass the data up to the user + */ + STACK_CALL(SSCF_UNI_DATA_IND, uvp->uv_upper, + uvp->uv_toku, cvp, + arg1, 0, err); + if (err) { + KB_FREEALL((KBuffer *)arg1); + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + KB_FREEALL((KBuffer *)arg1); + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + default: + KB_FREEALL((KBuffer *)arg1); + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RESYNC_IND: + /* + * We don't support SSCOP User-to-User data, so just + * get rid of any supplied to us + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_READY: + /* + * Incoming connection resynchronization request + */ + + /* + * Send resynch acknowledgement to sscop + */ + STACK_CALL(SSCOP_RESYNC_RSP, uvp->uv_lower, + uvp->uv_tokl, cvp, + 0, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + + if (uvp->uv_vers != UNI_VERS_3_0) { + + /* + * Notify the user that the connection + * has been resynced + */ + STACK_CALL(SSCF_UNI_ESTABLISH_IND, + uvp->uv_upper, uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, + "sscf_uni: stack memory\n"); + return; + } + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RESYNC_CNF: + /* + * Not supported in version 3.0 + */ + if (uvp->uv_vers == UNI_VERS_3_0) { + sscf_uni_abort(uvp, + "sscf_uni: SSCOP_RESYNC_CNF in 3.0\n"); + return; + } + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_OUTRESYN: + /* + * Peer acknowledging connection resynchronization + */ + + /* + * Now notify the user that the connection + * has been resynced + */ + uvp->uv_ustate = UVU_ACTIVE; + uvp->uv_lstate = UVL_READY; + STACK_CALL(SSCF_UNI_ESTABLISH_CNF, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_INRESYN: + case UVL_RECOVERY: + case UVL_READY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RECOVER_IND: + /* + * Not supported in version 3.0 + */ + if (uvp->uv_vers == UNI_VERS_3_0) { + sscf_uni_abort(uvp, + "sscf_uni: SSCOP_RECOVER_IND in 3.0\n"); + return; + } + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_READY: + /* + * Recover connection due to internal problems + */ + + /* + * Send recovery acknowledgement to sscop + */ + STACK_CALL(SSCOP_RECOVER_RSP, uvp->uv_lower, + uvp->uv_tokl, cvp, + 0, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + + /* + * Now notify the user that the connection + * has been recovered + */ + STACK_CALL(SSCF_UNI_ESTABLISH_IND, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_UNITDATA_IND: +#ifdef notdef + sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "UNITDATA_IND"); +#endif + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + case UVL_READY: + /* + * Incoming unassured data from peer + */ + + /* + * Pass the data up to the user + */ + STACK_CALL(SSCF_UNI_UNITDATA_IND, uvp->uv_upper, + uvp->uv_toku, cvp, + arg1, 0, err); + if (err) { + KB_FREEALL((KBuffer *)arg1); + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + KB_FREEALL((KBuffer *)arg1); + break; + + case UVL_INST: + default: + KB_FREEALL((KBuffer *)arg1); + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RETRIEVE_IND: + case SSCOP_RETRIEVECMP_IND: + /* + * Not supported + */ + default: + log(LOG_ERR, "sscf_uni_upper: unknown cmd 0x%x, uvp=0x%x\n", + cmd, (int)uvp); + } + + return; +} + diff --git a/sys/netatm/uni/sscf_uni_var.h b/sys/netatm/uni/sscf_uni_var.h new file mode 100644 index 0000000..ffed7de --- /dev/null +++ b/sys/netatm/uni/sscf_uni_var.h @@ -0,0 +1,115 @@ +/* + * + * =================================== + * 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: sscf_uni_var.h,v 1.5 1998/02/19 20:22:05 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCF UNI protocol control blocks + * + */ + +#ifndef _UNI_SSCF_UNI_VAR_H +#define _UNI_SSCF_UNI_VAR_H + +/* + * Structure containing information for each SSCF UNI connection. + */ +struct univcc { + u_char uv_ustate; /* SSCF-User state (see below) */ + u_char uv_lstate; /* SSCF-SSCOP state (see below) */ + u_short uv_flags; /* Connection flags (see below) */ + enum uni_vers uv_vers; /* UNI version */ + + /* Stack variables */ + Atm_connvc *uv_connvc; /* Connection vcc for this stack */ + void *uv_toku; /* Stack upper layer's token */ + void *uv_tokl; /* Stack lower layer's token */ + void (*uv_upper) /* Stack upper layer's interface */ + __P((int, void *, int, int)); + void (*uv_lower) /* Stack lower layer's interface */ + __P((int, void *, int, int)); +}; + +/* + * SSCF to SAAL User (Q.2931) Interface States + */ +#define UVU_INST 0 /* Instantiated, waiting for INIT */ +#define UVU_RELEASED 1 /* Connection released */ +#define UVU_PACTIVE 2 /* Awaiting connection establishment */ +#define UVU_PRELEASE 3 /* Awaiting connection release */ +#define UVU_ACTIVE 4 /* Connection established */ +#define UVU_TERM 5 /* Waiting for TERM */ + +/* + * SSCF to SSCOP Interface States + */ +#define UVL_INST 0 /* Instantiated, waiting for INIT */ +#define UVL_IDLE 1 /* Idle */ +#define UVL_OUTCONN 2 /* Outgoing connection pending */ +#define UVL_INCONN 3 /* Incoming connection pending */ +#define UVL_OUTDISC 4 /* Outgoing disconnection pending */ +#define UVL_OUTRESYN 5 /* Outgoing resynchronization pending */ +#define UVL_INRESYN 6 /* Incoming resynchornization pending */ +#define UVL_RECOVERY 8 /* Recovery pending */ +#define UVL_READY 10 /* Data transfer ready */ +#define UVL_TERM 11 /* Waiting for TERM */ + +/* + * Connection Flags + */ +#define UVF_NOESTIND 0x0001 /* Don't process ESTABLISH_IND */ + + +#ifdef ATM_KERNEL +/* + * Global function declarations + */ + /* sscf_uni.c */ +int sscf_uni_start __P((void)); +int sscf_uni_stop __P((void)); +void sscf_uni_abort __P((struct univcc *, char *)); +void sscf_uni_pdu_print __P((struct univcc *, KBuffer *, + char *)); + + /* sscf_uni_lower.c */ +void sscf_uni_lower __P((int, void *, int, int)); + + /* sscf_uni_upper.c */ +void sscf_uni_upper __P((int, void *, int, int)); + + +/* + * External variables + */ +extern int sscf_uni_vccnt; + +#endif /* ATM_KERNEL */ + +#endif /* _UNI_SSCF_UNI_VAR_H */ diff --git a/sys/netatm/uni/sscop.c b/sys/netatm/uni/sscop.c new file mode 100644 index 0000000..d65118b --- /dev/null +++ b/sys/netatm/uni/sscop.c @@ -0,0 +1,409 @@ +/* + * + * =================================== + * 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: sscop.c,v 1.6 1998/03/24 21:10:43 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * Service Specific Connection Oriented Protocol (SSCOP) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop.c,v 1.6 1998/03/24 21:10:43 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Global variables + */ +int sscop_vccnt = 0; + +struct sscop *sscop_head = NULL; + +struct sscop_stat sscop_stat = {0}; + +struct atm_time sscop_timer = {0, 0}; + +struct sp_info sscop_pool = { + "sscop pool", /* si_name */ + sizeof(struct sscop), /* si_blksiz */ + 5, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + + +/* + * Local functions + */ +static int sscop_inst __P((struct stack_defn **, Atm_connvc *)); + + +/* + * Local variables + */ +static struct stack_defn sscop_service = { + NULL, + SAP_SSCOP, + 0, + sscop_inst, + sscop_lower, + sscop_upper, + 0 +}; + +static struct t_atm_cause sscop_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_TEMPORARY_FAILURE, + {0, 0, 0, 0} +}; + +static u_char sscop_maa_log[MAA_ERROR_COUNT] = { + 1, /* A */ + 1, /* B */ + 1, /* C */ + 1, /* D */ + 1, /* E */ + 1, /* F */ + 1, /* G */ + 1, /* H */ + 1, /* I */ + 1, /* J */ + 1, /* K */ + 1, /* L */ + 1, /* M */ + 0, /* N */ + 0, /* O */ + 0, /* P */ + 1, /* Q */ + 1, /* R */ + 1, /* S */ + 1, /* T */ + 1, /* U */ + 0, /* V */ + 0, /* W */ + 0, /* X */ + 1 /* INVAL */ +}; + + +/* + * Initialize SSCOP processing + * + * This will be called during module loading. We will register our stack + * service and wait for someone to talk to us. + * + * Arguments: + * none + * + * Returns: + * 0 initialization was successful + * errno initialization failed - reason indicated + * + */ +int +sscop_start() +{ + int err = 0; + + /* + * Register stack service + */ + if (err = atm_stack_register(&sscop_service)) + goto done; + + /* + * Start up timer + */ + atm_timeout(&sscop_timer, ATM_HZ/SSCOP_HZ, sscop_timeout); + +done: + return (err); +} + + +/* + * Terminate SSCOP processing + * + * This will be called just prior to unloading the module from memory. All + * signalling instances should have been terminated by now, so we just free + * up all of our resources. + * + * Called at splnet. + * + * Arguments: + * none + * + * Returns: + * 0 termination was successful + * errno termination failed - reason indicated + * + */ +int +sscop_stop() +{ + int err = 0; + + /* + * Any connections still exist?? + */ + if (sscop_vccnt) { + + /* + * Yes, can't stop yet + */ + return (EBUSY); + } + + /* + * Stop our timer + */ + (void) atm_untimeout(&sscop_timer); + + /* + * Deregister the stack service + */ + (void) atm_stack_deregister(&sscop_service); + + /* + * Free our storage pools + */ + atm_release_pool(&sscop_pool); + +done: + return (err); +} + + +/* + * SSCOP Stack Instantiation + * + * Called at splnet. + * + * Arguments: + * ssp pointer to array of stack definition pointers for connection + * ssp[0] points to upper layer's stack service definition + * ssp[1] points to this layer's stack service definition + * ssp[2] points to lower layer's stack service definition + * cvp pointer to connection vcc for this stack + * + * Returns: + * 0 instantiation successful + * errno instantiation failed - reason indicated + * + */ +static int +sscop_inst(ssp, cvp) + struct stack_defn **ssp; + Atm_connvc *cvp; +{ + struct stack_defn *sdp_up = ssp[0], + *sdp_me = ssp[1], + *sdp_low = ssp[2]; + struct sscop *sop; + int err; + + ATM_DEBUG2("sscop_inst: ssp=0x%x, cvp=0x%x\n", ssp, cvp); + + /* + * Validate lower SAP + */ + if ((sdp_low->sd_sap & SAP_CLASS_MASK) != SAP_CPCS) + return (EINVAL); + + /* + * Allocate our control block + */ + sop = (struct sscop *)atm_allocate(&sscop_pool); + if (sop == NULL) + return (ENOMEM); + + sop->so_state = SOS_INST; + sop->so_connvc = cvp; + sop->so_toku = sdp_up->sd_toku; + sop->so_upper = sdp_up->sd_upper; + + /* + * Store my token into service definition + */ + sdp_me->sd_toku = sop; + + /* + * Update and save input buffer headroom + */ + HEADIN(cvp, sizeof(struct pdu_hdr), 0); + /* sop->so_headin = cvp->cvc_attr.headin; */ + + /* + * Pass instantiation down the stack + */ + err = sdp_low->sd_inst(ssp + 1, cvp); + if (err) { + /* + * Lower layer instantiation failed, free our resources + */ + atm_free((caddr_t)sop); + return (err); + } + + /* + * Link in connection block + */ + LINK2TAIL(sop, struct sscop, sscop_head, so_next); + sscop_vccnt++; + sscop_stat.sos_connects++; + + /* + * Save and update output buffer headroom + */ + sop->so_headout = cvp->cvc_attr.headout; + HEADOUT(cvp, sizeof(struct pdu_hdr), 0); + + /* + * Save lower layer's interface info + */ + sop->so_lower = sdp_low->sd_lower; + sop->so_tokl = sdp_low->sd_toku; + + /* + * Initialize version (until INIT received) + */ + sop->so_vers = SSCOP_VERS_Q2110; + + return (0); +} + + +/* + * Report Management Error + * + * Called to report an error to the layer management entity. + * + * Arguments: + * sop pointer to sscop control block + * code error code + * + * Returns: + * none + * + */ +void +sscop_maa_error(sop, code) + struct sscop *sop; + int code; +{ + int i; + + /* + * Validate error code + */ + if ((code < MAA_ERROR_MIN) || + (code > MAA_ERROR_MAX)) + code = MAA_ERROR_INVAL; + i = code - MAA_ERROR_MIN; + + /* + * Bump statistics counters + */ + sscop_stat.sos_maa_error[i]++; + + /* + * Log error message + */ + if (sscop_maa_log[i] != 0) { + struct vccb *vcp = sop->so_connvc->cvc_vcc; + struct atm_pif *pip = vcp->vc_pif; + + log(LOG_ERR, + "sscop_maa_error: intf=%s%d vpi=%d vci=%d code=%c state=%d\n", + pip->pif_name, pip->pif_unit, + vcp->vc_vpi, vcp->vc_vci, code, sop->so_state); + } +} + + +/* + * Abort an SSCOP connection + * + * Called when an unrecoverable or "should never happen" error occurs. + * We log a message, send an END PDU to our peer and request the signalling + * manager to abort the connection. + * + * Arguments: + * sop pointer to sscop control block + * msg pointer to error message + * + * Returns: + * none + * + */ +void +sscop_abort(sop, msg) + struct sscop *sop; + char *msg; +{ + Atm_connvc *cvp = sop->so_connvc; + + /* + * Log and count error + */ + log(LOG_ERR, msg); + sscop_stat.sos_aborts++; + + /* + * Send an END PDU as a courtesy to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Set termination state + */ + sop->so_state = SOS_TERM; + + /* + * Flush all of our queues + */ + sscop_xmit_drain(sop); + sscop_rcvr_drain(sop); + + /* + * Tell Connection Manager to abort this connection + */ + (void) atm_cm_abort(cvp, &sscop_cause); +} + diff --git a/sys/netatm/uni/sscop.h b/sys/netatm/uni/sscop.h new file mode 100644 index 0000000..2f786b3 --- /dev/null +++ b/sys/netatm/uni/sscop.h @@ -0,0 +1,80 @@ +/* + * + * =================================== + * 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: sscop.h,v 1.4 1998/08/26 23:29:19 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP protocol definitions + * + */ + +#ifndef _UNI_SSCOP_H +#define _UNI_SSCOP_H + +/* + * SSCOP Version + */ +enum sscop_vers { + SSCOP_VERS_QSAAL, /* Version = Q.SAAL1 */ + SSCOP_VERS_Q2110 /* Version = Q.2110 */ +}; + + +/* + * SSCOP API definitions + */ +#define SSCOP_UU_NULL 0 /* User-to-User Info = null */ +#define SSCOP_RN_TOTAL -1 /* Retrieval Number = Total */ +#define SSCOP_RN_UNKNOWN -2 /* Retrieval Number = Unknown */ +#define SSCOP_BR_YES 1 /* Buffer Release = Yes */ +#define SSCOP_BR_NO 2 /* Buffer Release = No */ +#define SSCOP_SOURCE_SSCOP 1 /* Source = SSCOP */ +#define SSCOP_SOURCE_USER 2 /* Source = User */ +#define SSCOP_SOURCE_LAST 3 /* Source = from last END */ + + +/* + * Connection parameters for an SSCOP entity. + * Passed via an SSCOP_INIT stack call argument. + */ +struct sscop_parms { + u_short sp_maxinfo; /* k - max information field size */ + u_short sp_maxuu; /* j - max SSCOP-UU field size */ + short sp_maxcc; /* MaxCC - max value of VT(CC) */ + short sp_maxpd; /* MaxPD - max value of VT(PD) */ + u_short sp_timecc; /* Timer_CC value (ticks) */ + u_short sp_timekeep; /* Timer_KEEPALIVE value (ticks) */ + u_short sp_timeresp; /* Timer_NO-RESPONSE value (ticks) */ + u_short sp_timepoll; /* Timer_POLL value (ticks) */ + u_short sp_timeidle; /* Timer_IDLE value (ticks) */ + short sp_rcvwin; /* Receiver window size */ +}; + +#endif /* _UNI_SSCOP_H */ diff --git a/sys/netatm/uni/sscop_lower.c b/sys/netatm/uni/sscop_lower.c new file mode 100644 index 0000000..f76f702 --- /dev/null +++ b/sys/netatm/uni/sscop_lower.c @@ -0,0 +1,349 @@ +/* + * + * =================================== + * 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: sscop_lower.c,v 1.6 1998/04/07 23:21:28 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - SSCOP SAP interface processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_lower.c,v 1.6 1998/04/07 23:21:28 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local variables + */ +/* + * Stack commands with arg1 containing an buffer pointer + */ +static u_char sscop_buf1[] = { + 0, + 0, /* SSCOP_INIT */ + 0, /* SSCOP_TERM */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, /* SSCOP_ESTABLISH_REQ */ + 0, + 1, /* SSCOP_ESTABLISH_RSP */ + 0, + 1, /* SSCOP_RELEASE_REQ */ + 0, + 0, + 1, /* SSCOP_DATA_REQ */ + 0, + 1, /* SSCOP_RESYNC_REQ */ + 0, + 0, /* SSCOP_RESYNC_RSP */ + 0, + 0, + 0, /* SSCOP_RECOVER_RSP */ + 1, /* SSCOP_UNITDATA_REQ */ + 0, + 0, /* SSCOP_RETRIEVE_REQ */ + 0, + 0 +}; + + +/* + * SSCOP Lower Stack Command Handler + * + * This function will receive all of the stack commands issued from the + * layer above SSCOP (ie. using the SSCOP SAP). The appropriate processing + * function will be determined based on the received stack command and the + * current sscop control block state. + * + * Arguments: + * cmd stack command code + * tok session token + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscop_lower(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + struct sscop *sop = (struct sscop *)tok; + void (**stab) __P((struct sscop *, int, int)); + void (*func) __P((struct sscop *, int, int)); + int val; + + ATM_DEBUG5("sscop_lower: cmd=0x%x, sop=0x%x, state=%d, arg1=0x%x, arg2=0x%x\n", + cmd, (int)sop, sop->so_state, arg1, arg2); + + /* + * Validate stack command + */ + val = cmd & STKCMD_VAL_MASK; + if (((u_int)cmd < (u_int)SSCOP_CMD_MIN) || + ((u_int)cmd > (u_int)SSCOP_CMD_MAX) || + ((stab = (sop->so_vers == SSCOP_VERS_QSAAL ? + sscop_qsaal_aatab[val] : + sscop_q2110_aatab[val])) == NULL)) { + log(LOG_ERR, "sscop_lower: unknown cmd 0x%x, sop=0x%x\n", + cmd, (int)sop); + return; + } + + /* + * Validate sscop state + */ + if (sop->so_state > SOS_MAXSTATE) { + log(LOG_ERR, "sscop_lower: invalid state sop=0x%x, state=%d\n", + (int)sop, sop->so_state); + /* + * Release possible buffer + */ + if (sscop_buf1[val]) { + if (arg1) + KB_FREEALL((KBuffer *)arg1); + } + return; + } + + /* + * Validate command/state combination + */ + func = stab[sop->so_state]; + if (func == NULL) { + log(LOG_ERR, + "sscop_lower: invalid cmd/state: sop=0x%x, cmd=0x%x, state=%d\n", + (int)sop, cmd, sop->so_state); + /* + * Release possible buffer + */ + if (sscop_buf1[val]) { + if (arg1) + KB_FREEALL((KBuffer *)arg1); + } + return; + } + + /* + * Call event processing function + */ + (*func)(sop, arg1, arg2); + + return; +} + + +/* + * No-op Processor (no buffers) + * + * Arguments: + * sop pointer to sscop connection block + * arg1 command-specific argument + * arg2 command-specific argument + * + * Returns: + * none + * + */ +void +sscop_aa_noop_0(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + /* + * Nothing to do + */ + return; +} + + +/* + * No-op Processor (arg1 == buffer) + * + * Arguments: + * sop pointer to sscop connection block + * arg1 command-specific argument (buffer pointer) + * arg2 command-specific argument + * + * Returns: + * none + * + */ +void +sscop_aa_noop_1(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Just free buffer chain + */ + if (arg1) + KB_FREEALL((KBuffer *)arg1); + + return; +} + + +/* + * SSCOP_INIT / SOS_INST Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscop_init_inst(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + int err; + + /* + * Make ourselves ready and pass on the INIT + */ + sop->so_state = SOS_IDLE; + + /* + * Validate SSCOP version to use + */ + switch ((enum sscop_vers)arg1) { + case SSCOP_VERS_QSAAL: + break; + + case SSCOP_VERS_Q2110: + break; + + default: + sscop_abort(sop, "sscop: bad version\n"); + return; + } + sop->so_vers = (enum sscop_vers)arg1; + + /* + * Copy SSCOP connection parameters to use + */ + sop->so_parm = *(struct sscop_parms *)arg2; + + /* + * Initialize lower layers + */ + STACK_CALL(CPCS_INIT, sop->so_lower, sop->so_tokl, sop->so_connvc, + 0, 0, err); + if (err) { + /* + * Should never happen + */ + sscop_abort(sop, "sscop: INIT failure\n"); + return; + } + return; +} + + +/* + * SSCOP_TERM / SOS_* Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscop_term_all(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + int err; + + /* + * Set termination state + */ + sop->so_state = SOS_TERM; + + /* + * Pass the TERM down the stack + */ + STACK_CALL(CPCS_TERM, sop->so_lower, sop->so_tokl, sop->so_connvc, + 0, 0, err); + if (err) { + /* + * Should never happen + */ + sscop_abort(sop, "sscop: TERM failure\n"); + return; + } + + /* + * Unlink and free the connection block + */ + UNLINK(sop, struct sscop, sscop_head, so_next); + atm_free((caddr_t)sop); + sscop_vccnt--; + return; +} + diff --git a/sys/netatm/uni/sscop_misc.h b/sys/netatm/uni/sscop_misc.h new file mode 100644 index 0000000..4348cef --- /dev/null +++ b/sys/netatm/uni/sscop_misc.h @@ -0,0 +1,97 @@ +/* + * + * =================================== + * 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: sscop_misc.h,v 1.4 1998/08/26 23:29:19 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP miscellaneous definitions + * + */ + +#ifndef _UNI_SSCOP_MISC_H +#define _UNI_SSCOP_MISC_H + +/* + * SSCOP command definitions + */ +#define SSCOP_CMD_MIN SSCOP_INIT /* Minimum SSCOP CMD value */ +#define SSCOP_CMD_MAX SSCOP_RETRIEVECMP_IND /* Maximum SSCOP CMD value */ +#define SSCOP_CMD_SIZE 36 /* Size of command lookup table */ + + +/* + * Management Errors + */ +#define MAA_ERROR_MIN 'A' +#define MAA_ERROR_MAX 'X' +#define MAA_ERROR_INVAL (MAA_ERROR_MAX + 1) +#define MAA_ERROR_COUNT (MAA_ERROR_MAX - MAA_ERROR_MIN + 2) + + +/* + * SSCOP Sequence Numbers + * + * SSCOP sequence numbers are 24 bit integers using modulo arithmetic. + * The macros below must be used to modify and compare such numbers. + * Comparison of sequence numbers is always relative to some base number (b). + */ +typedef u_int sscop_seq; + +#define SEQ_MOD 0xffffff +#define SEQ_VAL(v) ((v) & SEQ_MOD) +#define SEQ_SET(s,v) ((s) = SEQ_VAL(v)) +#define SEQ_ADD(s,v) (SEQ_VAL((s) + (v))) +#define SEQ_SUB(s,v) (SEQ_VAL((s) - (v))) +#define SEQ_INCR(s,v) ((s) = SEQ_VAL((s) + (v))) +#define SEQ_DECR(s,v) ((s) = SEQ_VAL((s) - (v))) +#define SEQ_EQ(x,y) (SEQ_VAL(x) == SEQ_VAL(y)) +#define SEQ_NEQ(x,y) (SEQ_VAL(x) != SEQ_VAL(y)) +#define SEQ_LT(x,y,b) (SEQ_VAL((x) - (b)) < SEQ_VAL((y) - (b))) +#define SEQ_LEQ(x,y,b) (SEQ_VAL((x) - (b)) <= SEQ_VAL((y) - (b))) +#define SEQ_GT(x,y,b) (SEQ_VAL((x) - (b)) > SEQ_VAL((y) - (b))) +#define SEQ_GEQ(x,y,b) (SEQ_VAL((x) - (b)) >= SEQ_VAL((y) - (b))) + + +/* + * SSCOP Timers + * + * All of the SSCOP timer fields are maintained in terms of clock ticks. + * The timers tick 2 times per second. + */ +#define SSCOP_HZ 2 /* SSCOP ticks per second */ + +#define SSCOP_T_NUM 4 /* Number of timers per connection */ + +#define SSCOP_T_POLL 0 /* Timer_POLL / Timer_KEEP-ALIVE */ +#define SSCOP_T_NORESP 1 /* Timer_NO-RESPONSE */ +#define SSCOP_T_CC 2 /* Timer_CC */ +#define SSCOP_T_IDLE 3 /* Timer_IDLE */ + +#endif /* _UNI_SSCOP_MISC_H */ diff --git a/sys/netatm/uni/sscop_pdu.c b/sys/netatm/uni/sscop_pdu.c new file mode 100644 index 0000000..b9aec03 --- /dev/null +++ b/sys/netatm/uni/sscop_pdu.c @@ -0,0 +1,1237 @@ +/* + * + * =================================== + * 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: sscop_pdu.c,v 1.6 1998/04/07 23:21:36 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - PDU subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_pdu.c,v 1.6 1998/04/07 23:21:36 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + +/* + * Local functions + */ +static KBuffer * sscop_stat_init __P((struct sscop *)); +static KBuffer * sscop_stat_add __P((sscop_seq, KBuffer *)); +static int sscop_stat_end __P((struct sscop *, sscop_seq, + KBuffer *, KBuffer *)); +static int sscop_recv_locate __P((struct sscop *, sscop_seq, + struct pdu_hdr **)); + + +/* + * Build and send BGN PDU + * + * A BGN PDU will be constructed and passed down the protocol stack. + * The SSCOP-UU/N(UU) field is not supported. + * + * Arguments: + * sop pointer to sscop connection control block + * source originator of BGN PDU (Q.SAAL1 only) + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_bgn(sop, source) + struct sscop *sop; + int source; +{ + KBuffer *m; + struct bgn_pdu *bp; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct bgn_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct bgn_pdu))); + KB_LEN(m) = sizeof(struct bgn_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, bp, struct bgn_pdu *); + *(int *)&bp->bgn_rsvd[0] = 0; + if (sop->so_vers != SSCOP_VERS_QSAAL) + bp->bgn_nsq = sop->so_sendconn; + bp->bgn_nmr = + htonl((PT_BGN << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax)); + if ((sop->so_vers == SSCOP_VERS_QSAAL) && + (source == SSCOP_SOURCE_SSCOP)) + bp->bgn_type |= PT_SOURCE_SSCOP; + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send BGAK PDU + * + * A BGAK PDU will be constructed and passed down the protocol stack. + * The SSCOP-UU/N(UU) field is not supported. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_bgak(sop) + struct sscop *sop; +{ + KBuffer *m; + struct bgak_pdu *bp; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct bgak_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct bgak_pdu))); + KB_LEN(m) = sizeof(struct bgak_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, bp, struct bgak_pdu *); + bp->bgak_rsvd = 0; + bp->bgak_nmr = + htonl((PT_BGAK << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax)); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send BGREJ PDU + * + * A BGREJ PDU will be constructed and passed down the protocol stack. + * The SSCOP-UU/N(UU) field is not supported. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_bgrej(sop) + struct sscop *sop; +{ + KBuffer *m; + struct bgrej_pdu *bp; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct bgrej_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct bgrej_pdu))); + KB_LEN(m) = sizeof(struct bgrej_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, bp, struct bgrej_pdu *); + bp->bgrej_rsvd2 = 0; + *(u_int *)&bp->bgrej_type = htonl((PT_BGREJ << PT_TYPE_SHIFT) | 0); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send END PDU + * + * An END PDU will be constructed and passed down the protocol stack. + * The SSCOP-UU/N(UU) field is not supported. + * + * Arguments: + * sop pointer to sscop connection control block + * source originator of END PDU + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_end(sop, source) + struct sscop *sop; + int source; +{ + KBuffer *m; + struct end_pdu *ep; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct end_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct end_pdu))); + KB_LEN(m) = sizeof(struct end_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, ep, struct end_pdu *); + ep->end_rsvd2 = 0; + *(u_int *)&ep->end_type = htonl((PT_END << PT_TYPE_SHIFT) | 0); + if (source == SSCOP_SOURCE_SSCOP) { + ep->end_type |= PT_SOURCE_SSCOP; + sop->so_flags |= SOF_ENDSSCOP; + } else if (source == SSCOP_SOURCE_USER) + sop->so_flags &= ~SOF_ENDSSCOP; + else if ((source == SSCOP_SOURCE_LAST) && + (sop->so_flags & SOF_ENDSSCOP)) + ep->end_type |= PT_SOURCE_SSCOP; + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send ENDAK PDU + * + * An ENDAK PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_endak(sop) + struct sscop *sop; +{ + KBuffer *m; + struct endak_q2110_pdu *e2p; + struct endak_qsaal_pdu *esp; + int err, size; + + + /* + * Get size of PDU + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) + size = sizeof(struct endak_qsaal_pdu); + else + size = sizeof(struct endak_q2110_pdu); + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size)); + KB_LEN(m) = size; + + /* + * Build PDU + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) { + KB_DATASTART(m, esp, struct endak_qsaal_pdu *); + *(u_int *)&esp->endak_type = + htonl((PT_ENDAK << PT_TYPE_SHIFT) | 0); + } else { + KB_DATASTART(m, e2p, struct endak_q2110_pdu *); + e2p->endak_rsvd2 = 0; + *(u_int *)&e2p->endak_type = + htonl((PT_ENDAK << PT_TYPE_SHIFT) | 0); + } + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send RS PDU + * + * A RS PDU will be constructed and passed down the protocol stack. + * The SSCOP-UU/N(UU) field is not supported. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_rs(sop) + struct sscop *sop; +{ + KBuffer *m; + struct rs_pdu *rp; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct rs_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct rs_pdu))); + KB_LEN(m) = sizeof(struct rs_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, rp, struct rs_pdu *); + *(int *)&rp->rs_rsvd[0] = 0; + if (sop->so_vers != SSCOP_VERS_QSAAL) { + rp->rs_nsq = sop->so_sendconn; + rp->rs_nmr = htonl((PT_RS << PT_TYPE_SHIFT) | + SEQ_VAL(sop->so_rcvmax)); + } else { + rp->rs_nmr = htonl((PT_RS << PT_TYPE_SHIFT) | 0); + } + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send RSAK PDU + * + * An RSAK PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_rsak(sop) + struct sscop *sop; +{ + KBuffer *m; + struct rsak_q2110_pdu *r2p; + struct rsak_qsaal_pdu *rsp; + int err, size; + + + /* + * Get size of PDU + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) + size = sizeof(struct rsak_qsaal_pdu); + else + size = sizeof(struct rsak_q2110_pdu); + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size)); + KB_LEN(m) = size; + + /* + * Build PDU + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) { + KB_DATASTART(m, rsp, struct rsak_qsaal_pdu *); + *(u_int *)&rsp->rsaks_type = + htonl((PT_RSAK << PT_TYPE_SHIFT) | 0); + } else { + KB_DATASTART(m, r2p, struct rsak_q2110_pdu *); + r2p->rsak_rsvd = 0; + r2p->rsak_nmr = htonl((PT_RSAK << PT_TYPE_SHIFT) | + SEQ_VAL(sop->so_rcvmax)); + } + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send ER PDU + * + * An ER PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_er(sop) + struct sscop *sop; +{ + KBuffer *m; + struct er_pdu *ep; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct er_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct er_pdu))); + KB_LEN(m) = sizeof(struct er_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, ep, struct er_pdu *); + *(int *)&ep->er_rsvd[0] = 0; + ep->er_nsq = sop->so_sendconn; + ep->er_nmr = htonl((PT_ER << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax)); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send ERAK PDU + * + * An ERAK PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_erak(sop) + struct sscop *sop; +{ + KBuffer *m; + struct erak_pdu *ep; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct erak_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct erak_pdu))); + KB_LEN(m) = sizeof(struct erak_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, ep, struct erak_pdu *); + ep->erak_rsvd = 0; + ep->erak_nmr = htonl((PT_ERAK << PT_TYPE_SHIFT) | + SEQ_VAL(sop->so_rcvmax)); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send POLL PDU + * + * A POLL PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_poll(sop) + struct sscop *sop; +{ + KBuffer *m; + struct poll_pdu *pp; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct poll_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct poll_pdu))); + KB_LEN(m) = sizeof(struct poll_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, pp, struct poll_pdu *); + pp->poll_nps = htonl(SEQ_VAL(sop->so_pollsend)); + pp->poll_ns = htonl((PT_POLL << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_send)); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * STAT PDU Construction - Initialize for new PDU + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * addr pointer to initialized buffer + * 0 unable to allocate buffer + * + */ +static KBuffer * +sscop_stat_init(sop) + struct sscop *sop; +{ + KBuffer *m; + +#define STAT_INIT_SIZE (sizeof(struct stat_pdu) + 2 * sizeof(sscop_seq)) + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, STAT_INIT_SIZE, KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (0); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, sop->so_headout < (KB_BFRLEN(m) - STAT_INIT_SIZE) ? + sop->so_headout : 0); + KB_LEN(m) = 0; + + return (m); +#undef STAT_INIT_SIZE +} + + +/* + * STAT PDU Construction - Add List Element + * + * Arguments: + * elem sequence number to add to list + * m pointer to current buffer + * + * Returns: + * addr pointer to current buffer (updated) + * 0 buffer allocation failure + * + */ +static KBuffer * +sscop_stat_add(elem, m) + sscop_seq elem; + KBuffer *m; +{ + KBuffer *n; + sscop_seq *sp; + int space; + + /* + * See if new element will fit in current buffer + */ + KB_TAILROOM(m, space); + if (space < sizeof(elem)) { + + /* + * Nope, so get another buffer + */ + KB_ALLOC(n, sizeof(elem), KB_F_NOWAIT, KB_T_DATA); + if (n == NULL) + return (0); + + /* + * Link in new buffer + */ + KB_LINK(n, m); + KB_LEN(n) = 0; + m = n; + } + + /* + * Add new element + */ + KB_DATAEND(m, sp, sscop_seq *); + *sp = htonl(elem); + KB_LEN(m) += sizeof (elem); + return (m); +} + + +/* + * STAT PDU Construction - Add Trailer and Send + * + * Arguments: + * sop pointer to sscop connection control block + * nps received poll sequence number (POLL.N(PS)) + * head pointer to head of buffer chain + * m pointer to current (last) buffer + * + * Returns: + * 0 STAT successfully sent + * else unable to send STAT or truncated STAT was sent - buffer freed + * + */ +static int +sscop_stat_end(sop, nps, head, m) + struct sscop *sop; + sscop_seq nps; + KBuffer *head; + KBuffer *m; +{ + struct stat_pdu *sp; + KBuffer *n; + int err, space, trunc = 0; + + /* + * See if PDU trailer will fit in current buffer + */ + KB_TAILROOM(m, space); + if (space < sizeof(struct stat_pdu)) { + + /* + * Doesn't fit, so get another buffer + */ + KB_ALLOC(n, sizeof(struct stat_pdu), KB_F_NOWAIT, KB_T_DATA); + if (n == NULL) { + /* + * Out of buffers - truncate elements and send + * what we can, but tell caller that we can't + * send any more segments. + */ + trunc = 1; + do { + KB_LEN(m) -= sizeof(sscop_seq); + space += sizeof(sscop_seq); + } while (space < sizeof(struct stat_pdu)); + } else { + /* + * Link in new buffer + */ + KB_LINK(n, m); + KB_LEN(n) = 0; + m = n; + } + } + + /* + * Build PDU trailer + */ + KB_DATAEND(m, sp, struct stat_pdu *); + sp->stat_nps = htonl(nps); + sp->stat_nmr = htonl(sop->so_rcvmax); + sp->stat_nr = htonl(sop->so_rcvnext); + sp->stat_type = PT_STAT; + KB_LEN(m) += sizeof(struct stat_pdu); + + /* + * Finally, send the STAT + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)head, 0, err); + + if (err) { + /* + * We lie about the STACK_CALL failing... + */ + KB_FREEALL(head); + } + + if (trunc) + return (1); + else + return (0); +} + + +/* + * Check for PDU in Receive Queue + * + * A receive queue will be searched for an SD PDU matching the requested + * sequence number. The caller must supply a pointer to the address of the + * PDU in the particular receive queue at which to begin the search. This + * function will update that pointer as it traverses the queue. + * + * Arguments: + * sop pointer to sscop connection control block + * seq sequence number of PDU to locate + * currp address of pointer to PDU in receive queue to start search + * + * Returns: + * 0 reqeusted PDU not in receive queue + * 1 requested PDU located in receive queue + * + */ +static int +sscop_recv_locate(sop, seq, currp) + struct sscop *sop; + sscop_seq seq; + struct pdu_hdr **currp; +{ + sscop_seq cs; + + /* + * Search queue until we know the answer + */ + while (1) { + /* + * If we're at the end of the queue, the PDU isn't there + */ + if (*currp == NULL) + return (0); + + /* + * Get the current PDU sequence number + */ + cs = (*currp)->ph_ns; + + /* + * See if we're at the requested PDU + */ + if (seq == cs) + return (1); + + /* + * If we're past the requested seq number, + * the PDU isn't there + */ + if (SEQ_LT(seq, cs, sop->so_rcvnext)) + return (0); + + /* + * Go to next PDU and keep looking + */ + *currp = (*currp)->ph_recv_lk; + } +} + + +/* + * Build and send STAT PDU + * + * A STAT PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * nps received poll sequence number (POLL.N(PS)) + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send complete pdu + * + */ +int +sscop_send_stat(sop, nps) + struct sscop *sop; + sscop_seq nps; +{ + KBuffer *head, *curr, *n; + struct pdu_hdr *rq = sop->so_recv_hd; + sscop_seq i; + sscop_seq vrh = sop->so_rcvhigh; + sscop_seq vrr = sop->so_rcvnext; + int len = 0; + + /* + * Initialize for start of STAT PDU + */ + head = sscop_stat_init(sop); + if (head == NULL) + return (1); + curr = head; + + /* + * Start with first PDU not yet received + */ + i = vrr; + + /* + * Keep looping until we get to last sent PDU + */ + while (i != vrh) { + + /* + * Find next missing PDU + */ + while (SEQ_LT(i, vrh, vrr) && sscop_recv_locate(sop, i, &rq)) { + SEQ_INCR(i, 1); + } + + /* + * Add odd (start of missing gap) STAT element + */ + n = sscop_stat_add(i, curr); + if (n == NULL) { + goto nobufs; + } + curr = n; + len++; + + /* + * Have we reached the last sent PDU sequence number?? + */ + if (i == vrh) { + /* + * Yes, then we're done, send STAT + */ + break; + } + + /* + * Have we reached the max STAT size yet?? + */ + if (len >= PDU_MAX_ELEM) { + /* + * Yes, send this STAT segment + */ + if (sscop_stat_end(sop, nps, head, curr)) { + return (1); + } + + /* + * Start a new segment + */ + head = sscop_stat_init(sop); + if (head == NULL) + return (1); + curr = head; + + /* + * Restart missing gap + */ + curr = sscop_stat_add(i, curr); + if (curr == NULL) { + KB_FREEALL(head); + return (1); + } + len = 1; + } + + /* + * Now find the end of the missing gap + */ + do { + SEQ_INCR(i, 1); + } while (SEQ_LT(i, vrh, vrr) && + (sscop_recv_locate(sop, i, &rq) == 0)); + + /* + * Add even (start of received gap) STAT element + */ + n = sscop_stat_add(i, curr); + if (n == NULL) { + goto nobufs; + } + curr = n; + len++; + } + + /* + * Finally, send the STAT PDU (or last STAT segment) + */ + if (sscop_stat_end(sop, nps, head, curr)) { + return (1); + } + + return (0); + +nobufs: + /* + * Send a truncated STAT PDU + */ + sscop_stat_end(sop, nps, head, curr); + + return (1); +} + + +/* + * Build and send USTAT PDU + * + * A USTAT PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * ns sequence number for second list element + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_ustat(sop, ns) + struct sscop *sop; + sscop_seq ns; +{ + KBuffer *m; + struct ustat_pdu *up; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct ustat_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct ustat_pdu))); + KB_LEN(m) = sizeof(struct ustat_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, up, struct ustat_pdu *); + up->ustat_le1 = htonl(SEQ_VAL(sop->so_rcvhigh)); + up->ustat_le2 = htonl(SEQ_VAL(ns)); + up->ustat_nmr = htonl(SEQ_VAL(sop->so_rcvmax)); + up->ustat_nr = + htonl((PT_USTAT << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvnext)); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send UD PDU + * + * A UD PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * m pointer to user data buffer chain + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu (buffer released) + * + */ +int +sscop_send_ud(sop, m) + struct sscop *sop; + KBuffer *m; +{ + KBuffer *ml, *n; + int len = 0, err; + int pad, trlen, space; + u_char *cp; + + /* + * Count data and get to last buffer in chain + */ + for (ml = m; ; ml = KB_NEXT(ml)) { + len += KB_LEN(ml); + if (KB_NEXT(ml) == NULL) + break; + } + + /* + * Verify data length + */ + if (len > sop->so_parm.sp_maxinfo) { + KB_FREEALL(m); + sscop_abort(sop, "sscop: maximum unitdata size exceeded\n"); + return (1); + } + + /* + * Figure out how much padding we'll need + */ + pad = ((len + (PDU_PAD_ALIGN - 1)) & ~(PDU_PAD_ALIGN - 1)) - len; + trlen = pad + sizeof(struct ud_pdu); + + /* + * Get space for PDU trailer and padding + */ + KB_TAILROOM(ml, space); + if (space < trlen) { + /* + * Allocate & link buffer for pad and trailer + */ + KB_ALLOC(n, trlen, KB_F_NOWAIT, KB_T_HEADER); + if (n == NULL) + return (1); + + KB_LEN(n) = 0; + KB_LINK(n, ml); + ml = n; + } + + /* + * Build the PDU trailer + * + * Since we can't be sure of alignment in the buffers, we + * have to move this a byte at a time. + */ + KB_DATAEND(ml, cp, u_char *); + cp += pad; + *cp++ = (pad << PT_PAD_SHIFT) | PT_UD; + KM_ZERO(cp, 3); + KB_LEN(ml) += trlen; + + /* + * Now pass PDU down the stack + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Print an SSCOP PDU + * + * Arguments: + * sop pointer to sscop connection control block + * m pointer to pdu buffer chain + * msg pointer to message string + * + * Returns: + * none + * + */ +void +sscop_pdu_print(sop, m, msg) + struct sscop *sop; + KBuffer *m; + char *msg; +{ + char buf[128]; + struct vccb *vcp; + + vcp = sop->so_connvc->cvc_vcc; + sprintf(buf, "sscop %s: vcc=(%d,%d)\n", msg, vcp->vc_vpi, vcp->vc_vci); + atm_pdu_print(m, buf); +} + diff --git a/sys/netatm/uni/sscop_pdu.h b/sys/netatm/uni/sscop_pdu.h new file mode 100644 index 0000000..387a602 --- /dev/null +++ b/sys/netatm/uni/sscop_pdu.h @@ -0,0 +1,317 @@ +/* + * + * =================================== + * 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: sscop_pdu.h,v 1.3 1997/05/06 22:20:15 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP Protocol Data Unit (PDU) definitions + * + */ + +#ifndef _UNI_SSCOP_PDU_H +#define _UNI_SSCOP_PDU_H + +/* + * SSCOP PDU Constants + */ +#define PDU_MIN_LEN 4 /* Minimum PDU length */ +#define PDU_LEN_MASK 3 /* PDU length must be 32-bit aligned */ +#define PDU_ADDR_MASK 3 /* PDUs must be 32-bit aligned */ +#define PDU_SEQ_MASK 0x00ffffff /* Mask for 24-bit sequence values */ +#define PDU_MAX_INFO 65528 /* Maximum length of PDU info field */ +#define PDU_MAX_UU 65524 /* Maximum length of SSCOP-UU field */ +#define PDU_MAX_STAT 65520 /* Maximum length of STAT list */ +#define PDU_MAX_ELEM 67 /* Maximum elements sent in STAT */ +#define PDU_PAD_ALIGN 4 /* I-field padding alignment */ + + +/* + * PDU Queueing Header + * + * There will be a queueing header tacked on to the front of each + * buffer chain that is placed on any of the sscop SD PDU queues (not + * including the SD transmission queue). Note that this header will + * not be included in the buffer data length/offset fields. + */ +struct pdu_hdr { + union { + struct pdu_hdr *phu_pack_lk; /* Pending ack queue link */ + struct pdu_hdr *phu_recv_lk; /* Receive queue link */ + } ph_u; + struct pdu_hdr *ph_rexmit_lk; /* Retranmit queue link */ + sscop_seq ph_ns; /* SD.N(S) - SD's sequence number */ + sscop_seq ph_nps; /* SD.N(PS) - SD's poll sequence */ + KBuffer *ph_buf; /* Pointer to containing buffer */ +}; +#define ph_pack_lk ph_u.phu_pack_lk +#define ph_recv_lk ph_u.phu_recv_lk + + +/* + * SSCOP PDU formats + * + * N.B. - all SSCOP PDUs are trailer oriented (don't ask me...) + */ + +/* + * PDU Type Fields + */ +#define PT_PAD_MASK 0xc0 /* Pad length mask */ +#define PT_PAD_SHIFT 6 /* Pad byte shift count */ +#define PT_SOURCE_SSCOP 0x10 /* Source = SSCOP */ +#define PT_TYPE_MASK 0x0f /* Type mask */ +#define PT_TYPE_MAX 0x0f /* Maximum pdu type */ +#define PT_TYPE_SHIFT 24 /* Type word shift count */ + +#define PT_BGN 0x01 /* Begin */ +#define PT_BGAK 0x02 /* Begin Acknowledge */ +#define PT_BGREJ 0x07 /* Begin Reject */ +#define PT_END 0x03 /* End */ +#define PT_ENDAK 0x04 /* End Acknowledge */ +#define PT_RS 0x05 /* Resynchronization */ +#define PT_RSAK 0x06 /* Resynchronization Acknowledge */ +#define PT_ER 0x09 /* Error Recovery */ +#define PT_ERAK 0x0f /* Error Recovery Acknowledge */ +#define PT_SD 0x08 /* Sequenced Data */ +#define PT_SDP 0x09 /* Sequenced Data with Poll */ +#define PT_POLL 0x0a /* Status Request */ +#define PT_STAT 0x0b /* Solicited Status Response */ +#define PT_USTAT 0x0c /* Unsolicited Status Response */ +#define PT_UD 0x0d /* Unnumbered Data */ +#define PT_MD 0x0e /* Management Data */ + +/* + * Begin PDU + */ +struct bgn_pdu { + u_char bgn_rsvd[3]; /* Reserved */ + u_char bgn_nsq; /* N(SQ) */ + union { + u_char bgnu_type; /* PDU type, etc */ + sscop_seq bgnu_nmr; /* N(MR) */ + } bgn_u; +}; +#define bgn_type bgn_u.bgnu_type +#define bgn_nmr bgn_u.bgnu_nmr + +/* + * Begin Acknowledge PDU + */ +struct bgak_pdu { + int bgak_rsvd; /* Reserved */ + union { + u_char bgaku_type; /* PDU type, etc */ + sscop_seq bgaku_nmr; /* N(MR) */ + } bgak_u; +}; +#define bgak_type bgak_u.bgaku_type +#define bgak_nmr bgak_u.bgaku_nmr + +/* + * Begin Reject PDU + */ +struct bgrej_pdu { + int bgrej_rsvd2; /* Reserved */ + u_char bgrej_type; /* PDU type, etc */ + u_char bgrej_rsvd1[3]; /* Reserved */ +}; + +/* + * End PDU + */ +struct end_pdu { + int end_rsvd2; /* Reserved */ + u_char end_type; /* PDU type, etc */ + u_char end_rsvd1[3]; /* Reserved */ +}; + +/* + * End Acknowledge PDU (Q.2110) + */ +struct endak_q2110_pdu { + int endak_rsvd2; /* Reserved */ + u_char endak_type; /* PDU type, etc */ + u_char endak_rsvd1[3]; /* Reserved */ +}; + +/* + * End Acknowledge PDU (Q.SAAL) + */ +struct endak_qsaal_pdu { + u_char endak_type; /* PDU type, etc */ + u_char endak_rsvd[3]; /* Reserved */ +}; + +/* + * Resynchronization PDU + */ +struct rs_pdu { + char rs_rsvd[3]; /* Reserved */ + u_char rs_nsq; /* N(SQ) */ + union { + u_char rsu_type; /* PDU type, etc */ + sscop_seq rsu_nmr; /* N(MR) */ + } rs_u; +}; +#define rs_type rs_u.rsu_type +#define rs_nmr rs_u.rsu_nmr + +/* + * Resynchronization Acknowledge PDU (Q.2110) + */ +struct rsak_q2110_pdu { + int rsak_rsvd; /* Reserved */ + union { + u_char rsaku_type; /* PDU type, etc */ + sscop_seq rsaku_nmr; /* N(MR) */ + } rsak_u; +}; +#define rsak2_type rsak_u.rsaku_type +#define rsak_nmr rsak_u.rsaku_nmr + +/* + * Resynchronization Acknowledge PDU (Q.SAAL) + */ +struct rsak_qsaal_pdu { + u_char rsaks_type; /* PDU type, etc */ + u_char rsak_rsvd[3]; /* Reserved */ +}; + +/* + * Error Recovery PDU + */ +struct er_pdu { + char er_rsvd[3]; /* Reserved */ + u_char er_nsq; /* N(SQ) */ + union { + u_char eru_type; /* PDU type, etc */ + sscop_seq eru_nmr; /* N(MR) */ + } er_u; +}; +#define er_type er_u.eru_type +#define er_nmr er_u.eru_nmr + +/* + * Error Recovery Acknowledge PDU + */ +struct erak_pdu { + int erak_rsvd; /* Reserved */ + union { + u_char eraku_type; /* PDU type, etc */ + sscop_seq eraku_nmr; /* N(MR) */ + } erak_u; +}; +#define erak_type erak_u.eraku_type +#define erak_nmr erak_u.eraku_nmr + +/* + * Sequenced Data PDU + */ +struct sd_pdu { + union { + u_char sdu_type; /* PDU type, etc */ + sscop_seq sdu_ns; /* N(S) */ + } sd_u; +}; +#define sd_type sd_u.sdu_type +#define sd_ns sd_u.sdu_ns + +/* + * Sequenced Data with Poll PDU + */ +struct sdp_pdu { + sscop_seq sdp_nps; /* N(PS) */ + union { + u_char sdpu_type; /* PDU type, etc */ + sscop_seq sdpu_ns; /* N(S) */ + } sdp_u; +}; +#define sdp_type sdp_u.sdpu_type +#define sdp_ns sdp_u.sdpu_ns + +/* + * Poll PDU + */ +struct poll_pdu { + sscop_seq poll_nps; /* N(PS) */ + union { + u_char pollu_type; /* PDU type, etc */ + sscop_seq pollu_ns; /* N(S) */ + } poll_u; +}; +#define poll_type poll_u.pollu_type +#define poll_ns poll_u.pollu_ns + +/* + * Solicited Status PDU + */ +struct stat_pdu { + sscop_seq stat_nps; /* N(PS) */ + sscop_seq stat_nmr; /* N(MR) */ + union { + u_char statu_type; /* PDU type, etc */ + sscop_seq statu_nr; /* N(R) */ + } stat_u; +}; +#define stat_type stat_u.statu_type +#define stat_nr stat_u.statu_nr + +/* + * Unsolicited Status PDU + */ +struct ustat_pdu { + sscop_seq ustat_le1; /* List element 1 */ + sscop_seq ustat_le2; /* List element 2 */ + sscop_seq ustat_nmr; /* N(MR) */ + union { + u_char ustatu_type; /* PDU type, etc */ + sscop_seq ustatu_nr; /* N(R) */ + } ustat_u; +}; +#define ustat_type ustat_u.ustatu_type +#define ustat_nr ustat_u.ustatu_nr + +/* + * Unit Data PDU + */ +struct ud_pdu { + u_char ud_type; /* PDU type, etc */ + u_char ud_rsvd[3]; /* Reserved */ +}; + +/* + * Management Data PDU + */ +struct md_pdu { + u_char md_type; /* PDU type, etc */ + u_char md_rsvd[3]; /* Reserved */ +}; + +#endif /* _UNI_SSCOP_PDU_H */ diff --git a/sys/netatm/uni/sscop_sigaa.c b/sys/netatm/uni/sscop_sigaa.c new file mode 100644 index 0000000..8f347ce --- /dev/null +++ b/sys/netatm/uni/sscop_sigaa.c @@ -0,0 +1,449 @@ +/* + * + * =================================== + * 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: sscop_sigaa.c,v 1.1 1998/04/07 23:15:11 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP Common - Process AA-signals (SAP_SSCOP) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_sigaa.c,v 1.1 1998/04/07 23:15:11 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * SSCOP_ESTABLISH_REQ / SOS_IDLE Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 buffer release parameter + * + * Returns: + * none + * + */ +void +sscop_estreq_idle(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * We currently only support BR=YES + */ + if (arg2 != SSCOP_BR_YES) { + sscop_abort(sop, "sscop: BR != YES\n"); + return; + } + + /* + * Initialize receiver window + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + /* + * Send first BGN PDU + */ + sop->so_connctl = 1; + SEQ_INCR(sop->so_sendconn, 1); + (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER); + + /* + * Reset transmitter state + */ + if (sop->so_vers == SSCOP_VERS_Q2110) + q2110_clear_xmit(sop); + else + qsaal1_reset_xmit(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for BGAK + */ + sop->so_state = SOS_OUTCONN; + + return; +} + + +/* + * SSCOP_ESTABLISH_RSP / SOS_INCONN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 buffer release parameter + * + * Returns: + * none + * + */ +void +sscop_estrsp_inconn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * We currently only support BR=YES + */ + if (arg2 != SSCOP_BR_YES) { + sscop_abort(sop, "sscop: BR != YES\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_Q2110) { + /* + * Clear transmitter buffers + */ + q2110_clear_xmit(sop); + + /* + * Initialize state variables + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + q2110_init_state(sop); + } else { + /* + * Reset transmitter state + */ + qsaal1_reset_xmit(sop); + } + + /* + * Send BGAK PDU + */ + (void) sscop_send_bgak(sop); + + /* + * Start polling timer + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + + /* + * Start lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * OK, we're ready for data + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * SSCOP_RELEASE_REQ / SOS_OUTCONN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 unused + * + * Returns: + * none + * + */ +void +sscop_relreq_outconn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Clear reestablishment flag + */ + sop->so_flags &= ~SOF_REESTAB; + + /* + * Send first END PDU + */ + sop->so_connctl = 1; + (void) sscop_send_end(sop, SSCOP_SOURCE_USER); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for ENDAK + */ + sop->so_state = SOS_OUTDISC; + + return; +} + + +/* + * SSCOP_RELEASE_REQ / SOS_INCONN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 unused + * + * Returns: + * none + * + */ +void +sscop_relreq_inconn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Return a BGREJ PDU + */ + (void) sscop_send_bgrej(sop); + + /* + * Back to IDLE state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * SSCOP_RELEASE_REQ / SOS_READY Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 unused + * + * Returns: + * none + * + */ +void +sscop_relreq_ready(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Send first END PDU + */ + sop->so_connctl = 1; + (void) sscop_send_end(sop, SSCOP_SOURCE_USER); + + if (sop->so_vers == SSCOP_VERS_Q2110) { + /* + * Clear out appropriate queues + */ + if (sop->so_state == SOS_READY) + q2110_prep_retrieve(sop); + else + sscop_rcvr_drain(sop); + } else { + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + } + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for ENDAK + */ + sop->so_state = SOS_OUTDISC; + + return; +} + + +/* + * SSCOP_DATA_REQ / SOS_READY Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing assured user data + * arg2 unused + * + * Returns: + * none + * + */ +void +sscop_datreq_ready(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + KBuffer *m = (KBuffer *)arg1; + + /* + * We must have a buffer (even if it contains no data) + */ + if (m == NULL) { + sscop_abort(sop, "sscop_datreq_ready: no buffer\n"); + return; + } + + /* + * Place data at end of transmission queue + */ + KB_QNEXT(m) = NULL; + if (sop->so_xmit_hd == NULL) + sop->so_xmit_hd = m; + else + KB_QNEXT(sop->so_xmit_tl) = m; + sop->so_xmit_tl = m; + + /* + * Service the transmit queues + */ + sscop_service_xmit(sop); + + return; +} + + +/* + * SSCOP_UNITDATA_REQ / SOS_* Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing unassured user data + * arg2 unused + * + * Returns: + * none + * + */ +void +sscop_udtreq_all(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + KBuffer *m = (KBuffer *)arg1; + + /* + * We must have a buffer (even if it contains no data) + */ + if (m == NULL) { + sscop_abort(sop, "sscop_udtreq_all: no buffer\n"); + return; + } + + /* + * Send the data in a UD PDU + */ + (void) sscop_send_ud(sop, m); + + return; +} + diff --git a/sys/netatm/uni/sscop_sigcpcs.c b/sys/netatm/uni/sscop_sigcpcs.c new file mode 100644 index 0000000..a9bf504 --- /dev/null +++ b/sys/netatm/uni/sscop_sigcpcs.c @@ -0,0 +1,2311 @@ +/* + * + * =================================== + * 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: sscop_sigcpcs.c,v 1.2 1998/07/24 20:18:09 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP Common - Process CPCS-signals (SSCOP PDUs) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_sigcpcs.c,v 1.2 1998/07/24 20:18:09 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * No-op Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_noop(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + /* + * Just free PDU + */ + KB_FREEALL(m); + + return; +} + + +/* + * BGN PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgn_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err, source; + + if (sop->so_vers == SSCOP_VERS_Q2110) { + /* + * "Power-up Robustness" option + * + * Accept BGN regardless of BGN.N(SQ) + */ + sop->so_rcvconn = bp->bgn_nsq; + + } else { + /* + * If retransmitted BGN, reject it + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + (void) sscop_send_bgrej(sop); + return; + } + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Get Source value + */ + if (bp->bgn_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Reset receiver state variables + */ + qsaal1_reset_rcvr(sop); + } else + source = 0; + + /* + * Set initial transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + /* + * Pass connection request up to user + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user's response + */ + sop->so_state = SOS_INCONN; + + return; +} + + +/* + * BGN PDU / SOS_OUTDISC Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgn_outdisc(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err, source; + + /* + * If retransmitted BGN, ACK it and send new END + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + (void) sscop_send_bgak(sop); + (void) sscop_send_end(sop, SSCOP_SOURCE_LAST); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Get Source value + */ + if (bp->bgn_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Reset receiver variables + */ + qsaal1_reset_rcvr(sop); + + } else + source = 0; + + /* + * Tell user about incoming connection + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user's response + */ + sop->so_state = SOS_INCONN; + + return; +} + + +/* + * BGN PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgn_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err, source; + + /* + * If retransmitted BGN, ACK it and send new RS + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + (void) sscop_send_bgak(sop); + (void) sscop_send_rs(sop); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Get (possible) Source value + */ + if (bp->bgn_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Reset receiver variables + */ + qsaal1_reset_rcvr(sop); + + } else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Now tell user of a "new" incoming connection + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user's response + */ + sop->so_state = SOS_INCONN; + + return; +} + + +/* + * BGN PDU / SOS_INRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgn_inresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err, source; + + /* + * If retransmitted BGN, oops + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + sscop_maa_error(sop, 'B'); + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Get (possible) Source value + */ + if (bp->bgn_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Reset receiver variables + */ + qsaal1_reset_rcvr(sop); + + } else { + /* + * Stop possible retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Drain receiver queues + */ + sscop_rcvr_drain(sop); + + /* + * Tell user current connection has been released + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + source = 0; + } + + /* + * Tell user of incoming connection + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user's response + */ + sop->so_state = SOS_INCONN; + + return; +} + + +/* + * BGAK PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgak_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'C'); + KB_FREEALL(m); + + return; +} + + +/* + * BGAK PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgak_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_bgak_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * BGAK PDU / SOS_OUTCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgak_outconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgak_pdu *bp = (struct bgak_pdu *)trlr; + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgak_nmr)); + + /* + * Notify user of connection establishment + */ + if (sop->so_flags & SOF_REESTAB) { + KB_FREEALL(m); + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + sop->so_flags &= ~SOF_REESTAB; + } else { + STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Reset receiver variables + */ + qsaal1_reset_rcvr(sop); + + /* + * Start polling timer + */ + sscop_set_poll(sop); + + /* + * Start lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + } else { + /* + * Initialize state variables + */ + q2110_init_state(sop); + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + } + + /* + * OK, we're ready for data + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * BGREJ PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgrej_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'D'); + KB_FREEALL(m); + return; +} + + +/* + * BGREJ PDU / SOS_OUTCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgrej_outconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int source, uu, err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Clear reestablishment flag + */ + sop->so_flags &= ~SOF_REESTAB; + + KB_FREEALL(m); + m = NULL; + uu = SSCOP_UU_NULL; + source = SSCOP_SOURCE_SSCOP; + } else { + uu = (int)m; + source = SSCOP_SOURCE_USER; + } + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, uu, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * BGREJ PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgrej_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Report protocol error + */ + sscop_bgrej_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * BGREJ PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgrej_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Report protocol error + */ + sscop_bgrej_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * BGREJ PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgrej_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Report protocol error + */ + sscop_bgrej_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + } else { + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_end_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Return an ENDAK to peer + */ + (void) sscop_send_endak(sop); + + return; +} + + +/* + * END PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_end_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct end_pdu *ep = (struct end_pdu *)trlr; + int err, source; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Get Source value + */ + if (ep->end_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_OUTDISC Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_end_outdisc(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Release buffers + */ + KB_FREEALL(m); + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * ENDAK PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_endak_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'F'); + KB_FREEALL(m); + + return; +} + + +/* + * ENDAK PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_endak_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Report protocol error + */ + sscop_endak_error(sop, m, trlr); + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * ENDAK PDU / SOS_OUTDISC Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_endak_outdisc(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Release buffers + */ + KB_FREEALL(m); + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * ENDAK PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_endak_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Report protocol error + */ + sscop_endak_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + } else { + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * RS PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_rs_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'J'); + KB_FREEALL(m); + + return; +} + + +/* + * RS PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_rs_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Report error condition + */ + sscop_rs_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + return; +} + + +/* + * RSAK PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_rsak_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'K'); + KB_FREEALL(m); + + return; +} + + +/* + * RSAK PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_rsak_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Report error condition + */ + sscop_rsak_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * RSAK PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_rsak_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct rsak_q2110_pdu *rp = (struct rsak_q2110_pdu *)trlr; + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Notify user of resynchronization completion + */ + STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Start the polling timer + */ + sscop_set_poll(sop); + + /* + * Start lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + } else { + /* + * Initialize state variables + */ + SEQ_SET(sop->so_sendmax, ntohl(rp->rsak_nmr)); + q2110_init_state(sop); + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + } + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Now go back to data transfer state + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * SD PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_sd_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'A'); + KB_FREEALL(m); + + return; +} + + +/* + * SD PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_sd_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_sd_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * SD PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_sd_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Record error condition + */ + sscop_sd_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * POLL PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_poll_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'G'); + KB_FREEALL(m); + + return; +} + + +/* + * POLL PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_poll_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Report error condition + */ + sscop_poll_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * POLL PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_poll_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Record error condition + */ + sscop_poll_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * STAT PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_stat_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'H'); + KB_FREEALL(m); + + return; +} + + +/* + * STAT PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_stat_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Report error condition + */ + sscop_stat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * STAT PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_stat_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Record error condition + */ + sscop_stat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * STAT PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_stat_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct stat_pdu *sp = (struct stat_pdu *)trlr; + struct pdu_hdr *php; + KBuffer *m0 = m; + sscop_seq seq1, seq2, opa; + int cnt = 0; + + NTOHL(sp->stat_nps); + NTOHL(sp->stat_nmr); + NTOHL(sp->stat_nr); + + /* + * Validate peer's received poll sequence number + */ + if (SEQ_GT(sop->so_pollack, sp->stat_nps, sop->so_pollack) || + SEQ_GT(sp->stat_nps, sop->so_pollsend, sop->so_pollack)) { + /* + * Bad poll sequence number + */ + sscop_maa_error(sop, 'R'); + goto goterr; + } + + /* + * Validate peer's current receive data sequence number + */ + if (SEQ_GT(sop->so_ack, sp->stat_nr, sop->so_ack) || + SEQ_GT(sp->stat_nr, sop->so_send, sop->so_ack)) { + /* + * Bad data sequence number + */ + sscop_maa_error(sop, 'S'); + goto goterr; + } + + /* + * Free acknowledged PDUs + */ + for (seq1 = sop->so_ack, SEQ_SET(seq2, sp->stat_nr); + SEQ_LT(seq1, seq2, sop->so_ack); + SEQ_INCR(seq1, 1)) { + sscop_pack_free(sop, seq1); + } + + /* + * Update transmit state variables + */ + opa = sop->so_pollack; + sop->so_ack = seq2; + SEQ_SET(sop->so_pollack, sp->stat_nps); + SEQ_SET(sop->so_sendmax, sp->stat_nmr); + + /* + * Get first element in STAT list + */ + while (m && (KB_LEN(m) == 0)) + m = KB_NEXT(m); + if (m == NULL) + goto done; + m = sscop_stat_getelem(m, &seq1); + + /* + * Make sure there's a second element too + */ + if (m == NULL) + goto done; + + /* + * Validate first element (start of missing pdus) + */ + if (SEQ_GT(sop->so_ack, seq1, sop->so_ack) || + SEQ_GEQ(seq1, sop->so_send, sop->so_ack)) { + /* + * Bad element sequence number + */ + sscop_maa_error(sop, 'S'); + goto goterr; + } + + /* + * Loop thru all STAT elements in list + */ + while (m) { + /* + * Get next even element (start of received pdus) + */ + m = sscop_stat_getelem(m, &seq2); + + /* + * Validate seqence number + */ + if (SEQ_GEQ(seq1, seq2, sop->so_ack) || + SEQ_GT(seq2, sop->so_send, sop->so_ack)) { + /* + * Bad element sequence number + */ + sscop_maa_error(sop, 'S'); + goto goterr; + } + + /* + * Process each missing sequence number in this gap + */ + while (SEQ_LT(seq1, seq2, sop->so_ack)) { + /* + * Find corresponding SD PDU on pending ack queue + */ + php = sscop_pack_locate(sop, seq1); + if (php == NULL) { + sscop_maa_error(sop, 'S'); + goto goterr; + } + + /* + * Retransmit this SD PDU only if it was last sent + * during an earlier poll sequence and it's not + * already scheduled for retranmission. + */ + if (SEQ_LT(php->ph_nps, sp->stat_nps, opa) && + (php->ph_rexmit_lk == NULL) && + (sop->so_rexmit_tl != php)) { + /* + * Put PDU on retransmit queue and schedule + * transmit servicing + */ + sscop_rexmit_insert(sop, php); + sop->so_flags |= SOF_XMITSRVC; + cnt++; + } + + /* + * Bump to next sequence number + */ + SEQ_INCR(seq1, 1); + } + + /* + * Now process series of acknowledged PDUs + * + * Get next odd element (start of missing pdus), + * but make sure there is one and that it's valid + */ + if (m == NULL) + goto done; + m = sscop_stat_getelem(m, &seq2); + if (SEQ_GEQ(seq1, seq2, sop->so_ack) || + SEQ_GT(seq2, sop->so_send, sop->so_ack)) { + /* + * Bad element sequence number + */ + sscop_maa_error(sop, 'S'); + goto goterr; + } + + /* + * Process each acked sequence number + */ + while (SEQ_LT(seq1, seq2, sop->so_ack)) { + /* + * Can we clear transmit buffers ?? + */ + if ((sop->so_flags & SOF_NOCLRBUF) == 0) { + /* + * Yes, free acked buffers + */ + sscop_pack_free(sop, seq1); + } + + /* + * Bump to next sequence number + */ + SEQ_INCR(seq1, 1); + } + } + +done: + /* + * Free PDU buffer chain + */ + KB_FREEALL(m0); + + /* + * Report retransmitted PDUs + */ + if (cnt) + sscop_maa_error(sop, 'V'); + + /* + * Record transmit window closed transitions + */ + if (SEQ_LT(sop->so_send, sop->so_sendmax, sop->so_ack)) { + if (sop->so_flags & SOF_NOCREDIT) { + sop->so_flags &= ~SOF_NOCREDIT; + sscop_maa_error(sop, 'X'); + } + } else { + if ((sop->so_flags & SOF_NOCREDIT) == 0) { + sop->so_flags |= SOF_NOCREDIT; + sscop_maa_error(sop, 'W'); + } + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Restart lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + else { + /* + * Determine new polling phase + */ + if ((sop->so_timer[SSCOP_T_POLL] != 0) && + ((sop->so_flags & SOF_KEEPALIVE) == 0)) { + /* + * Remain in active phase - reset NO-RESPONSE timer + */ + sop->so_timer[SSCOP_T_NORESP] = + sop->so_parm.sp_timeresp; + + } else if (sop->so_timer[SSCOP_T_IDLE] == 0) { + /* + * Go from transient to idle phase + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = sop->so_parm.sp_timeidle; + } + } + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; + +goterr: + /* + * Protocol/parameter error encountered + */ + + /* + * Free PDU buffer chain + */ + KB_FREEALL(m0); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Reestablish a new connection + */ + qsaal1_reestablish(sop); + else + /* + * Initiate error recovery + */ + q2110_error_recovery(sop); + + return; +} + + +/* + * USTAT PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_ustat_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'I'); + KB_FREEALL(m); + + return; +} + + +/* + * USTAT PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_ustat_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Report error condition + */ + sscop_ustat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * USTAT PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_ustat_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Record error condition + */ + sscop_ustat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * USTAT PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_ustat_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct ustat_pdu *up = (struct ustat_pdu *)trlr; + struct pdu_hdr *php; + sscop_seq seq1, seq2; + + NTOHL(up->ustat_nmr); + NTOHL(up->ustat_nr); + + /* + * Validate peer's current receive data sequence number + */ + if (SEQ_GT(sop->so_ack, up->ustat_nr, sop->so_ack) || + SEQ_GEQ(up->ustat_nr, sop->so_send, sop->so_ack)) { + /* + * Bad data sequence number + */ + goto goterr; + } + + /* + * Free acknowledged PDUs + */ + for (seq1 = sop->so_ack, SEQ_SET(seq2, up->ustat_nr); + SEQ_LT(seq1, seq2, sop->so_ack); + SEQ_INCR(seq1, 1)) { + sscop_pack_free(sop, seq1); + } + + /* + * Update transmit state variables + */ + sop->so_ack = seq2; + SEQ_SET(sop->so_sendmax, up->ustat_nmr); + + /* + * Get USTAT list elements + */ + SEQ_SET(seq1, ntohl(up->ustat_le1)); + SEQ_SET(seq2, ntohl(up->ustat_le2)); + + /* + * Validate elements + */ + if (SEQ_GT(sop->so_ack, seq1, sop->so_ack) || + SEQ_GEQ(seq1, seq2, sop->so_ack) || + SEQ_GEQ(seq2, sop->so_send, sop->so_ack)) { + /* + * Bad element sequence number + */ + goto goterr; + } + + /* + * Process each missing sequence number in this gap + */ + while (SEQ_LT(seq1, seq2, sop->so_ack)) { + /* + * Find corresponding SD PDU on pending ack queue + */ + php = sscop_pack_locate(sop, seq1); + if (php == NULL) { + goto goterr; + } + + /* + * Retransmit this SD PDU if it's not + * already scheduled for retranmission. + */ + if ((php->ph_rexmit_lk == NULL) && + (sop->so_rexmit_tl != php)) { + /* + * Put PDU on retransmit queue and schedule + * transmit servicing + */ + sscop_rexmit_insert(sop, php); + sop->so_flags |= SOF_XMITSRVC; + } + + /* + * Bump to next sequence number + */ + SEQ_INCR(seq1, 1); + } + + /* + * Report retransmitted PDUs + */ + sscop_maa_error(sop, 'V'); + + /* + * Free PDU buffer chain + */ + KB_FREEALL(m); + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; + +goterr: + /* + * Protocol/parameter error encountered + */ + sscop_maa_error(sop, 'T'); + + /* + * Free PDU buffer chain + */ + KB_FREEALL(m); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Reestablish a new connection + */ + qsaal1_reestablish(sop); + else + /* + * Initiate error recovery + */ + q2110_error_recovery(sop); + + return; +} + + +/* + * UD PDU / SOS_* Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_ud_all(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Pass data up to user + */ + STACK_CALL(SSCOP_UNITDATA_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) + KB_FREEALL(m); + return; +} + + +/* + * MD PDU / SOS_* Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_md_all(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * We don't support MD PDUs + */ + KB_FREEALL(m); + return; +} + diff --git a/sys/netatm/uni/sscop_subr.c b/sys/netatm/uni/sscop_subr.c new file mode 100644 index 0000000..2d01229 --- /dev/null +++ b/sys/netatm/uni/sscop_subr.c @@ -0,0 +1,972 @@ +/* + * + * =================================== + * 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: sscop_subr.c,v 1.7 1998/08/26 23:29:19 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - Subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_subr.c,v 1.7 1998/08/26 23:29:19 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static int sscop_proc_xmit __P((struct sscop *)); + + +/* + * Get Next Element from STAT PDU + * + * Arguments: + * m pointer to current buffer in STAT PDU + * pelem pointer to location to store element value + * + * Returns: + * addr pointer to updated current buffer in STAT PDU + * + */ +KBuffer * +sscop_stat_getelem(m, pelem) + KBuffer *m; + sscop_seq *pelem; +{ + caddr_t cp; + + /* + * Get to start of element + * + * Note that we always ensure that the current buffer has + * at least one byte of the next element. + */ + KB_DATASTART(m, cp, caddr_t); + + /* + * See how much of element is in this buffer + */ + if (KB_LEN(m) >= sizeof(sscop_seq)) { + /* + * Get element from this buffer + */ + if ((int)cp & (sizeof(sscop_seq) - 1)) + KM_COPY(cp, (caddr_t)pelem, sizeof(sscop_seq)); + else + *pelem = *(sscop_seq *)cp; + + /* + * Update buffer controls + */ + KB_HEADADJ(m, -sizeof(sscop_seq)); + } else { + /* + * Get element split between two buffers + */ + int i, j; + + /* + * Copy what's in this buffer + */ + i = KB_LEN(m); + KM_COPY(cp, (caddr_t)pelem, i); + KB_LEN(m) = 0; + + /* + * Now get to next buffer + */ + while (m && (KB_LEN(m) == 0)) + m = KB_NEXT(m); + + /* + * And copy remainder of element + */ + j = sizeof(sscop_seq) - i; + KB_DATASTART(m, cp, caddr_t); + KM_COPY(cp, (caddr_t)pelem + i, j); + + /* + * Update buffer controls + */ + KB_HEADADJ(m, -j); + } + + /* + * Put element (sequence number) into host order + */ + NTOHL(*pelem); + + /* + * Get pointers set for next call + */ + while (m && (KB_LEN(m) == 0)) + m = KB_NEXT(m); + + return (m); +} + + +/* + * Locate SD PDU on Pending Ack Queue + * + * Arguments: + * sop pointer to sscop connection block + * seq sequence number of PDU to locate + * + * Returns: + * addr pointer to located PDU header + * 0 SD PDU sequence number not found + * + */ +struct pdu_hdr * +sscop_pack_locate(sop, seq) + struct sscop *sop; + sscop_seq seq; +{ + struct pdu_hdr *php; + + /* + * Loop thru queue until we either find the PDU or the queue's + * sequence numbers are greater than the PDU's sequence number, + * indicating that the PDU is not on the queue. + */ + for (php = sop->so_pack_hd; php; php = php->ph_pack_lk) { + if (php->ph_ns == seq) + break; + + if (SEQ_GT(php->ph_ns, seq, sop->so_ack)) { + php = NULL; + break; + } + } + + return (php); +} + + +/* + * Free Acknowledged SD PDU + * + * Arguments: + * sop pointer to sscop connection block + * seq sequence number of PDU to free + * + * Returns: + * none + * + */ +void +sscop_pack_free(sop, seq) + struct sscop *sop; + sscop_seq seq; +{ + struct pdu_hdr *php, *prev; + + /* + * Unlink PDU from pending ack queue + * + * First, check for an empty queue + */ + php = sop->so_pack_hd; + if (php == NULL) + return; + + /* + * Now check for PDU at head of queue + */ + if (php->ph_ns == seq) { + if ((sop->so_pack_hd = php->ph_pack_lk) == NULL) + sop->so_pack_tl = NULL; + goto found; + } + + /* + * Otherwise, loop thru queue until we either find the PDU or + * the queue's sequence numbers are greater than the PDU's + * sequence number, indicating that the PDU is not on the queue. + */ + prev = php; + php = php->ph_pack_lk; + while (php) { + if (php->ph_ns == seq) { + if ((prev->ph_pack_lk = php->ph_pack_lk) == NULL) + sop->so_pack_tl = prev; + goto found; + } + + if (SEQ_GT(php->ph_ns, seq, sop->so_ack)) + return; + + prev = php; + php = php->ph_pack_lk; + } + + return; + +found: + /* + * We've got the ack'ed PDU - unlink it from retransmit queue + */ + sscop_rexmit_unlink(sop, php); + + /* + * Free PDU buffers + */ + KB_FREEALL(php->ph_buf); + + return; +} + + +/* + * Insert SD PDU into Retransmit Queue + * + * Arguments: + * sop pointer to sscop connection block + * php pointer to SD PDU header + * + * Returns: + * none + * + */ +void +sscop_rexmit_insert(sop, php) + struct sscop *sop; + struct pdu_hdr *php; +{ + struct pdu_hdr *curr, *next; + sscop_seq seq = php->ph_ns; + + /* + * Check for an empty queue + */ + if ((curr = sop->so_rexmit_hd) == NULL) { + php->ph_rexmit_lk = NULL; + sop->so_rexmit_hd = php; + sop->so_rexmit_tl = php; + return; + } + + /* + * Now see if PDU belongs at head of queue + */ + if (SEQ_LT(seq, curr->ph_ns, sop->so_ack)) { + php->ph_rexmit_lk = curr; + sop->so_rexmit_hd = php; + return; + } + + /* + * Otherwise, loop thru the queue until we find the + * proper insertion point for the PDU + */ + while (next = curr->ph_rexmit_lk) { + if (SEQ_LT(seq, next->ph_ns, sop->so_ack)) { + php->ph_rexmit_lk = next; + curr->ph_rexmit_lk = php; + return; + } + curr = next; + } + + /* + * Insert PDU at end of queue + */ + php->ph_rexmit_lk = NULL; + curr->ph_rexmit_lk = php; + sop->so_rexmit_tl = php; + + return; +} + + +/* + * Unlink SD PDU from Retransmit Queue + * + * Arguments: + * sop pointer to sscop connection block + * php pointer to PDU header to unlink + * + * Returns: + * none + * + */ +void +sscop_rexmit_unlink(sop, php) + struct sscop *sop; + struct pdu_hdr *php; +{ + struct pdu_hdr *curr; + + /* + * See if PDU is on retransmit queue + */ + if ((php->ph_rexmit_lk == NULL) && (sop->so_rexmit_tl != php)) + return; + + /* + * It's here somewhere, so first check for the PDU at the + * head of the queue + */ + if (php == sop->so_rexmit_hd) { + if ((sop->so_rexmit_hd = php->ph_rexmit_lk) == NULL) + sop->so_rexmit_tl = NULL; + php->ph_rexmit_lk = NULL; + return; + } + + /* + * Otherwise, loop thru the queue until we find the PDU + */ + for (curr = sop->so_rexmit_hd; curr; curr = curr->ph_rexmit_lk) { + if (curr->ph_rexmit_lk == php) + break; + } + if (curr) { + if ((curr->ph_rexmit_lk = php->ph_rexmit_lk) == NULL) + sop->so_rexmit_tl = curr; + } else { + log(LOG_ERR, + "sscop_rexmit_unlink: Not found - sop=0x%x, php=0x%x\n", + (int)sop, (int)php); +#ifdef DIAGNOSTIC + panic("sscop_rexmit_unlink: Not found"); +#endif + } + php->ph_rexmit_lk = NULL; + + return; +} + + +/* + * Drain Transmission Queues + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +sscop_xmit_drain(sop) + struct sscop *sop; +{ + KBuffer *m; + struct pdu_hdr *php; + + /* + * Free transmission queue buffers + */ + while (m = sop->so_xmit_hd) { + sop->so_xmit_hd = KB_QNEXT(m); + KB_FREEALL(m); + } + sop->so_xmit_tl = NULL; + + /* + * Free retransmission queue + * + * All retranmission buffers are also on the pending ack + * queue (but not the converse), so we just clear the queue + * pointers here and do all the real work below. + */ + sop->so_rexmit_hd = NULL; + sop->so_rexmit_tl = NULL; + + /* + * Free pending ack queue buffers + */ + while (php = sop->so_pack_hd) { + sop->so_pack_hd = php->ph_pack_lk; + KB_FREEALL(php->ph_buf); + } + sop->so_pack_tl = NULL; + + /* + * Clear service required flag + */ + sop->so_flags &= ~SOF_XMITSRVC; + + return; +} + + +/* + * Insert SD PDU into Receive Queue + * + * Arguments: + * sop pointer to sscop connection block + * php pointer to SD PDU header + * + * Returns: + * 0 PDU successfully inserted into queue + * 1 duplicate sequence number PDU on queue, PDU not inserted + * + */ +int +sscop_recv_insert(sop, php) + struct sscop *sop; + struct pdu_hdr *php; +{ + struct pdu_hdr *curr, *next; + sscop_seq seq = php->ph_ns; + + /* + * Check for an empty queue + */ + if ((curr = sop->so_recv_hd) == NULL) { + php->ph_recv_lk = NULL; + sop->so_recv_hd = php; + sop->so_recv_tl = php; + return (0); + } + + /* + * Now see if PDU belongs at head of queue + */ + if (SEQ_LT(seq, curr->ph_ns, sop->so_rcvnext)) { + php->ph_recv_lk = curr; + sop->so_recv_hd = php; + return (0); + } + + /* + * Otherwise, loop thru the queue until we find the + * proper insertion point for the PDU. We also check + * to make sure there isn't a PDU already on the queue + * with a matching sequence number. + */ + while (next = curr->ph_recv_lk) { + if (SEQ_LT(seq, next->ph_ns, sop->so_rcvnext)) { + if (seq == curr->ph_ns) + return (1); + php->ph_recv_lk = next; + curr->ph_recv_lk = php; + return (0); + } + curr = next; + } + + /* + * Insert PDU at end of queue + */ + if (seq == curr->ph_ns) + return (1); + php->ph_recv_lk = NULL; + curr->ph_recv_lk = php; + sop->so_recv_tl = php; + + return (0); +} + + +/* + * Drain Receiver Queues + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +sscop_rcvr_drain(sop) + struct sscop *sop; +{ + struct pdu_hdr *php; + + /* + * Free receive queue buffers + */ + while (php = sop->so_recv_hd) { + sop->so_recv_hd = php->ph_recv_lk; + KB_FREEALL(php->ph_buf); + } + sop->so_recv_tl = NULL; + + return; +} + + +/* + * Service connection's transmit queues + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +sscop_service_xmit(sop) + struct sscop *sop; +{ + KBuffer *m, *n; + struct pdu_hdr *php; + int err = 0, pollsent = 0; + + /* + * Initially assume we need service + */ + sop->so_flags |= SOF_XMITSRVC; + + /* + * Loop until done with queues + * + * (Congestion control will be added later) + */ + while (1) { + if (php = sop->so_rexmit_hd) { + + /* + * Send SD PDU from retransmit queue + * + * First, get a copy of the PDU to send + */ + m = php->ph_buf; + if (KB_LEN(m) == 0) + m = KB_NEXT(m); + KB_COPY(m, 0, KB_COPYALL, n, KB_F_NOWAIT); + if (n == NULL) { + err = 1; + break; + } + + /* + * Now pass it down the stack + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, + sop->so_tokl, sop->so_connvc, (int)n, 0, err); + if (err) { + KB_FREEALL(n); + break; + } + + /* + * PDU is on its way, so remove it from + * the retransmit queue + */ + if (sop->so_rexmit_tl == php) { + sop->so_rexmit_hd = NULL; + sop->so_rexmit_tl = NULL; + } else { + sop->so_rexmit_hd = php->ph_rexmit_lk; + } + php->ph_rexmit_lk = NULL; + + /* + * Update PDU's poll sequence + */ + php->ph_nps = sop->so_pollsend; + + } else if (sop->so_xmit_hd) { + + /* + * Newly arrived data waiting to be sent. + * See if transmit window allows us to send it. + */ + if (SEQ_LT(sop->so_send, sop->so_sendmax, sop->so_ack)){ + /* + * OK, send SD PDU from transmission queue + */ + err = sscop_proc_xmit(sop); + if (err) + break; + } else { + /* + * Can't send now, so leave idle phase. + */ + if (sop->so_timer[SSCOP_T_IDLE] != 0) { + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_timer[SSCOP_T_NORESP] = + sop->so_parm.sp_timeresp; + err = 1; + } + break; + } + + } else { + + /* + * We're finished, so clear service required flag + */ + sop->so_flags &= ~SOF_XMITSRVC; + break; + } + + /* + * We've sent another SD PDU + */ + sop->so_polldata++; + + /* + * Transition into active (polling) phase + */ + if (sop->so_timer[SSCOP_T_POLL] != 0) { + if (sop->so_flags & SOF_KEEPALIVE) { + /* + * Leaving transient phase + */ + sop->so_flags &= ~SOF_KEEPALIVE; + sop->so_timer[SSCOP_T_POLL] = + sop->so_parm.sp_timepoll; + } + } else { + /* + * Leaving idle phase + */ + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_timer[SSCOP_T_NORESP] = + sop->so_parm.sp_timeresp; + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + } + + /* + * Let's see if we need to send a POLL yet + */ + if (sop->so_polldata < sop->so_parm.sp_maxpd) + continue; + + /* + * Yup, send another poll out + */ + SEQ_INCR(sop->so_pollsend, 1); + (void) sscop_send_poll(sop); + pollsent++; + + /* + * Reset data counter for this poll cycle + */ + sop->so_polldata = 0; + + /* + * Restart polling timer in active phase + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + } + + /* + * If we need/want to send a poll, but haven't sent any yet + * on this servicing, send one now + */ + if (err && (pollsent == 0)) { + /* + * Send poll + */ + SEQ_INCR(sop->so_pollsend, 1); + (void) sscop_send_poll(sop); + + /* + * Reset data counter for this poll cycle + */ + sop->so_polldata = 0; + + /* + * Restart polling timer in active phase + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_flags &= ~SOF_KEEPALIVE; + } + + return; +} + + +/* + * Process Transmission Queue PDU + * + * For the first entry on the transmission queue: add a PDU header and + * trailer, send a copy of the PDU down the stack and move the PDU from + * the transmission queue to the pending ack queue. + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * 0 head of transmission queue successfully processed + * else processing error, tranmission queue unchanged + * + */ +static int +sscop_proc_xmit(sop) + struct sscop *sop; +{ + KBuffer *m, *ml, *n; + struct pdu_hdr *php; + sscop_seq seq; + int len = 0, err; + int pad, trlen, space; + u_char *cp; + + /* + * Get first buffer chain on queue + */ + if ((m = sop->so_xmit_hd) == NULL) + return (0); + + /* + * Count data and get to last buffer in chain + */ + for (ml = m; ; ml = KB_NEXT(ml)) { + len += KB_LEN(ml); + if (KB_NEXT(ml) == NULL) + break; + } + + /* + * Verify data length + */ + if (len > sop->so_parm.sp_maxinfo) { + sscop_abort(sop, "sscop: maximum data size exceeded\n"); + return (1); + } + + /* + * Get space for PDU header + */ + KB_HEADROOM(m, space); + if (space < sizeof(struct pdu_hdr)) { + /* + * Allocate & link buffer for header + */ + KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER); + if (n == NULL) + return (1); + + KB_LEN(n) = 0; + KB_HEADSET(n, sizeof(struct pdu_hdr)); + KB_LINKHEAD(n, m); + KB_QNEXT(n) = KB_QNEXT(m); + KB_QNEXT(m) = NULL; + sop->so_xmit_hd = n; + if (sop->so_xmit_tl == m) + sop->so_xmit_tl = n; + m = n; + } + + /* + * Figure out how much padding we'll need + */ + pad = ((len + (PDU_PAD_ALIGN - 1)) & ~(PDU_PAD_ALIGN - 1)) - len; + trlen = pad + sizeof(struct sd_pdu); + + /* + * Now get space for PDU trailer and padding + */ + KB_TAILROOM(ml, space); + if (space < trlen) { + /* + * Allocate & link buffer for pad and trailer + */ + KB_ALLOC(n, trlen, KB_F_NOWAIT, KB_T_HEADER); + if (n == NULL) + return (1); + + KB_LEN(n) = 0; + KB_LINK(n, ml); + ml = n; + } + + /* + * Build the PDU trailer + * + * Since we can't be sure of alignment in the buffers, we + * have to move this a byte at a time and we have to be + * careful with host byte order issues. + */ + KB_DATASTART(ml, cp, u_char *); + cp += KB_LEN(ml) + pad; + *cp++ = (pad << PT_PAD_SHIFT) | PT_SD; + seq = sop->so_send; + *(cp + 2) = (u_char)(seq & 0xff); + seq >>= 8; + *(cp + 1) = (u_char)(seq & 0xff); + seq >>= 8; + *(cp) = (u_char)(seq & 0xff); + KB_LEN(ml) += trlen; + + /* + * Get a copy of the SD PDU to send + */ + if (KB_LEN(m) == 0) + n = KB_NEXT(m); + else + n = m; + KB_COPY(n, 0, KB_COPYALL, n, KB_F_NOWAIT); + if (n == NULL) { + KB_LEN(ml) -= trlen; + return (1); + } + + /* + * Now pass copy down the stack + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)n, 0, err); + if (err) { + KB_FREEALL(n); + KB_LEN(ml) -= trlen; + return (1); + } + + /* + * PDU is on its way, so remove buffer from + * the transmission queue + */ + if (sop->so_xmit_tl == m) { + sop->so_xmit_hd = NULL; + sop->so_xmit_tl = NULL; + } else { + sop->so_xmit_hd = KB_QNEXT(m); + } + KB_QNEXT(m) = NULL; + + /* + * Build PDU header + * + * We can at least assume/require that the start of + * the user data is aligned. Also note that we don't + * include this header in the buffer len/offset fields. + */ + KB_DATASTART(m, php, struct pdu_hdr *); + php--; + php->ph_ns = sop->so_send; + php->ph_nps = sop->so_pollsend; + php->ph_buf = m; + php->ph_rexmit_lk = NULL; + php->ph_pack_lk = NULL; + + /* + * Put PDU onto the pending ack queue + */ + if (sop->so_pack_hd == NULL) + sop->so_pack_hd = php; + else + sop->so_pack_tl->ph_pack_lk = php; + sop->so_pack_tl = php; + + /* + * Finally, bump send sequence number + */ + SEQ_INCR(sop->so_send, 1); + + return (0); +} + + +/* + * Detect Retransmitted PDUs + * + * Arguments: + * sop pointer to sscop connection block + * nsq connection sequence value (N(SQ)) from received PDU + * + * Returns: + * 0 received PDU was NOT retransmitted + * 1 received PDU was retransmitted + * + */ +int +sscop_is_rexmit(sop, nsq) + struct sscop *sop; + u_char nsq; +{ + + /* + * For Q.SAAL1, N(SQ) doesn't exist + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) + return (0); + + /* + * If we've already received the N(SQ) value, + * then this PDU has been retransmitted + */ + if (nsq == sop->so_rcvconn) + return (1); + + /* + * New PDU, save its N(SQ) + */ + sop->so_rcvconn = nsq; + + return (0); +} + + +/* + * Start connection poll timer + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +sscop_set_poll(sop) + struct sscop *sop; +{ + + /* + * Decide which polling timer value to set + */ + if ((sop->so_xmit_hd != NULL) || SEQ_NEQ(sop->so_send, sop->so_ack)) { + /* + * Data outstanding, poll frequently + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_flags &= ~SOF_KEEPALIVE; + } else { + /* + * No data outstanding, just poll occassionally + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timekeep; + sop->so_flags |= SOF_KEEPALIVE; + } + + return; +} + diff --git a/sys/netatm/uni/sscop_timer.c b/sys/netatm/uni/sscop_timer.c new file mode 100644 index 0000000..8c23344b --- /dev/null +++ b/sys/netatm/uni/sscop_timer.c @@ -0,0 +1,576 @@ +/* + * + * =================================== + * 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: sscop_timer.c,v 1.6 1998/04/07 23:21:48 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - Timer processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_timer.c,v 1.6 1998/04/07 23:21:48 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_poll_expire __P((struct sscop *)); +static void sscop_noresponse_expire __P((struct sscop *)); +static void sscop_cc_expire __P((struct sscop *)); +static void sscop_idle_expire __P((struct sscop *)); + +/* + * Local variables + */ +static void (*sscop_expired[SSCOP_T_NUM]) __P((struct sscop *)) = { + sscop_poll_expire, + sscop_noresponse_expire, + sscop_cc_expire, + sscop_idle_expire +}; + + +/* + * Process an SSCOP timer tick + * + * This function is called SSCOP_HZ times a second in order to update + * all of the sscop connection timers. The sscop expiration function + * will be called to process all timer expirations. + * + * Called at splnet. + * + * Arguments: + * tip pointer to sscop timer control block + * + * Returns: + * none + * + */ +void +sscop_timeout(tip) + struct atm_time *tip; +{ + struct sscop *sop, **sprev; + int i; + + + /* + * Schedule next timeout + */ + atm_timeout(&sscop_timer, ATM_HZ/SSCOP_HZ, sscop_timeout); + + /* + * Run through all connections, updating each active timer. + * If an expired timer is found, notify that entry. + */ + sprev = &sscop_head; + while (sop = *sprev) { + + /* + * Check out each timer + */ + for (i =0; i < SSCOP_T_NUM; i++) { + + /* + * Decrement timer if it's active + */ + if (sop->so_timer[i] && (--sop->so_timer[i] == 0)) { + +#ifdef DIAGNOSTIC + { + static char *tn[] = { + "POLL", + "NORESPONSE", + "CC", + "IDLE" + }; + ATM_DEBUG3("sscop_timer: %s expired, sop=0x%x, state=%d\n", + tn[i], (int)sop, sop->so_state); + } +#endif + + /* + * Expired timer - process it + */ + (*sscop_expired[i])(sop); + + /* + * Make sure connection still exists + */ + if (*sprev != sop) + break; + } + } + + /* + * Update previous pointer if current control + * block wasn't deleted + */ + if (*sprev == sop) + sprev = &sop->so_next; + } +} + + +/* + * Process an SSCOP Timer_POLL expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_poll_expire(sop) + struct sscop *sop; +{ + + /* + * Validate current state + */ + if ((sop->so_state != SOS_READY) && + ((sop->so_state != SOS_INRESYN) || + (sop->so_vers != SSCOP_VERS_QSAAL))) { + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_POLL", (int)sop, sop->so_state); + return; + } + + /* + * Send next poll along its way + */ + SEQ_INCR(sop->so_pollsend, 1); + (void) sscop_send_poll(sop); + + /* + * Reset data counter for this poll cycle + */ + sop->so_polldata = 0; + + /* + * Reset polling timer + */ + sscop_set_poll(sop); + + return; +} + + +/* + * Process an SSCOP Timer_IDLE expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_idle_expire(sop) + struct sscop *sop; +{ + + /* + * Timer_IDLE only valid in READY state + */ + if (sop->so_state != SOS_READY) { + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_IDLE", (int)sop, sop->so_state); + return; + } + + /* + * Send next poll along its way + */ + SEQ_INCR(sop->so_pollsend, 1); + (void) sscop_send_poll(sop); + + /* + * Reset data counter for this poll cycle + */ + sop->so_polldata = 0; + + /* + * Start NO-RESPONSE timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Reset polling timer + */ + sscop_set_poll(sop); + + return; +} + + +/* + * Process an SSCOP Timer_NORESPONSE expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_noresponse_expire(sop) + struct sscop *sop; +{ + int err; + + /* + * Validate current state + */ + if ((sop->so_state != SOS_READY) && + ((sop->so_state != SOS_INRESYN) || + (sop->so_vers != SSCOP_VERS_QSAAL))) { + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_NORESPONSE", (int)sop, sop->so_state); + return; + } + + /* + * Peer seems to be dead, so terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_NORESP] = 1; + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report peer's failure + */ + sscop_maa_error(sop, 'P'); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + else + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * Process an SSCOP Timer_CC expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_cc_expire(sop) + struct sscop *sop; +{ + int err; + + /* + * Process timeout based on protocol state + */ + switch (sop->so_state) { + + case SOS_OUTCONN: + /* + * No response to our BGN yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another BGN PDU + */ + sop->so_connctl++; + (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + /* + * Clear reestablishment flag + */ + sop->so_flags &= ~SOF_REESTAB; + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + case SOS_OUTDISC: + /* + * No response to our END yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another END PDU + */ + sop->so_connctl++; + (void) sscop_send_end(sop, SSCOP_SOURCE_LAST); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, force session termination + */ + STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, + sop->so_toku, sop->so_connvc, 0, 0, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + case SOS_OUTRESYN: +rexmitrs: + /* + * No response to our RS yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another RS PDU + */ + sop->so_connctl++; + (void) sscop_send_rs(sop); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + case SOS_CONRESYN: /* Q.SAAL1 */ +#if (SOS_OUTRECOV != SOS_CONRESYN) + case SOS_OUTRECOV: /* Q.2110 */ +#endif + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Handle timeout for SOS_CONRESYN + */ + goto rexmitrs; + } + + /* + * Handle timeout for SOS_OUTRECOV + */ + + /* + * No response to our ER yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another ER PDU + */ + sop->so_connctl++; + (void) sscop_send_er(sop); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + default: + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_CC", (int)sop, sop->so_state); + } +} + diff --git a/sys/netatm/uni/sscop_upper.c b/sys/netatm/uni/sscop_upper.c new file mode 100644 index 0000000..be9556d --- /dev/null +++ b/sys/netatm/uni/sscop_upper.c @@ -0,0 +1,412 @@ +/* + * + * =================================== + * 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: sscop_upper.c,v 1.6 1998/08/26 23:29:20 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - CPCS SAP interface processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_upper.c,v 1.6 1998/08/26 23:29:20 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static caddr_t sscop_pdu_receive __P((KBuffer *, struct sscop *, int *)); + + +/* + * Local variables + */ +static union { + struct bgn_pdu t_bgn; + struct bgak_pdu t_bgak; + struct end_pdu t_end; + struct endak_q2110_pdu t_endak_q2110; + struct endak_qsaal_pdu t_endak_qsaal; + struct rs_pdu t_rs; + struct rsak_q2110_pdu t_rsak_q2110; + struct rsak_qsaal_pdu t_rsak_qsaal; + struct bgrej_pdu t_bgrej; + struct sd_pdu t_sd; + struct sdp_pdu t_sdp; + struct er_pdu t_er; + struct poll_pdu t_poll; + struct stat_pdu t_stat; + struct ustat_pdu t_ustat; + struct ud_pdu t_ud; + struct md_pdu t_md; + struct erak_pdu t_erak; +} sscop_trailer; + + +/* + * PDU length validation table + */ +struct pdulen { + int min; + int max; +}; + +static struct pdulen qsaal_pdulen[] = { + {0, 0}, + {sizeof(struct bgn_pdu), sizeof(struct bgn_pdu)}, + {sizeof(struct bgak_pdu), sizeof(struct bgak_pdu)}, + {sizeof(struct end_pdu), sizeof(struct end_pdu)}, + {sizeof(struct endak_qsaal_pdu),sizeof(struct endak_qsaal_pdu)}, + {sizeof(struct rs_pdu), sizeof(struct rs_pdu)}, + {sizeof(struct rsak_qsaal_pdu), sizeof(struct rsak_qsaal_pdu)}, + {sizeof(struct bgrej_pdu), sizeof(struct bgrej_pdu)}, + {sizeof(struct sd_pdu), sizeof(struct sd_pdu) + PDU_MAX_INFO}, + {sizeof(struct sdp_pdu), sizeof(struct sdp_pdu) + PDU_MAX_INFO}, + {sizeof(struct poll_pdu), sizeof(struct poll_pdu)}, + {sizeof(struct stat_pdu), sizeof(struct stat_pdu) + PDU_MAX_STAT}, + {sizeof(struct ustat_pdu), sizeof(struct ustat_pdu)}, + {sizeof(struct ud_pdu), sizeof(struct ud_pdu) + PDU_MAX_INFO}, + {sizeof(struct md_pdu), sizeof(struct md_pdu) + PDU_MAX_INFO}, + {0, 0} +}; + +static struct pdulen q2110_pdulen[] = { + {0, 0}, + {sizeof(struct bgn_pdu), sizeof(struct bgn_pdu) + PDU_MAX_UU}, + {sizeof(struct bgak_pdu), sizeof(struct bgak_pdu) + PDU_MAX_UU}, + {sizeof(struct end_pdu), sizeof(struct end_pdu) + PDU_MAX_UU}, + {sizeof(struct endak_q2110_pdu),sizeof(struct endak_q2110_pdu)}, + {sizeof(struct rs_pdu), sizeof(struct rs_pdu) + PDU_MAX_UU}, + {sizeof(struct rsak_q2110_pdu), sizeof(struct rsak_q2110_pdu)}, + {sizeof(struct bgrej_pdu), sizeof(struct bgrej_pdu) + PDU_MAX_UU}, + {sizeof(struct sd_pdu), sizeof(struct sd_pdu) + PDU_MAX_INFO}, + {sizeof(struct er_pdu), sizeof(struct er_pdu)}, + {sizeof(struct poll_pdu), sizeof(struct poll_pdu)}, + {sizeof(struct stat_pdu), sizeof(struct stat_pdu) + PDU_MAX_STAT}, + {sizeof(struct ustat_pdu), sizeof(struct ustat_pdu)}, + {sizeof(struct ud_pdu), sizeof(struct ud_pdu) + PDU_MAX_INFO}, + {sizeof(struct md_pdu), sizeof(struct md_pdu) + PDU_MAX_INFO}, + {sizeof(struct erak_pdu), sizeof(struct erak_pdu)} +}; + + +/* + * PDUs with Pad Length Fields + */ +static u_char qsaal_padlen[] = { + 0, /* --- */ + 0, /* BGN */ + 0, /* BGAK */ + 0, /* END */ + 0, /* ENDAK */ + 0, /* RS */ + 0, /* RSAK */ + 0, /* BGREJ */ + 1, /* SD */ + 1, /* SDP */ + 0, /* POLL */ + 0, /* STAT */ + 0, /* USTAT */ + 1, /* UD */ + 1, /* MD */ + 0 /* --- */ +}; + +static u_char q2110_padlen[] = { + 0, /* --- */ + 1, /* BGN */ + 1, /* BGAK */ + 1, /* END */ + 0, /* ENDAK */ + 1, /* RS */ + 0, /* RSAK */ + 1, /* BGREJ */ + 1, /* SD */ + 0, /* ER */ + 0, /* POLL */ + 0, /* STAT */ + 0, /* USTAT */ + 1, /* UD */ + 1, /* MD */ + 0 /* ERAK */ +}; + + +/* + * SSCOP Upper Stack Command Handler + * + * This function will receive all of the stack commands issued from the + * layer below SSCOP (ie. CPCS). Currently, only incoming PDUs will be + * received here. The appropriate processing function will be determined + * based on the received PDU type and the current sscop control block state. + * + * Arguments: + * cmd stack command code + * tok session token + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscop_upper(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + struct sscop *sop = (struct sscop *)tok; + void (**ptab) __P((struct sscop *, KBuffer *, caddr_t)); + void (*func) __P((struct sscop *, KBuffer *, caddr_t)); + caddr_t trlr; + int type; + + ATM_DEBUG5("sscop_upper: cmd=0x%x, sop=0x%x, state=%d, arg1=0x%x, arg2=0x%x\n", + cmd, (int)sop, sop->so_state, arg1, arg2); + + switch (cmd) { + + case CPCS_UNITDATA_SIG: + /* + * Decode/validate received PDU + */ + trlr = sscop_pdu_receive((KBuffer *)arg1, sop, &type); + if (trlr == NULL) { + return; + } + + /* + * Validate sscop state + */ + if (sop->so_state > SOS_MAXSTATE) { + log(LOG_ERR, + "sscop_upper: invalid state sop=0x%x, state=%d\n", + (int)sop, sop->so_state); + KB_FREEALL((KBuffer *)arg1); + return; + } + + /* + * Call event processing function + */ + ptab = sop->so_vers == SSCOP_VERS_QSAAL ? + sscop_qsaal_pdutab[type]: + sscop_q2110_pdutab[type]; + func = ptab[sop->so_state]; + if (func == NULL) { + log(LOG_ERR, + "sscop_upper: unsupported pdu=%d, state=%d\n", + type, sop->so_state); + break; + } + (*func)(sop, (KBuffer *)arg1, trlr); + break; + + default: + log(LOG_ERR, "sscop_upper: unknown cmd 0x%x, sop=0x%x\n", + cmd, (int)sop); + } + + return; +} + + +/* + * Decode and Validate Received PDU + * + * This function will process all received SSCOP PDUs. The PDU type will be + * determined and PDU format validation will be performed. If the PDU is + * successfully decoded and validated, the buffer chain will have the PDU + * trailer removed, but any resultant zero-length buffers will NOT be freed. + * If the PDU fails validation, then the buffer chain will be freed. + * + * Arguments: + * m pointer to PDU buffer chain + * sop pointer to sscop connection block + * typep address to store PDU type + * + * Returns: + * addr pointer to (contiguous) PDU trailer + * 0 invalid PDU, buffer chain freed + * + */ +static caddr_t +sscop_pdu_receive(m, sop, typep) + KBuffer *m; + struct sscop *sop; + int *typep; +{ + KBuffer *m0, *ml, *mn; + caddr_t cp, tp; + int len, tlen, type, plen; + + /* + * Calculate PDU length and find the last two buffers in the chain + */ + len = 0; + for (m0 = m, ml = mn = NULL; m0; m0 = KB_NEXT(m0)) { + len += KB_LEN(m0); + mn = ml; + ml = m0; + } + + /* + * Make sure we've got a minimum sized PDU + */ + if (len < PDU_MIN_LEN) + goto badpdu; + + /* + * Get PDU type field + */ + if (KB_LEN(ml) >= PDU_MIN_LEN) { + KB_DATAEND(ml, tp, caddr_t); + tp -= PDU_MIN_LEN; + } else { + KB_DATAEND(mn, tp, caddr_t); + tp -= (PDU_MIN_LEN - KB_LEN(ml)); + } + *typep = type = *tp & PT_TYPE_MASK; + + /* + * Check up on PDU length + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) { + if ((len < (tlen = qsaal_pdulen[type].min)) || + (len > qsaal_pdulen[type].max) || + (len & PDU_LEN_MASK)) + goto badpdu; + } else { + if ((len < (tlen = q2110_pdulen[type].min)) || + (len > q2110_pdulen[type].max) || + (len & PDU_LEN_MASK)) + goto badpdu; + } + + /* + * Get a contiguous, aligned PDU trailer and adjust buffer + * controls to remove trailer + */ + if (KB_LEN(ml) >= tlen) { + /* + * Trailer is contained in last buffer + */ + KB_TAILADJ(ml, -tlen); + KB_DATAEND(ml, cp, caddr_t); + if ((int)cp & PDU_ADDR_MASK) { + /* + * Trailer not aligned in buffer, use local memory + */ + KM_COPY(cp, (caddr_t)&sscop_trailer, tlen); + cp = (caddr_t)&sscop_trailer; + } + } else { + /* + * Trailer is split across buffers, use local memory + */ + caddr_t cp1; + int off = tlen - KB_LEN(ml); + + cp = (caddr_t)&sscop_trailer; + + /* + * Ensure trailer is within last two buffers + */ + if ((mn == NULL) || (KB_LEN(mn) < off)) + goto badpdu; + + KB_DATASTART(ml, cp1, caddr_t); + KM_COPY(cp1, cp + off, KB_LEN(ml)); + KB_LEN(ml) = 0; + KB_TAILADJ(mn, -off); + KB_DATAEND(mn, cp1, caddr_t); + KM_COPY(cp1, cp, off); + } + + /* + * Get possible PDU Pad Length + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) { + if (qsaal_padlen[type]) + plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT; + else + plen = 0; + } else { + if (q2110_padlen[type]) + plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT; + else + plen = 0; + } + + /* + * Perform Pad Length adjustments + */ + if (plen) { + if (KB_LEN(ml) >= plen) { + /* + * All pad bytes in last buffer + */ + KB_TAILADJ(ml, -plen); + } else { + /* + * Pad bytes split between buffers + */ + plen -= KB_LEN(ml); + if ((mn == NULL) || (KB_LEN(mn) < plen)) + goto badpdu; + KB_LEN(ml) = 0; + KB_TAILADJ(mn, -plen); + } + } + + return (cp); + +badpdu: + /* + * This MAA Error is only supposed to be for a PDU length violation, + * but we use it for any PDU format error. + */ + sscop_maa_error(sop, 'U'); + sscop_pdu_print(sop, m, "badpdu received"); + KB_FREEALL(m); + return (NULL); +} + diff --git a/sys/netatm/uni/sscop_var.h b/sys/netatm/uni/sscop_var.h new file mode 100644 index 0000000..9a739d3 --- /dev/null +++ b/sys/netatm/uni/sscop_var.h @@ -0,0 +1,283 @@ +/* + * + * =================================== + * 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: sscop_var.h,v 1.6 1998/04/07 23:21:57 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP protocol control blocks + * + */ + +#ifndef _UNI_SSCOP_VAR_H +#define _UNI_SSCOP_VAR_H + +/* + * Structure containing information for each SSCOP connection. + */ +struct sscop { + struct sscop *so_next; /* Next connection in chain */ + u_char so_state; /* Connection state (see below) */ + u_short so_flags; /* Connection flags (see below) */ + enum sscop_vers so_vers; /* SSCOP version */ + + /* Transmitter variables */ + sscop_seq so_send; /* VT(S) - next SD to send */ + sscop_seq so_sendmax; /* VT(MS) - max SD to send + 1 */ + sscop_seq so_ack; /* VT(A) - next expected ack */ + sscop_seq so_pollsend; /* VT(PS) - last POLL sent */ + sscop_seq so_pollack; /* VT(PA) - next expected STAT */ + short so_polldata; /* VT(PD) - SD's sent between POLLs */ + short so_connctl; /* VT(CC) - un-ack'd BGN,END,ER,RS */ + u_char so_sendconn; /* VT(SQ) - last BGN,ER,RS sent */ + + /* Receiver variables */ + sscop_seq so_rcvnext; /* VR(R) - next SD to receive */ + sscop_seq so_rcvhigh; /* VR(H) - next highest SD to receive */ + sscop_seq so_rcvmax; /* VR(MR) - max SD to receive + 1 */ + u_char so_rcvconn; /* VR(SQ) - last BGN,ER,RS received */ + + /* PDU queues */ + KBuffer *so_xmit_hd; /* SD transmission queue head */ + KBuffer *so_xmit_tl; /* SD transmission queue tail */ + struct pdu_hdr *so_rexmit_hd; /* SD retransmission queue head */ + struct pdu_hdr *so_rexmit_tl; /* SD retransmission queue head */ + struct pdu_hdr *so_pack_hd; /* SD pending ack queue head */ + struct pdu_hdr *so_pack_tl; /* SD pending ack queue tail */ + struct pdu_hdr *so_recv_hd; /* SD receive queue head */ + struct pdu_hdr *so_recv_tl; /* SD receive queue tail */ + + /* Connection parameters */ + struct sscop_parms so_parm; /* Connection parameters */ + + /* Timers */ + u_short so_timer[SSCOP_T_NUM]; /* Connection timers */ + + /* Stack variables */ + Atm_connvc *so_connvc; /* Connection vcc for this stack */ + void *so_toku; /* Stack upper layer's token */ + void *so_tokl; /* Stack lower layer's token */ + void (*so_upper) /* Stack upper layer's interface */ + __P((int, void *, int, int)); + void (*so_lower) /* Stack lower layer's interface */ + __P((int, void *, int, int)); + u_short so_headout; /* Output buffer headroom */ +}; + +/* + * Connection States + * + * Notes: + * # - state valid only for Q.SAAL1 + * ## - state valid only for Q.2110 + */ +#define SOS_INST 0 /* Instantiated, waiting for INIT */ +#define SOS_IDLE 1 /* Idle connection */ +#define SOS_OUTCONN 2 /* Outgoing connection pending */ +#define SOS_INCONN 3 /* Incoming connection pending */ +#define SOS_OUTDISC 4 /* Outgoing disconnection pending */ +#define SOS_OUTRESYN 5 /* Outgoing resynchronization pending */ +#define SOS_INRESYN 6 /* Incoming resynchronization pending */ +#define SOS_CONRESYN 7 /* Concurrent resynch pending (#) */ +#define SOS_OUTRECOV 7 /* Outgoing recovery pending (##) */ +#define SOS_RECOVRSP 8 /* Recovery response pending (##) */ +#define SOS_INRECOV 9 /* Incoming recovery pending (##) */ +#define SOS_READY 10 /* Data transfer ready */ +#define SOS_TERM 11 /* Waiting for TERM */ + +#define SOS_MAXSTATE 11 /* Maximum state value */ +#define SOS_NUMSTATES (SOS_MAXSTATE+1)/* Number of states */ + +/* + * Connection Flags + */ +#define SOF_NOCLRBUF 0x0001 /* Clear buffers = no */ +#define SOF_REESTAB 0x0002 /* SSCOP initiated reestablishment */ +#define SOF_XMITSRVC 0x0004 /* Transmit queues need servicing */ +#define SOF_KEEPALIVE 0x0008 /* Polling in transient phase */ +#define SOF_ENDSSCOP 0x0010 /* Last END PDU, SOURCE=SSCOP */ +#define SOF_NOCREDIT 0x0020 /* Transmit window closed */ + + +/* + * SSCOP statistics + */ +struct sscop_stat { + u_long sos_connects; /* Connection instances */ + u_long sos_aborts; /* Connection aborts */ + u_long sos_maa_error[MAA_ERROR_COUNT]; /* Management errors */ +}; + +#ifdef ATM_KERNEL +/* + * Global function declarations + */ + /* sscop.c */ +int sscop_start __P((void)); +int sscop_stop __P((void)); +void sscop_maa_error __P((struct sscop *, int)); +void sscop_abort __P((struct sscop *, char *)); + + /* sscop_lower.c */ +void sscop_lower __P((int, void *, int, int)); +void sscop_aa_noop_0 __P((struct sscop *, int, int)); +void sscop_aa_noop_1 __P((struct sscop *, int, int)); +void sscop_init_inst __P((struct sscop *, int, int)); +void sscop_term_all __P((struct sscop *, int, int)); + + /* sscop_pdu.c */ +int sscop_send_bgn __P((struct sscop *, int)); +int sscop_send_bgak __P((struct sscop *)); +int sscop_send_bgrej __P((struct sscop *)); +int sscop_send_end __P((struct sscop *, int)); +int sscop_send_endak __P((struct sscop *)); +int sscop_send_rs __P((struct sscop *)); +int sscop_send_rsak __P((struct sscop *)); +int sscop_send_er __P((struct sscop *)); +int sscop_send_erak __P((struct sscop *)); +int sscop_send_poll __P((struct sscop *)); +int sscop_send_stat __P((struct sscop *, sscop_seq)); +int sscop_send_ustat __P((struct sscop *, sscop_seq)); +int sscop_send_ud __P((struct sscop *, KBuffer *)); +void sscop_pdu_print __P((struct sscop *, KBuffer *, char *)); + + /* sscop_sigaa.c */ +void sscop_estreq_idle __P((struct sscop *, int, int)); +void sscop_estrsp_inconn __P((struct sscop *, int, int)); +void sscop_relreq_outconn __P((struct sscop *, int, int)); +void sscop_relreq_inconn __P((struct sscop *, int, int)); +void sscop_relreq_ready __P((struct sscop *, int, int)); +void sscop_datreq_ready __P((struct sscop *, int, int)); +void sscop_udtreq_all __P((struct sscop *, int, int)); + + /* sscop_sigcpcs.c */ +void sscop_noop __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgn_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgn_outdisc __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgn_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgn_inresyn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgak_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgak_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgak_outconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgrej_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgrej_outconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgrej_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgrej_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgrej_ready __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_end_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_end_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_end_outdisc __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_endak_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_endak_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_endak_outdisc __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_endak_ready __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_rs_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_rs_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_rsak_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_rsak_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_rsak_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_sd_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_sd_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_sd_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_poll_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_poll_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_poll_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_stat_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_stat_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_stat_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_stat_ready __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_ustat_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_ustat_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_ustat_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_ustat_ready __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_ud_all __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_md_all __P((struct sscop *, KBuffer *, caddr_t)); + + /* sscop_subr.c */ +KBuffer * sscop_stat_getelem __P((KBuffer *, sscop_seq *)); +struct pdu_hdr *sscop_pack_locate __P((struct sscop *, sscop_seq)); +void sscop_pack_free __P((struct sscop *, sscop_seq)); +void sscop_rexmit_insert __P((struct sscop *, struct pdu_hdr *)); +void sscop_rexmit_unlink __P((struct sscop *, struct pdu_hdr *)); +void sscop_xmit_drain __P((struct sscop *)); +int sscop_recv_insert __P((struct sscop *, struct pdu_hdr *)); +void sscop_rcvr_drain __P((struct sscop *)); +void sscop_service_xmit __P((struct sscop *)); +int sscop_is_rexmit __P((struct sscop *, u_char)); +void sscop_set_poll __P((struct sscop *)); + + /* sscop_timer.c */ +void sscop_timeout __P((struct atm_time *)); + + /* sscop_upper.c */ +void sscop_upper __P((int, void *, int, int)); + + /* q2110_sigaa.c */ + + /* q2110_sigcpcs.c */ + + /* q2110_subr.c */ +void q2110_clear_xmit __P((struct sscop *)); +void q2110_init_state __P((struct sscop *)); +void q2110_prep_retrieve __P((struct sscop *)); +void q2110_prep_recovery __P((struct sscop *)); +void q2110_deliver_data __P((struct sscop *)); +void q2110_error_recovery __P((struct sscop *)); + + /* qsaal1_sigaa.c */ + + /* qsaal1_sigcpcs.c */ + + /* qsaal1_subr.c */ +void qsaal1_reestablish __P((struct sscop *)); +void qsaal1_reset_xmit __P((struct sscop *)); +void qsaal1_reset_rcvr __P((struct sscop *)); +void qsaal1_clear_connection __P((struct sscop *)); + + +/* + * External variables + */ +extern struct sp_info sscop_pool; +extern int sscop_vccnt; +extern struct sscop *sscop_head; +extern struct sscop_stat sscop_stat; +extern struct atm_time sscop_timer; +extern void (*(*sscop_qsaal_aatab[])) + __P((struct sscop *, int, int)); +extern void (*(*sscop_q2110_aatab[])) + __P((struct sscop *, int, int)); +extern void (*(*sscop_qsaal_pdutab[])) + __P((struct sscop *, KBuffer *, caddr_t)); +extern void (*(*sscop_q2110_pdutab[])) + __P((struct sscop *, KBuffer *, caddr_t)); + +#endif /* ATM_KERNEL */ + +#endif /* _UNI_SSCOP_VAR_H */ diff --git a/sys/netatm/uni/uni.h b/sys/netatm/uni/uni.h new file mode 100644 index 0000000..700e859 --- /dev/null +++ b/sys/netatm/uni/uni.h @@ -0,0 +1,50 @@ +/* + * + * =================================== + * 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: uni.h,v 1.2 1997/05/06 22:20:39 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * Protocol definitions + * + */ + +#ifndef _UNI_UNI_H +#define _UNI_UNI_H + +/* + * UNI Version + */ +enum uni_vers { + UNI_VERS_3_0, + UNI_VERS_3_1, + UNI_VERS_4_0 +}; + +#endif /* _UNI_UNI_H */ diff --git a/sys/netatm/uni/uni_load.c b/sys/netatm/uni/uni_load.c new file mode 100644 index 0000000..23e7ff5 --- /dev/null +++ b/sys/netatm/uni/uni_load.c @@ -0,0 +1,450 @@ +/* + * + * =================================== + * 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: uni_load.c,v 1.6 1997/05/06 22:20:43 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * Loadable kernel module support + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uni_load.c,v 1.6 1997/05/06 22:20:43 mks Exp $"; +#endif + +#ifndef ATM_UNI_MODULE +#include "opt_atm.h" +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> + +/* + * External functions + */ +int sscop_start __P((void)); +int sscop_stop __P((void)); +int sscf_uni_start __P((void)); +int sscf_uni_stop __P((void)); +int uniip_start __P((void)); +int uniip_stop __P((void)); +int unisig_start __P((void)); +int unisig_stop __P((void)); + +/* + * Local functions + */ +static int uni_start __P((void)); +static int uni_stop __P((void)); + + +/* + * Initialize uni processing + * + * This will be called during module loading. We just notify all of our + * sub-services to initialize. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +static int +uni_start() +{ + int err; + + /* + * Verify software version + */ + if (atm_version != ATM_VERSION) { + log(LOG_ERR, "version mismatch: uni=%d.%d kernel=%d.%d\n", + ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION), + ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version)); + return (EINVAL); + } + + /* + * Initialize uni sub-services + */ + err = sscop_start(); + if (err) + goto done; + + err = sscf_uni_start(); + if (err) + goto done; + + err = unisig_start(); + if (err) + goto done; + + err = uniip_start(); + if (err) + goto done; + +done: + return (err); +} + + +/* + * Halt uni processing + * + * This will be called just prior to unloading the module from + * memory. All sub-services will be notified of the termination. + * + * Arguments: + * none + * + * Returns: + * 0 shutdown was successful + * errno shutdown failed - reason indicated + * + */ +static int +uni_stop() +{ + int err, s = splnet(); + + /* + * Terminate uni sub-services + */ + err = uniip_stop(); + if (err) + goto done; + + err = unisig_stop(); + if (err) + goto done; + + err = sscf_uni_stop(); + if (err) + goto done; + + err = sscop_stop(); + if (err) + goto done; + +done: + (void) splx(s); + return (err); +} + + +#ifdef ATM_UNI_MODULE +/* + ******************************************************************* + * + * Loadable Module Support + * + ******************************************************************* + */ +static int uni_doload __P((void)); +static int uni_dounload __P((void)); + +/* + * Generic module load processing + * + * This function is called by an OS-specific function when this + * module is being loaded. + * + * Arguments: + * none + * + * Returns: + * 0 load was successful + * errno load failed - reason indicated + * + */ +static int +uni_doload() +{ + int err = 0; + + /* + * Start us up + */ + err = uni_start(); + if (err) + /* Problems, clean up */ + (void)uni_stop(); + + return (err); +} + + +/* + * Generic module unload processing + * + * This function is called by an OS-specific function when this + * module is being unloaded. + * + * Arguments: + * none + * + * Returns: + * 0 unload was successful + * errno unload failed - reason indicated + * + */ +static int +uni_dounload() +{ + int err = 0; + + /* + * OK, try to clean up our mess + */ + err = uni_stop(); + + return (err); +} + + +#ifdef sun +/* + * Loadable driver description + */ +struct vdldrv uni_drv = { + VDMAGIC_PSEUDO, /* Pseudo Driver */ + "uni_mod", /* name */ + NULL, /* dev_ops */ + NULL, /* bdevsw */ + NULL, /* cdevsw */ + 0, /* blockmajor */ + 0 /* charmajor */ +}; + + +/* + * Loadable module support entry point + * + * This is the routine called by the vd driver for all loadable module + * functions for this pseudo driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * cmd vd command code + * vdp pointer to vd driver's structure + * vdi pointer to command-specific vdioctl_* structure + * vds pointer to status structure (VDSTAT only) + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +uni_mod(cmd, vdp, vdi, vds) + int cmd; + struct vddrv *vdp; + caddr_t vdi; + struct vdstat *vds; +{ + int err = 0; + + switch (cmd) { + + case VDLOAD: + /* + * Module Load + * + * We dont support any user configuration + */ + err = uni_doload(); + if (err == 0) + /* Let vd driver know about us */ + vdp->vdd_vdtab = (struct vdlinkage *)&uni_drv; + break; + + case VDUNLOAD: + /* + * Module Unload + */ + err = uni_dounload(); + break; + + case VDSTAT: + /* + * Module Status + */ + + /* Not much to say at the moment */ + + break; + + default: + log(LOG_ERR, "uni_mod: Unknown vd command 0x%x\n", cmd); + err = EINVAL; + } + + return (err); +} +#endif /* sun */ + +#ifdef __FreeBSD__ + +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +/* + * Loadable miscellaneous module description + */ +MOD_MISC(uni); + + +/* + * Loadable module support "load" entry point + * + * This is the routine called by the lkm driver whenever the + * modload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +uni_load(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(uni_doload()); +} + + +/* + * Loadable module support "unload" entry point + * + * This is the routine called by the lkm driver whenever the + * modunload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +uni_unload(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(uni_dounload()); +} + + +/* + * Loadable module support entry point + * + * This is the routine called by the lkm driver for all loadable module + * functions for this driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * ver lkm version + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +uni_mod(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd; + int ver; +{ + MOD_DISPATCH(uni, lkmtp, cmd, ver, + uni_load, uni_unload, lkm_nullcmd); +} +#endif /* __FreeBSD__ */ + +#else /* !ATM_UNI_MODULE */ + +/* + ******************************************************************* + * + * Kernel Compiled Module Support + * + ******************************************************************* + */ +static void uni_doload __P((void *)); + +SYSINIT(atmuni, SI_SUB_PROTO_END, SI_ORDER_ANY, uni_doload, NULL) + +/* + * Kernel initialization + * + * Arguments: + * arg Not used + * + * Returns: + * none + * + */ +static void +uni_doload(void *arg) +{ + int err = 0; + + /* + * Start us up + */ + err = uni_start(); + if (err) { + /* Problems, clean up */ + (void)uni_stop(); + + log(LOG_ERR, "ATM UNI unable to initialize (%d)!!\n", err); + } + return; +} +#endif /* ATM_UNI_MODULE */ + diff --git a/sys/netatm/uni/uniarp.c b/sys/netatm/uni/uniarp.c new file mode 100644 index 0000000..f316a73 --- /dev/null +++ b/sys/netatm/uni/uniarp.c @@ -0,0 +1,1231 @@ +/* + * + * =================================== + * 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: uniarp.c,v 1.10 1998/07/20 18:58:45 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp.c,v 1.10 1998/07/20 18:58:45 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Global variables + */ +struct uniarp *uniarp_arptab[UNIARP_HASHSIZ] = {NULL}; +struct uniarp *uniarp_nomaptab = NULL; +struct uniarp *uniarp_pvctab = NULL; +struct atm_time uniarp_timer = {0, 0}; /* Aging timer */ +struct uniarp_stat uniarp_stat = {0}; +int uniarp_print = 0; + +Atm_endpoint uniarp_endpt = { + NULL, + ENDPT_ATMARP, + uniarp_ioctl, + uniarp_getname, + uniarp_connected, + uniarp_cleared, + NULL, + NULL, + NULL, + NULL, + uniarp_cpcs_data, + NULL, + NULL, + NULL, + NULL +}; + +struct sp_info uniarp_pool = { + "uni arp pool", /* si_name */ + sizeof(struct uniarp), /* si_blksiz */ + 10, /* si_blkcnt */ + 200 /* si_maxallow */ +}; + + +/* + * Local variables + */ +static void uniarp_server_mode __P((struct uniip *)); +static void uniarp_client_mode __P((struct uniip *, Atm_addr *)); + + +/* + * Process module loading notification + * + * Called whenever the uni module is initializing. + * + * Arguments: + * none + * + * Returns: + * 0 initialization successful + * errno initialization failed - reason indicated + * + */ +int +uniarp_start() +{ + int err; + + /* + * Register our endpoint + */ + err = atm_endpoint_register(&uniarp_endpt); + + return (err); +} + + +/* + * Process module unloading notification + * + * Called whenever the uni module is about to be unloaded. All signalling + * instances will have been previously detached. All uniarp resources + * must be freed now. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +uniarp_stop() +{ + int i; + + /* + * Make sure the arp table is empty + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + if (uniarp_arptab[i] != NULL) + panic("uniarp_stop: arp table not empty"); + } + + /* + * Cancel timers + */ + (void) atm_untimeout(&uniarp_timer); + + /* + * De-register ourselves + */ + (void) atm_endpoint_deregister(&uniarp_endpt); + + /* + * Free our storage pools + */ + atm_release_pool(&uniarp_pool); +} + + +/* + * Process IP Network Interface Activation + * + * Called whenever an IP network interface becomes active. + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * + * Returns: + * none + * + */ +void +uniarp_ipact(uip) + struct uniip *uip; +{ + struct unisig *usp; + + ATM_DEBUG1("uniarp_ipact: uip=0x%x\n", (int)uip); + + /* + * Set initial state + */ + uip->uip_arpstate = UIAS_NOTCONF; + uip->uip_arpsvratm.address_format = T_ATM_ABSENT; + uip->uip_arpsvratm.address_length = 0; + uip->uip_arpsvrsub.address_format = T_ATM_ABSENT; + uip->uip_arpsvrsub.address_length = 0; + + usp = (struct unisig *)uip->uip_ipnif->inf_nif->nif_pif->pif_siginst; + if (usp->us_addr.address_format != T_ATM_ABSENT) + uip->uip_flags |= UIF_IFADDR; + + /* + * Make sure aging timer is running + */ + if ((uniarp_timer.ti_flag & TIF_QUEUED) == 0) + atm_timeout(&uniarp_timer, UNIARP_AGING, uniarp_aging); + + return; +} + + +/* + * Process IP Network Interface Deactivation + * + * Called whenever an IP network interface becomes inactive. All VCCs + * for this interface should already have been closed. + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * + * Returns: + * none + * + */ +void +uniarp_ipdact(uip) + struct uniip *uip; +{ + struct ip_nif *inp = uip->uip_ipnif; + struct uniarp *uap, *unext; + int i; + + ATM_DEBUG1("uniarp_ipdact: uip=0x%x\n", (int)uip); + + /* + * Delete all interface entries + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_intf != uip) + continue; + + /* + * All VCCs should (better) be gone by now + */ + if (uap->ua_ivp) + panic("uniarp_ipdact: entry not empty"); + + /* + * Clean up any loose ends + */ + UNIARP_CANCEL(uap); + + /* + * Delete entry from arp table and free entry + */ + UNIARP_DELETE(uap); + atm_free((caddr_t)uap); + } + } + + /* + * Clean up 'nomap' table + */ + for (uap = uniarp_nomaptab; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_intf != uip) + continue; + + /* + * All VCCs should (better) be gone by now + */ + if (uap->ua_ivp) + panic("uniarp_ipdact: entry not empty"); + + /* + * Clean up any loose ends + */ + UNIARP_CANCEL(uap); + + /* + * Delete entry from 'no map' table and free entry + */ + UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next); + atm_free((caddr_t)uap); + } + + /* + * Also clean up pvc table + */ + for (uap = uniarp_pvctab; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_intf != uip) + continue; + + /* + * All PVCs should (better) be gone by now + */ + panic("uniarp_ipdact: pvc table not empty"); + } + + /* + * Cancel arp interface timer + */ + UNIIP_ARP_CANCEL(uip); + + /* + * Stop aging timer if this is the last active interface + */ + if (uniip_head == uip && uip->uip_next == NULL) + (void) atm_untimeout(&uniarp_timer); +} + + +/* + * Process Interface ATM Address Change + * + * This function is called whenever the ATM address for a physical + * interface is set/changed. + * + * Called at splnet. + * + * Arguments: + * sip pointer to interface's UNI signalling instance + * + * Returns: + * none + * + */ +void +uniarp_ifaddr(sip) + struct siginst *sip; +{ + struct atm_nif *nip; + struct uniip *uip; + + ATM_DEBUG1("uniarp_ifaddr: sip=0x%x\n", (int)sip); + + /* + * We've got to handle this for every network interface + */ + for (nip = sip->si_pif->pif_nif; nip; nip = nip->nif_pnext) { + + /* + * Find our control blocks + */ + for (uip = uniip_head; uip; uip = uip->uip_next) { + if (uip->uip_ipnif->inf_nif == nip) + break; + } + if (uip == NULL) + continue; + + /* + * We don't support changing prefix (yet) + */ + if (uip->uip_flags & UIF_IFADDR) { + log(LOG_ERR, "uniarp_ifaddr: change not supported\n"); + continue; + } + + /* + * Note that address has been set and figure out what + * to do next + */ + uip->uip_flags |= UIF_IFADDR; + + if (uip->uip_arpstate == UIAS_CLIENT_PADDR) { + /* + * This is what we're waiting for + */ + uniarp_client_mode(uip, NULL); + } + } + + return; +} + + +/* + * Set ATMARP Server Mode + * + * This function is called to configure the local node to become the + * ATMARP server for the specified LIS. + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * + * Returns: + * none + * + */ +static void +uniarp_server_mode(uip) + struct uniip *uip; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct ipvcc *ivp, *inext; + struct uniarp *uap, *unext; + int i; + + ATM_DEBUG1("uniarp_server_mode: uip=0x%x\n", (int)uip); + + /* + * Handle client/server mode changes first + */ + switch (uip->uip_arpstate) { + + case UIAS_NOTCONF: + case UIAS_SERVER_ACTIVE: + case UIAS_CLIENT_PADDR: + /* + * Nothing to undo + */ + break; + + case UIAS_CLIENT_POPEN: + /* + * We're becoming the server, so kill the pending connection + */ + UNIIP_ARP_CANCEL(uip); + if (ivp = uip->uip_arpsvrvcc) { + ivp->iv_flags &= ~IVF_NOIDLE; + uip->uip_arpsvrvcc = NULL; + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED); + } + break; + + case UIAS_CLIENT_REGISTER: + case UIAS_CLIENT_ACTIVE: + /* + * We're becoming the server, but leave existing VCC as a + * "normal" IP VCC + */ + UNIIP_ARP_CANCEL(uip); + ivp = uip->uip_arpsvrvcc; + ivp->iv_flags &= ~IVF_NOIDLE; + uip->uip_arpsvrvcc = NULL; + break; + } + + /* + * Revalidate status for all arp entries on this interface + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_intf != uip) + continue; + + if (uap->ua_origin >= UAO_PERM) + continue; + + if (uap->ua_origin >= UAO_SCSP) { + if (uniarp_validate_ip(uip, &uap->ua_dstip, + uap->ua_origin) == 0) + continue; + } + + if (uap->ua_ivp == NULL) { + UNIARP_CANCEL(uap); + UNIARP_DELETE(uap); + atm_free((caddr_t)uap); + continue; + } + + if (uap->ua_flags & UAF_VALID) { + uap->ua_flags |= UAF_LOCKED; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*ivp->iv_ipnif->inf_arpnotify) + (ivp, MAP_INVALID); + } + uap->ua_flags &= ~(UAF_LOCKED | UAF_VALID); + } + uap->ua_aging = 1; + uap->ua_origin = 0; + } + } + + /* + * OK, now let's make ourselves the server + */ + inp = uip->uip_ipnif; + nip = inp->inf_nif; + sgp = nip->nif_pif->pif_siginst; + ATM_ADDR_SEL_COPY(&sgp->si_addr, nip->nif_sel, &uip->uip_arpsvratm); + uip->uip_arpsvrip = IA_SIN(inp->inf_addr)->sin_addr; + uip->uip_arpstate = UIAS_SERVER_ACTIVE; + return; +} + + +/* + * Set ATMARP Client Mode + * + * This function is called to configure the local node to be an ATMARP + * client on the specified LIS using the specified ATMARP server. + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * aap pointer to the ATMARP server's ATM address + * + * Returns: + * none + * + */ +static void +uniarp_client_mode(uip, aap) + struct uniip *uip; + Atm_addr *aap; +{ + struct ip_nif *inp = uip->uip_ipnif; + struct uniarp *uap, *unext; + struct ipvcc *ivp, *inext; + int i; + + ATM_DEBUG2("uniarp_client_mode: uip=0x%x, atm=(%s,-)\n", + (int)uip, aap ? unisig_addr_print(aap): "-"); + + /* + * Handle client/server mode changes first + */ + switch (uip->uip_arpstate) { + + case UIAS_NOTCONF: + case UIAS_CLIENT_PADDR: + /* + * Nothing to undo + */ + break; + + case UIAS_CLIENT_POPEN: + /* + * If this is this a timeout retry, just go do it + */ + if (aap == NULL) + break; + + /* + * If this isn't really a different arpserver, we're done + */ + if (ATM_ADDR_EQUAL(aap, &uip->uip_arpsvratm)) + return; + + /* + * We're changing servers, so kill the pending connection + */ + UNIIP_ARP_CANCEL(uip); + if (ivp = uip->uip_arpsvrvcc) { + ivp->iv_flags &= ~IVF_NOIDLE; + uip->uip_arpsvrvcc = NULL; + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED); + } + break; + + case UIAS_CLIENT_REGISTER: + case UIAS_CLIENT_ACTIVE: + /* + * If this isn't really a different arpserver, we're done + */ + if (ATM_ADDR_EQUAL(aap, &uip->uip_arpsvratm)) + return; + + /* + * We're changing servers, but leave existing VCC as a + * "normal" IP VCC + */ + UNIIP_ARP_CANCEL(uip); + ivp = uip->uip_arpsvrvcc; + ivp->iv_flags &= ~IVF_NOIDLE; + uip->uip_arpsvrvcc = NULL; + break; + + case UIAS_SERVER_ACTIVE: + /* + * We're changing from server mode, so... + * + * Reset valid/authoritative status for all arp entries + * on this interface + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_intf != uip) + continue; + + if (uap->ua_origin >= UAO_PERM) + continue; + + if (uap->ua_ivp == NULL) { + UNIARP_CANCEL(uap); + UNIARP_DELETE(uap); + atm_free((caddr_t)uap); + continue; + } + + if (uap->ua_flags & UAF_VALID) { + uap->ua_flags |= UAF_LOCKED; + for (ivp = uap->ua_ivp; ivp; + ivp = inext) { + inext = ivp->iv_arpnext; + (*ivp->iv_ipnif->inf_arpnotify) + (ivp, MAP_INVALID); + } + uap->ua_flags &= + ~(UAF_LOCKED | UAF_VALID); + } + uap->ua_aging = 1; + uap->ua_origin = 0; + } + } + uip->uip_arpsvratm.address_format = T_ATM_ABSENT; + uip->uip_arpsvratm.address_length = 0; + uip->uip_arpsvrsub.address_format = T_ATM_ABSENT; + uip->uip_arpsvrsub.address_length = 0; + uip->uip_arpsvrip.s_addr = 0; + break; + } + + /* + * Save the arp server address, if supplied now + */ + if (aap) + ATM_ADDR_COPY(aap, &uip->uip_arpsvratm); + + /* + * If the interface's ATM address isn't set yet, then we + * can't do much until it is + */ + if ((uip->uip_flags & UIF_IFADDR) == 0) { + uip->uip_arpstate = UIAS_CLIENT_PADDR; + return; + } + + /* + * Just to keep things simple, if we already have (or are trying to + * setup) any SVCs to our new server, kill the connections so we can + * open a "fresh" SVC for the arpserver connection. + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = unext) { + unext = uap->ua_next; + + if (ATM_ADDR_EQUAL(&uip->uip_arpsvratm, + &uap->ua_dstatm) && + ATM_ADDR_EQUAL(&uip->uip_arpsvrsub, + &uap->ua_dstatmsub)) { + uap->ua_flags &= ~UAF_VALID; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_FAILED); + } + } + } + } + for (uap = uniarp_nomaptab; uap; uap = unext) { + unext = uap->ua_next; + + if (ATM_ADDR_EQUAL(&uip->uip_arpsvratm, &uap->ua_dstatm) && + ATM_ADDR_EQUAL(&uip->uip_arpsvrsub, &uap->ua_dstatmsub)) { + uap->ua_flags &= ~UAF_VALID; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_FAILED); + } + } + } + + /* + * Now, get an arp entry for the server connection + */ + uip->uip_arpstate = UIAS_CLIENT_POPEN; + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) { + UNIIP_ARP_TIMER(uip, 1 * ATM_HZ); + return; + } + + /* + * Next, initiate an SVC to the server + */ + if ((*inp->inf_createsvc)(&inp->inf_nif->nif_if, AF_ATM, + (caddr_t)&uip->uip_arpsvratm, &ivp)) { + atm_free((caddr_t)uap); + UNIIP_ARP_TIMER(uip, 1 * ATM_HZ); + return; + } + + /* + * Finally, get everything set up and wait for the SVC + * connection to complete + */ + uip->uip_arpsvrvcc = ivp; + ivp->iv_flags |= IVF_NOIDLE; + + ATM_ADDR_COPY(&uip->uip_arpsvratm, &uap->ua_dstatm); + ATM_ADDR_COPY(&uip->uip_arpsvrsub, &uap->ua_dstatmsub); + uap->ua_intf = uip; + + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + + LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next); + + return; +} + + +/* + * Process a UNI ARP interface timeout + * + * Called when a previously scheduled uniip arp interface timer expires. + * Processing will be based on the current uniip arp state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to uniip arp timer control block + * + * Returns: + * none + * + */ +void +uniarp_iftimeout(tip) + struct atm_time *tip; +{ + struct ip_nif *inp; + struct uniip *uip; + + + /* + * Back-off to uniip control block + */ + uip = (struct uniip *) + ((caddr_t)tip - (int)(&((struct uniip *)0)->uip_arptime)); + + ATM_DEBUG2("uniarp_iftimeout: uip=0x%x, state=%d\n", (int)uip, + uip->uip_arpstate); + + /* + * Process timeout based on protocol state + */ + switch (uip->uip_arpstate) { + + case UIAS_CLIENT_POPEN: + /* + * Retry opening arp server connection + */ + uniarp_client_mode(uip, NULL); + break; + + case UIAS_CLIENT_REGISTER: + /* + * Resend registration request + */ + inp = uip->uip_ipnif; + (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr)); + + /* + * Restart timer + */ + UNIIP_ARP_TIMER(uip, 2 * ATM_HZ); + + break; + + case UIAS_CLIENT_ACTIVE: + /* + * Refresh our registration + */ + inp = uip->uip_ipnif; + (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr)); + + /* + * Restart timer + */ + UNIIP_ARP_TIMER(uip, UNIARP_REGIS_RETRY); + + break; + + default: + log(LOG_ERR, "uniarp_iftimeout: invalid state %d\n", + uip->uip_arpstate); + } +} + + +/* + * UNI ARP IOCTL support + * + * Function will be called at splnet. + * + * Arguments: + * code PF_ATM sub-operation code + * data pointer to code specific parameter data area + * arg1 pointer to code specific argument + * + * Returns: + * 0 request procesed + * errno error processing request - reason indicated + * + */ +int +uniarp_ioctl(code, data, arg1) + int code; + caddr_t data; + caddr_t arg1; +{ + struct atmaddreq *aap; + struct atmdelreq *adp; + struct atmsetreq *asp; + struct atminfreq *aip; + struct air_arp_rsp aar; + struct air_asrv_rsp asr; + struct atm_pif *pip; + struct atm_nif *nip; + struct ipvcc *ivp, *inext; + struct uniip *uip; + struct uniarp *uap; + struct unisig *usp; + struct in_addr ip; + Atm_addr atmsub; + u_long dst; + int err = 0, i, buf_len; + caddr_t buf_addr; + + switch (code) { + + case AIOCS_ADD_ARP: + /* + * Add a permanent ARP mapping + */ + aap = (struct atmaddreq *)data; + uip = (struct uniip *)arg1; + if (aap->aar_arp_addr.address_format != T_ATM_ENDSYS_ADDR) { + err = EINVAL; + break; + } + atmsub.address_format = T_ATM_ABSENT; + atmsub.address_length = 0; + ip = SATOSIN(&aap->aar_arp_dst)->sin_addr; + + /* + * Validate IP address + */ + if (uniarp_validate_ip(uip, &ip, aap->aar_arp_origin) != 0) { + err = EADDRNOTAVAIL; + break; + } + + /* + * Add an entry to the cache + */ + err = uniarp_cache_svc(uip, &ip, &aap->aar_arp_addr, + &atmsub, aap->aar_arp_origin); + break; + + case AIOCS_DEL_ARP: + /* + * Delete an ARP mapping + */ + adp = (struct atmdelreq *)data; + uip = (struct uniip *)arg1; + ip = SATOSIN(&adp->adr_arp_dst)->sin_addr; + + /* + * Now find the entry to be deleted + */ + UNIARP_LOOKUP(ip.s_addr, uap); + if (uap == NULL) { + err = ENOENT; + break; + } + + /* + * Notify all VCCs using this entry that they must finish + * up now. + */ + uap->ua_flags |= UAF_LOCKED; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED); + } + + /* + * Now free up the entry + */ + UNIARP_CANCEL(uap); + UNIARP_DELETE(uap); + atm_free((caddr_t)uap); + break; + + case AIOCS_SET_ASV: + /* + * Set interface ARP server address + */ + asp = (struct atmsetreq *)data; + for (uip = uniip_head; uip; uip = uip->uip_next) { + if (uip->uip_ipnif->inf_nif == (struct atm_nif *)arg1) + break; + } + if (uip == NULL) { + err = ENOPROTOOPT; + break; + } + + /* + * Check for our own address + */ + usp = (struct unisig *) + uip->uip_ipnif->inf_nif->nif_pif->pif_siginst; + if (ATM_ADDR_EQUAL(&asp->asr_arp_addr, &usp->us_addr)) { + asp->asr_arp_addr.address_format = T_ATM_ABSENT; + } + + /* + * If we're going into server mode, make sure we can get + * the memory for the prefix list before continuing + */ + if (asp->asr_arp_addr.address_format == T_ATM_ABSENT) { + i = asp->asr_arp_plen / sizeof(struct uniarp_prf); + if (i <= 0) { + err = EINVAL; + break; + } + buf_len = i * sizeof(struct uniarp_prf); + buf_addr = KM_ALLOC(buf_len, M_DEVBUF, M_NOWAIT); + if (buf_addr == NULL) { + err = ENOMEM; + break; + } + err = copyin(asp->asr_arp_pbuf, buf_addr, buf_len); + if (err) { + KM_FREE(buf_addr, buf_len, M_DEVBUF); + break; + } + } else { + /* Silence the compiler */ + i = 0; + buf_addr = NULL; + } + + /* + * Free any existing prefix address list + */ + if (uip->uip_prefix != NULL) { + KM_FREE(uip->uip_prefix, + uip->uip_nprefix * sizeof(struct uniarp_prf), + M_DEVBUF); + uip->uip_prefix = NULL; + uip->uip_nprefix = 0; + } + + if (asp->asr_arp_addr.address_format == T_ATM_ABSENT) { + /* + * Set ATMARP server mode + */ + uip->uip_prefix = (struct uniarp_prf *)buf_addr; + uip->uip_nprefix = i; + uniarp_server_mode(uip); + } else + /* + * Set ATMARP client mode + */ + uniarp_client_mode(uip, &asp->asr_arp_addr); + break; + + case AIOCS_INF_ARP: + /* + * Get ARP table information + */ + aip = (struct atminfreq *)data; + + if (aip->air_arp_addr.sa_family != AF_INET) + break; + dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr; + + buf_addr = aip->air_buf_addr; + buf_len = aip->air_buf_len; + + pip = ((struct siginst *)arg1)->si_pif; + + /* + * Run through entire arp table + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) { + /* + * We only want valid entries learned + * from the supplied interface. + */ + nip = uap->ua_intf->uip_ipnif->inf_nif; + if (nip->nif_pif != pip) + continue; + if ((dst != INADDR_ANY) && + (dst != uap->ua_dstip.s_addr)) + continue; + + /* + * Make sure there's room in the user's buffer + */ + if (buf_len < sizeof(aar)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + SATOSIN(&aar.aap_arp_addr)->sin_family = + AF_INET; + SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr = + uap->ua_dstip.s_addr; + (void) sprintf(aar.aap_intf, "%s%d", + nip->nif_if.if_name, + nip->nif_if.if_unit); + aar.aap_flags = uap->ua_flags; + aar.aap_origin = uap->ua_origin; + if (uap->ua_flags & UAF_VALID) + aar.aap_age = uap->ua_aging + + uap->ua_retry * UNIARP_RETRY_AGE; + else + aar.aap_age = 0; + ATM_ADDR_COPY(&uap->ua_dstatm, &aar.aap_addr); + ATM_ADDR_COPY(&uap->ua_dstatmsub, + &aar.aap_subaddr); + + /* + * Copy the response into the user's buffer + */ + if (err = copyout((caddr_t)&aar, buf_addr, + sizeof(aar))) + break; + buf_addr += sizeof(aar); + buf_len -= sizeof(aar); + } + if (err) + break; + } + + /* + * Now go through the 'nomap' table + */ + if (err || (dst != INADDR_ANY)) + goto updbuf; + for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) { + /* + * We only want valid entries learned + * from the supplied interface. + */ + nip = uap->ua_intf->uip_ipnif->inf_nif; + if (nip->nif_pif != pip) + continue; + + /* + * Make sure there's room in the user's buffer + */ + if (buf_len < sizeof(aar)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + SATOSIN(&aar.aap_arp_addr)->sin_family = AF_INET; + SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr = 0; + (void) sprintf(aar.aap_intf, "%s%d", + nip->nif_if.if_name, nip->nif_if.if_unit); + aar.aap_flags = 0; + aar.aap_origin = uap->ua_origin; + aar.aap_age = 0; + ATM_ADDR_COPY(&uap->ua_dstatm, &aar.aap_addr); + ATM_ADDR_COPY(&uap->ua_dstatmsub, + &aar.aap_subaddr); + + /* + * Copy the response into the user's buffer + */ + if (err = copyout((caddr_t)&aar, buf_addr, + sizeof(aar))) + break; + buf_addr += sizeof(aar); + buf_len -= sizeof(aar); + } + +updbuf: + /* + * Update the buffer pointer and length + */ + aip->air_buf_addr = buf_addr; + aip->air_buf_len = buf_len; + + /* + * If the user wants the refresh status reset and no + * errors have been encountered, then do the reset + */ + if ((err == 0) && (aip->air_arp_flags & ARP_RESET_REF)) { + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; + uap = uap->ua_next) { + /* + * We only want valid entries learned + * from the supplied interface. + */ + nip = uap->ua_intf->uip_ipnif->inf_nif; + if (nip->nif_pif != pip) + continue; + if ((dst != INADDR_ANY) && + (dst != uap->ua_dstip.s_addr)) + continue; + + /* + * Reset refresh flag + */ + uap->ua_flags &= ~UAF_REFRESH; + } + } + } + break; + + case AIOCS_INF_ASV: + /* + * Get ARP server information + */ + aip = (struct atminfreq *)data; + + buf_addr = aip->air_buf_addr; + buf_len = aip->air_buf_len; + + for (uip = uniip_head; uip; uip = uip->uip_next) { + + if ((arg1 != NULL) && + (uip->uip_ipnif->inf_nif != (struct atm_nif *)arg1)) + continue; + + /* + * Make sure there's room in the user's buffer + */ + if (buf_len < sizeof(asr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + nip = uip->uip_ipnif->inf_nif; + (void) sprintf(asr.asp_intf, "%s%d", + nip->nif_if.if_name, nip->nif_if.if_unit); + asr.asp_state = uip->uip_arpstate; + if (uip->uip_arpstate == UIAS_SERVER_ACTIVE) { + asr.asp_addr.address_format = T_ATM_ABSENT; + asr.asp_addr.address_length = 0; + } else { + ATM_ADDR_COPY(&uip->uip_arpsvratm, + &asr.asp_addr); + } + asr.asp_subaddr.address_format = T_ATM_ABSENT; + asr.asp_subaddr.address_length = 0; + asr.asp_nprefix = uip->uip_nprefix; + + /* + * Copy the response into the user's buffer + */ + if (err = copyout((caddr_t)&asr, buf_addr, sizeof(asr))) + break; + buf_addr += sizeof(asr); + buf_len -= sizeof(asr); + + /* + * Copy the prefix list into the user's buffer + */ + if (uip->uip_nprefix) { + i = uip->uip_nprefix + * sizeof(struct uniarp_prf); + if (buf_len < i) { + err = ENOSPC; + break; + } + if (err = copyout(uip->uip_prefix, buf_addr, i)) + break; + buf_addr += i; + buf_len -= i; + } + } + + /* + * Update the buffer pointer and length + */ + aip->air_buf_addr = buf_addr; + aip->air_buf_len = buf_len; + break; + + default: + err = EOPNOTSUPP; + } + + return (err); +} + + +/* + * Get Connection's Application/Owner Name + * + * Arguments: + * tok uniarp connection token (pointer to ipvcc) + * + * Returns: + * addr pointer to string containing our name + * + */ +caddr_t +uniarp_getname(tok) + void *tok; +{ + return ("ATMARP"); +} + diff --git a/sys/netatm/uni/uniarp_cache.c b/sys/netatm/uni/uniarp_cache.c new file mode 100644 index 0000000..6c9537e --- /dev/null +++ b/sys/netatm/uni/uniarp_cache.c @@ -0,0 +1,420 @@ +/* + * + * =================================== + * 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: uniarp_cache.c,v 1.8 1998/08/26 23:29:20 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - ARP cache processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_cache.c,v 1.8 1998/08/26 23:29:20 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Add data to the arp table cache + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * ip pointer to IP address structure + * atm pointer to ATM address structure + * atmsub pointer to ATM subaddress structure + * origin source of arp information + * + * Returns: + * 0 cache successfully updated + * else updated failed - reason indicated + * + */ +int +uniarp_cache_svc(uip, ip, atm, atmsub, origin) + struct uniip *uip; + struct in_addr *ip; + Atm_addr *atm; + Atm_addr *atmsub; + u_int origin; +{ + struct ip_nif *inp; + struct ipvcc *ivp, *inext, *itail; + struct uniarp *nouap, *ipuap; + char abuf[64]; + +#ifdef DIAGNOSTIC + strncpy(abuf, unisig_addr_print(atmsub), sizeof(abuf)); + ATM_DEBUG4("cache_svc: ip=%s, atm=(%s,%s), origin=%d\n", + inet_ntoa(*ip), unisig_addr_print(atm), abuf, origin); +#endif + + /* + * Get interface info + */ + inp = uip->uip_ipnif; + + /* + * Find both cached entry and 'nomap' entries for this data. + */ + UNIARP_LOOKUP(ip->s_addr, ipuap); + for (nouap = uniarp_nomaptab; nouap; nouap = nouap->ua_next) { + if (ATM_ADDR_EQUAL(atm, &nouap->ua_dstatm) && + ATM_ADDR_EQUAL(atmsub, &nouap->ua_dstatmsub) && + (nouap->ua_intf == uip)) + break; + } + + /* + * If there aren't any entries yet, create one + */ + if ((ipuap == NULL) && (nouap == NULL)) { + ipuap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (ipuap == NULL) + return (ENOMEM); + ipuap->ua_dstip.s_addr = ip->s_addr; + ipuap->ua_dstatm.address_format = T_ATM_ABSENT; + ipuap->ua_dstatmsub.address_format = T_ATM_ABSENT; + ipuap->ua_intf = uip; + UNIARP_ADD(ipuap); + } + + /* + * If there's no cached mapping, then make the 'nomap' entry + * the new cached entry. + */ + if (ipuap == NULL) { + UNLINK(nouap, struct uniarp, uniarp_nomaptab, ua_next); + nouap->ua_dstip.s_addr = ip->s_addr; + ipuap = nouap; + nouap = NULL; + UNIARP_ADD(ipuap); + } + + /* + * We need to check the consistency of the new data with any + * cached data. So taking the easy case first, if there isn't + * an ATM address in the cache then we can skip all these checks. + */ + if (ipuap->ua_dstatm.address_format != T_ATM_ABSENT) { + /* + * See if the new data conflicts with what's in the cache + */ + if (ATM_ADDR_EQUAL(atm, &ipuap->ua_dstatm) && + ATM_ADDR_EQUAL(atmsub, &ipuap->ua_dstatmsub) && + (uip == ipuap->ua_intf)) { + /* + * No conflicts here + */ + goto dataok; + } + + /* + * Data conflict...how we deal with this depends on + * the origins of the conflicting data + */ + if (origin == ipuap->ua_origin) { + /* + * The new data has equal precedence - if there are + * any VCCs using this entry, then we reject this + * "duplicate IP address" update. + */ + if (ipuap->ua_ivp != NULL) { + strncpy(abuf, unisig_addr_print(atmsub), + sizeof(abuf)); + log(LOG_WARNING, + "uniarp: duplicate IP address %s from %s,%s\n", + inet_ntoa(*ip), unisig_addr_print(atm), + abuf); + return (EACCES); + } + + } else if (origin > ipuap->ua_origin) { + /* + * New data's origin has higher precedence, + * so accept the new mapping and notify IP/ATM + * that a mapping change has occurred. IP/ATM will + * close any VCC's which aren't waiting for this map. + */ + ipuap->ua_flags |= UAF_LOCKED; + for (ivp = ipuap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_CHANGED); + } + ipuap->ua_flags &= ~UAF_LOCKED; + } else { + /* + * New data is of lesser origin precedence, + * so we just reject the update attempt. + */ + return (EACCES); + } + + strncpy(abuf, unisig_addr_print(atmsub), sizeof(abuf)); + log(LOG_WARNING, + "uniarp: ATM address for %s changed to %s,%s\n", + inet_ntoa(*ip), unisig_addr_print(atm), abuf); + } + + /* + * Update the cache entry with the new data + */ + ATM_ADDR_COPY(atm, &ipuap->ua_dstatm); + ATM_ADDR_COPY(atmsub, &ipuap->ua_dstatmsub); + ipuap->ua_intf = uip; + +dataok: + /* + * Update cache data origin + */ + ipuap->ua_origin = MAX(ipuap->ua_origin, origin); + + /* + * Ok, now act on this new/updated cache data + */ + ipuap->ua_flags |= UAF_LOCKED; + + /* + * Save pointer to last VCC currently on cached entry chain that + * will need to be notified of the map becoming valid + */ + itail = NULL; + if ((ipuap->ua_flags & UAF_VALID) == 0) { + + for (itail = ipuap->ua_ivp; itail && itail->iv_arpnext; + itail = itail->iv_arpnext) { + } + } + + /* + * If there was a 'nomap' entry for this mapping, then we need to + * announce the new mapping to them first. + */ + if (nouap) { + + /* + * Move the VCCs from this entry to the cache entry and + * let them know there's a valid mapping now + */ + for (ivp = nouap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + + UNLINK(ivp, struct ipvcc, nouap->ua_ivp, iv_arpnext); + + LINK2TAIL(ivp, struct ipvcc, ipuap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)ipuap; + + (*inp->inf_arpnotify)(ivp, MAP_VALID); + } + + /* + * Unlink and free the 'nomap' entry + */ + UNLINK(nouap, struct uniarp, uniarp_nomaptab, ua_next); + UNIARP_CANCEL(nouap); + atm_free((caddr_t)nouap); + } + + /* + * Now, if this entry wasn't valid, notify the remaining VCCs + */ + if (itail) { + + for (ivp = ipuap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_VALID); + if (ivp == itail) + break; + } + } + ipuap->ua_flags &= ~UAF_LOCKED; + + /* + * We now have a valid cache entry, so cancel any retry timer + * and reset the aging timeout + */ + UNIARP_CANCEL(ipuap); + if ((ipuap->ua_origin == UAO_REGISTER) && (origin != UAO_REGISTER)) { + if (((ipuap->ua_flags & UAF_VALID) == 0) || + (ipuap->ua_aging <= + UNIARP_SERVER_AGE - UNIARP_MIN_REFRESH)) { + ipuap->ua_flags |= UAF_REFRESH; + ipuap->ua_aging = UNIARP_SERVER_AGE; + ipuap->ua_retry = UNIARP_SERVER_RETRY; + } + } else { + if (uip->uip_arpstate == UIAS_SERVER_ACTIVE) { + ipuap->ua_aging = UNIARP_SERVER_AGE; + ipuap->ua_retry = UNIARP_SERVER_RETRY; + } else { + ipuap->ua_aging = UNIARP_CLIENT_AGE; + ipuap->ua_retry = UNIARP_CLIENT_RETRY; + } + ipuap->ua_flags |= UAF_REFRESH; + } + ipuap->ua_flags |= UAF_VALID; + ipuap->ua_flags &= ~UAF_USED; + return (0); +} + + +/* + * Process ARP data from a PVC + * + * The arp table cache is never updated with PVC information. + * + * Called at splnet. + * + * Arguments: + * ivp pointer to input PVC's IPVCC control block + * ip pointer to IP address structure + * atm pointer to ATM address structure + * atmsub pointer to ATM subaddress structure + * + * Returns: + * none + * + */ +void +uniarp_cache_pvc(ivp, ip, atm, atmsub) + struct ipvcc *ivp; + struct in_addr *ip; + Atm_addr *atm; + Atm_addr *atmsub; +{ + struct ip_nif *inp; + struct uniarp *uap; + +#ifdef DIAGNOSTIC + char buf[64]; + int vpi = 0, vci = 0; + + if ((ivp->iv_conn) && (ivp->iv_conn->co_connvc)) { + vpi = ivp->iv_conn->co_connvc->cvc_vcc->vc_vpi; + vci = ivp->iv_conn->co_connvc->cvc_vcc->vc_vci; + } + strncpy(buf, unisig_addr_print(atmsub), sizeof(buf)); + ATM_DEBUG5("cache_pvc: vcc=(%d,%d), ip=%s, atm=(%s,%s)\n", + vpi, vci, inet_ntoa(*ip), unisig_addr_print(atm), buf); +#endif + + /* + * Get PVC info + */ + inp = ivp->iv_ipnif; + uap = (struct uniarp *)ivp->iv_arpent; + + /* + * See if IP address for PVC has changed + */ + if (uap->ua_dstip.s_addr != ip->s_addr) { + if (uap->ua_dstip.s_addr != 0) + (*inp->inf_arpnotify)(ivp, MAP_CHANGED); + uap->ua_dstip.s_addr = ip->s_addr; + } + + /* + * Let IP/ATM know if address has become valid + */ + if ((uap->ua_flags & UAF_VALID) == 0) + (*inp->inf_arpnotify)(ivp, MAP_VALID); + uap->ua_flags |= UAF_VALID; + uap->ua_aging = UNIARP_CLIENT_AGE; + uap->ua_retry = UNIARP_CLIENT_RETRY; + + /* + * Save ATM addresses just for debugging + */ + ATM_ADDR_COPY(atm, &uap->ua_dstatm); + ATM_ADDR_COPY(atmsub, &uap->ua_dstatmsub); + + return; +} + + +/* + * Validate IP address + * + * Arguments: + * uip pointer to UNI IP interface + * ip pointer to IP address structure + * origin source of arp information + * + * Returns: + * 0 IP address is acceptable + * else invalid IP address + * + */ +int +uniarp_validate_ip(uip, ip, origin) + struct uniip *uip; + struct in_addr *ip; + u_int origin; +{ + struct uniarp_prf *upp; + int i; + + + /* + * Can't be multicast or broadcast address + */ + if (IN_MULTICAST(ntohl(ip->s_addr)) || +#if (defined(BSD) && (BSD >= 199306)) + in_broadcast(*ip, &uip->uip_ipnif->inf_nif->nif_if)) +#else + in_broadcast(*ip)) +#endif + return (1); + + /* + * For ATMARP registration information (including SCSP data), + * the address must be allowed by the interface's prefix list. + */ + if ((origin == UAO_REGISTER) || (origin == UAO_SCSP)) { + for (i = uip->uip_nprefix, upp = uip->uip_prefix; + i; i--, upp++) { + if ((ip->s_addr & upp->upf_mask.s_addr) == + upp->upf_addr.s_addr) + break; + } + if (i == 0) + return (1); + } + + return (0); +} + diff --git a/sys/netatm/uni/uniarp_input.c b/sys/netatm/uni/uniarp_input.c new file mode 100644 index 0000000..cceeaa9 --- /dev/null +++ b/sys/netatm/uni/uniarp_input.c @@ -0,0 +1,853 @@ +/* + * + * =================================== + * 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: uniarp_input.c,v 1.10 1998/07/13 00:04:32 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - Input packet processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_input.c,v 1.10 1998/07/13 00:04:32 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Local functions + */ +static void proc_arp_req __P((struct ipvcc *, KBuffer *)); +static void proc_arp_rsp __P((struct ipvcc *, KBuffer *)); +static void proc_arp_nak __P((struct ipvcc *, KBuffer *)); +static void proc_inarp_req __P((struct ipvcc *, KBuffer *)); +static void proc_inarp_rsp __P((struct ipvcc *, KBuffer *)); + + +/* + * Local variables + */ +static Atm_addr satm; +static Atm_addr satmsub; +static Atm_addr tatm; +static Atm_addr tatmsub; +static struct in_addr sip; +static struct in_addr tip; + + +/* + * Process ATMARP Input Data + * + * Arguments: + * tok uniarp connection token (pointer to ipvcc) + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +void +uniarp_cpcs_data(tok, m) + void *tok; + KBuffer *m; +{ + struct ipvcc *ivp = tok; + struct atmarp_hdr *ahp; + KBuffer *n; + int len, plen = sizeof(struct atmarp_hdr); + +#ifdef DIAGNOSTIC + if (uniarp_print) + uniarp_pdu_print(ivp, m, "receive"); +#endif + + /* + * Verify IP's VCC state + */ + if (ivp->iv_state != IPVCC_ACTIVE) { + goto bad; + } + + /* + * Get the fixed fields together + */ + if (KB_LEN(m) < sizeof(struct atmarp_hdr)) { + KB_PULLUP(m, sizeof(struct atmarp_hdr), m); + if (m == NULL) + goto bad; + } + + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Initial packet verification + */ + if ((ahp->ah_hrd != htons(ARP_ATMFORUM)) || + (ahp->ah_pro != htons(ETHERTYPE_IP))) + goto bad; + + /* + * Verify/gather source address fields + */ + if (len = (ahp->ah_shtl & ARP_TL_LMASK)) { + if (ahp->ah_shtl & ARP_TL_E164) { + if (len > sizeof(struct atm_addr_e164)) + goto bad; + satm.address_format = T_ATM_E164_ADDR; + } else { + if (len != sizeof(struct atm_addr_nsap)) + goto bad; + satm.address_format = T_ATM_ENDSYS_ADDR; + } + satm.address_length = len; + if (KB_COPYDATA(m, plen, len, (caddr_t)satm.address)) + goto bad; + plen += len; + } else { + satm.address_format = T_ATM_ABSENT; + satm.address_length = 0; + } + + if (len = (ahp->ah_sstl & ARP_TL_LMASK)) { + if (((ahp->ah_sstl & ARP_TL_TMASK) != ARP_TL_NSAPA) || + (len != sizeof(struct atm_addr_nsap))) + goto bad; + satmsub.address_format = T_ATM_ENDSYS_ADDR; + satmsub.address_length = len; + if (KB_COPYDATA(m, plen, len, (caddr_t)satmsub.address)) + goto bad; + plen += len; + } else { + satmsub.address_format = T_ATM_ABSENT; + satmsub.address_length = 0; + } + + if (len = ahp->ah_spln) { + if (len != sizeof(struct in_addr)) + goto bad; + if (KB_COPYDATA(m, plen, len, (caddr_t)&sip)) + goto bad; + plen += len; + } else { + sip.s_addr = 0; + } + + /* + * Verify/gather target address fields + */ + if (len = (ahp->ah_thtl & ARP_TL_LMASK)) { + if (ahp->ah_thtl & ARP_TL_E164) { + if (len > sizeof(struct atm_addr_e164)) + goto bad; + tatm.address_format = T_ATM_E164_ADDR; + } else { + if (len != sizeof(struct atm_addr_nsap)) + goto bad; + tatm.address_format = T_ATM_ENDSYS_ADDR; + } + tatm.address_length = len; + if (KB_COPYDATA(m, plen, len, (caddr_t)tatm.address)) + goto bad; + plen += len; + } else { + tatm.address_format = T_ATM_ABSENT; + tatm.address_length = 0; + } + + if (len = (ahp->ah_tstl & ARP_TL_LMASK)) { + if (((ahp->ah_tstl & ARP_TL_TMASK) != ARP_TL_NSAPA) || + (len != sizeof(struct atm_addr_nsap))) + goto bad; + tatmsub.address_format = T_ATM_ENDSYS_ADDR; + tatmsub.address_length = len; + if (KB_COPYDATA(m, plen, len, (caddr_t)tatmsub.address)) + goto bad; + plen += len; + } else { + tatmsub.address_format = T_ATM_ABSENT; + tatmsub.address_length = 0; + } + + if (len = ahp->ah_tpln) { + if (len != sizeof(struct in_addr)) + goto bad; + if (KB_COPYDATA(m, plen, len, (caddr_t)&tip)) + goto bad; + plen += len; + } else { + tip.s_addr = 0; + } + + /* + * Verify packet length + */ + for (len = 0, n = m; n; n = KB_NEXT(n)) + len += KB_LEN(n); + if (len != plen) + goto bad; + + /* + * Now finish with packet-specific processing + */ + switch (ntohs(ahp->ah_op)) { + case ARP_REQUEST: + proc_arp_req(ivp, m); + break; + + case ARP_REPLY: + proc_arp_rsp(ivp, m); + break; + + case INARP_REQUEST: + proc_inarp_req(ivp, m); + break; + + case INARP_REPLY: + proc_inarp_rsp(ivp, m); + break; + + case ARP_NAK: + proc_arp_nak(ivp, m); + break; + + default: + goto bad; + } + + return; + +bad: + uniarp_stat.uas_rcvdrop++; + if (m) + KB_FREEALL(m); +} + + +/* + * Process an ATMARP request packet + * + * Arguments: + * ivp pointer to input VCC's IPVCC control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +proc_arp_req(ivp, m) + struct ipvcc *ivp; + KBuffer *m; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct uniip *uip; + struct uniarp *uap; + struct in_addr myip; + int s = splnet(); + + /* + * Only an arp server should receive these + */ + inp = ivp->iv_ipnif; + nip = inp->inf_nif; + uip = (struct uniip *)inp->inf_isintf; + if ((uip == NULL) || + (uip->uip_arpstate != UIAS_SERVER_ACTIVE)) + goto drop; + + /* + * These should be sent only on SVCs + */ + if ((ivp->iv_flags & IVF_SVC) == 0) + goto drop; + + /* + * Locate our addresses + */ + sgp = nip->nif_pif->pif_siginst; + myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr; + + /* + * Target IP address must be present + */ + if (tip.s_addr == 0) + goto drop; + + /* + * Drop packet if both Source addresses aren't present + */ + if ((sip.s_addr == 0) || (satm.address_format == T_ATM_ABSENT)) + goto drop; + + /* + * Source addresses can't be ours + */ + if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) && + ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &satmsub)) { + struct vccb *vcp = ivp->iv_conn->co_connvc->cvc_vcc; + + log(LOG_WARNING, + "uniarp: vcc=(%d,%d) reports our ATM address\n", + vcp->vc_vpi, vcp->vc_vci); + goto drop; + } + if (sip.s_addr == myip.s_addr) { + struct vccb *vcp = ivp->iv_conn->co_connvc->cvc_vcc; + + log(LOG_WARNING, + "uniarp: vcc=(%d,%d) reports our IP address\n", + vcp->vc_vpi, vcp->vc_vci); + goto drop; + } + + /* + * Validate Source IP address + */ + if (uniarp_validate_ip(uip, &sip, UAO_REGISTER) != 0) + goto drop; + + /* + * If the source and target IP addresses are the same, then this + * must be a client registration request (RFC-2225). Otherwise, + * try to accomodate old clients (per RFC-2225 8.4.4). + */ + if (sip.s_addr == tip.s_addr) + (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, + UAO_REGISTER); + else { + uap = (struct uniarp *)ivp->iv_arpent; + if ((uap == NULL) || (uap->ua_origin < UAO_REGISTER)) + (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, + UAO_REGISTER); + } + + /* + * Lookup the target IP address in the cache (and also check if + * the query is for our address). + */ + UNIARP_LOOKUP(tip.s_addr, uap); + if (uap && (uap->ua_flags & UAF_VALID)) { + /* + * We've found a valid mapping + */ + (void) uniarp_arp_rsp(uip, &uap->ua_arpmap, &sip, &satm, + &satmsub, ivp); + + } else if (tip.s_addr == myip.s_addr) { + /* + * We're the target, so respond accordingly + */ + (void) uniarp_arp_rsp(uip, &uip->uip_arpsvrmap, &sip, &satm, + &satmsub, ivp); + + } else { + /* + * We don't know who the target is, so NAK the query + */ + (void) uniarp_arp_nak(uip, m, ivp); + m = NULL; + } + +drop: + (void) splx(s); + if (m) + KB_FREEALL(m); + return; +} + + +/* + * Process an ATMARP reply packet + * + * Arguments: + * ivp pointer to input VCC's IPVCC control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +proc_arp_rsp(ivp, m) + struct ipvcc *ivp; + KBuffer *m; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct uniip *uip; + struct uniarp *uap; + struct in_addr myip; + int s = splnet(); + + /* + * Only the arp server should send these + */ + inp = ivp->iv_ipnif; + nip = inp->inf_nif; + uip = (struct uniip *)inp->inf_isintf; + if ((uip == NULL) || + (uip->uip_arpsvrvcc != ivp)) + goto drop; + + /* + * Locate our addresses + */ + sgp = nip->nif_pif->pif_siginst; + myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr; + + /* + * Target addresses must be ours + */ + if ((tip.s_addr != myip.s_addr) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &tatm) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &tatmsub)) + goto drop; + + /* + * Drop packet if both Source addresses aren't present + */ + if ((sip.s_addr == 0) || (satm.address_format == T_ATM_ABSENT)) + goto drop; + + /* + * If the Source addresses are ours, this is an arp server + * registration response + */ + if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) && + ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &satmsub)) { + if (sip.s_addr == myip.s_addr) { + /* + * Registration response - update our state and + * set a registration refresh timer + */ + if (uip->uip_arpstate == UIAS_CLIENT_REGISTER) + uip->uip_arpstate = UIAS_CLIENT_ACTIVE; + + if (uip->uip_arpstate == UIAS_CLIENT_ACTIVE) { + UNIIP_ARP_CANCEL(uip); + UNIIP_ARP_TIMER(uip, UNIARP_REGIS_REFRESH); + } + + /* + * If the cache entry for the server VCC isn't valid + * yet, then send an Inverse ATMARP request to solicit + * the server's IP address + */ + uap = (struct uniarp *)ivp->iv_arpent; + if ((uap->ua_flags & UAF_VALID) == 0) { + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, + &uap->ua_dstatmsub, ivp); + } + goto drop; + } else { + log(LOG_WARNING, + "uniarp: arpserver has our IP address wrong\n"); + goto drop; + } + } else if (sip.s_addr == myip.s_addr) { + log(LOG_WARNING, + "uniarp: arpserver has our ATM address wrong\n"); + goto drop; + } + + /* + * Validate the Source IP address + */ + if (uniarp_validate_ip(uip, &sip, UAO_LOOKUP) != 0) + goto drop; + + /* + * Now we believe this packet contains an authoritative mapping, + * which we probably need to setup an outgoing SVC connection + */ + (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, UAO_LOOKUP); + +drop: + (void) splx(s); + KB_FREEALL(m); + return; +} + + +/* + * Process an ATMARP negative ack packet + * + * Arguments: + * ivp pointer to input VCC's IPVCC control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +proc_arp_nak(ivp, m) + struct ipvcc *ivp; + KBuffer *m; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct uniip *uip; + struct uniarp *uap; + struct in_addr myip; + struct ipvcc *inext; + int s = splnet(); + + /* + * Only the arp server should send these + */ + inp = ivp->iv_ipnif; + nip = inp->inf_nif; + uip = (struct uniip *)inp->inf_isintf; + if ((uip == NULL) || + (uip->uip_arpsvrvcc != ivp)) + goto drop; + + /* + * Locate our addresses + */ + sgp = nip->nif_pif->pif_siginst; + myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr; + + /* + * Source addresses must be ours + */ + if ((sip.s_addr != myip.s_addr) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &satmsub)) + goto drop; + + /* + * Drop packet if the Target IP address isn't there or if this + * is a registration response, indicating an old or flakey server + */ + if ((tip.s_addr == 0) || (tip.s_addr == myip.s_addr)) + goto drop; + + /* + * Otherwise, see who we were looking for + */ + UNIARP_LOOKUP(tip.s_addr, uap); + if (uap == NULL) + goto drop; + + /* + * This entry isn't valid any longer, so notify all VCCs using this + * entry that they must finish up. The last notify should cause + * this entry to be freed by the vcclose() function. + */ + uap->ua_flags &= ~UAF_VALID; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_FAILED); + } + +drop: + (void) splx(s); + KB_FREEALL(m); + return; +} + + +/* + * Process an InATMARP request packet + * + * Arguments: + * ivp pointer to input VCC's IPVCC control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +proc_inarp_req(ivp, m) + struct ipvcc *ivp; + KBuffer *m; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct uniip *uip; + struct in_addr myip; + int s = splnet(); + + /* + * Get interface pointers + */ + inp = ivp->iv_ipnif; + nip = inp->inf_nif; + uip = (struct uniip *)inp->inf_isintf; + if (uip == NULL) + goto drop; + + /* + * Locate our addresses + */ + sgp = nip->nif_pif->pif_siginst; + myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr; + + /* + * Packet must have a Source IP address and, if it was received + * over an SVC, a Source ATM address too. + */ + if ((sip.s_addr == 0) || + ((ivp->iv_flags & IVF_SVC) && (satm.address_format == T_ATM_ABSENT))) + goto drop; + + /* + * Validate Source ATM address + * - can't be me + */ + if (satm.address_format != T_ATM_ABSENT) { + if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) && + ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, + &satmsub)) + goto drop; + } + + /* + * Validate Source IP address + */ + if ((sip.s_addr == myip.s_addr) || + (uniarp_validate_ip(uip, &sip, UAO_PEER_REQ) != 0)) + goto drop; + + /* + * The Target ATM address is required for a packet received over + * an SVC, optional for a PVC. If one is present, it must be our + * address. + */ + if ((ivp->iv_flags & IVF_SVC) && (tatm.address_format == T_ATM_ABSENT)) + goto drop; + if ((tatm.address_format != T_ATM_ABSENT) && + (!ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &tatm) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &tatmsub))) + goto drop; + + /* + * See where this packet is from + */ + if (ivp->iv_flags & IVF_PVC) { + /* + * Process the PVC arp data, although we don't really + * update the arp cache with this information + */ + uniarp_cache_pvc(ivp, &sip, &satm, &satmsub); + + } else if (uip->uip_arpsvrvcc == ivp) { + /* + * Packet is from the arp server, so we've received a + * registration/refresh request (1577 version). + * + * Therefore, update cache with authoritative data. + */ + (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, UAO_LOOKUP); + + /* + * Make sure the cache update didn't kill the server VCC + */ + if (uip->uip_arpsvrvcc != ivp) + goto drop; + + /* + * Update the server state and set the + * registration refresh timer + */ + uip->uip_arpstate = UIAS_CLIENT_ACTIVE; + UNIIP_ARP_CANCEL(uip); + UNIIP_ARP_TIMER(uip, UNIARP_REGIS_REFRESH); + } else { + /* + * Otherwise, we consider this source mapping data as + * non-authoritative and update the cache appropriately + */ + if (uniarp_cache_svc(uip, &sip, &satm, &satmsub, UAO_PEER_REQ)) + goto drop; + } + + /* + * Send an InATMARP response back to originator + */ + (void) uniarp_inarp_rsp(uip, &sip, &satm, &satmsub, ivp); + +drop: + (void) splx(s); + KB_FREEALL(m); + return; +} + + +/* + * Process an InATMARP response packet + * + * Arguments: + * ivp pointer to input VCC's IPVCC control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +proc_inarp_rsp(ivp, m) + struct ipvcc *ivp; + KBuffer *m; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct uniip *uip; + struct uniarp *uap; + struct in_addr myip; + int s = splnet(); + + /* + * Get interface pointers + */ + inp = ivp->iv_ipnif; + nip = inp->inf_nif; + uip = (struct uniip *)inp->inf_isintf; + if (uip == NULL) + goto drop; + + /* + * Locate our addresses + */ + sgp = nip->nif_pif->pif_siginst; + myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr; + + /* + * Packet must have a Source IP address and, if it was received + * over an SVC, a Source ATM address too. + */ + if ((sip.s_addr == 0) || + ((ivp->iv_flags & IVF_SVC) && (satm.address_format == T_ATM_ABSENT))) + goto drop; + + /* + * Validate Source ATM address + * - can't be me + */ + if (satm.address_format != T_ATM_ABSENT) { + if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) && + ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, + &satmsub)) + goto drop; + } + + /* + * Validate Source IP address + * - must be in our LIS + * - can't be me + * - can't be broadcast + * - can't be multicast + */ + if ((sip.s_addr == myip.s_addr) || + (uniarp_validate_ip(uip, &sip, UAO_PEER_RSP) != 0)) + goto drop; + + /* + * The Target ATM address is required for a packet received over + * an SVC, optional for a PVC. If one is present, it must be our + * address. + */ + if ((ivp->iv_flags & IVF_SVC) && (tatm.address_format == T_ATM_ABSENT)) + goto drop; + if ((tatm.address_format != T_ATM_ABSENT) && + (!ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &tatm) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &tatmsub))) + goto drop; + + /* + * See where this packet is from + */ + if (ivp->iv_flags & IVF_PVC) { + /* + * Process the PVC arp data, although we don't really + * update the arp cache with this information + */ + uniarp_cache_pvc(ivp, &sip, &satm, &satmsub); + + } else { + /* + * Can't tell the difference between an RFC-1577 registration + * and a data connection from a client of another arpserver + * on our LIS (using SCSP) - so we'll update the cache now + * with what we've got. Our clients will get "registered" + * when (if) they query us with an arp request. + */ + (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, + UAO_PEER_RSP); + } + +drop: + (void) splx(s); + KB_FREEALL(m); + return; +} + + +/* + * Print an ATMARP PDU + * + * Arguments: + * ivp pointer to input VCC control block + * m pointer to pdu buffer chain + * msg pointer to message string + * + * Returns: + * none + * + */ +void +uniarp_pdu_print(ivp, m, msg) + struct ipvcc *ivp; + KBuffer *m; + char *msg; +{ + char buf[128]; + struct vccb *vcp; + + vcp = ivp->iv_conn->co_connvc->cvc_vcc; + sprintf(buf, "uniarp %s: vcc=(%d,%d)\n", msg, vcp->vc_vpi, vcp->vc_vci); + atm_pdu_print(m, buf); +} + diff --git a/sys/netatm/uni/uniarp_output.c b/sys/netatm/uni/uniarp_output.c new file mode 100644 index 0000000..81fab93 --- /dev/null +++ b/sys/netatm/uni/uniarp_output.c @@ -0,0 +1,797 @@ +/* + * + * =================================== + * 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: uniarp_output.c,v 1.7 1998/06/29 22:15:41 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - Output packet processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_output.c,v 1.7 1998/06/29 22:15:41 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Issue an ATMARP Request PDU + * + * Arguments: + * uip pointer to IP interface + * tip pointer to target IP address + * + * Returns: + * 0 PDU was successfully sent + * else unable to send PDU + * + */ +int +uniarp_arp_req(uip, tip) + struct uniip *uip; + struct in_addr *tip; +{ + KBuffer *m; + struct atmarp_hdr *ahp; + struct atm_nif *nip; + struct ip_nif *inp; + struct ipvcc *ivp; + struct siginst *sip; + char *cp; + int len, err; + + inp = uip->uip_ipnif; + nip = inp->inf_nif; + sip = inp->inf_nif->nif_pif->pif_siginst; + + /* + * Figure out how long pdu is going to be + */ + len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr)); + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + len += sip->si_addr.address_length; + break; + + case T_ATM_E164_ADDR: + len += sip->si_addr.address_length; + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) + len += sip->si_subaddr.address_length; + break; + } + + /* + * Get a buffer for pdu + */ + KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return (1); + + /* + * Place aligned pdu at end of buffer + */ + KB_TAILALIGN(m, len); + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Setup variable fields pointer + */ + cp = (char *)ahp + sizeof(struct atmarp_hdr); + + /* + * Build fields + */ + ahp->ah_hrd = htons(ARP_ATMFORUM); + ahp->ah_pro = htons(ETHERTYPE_IP); + len = sip->si_addr.address_length; + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + + ahp->ah_sstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len); + cp += len; + + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) { + len = sip->si_subaddr.address_length; + ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_ssa */ + KM_COPY(sip->si_subaddr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + } else + ahp->ah_sstl = 0; + break; + + default: + ahp->ah_shtl = 0; + ahp->ah_sstl = 0; + } + + ahp->ah_op = htons(ARP_REQUEST); + ahp->ah_spln = sizeof(struct in_addr); + + /* ah_spa */ + KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp, + sizeof(struct in_addr)); + cp += sizeof(struct in_addr); + + ahp->ah_thtl = 0; + ahp->ah_tstl = 0; + + ahp->ah_tpln = sizeof(struct in_addr); + + /* ah_tpa */ + KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr)); + + /* + * Finally, send the pdu to the ATMARP server + */ + ivp = uip->uip_arpsvrvcc; + if (uniarp_print) + uniarp_pdu_print(ivp, m, "send"); + err = atm_cm_cpcs_data(ivp->iv_arpconn, m); + if (err) { + /* + * Didn't make it + */ + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Issue an ATMARP Response PDU + * + * Arguments: + * uip pointer to IP interface + * amp pointer to source map entry + * tip pointer to target IP address + * tatm pointer to target ATM address + * tsub pointer to target ATM subaddress + * ivp pointer to vcc over which to send pdu + * + * Returns: + * 0 PDU was successfully sent + * else unable to send PDU + * + */ +int +uniarp_arp_rsp(uip, amp, tip, tatm, tsub, ivp) + struct uniip *uip; + struct arpmap *amp; + struct in_addr *tip; + Atm_addr *tatm; + Atm_addr *tsub; + struct ipvcc *ivp; +{ + KBuffer *m; + struct atmarp_hdr *ahp; + char *cp; + int len, err; + + /* + * Figure out how long pdu is going to be + */ + len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr)); + switch (amp->am_dstatm.address_format) { + case T_ATM_ENDSYS_ADDR: + len += amp->am_dstatm.address_length; + break; + + case T_ATM_E164_ADDR: + len += amp->am_dstatm.address_length; + if (amp->am_dstatmsub.address_format == T_ATM_ENDSYS_ADDR) + len += amp->am_dstatmsub.address_length; + break; + } + + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + len += tatm->address_length; + break; + + case T_ATM_E164_ADDR: + len += tatm->address_length; + if (tsub->address_format == T_ATM_ENDSYS_ADDR) + len += tsub->address_length; + break; + } + + /* + * Get a buffer for pdu + */ + KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return (1); + + /* + * Place aligned pdu at end of buffer + */ + KB_TAILALIGN(m, len); + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Setup variable fields pointer + */ + cp = (char *)ahp + sizeof(struct atmarp_hdr); + + /* + * Build fields + */ + ahp->ah_hrd = htons(ARP_ATMFORUM); + ahp->ah_pro = htons(ETHERTYPE_IP); + len = amp->am_dstatm.address_length; + switch (amp->am_dstatm.address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(amp->am_dstatm.address, cp, len); + cp += len; + + ahp->ah_sstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(amp->am_dstatm.address, cp, len); + cp += len; + + if (amp->am_dstatmsub.address_format == T_ATM_ENDSYS_ADDR) { + len = amp->am_dstatmsub.address_length; + ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_ssa */ + KM_COPY(amp->am_dstatmsub.address, cp, len); + cp += len; + } else + ahp->ah_sstl = 0; + break; + + default: + ahp->ah_shtl = 0; + ahp->ah_sstl = 0; + } + + ahp->ah_op = htons(ARP_REPLY); + ahp->ah_spln = sizeof(struct in_addr); + + /* ah_spa */ + KM_COPY((caddr_t)&->am_dstip, cp, sizeof(struct in_addr)); + cp += sizeof(struct in_addr); + + len = tatm->address_length; + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + ahp->ah_tstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + if (tsub->address_format == T_ATM_ENDSYS_ADDR) { + len = tsub->address_length; + ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tsa */ + KM_COPY(tsub->address, cp, len); + cp += len; + } else + ahp->ah_tstl = 0; + break; + + default: + ahp->ah_thtl = 0; + ahp->ah_tstl = 0; + } + + ahp->ah_tpln = sizeof(struct in_addr); + + /* ah_tpa */ + KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr)); + + /* + * Finally, send the pdu to the vcc peer + */ + if (uniarp_print) + uniarp_pdu_print(ivp, m, "send"); + err = atm_cm_cpcs_data(ivp->iv_arpconn, m); + if (err) { + /* + * Didn't make it + */ + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Issue an ATMARP NAK PDU + * + * Arguments: + * uip pointer to IP interface + * m pointer to ATMARP_REQ buffer chain + * ivp pointer to vcc over which to send pdu + * + * Returns: + * 0 PDU was successfully sent + * else unable to send PDU + * + */ +int +uniarp_arp_nak(uip, m, ivp) + struct uniip *uip; + KBuffer *m; + struct ipvcc *ivp; +{ + struct atmarp_hdr *ahp; + int err; + + /* + * Get the fixed fields together + */ + if (KB_LEN(m) < sizeof(struct atmarp_hdr)) { + KB_PULLUP(m, sizeof(struct atmarp_hdr), m); + if (m == NULL) + return (1); + } + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Set new op-code + */ + ahp->ah_op = htons(ARP_NAK); + + /* + * Finally, send the pdu to the vcc peer + */ + if (uniarp_print) + uniarp_pdu_print(ivp, m, "send"); + err = atm_cm_cpcs_data(ivp->iv_arpconn, m); + if (err) { + /* + * Didn't make it + */ + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Issue an InATMARP Request PDU + * + * Arguments: + * uip pointer to IP interface + * tatm pointer to target ATM address + * tsub pointer to target ATM subaddress + * ivp pointer to vcc over which to send pdu + * + * Returns: + * 0 PDU was successfully sent + * else unable to send PDU + * + */ +int +uniarp_inarp_req(uip, tatm, tsub, ivp) + struct uniip *uip; + Atm_addr *tatm; + Atm_addr *tsub; + struct ipvcc *ivp; +{ + KBuffer *m; + struct atmarp_hdr *ahp; + struct atm_nif *nip; + struct ip_nif *inp; + struct siginst *sip; + char *cp; + int len, err; + + inp = uip->uip_ipnif; + nip = inp->inf_nif; + sip = inp->inf_nif->nif_pif->pif_siginst; + + /* + * Figure out how long pdu is going to be + */ + len = sizeof(struct atmarp_hdr) + sizeof(struct in_addr); + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + len += sip->si_addr.address_length; + break; + + case T_ATM_E164_ADDR: + len += sip->si_addr.address_length; + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) + len += sip->si_subaddr.address_length; + break; + } + + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + len += tatm->address_length; + break; + + case T_ATM_E164_ADDR: + len += tatm->address_length; + if (tsub->address_format == T_ATM_ENDSYS_ADDR) + len += tsub->address_length; + break; + } + + /* + * Get a buffer for pdu + */ + KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return (1); + + /* + * Place aligned pdu at end of buffer + */ + KB_TAILALIGN(m, len); + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Setup variable fields pointer + */ + cp = (char *)ahp + sizeof(struct atmarp_hdr); + + /* + * Build fields + */ + ahp->ah_hrd = htons(ARP_ATMFORUM); + ahp->ah_pro = htons(ETHERTYPE_IP); + len = sip->si_addr.address_length; + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + + ahp->ah_sstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len); + cp += len; + + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) { + len = sip->si_subaddr.address_length; + ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_ssa */ + KM_COPY(sip->si_subaddr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + } else + ahp->ah_sstl = 0; + break; + + default: + ahp->ah_shtl = 0; + ahp->ah_sstl = 0; + } + + ahp->ah_op = htons(INARP_REQUEST); + ahp->ah_spln = sizeof(struct in_addr); + + /* ah_spa */ + KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp, + sizeof(struct in_addr)); + cp += sizeof(struct in_addr); + + len = tatm->address_length; + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + ahp->ah_tstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + if (tsub->address_format == T_ATM_ENDSYS_ADDR) { + len = tsub->address_length; + ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tsa */ + KM_COPY(tsub->address, cp, len); + cp += len; + } else + ahp->ah_tstl = 0; + break; + + default: + ahp->ah_thtl = 0; + ahp->ah_tstl = 0; + } + + ahp->ah_tpln = 0; + + /* + * Finally, send the pdu to the vcc peer + */ + if (uniarp_print) + uniarp_pdu_print(ivp, m, "send"); + err = atm_cm_cpcs_data(ivp->iv_arpconn, m); + if (err) { + /* + * Didn't make it + */ + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Issue an InATMARP Response PDU + * + * Arguments: + * uip pointer to IP interface + * tip pointer to target IP address + * tatm pointer to target ATM address + * tsub pointer to target ATM subaddress + * ivp pointer to vcc over which to send pdu + * + * Returns: + * 0 PDU was successfully sent + * else unable to send PDU + * + */ +int +uniarp_inarp_rsp(uip, tip, tatm, tsub, ivp) + struct uniip *uip; + struct in_addr *tip; + Atm_addr *tatm; + Atm_addr *tsub; + struct ipvcc *ivp; +{ + KBuffer *m; + struct atmarp_hdr *ahp; + struct atm_nif *nip; + struct ip_nif *inp; + struct siginst *sip; + char *cp; + int len, err; + + inp = uip->uip_ipnif; + nip = inp->inf_nif; + sip = inp->inf_nif->nif_pif->pif_siginst; + + /* + * Figure out how long pdu is going to be + */ + len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr)); + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + len += sip->si_addr.address_length; + break; + + case T_ATM_E164_ADDR: + len += sip->si_addr.address_length; + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) + len += sip->si_subaddr.address_length; + break; + } + + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + len += tatm->address_length; + break; + + case T_ATM_E164_ADDR: + len += tatm->address_length; + if (tsub->address_format == T_ATM_ENDSYS_ADDR) + len += tsub->address_length; + break; + } + + /* + * Get a buffer for pdu + */ + KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return (1); + + /* + * Place aligned pdu at end of buffer + */ + KB_TAILALIGN(m, len); + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Setup variable fields pointer + */ + cp = (char *)ahp + sizeof(struct atmarp_hdr); + + /* + * Build fields + */ + ahp->ah_hrd = htons(ARP_ATMFORUM); + ahp->ah_pro = htons(ETHERTYPE_IP); + len = sip->si_addr.address_length; + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + + ahp->ah_sstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len); + cp += len; + + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) { + len = sip->si_subaddr.address_length; + ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_ssa */ + KM_COPY(sip->si_subaddr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + } else + ahp->ah_sstl = 0; + break; + + default: + ahp->ah_shtl = 0; + ahp->ah_sstl = 0; + } + + ahp->ah_op = htons(INARP_REPLY); + ahp->ah_spln = sizeof(struct in_addr); + + /* ah_spa */ + KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp, + sizeof(struct in_addr)); + cp += sizeof(struct in_addr); + + len = tatm->address_length; + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + ahp->ah_tstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + if (tsub->address_format == T_ATM_ENDSYS_ADDR) { + len = tsub->address_length; + ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tsa */ + KM_COPY(tsub->address, cp, len); + cp += len; + } else + ahp->ah_tstl = 0; + break; + + default: + ahp->ah_thtl = 0; + ahp->ah_tstl = 0; + } + + ahp->ah_tpln = sizeof(struct in_addr); + + /* ah_tpa */ + KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr)); + + /* + * Finally, send the pdu to the vcc peer + */ + if (uniarp_print) + uniarp_pdu_print(ivp, m, "send"); + err = atm_cm_cpcs_data(ivp->iv_arpconn, m); + if (err) { + /* + * Didn't make it + */ + KB_FREEALL(m); + return (1); + } + + return (0); +} + diff --git a/sys/netatm/uni/uniarp_timer.c b/sys/netatm/uni/uniarp_timer.c new file mode 100644 index 0000000..1f00202 --- /dev/null +++ b/sys/netatm/uni/uniarp_timer.c @@ -0,0 +1,320 @@ +/* + * + * =================================== + * 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: uniarp_timer.c,v 1.8 1998/06/29 22:44:31 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - Timer processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_timer.c,v 1.8 1998/06/29 22:44:31 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Local functions + */ +static void uniarp_svc_oldage __P((struct uniarp *)); +static void uniarp_pvc_oldage __P((struct uniarp *)); + + +/* + * Process a UNI ATMARP entry timeout + * + * Called when a previously scheduled uniarp control block timer expires. + * + * Called at splnet. + * + * Arguments: + * tip pointer to uniarp timer control block + * + * Returns: + * none + * + */ +void +uniarp_timeout(tip) + struct atm_time *tip; +{ + struct uniip *uip; + struct uniarp *uap; + struct ipvcc *ivp; + + + /* + * Back-off to uniarp control block + */ + uap = (struct uniarp *) + ((caddr_t)tip - (int)(&((struct uniarp *)0)->ua_time)); + uip = uap->ua_intf; + + + /* + * Do we know the IP address for this entry yet?? + */ + if (uap->ua_dstip.s_addr == 0) { + + /* + * No, then send another InATMARP_REQ on each active VCC + * associated with this entry to solicit the peer's identity. + */ + for (ivp = uap->ua_ivp; ivp; ivp = ivp->iv_arpnext) { + if (ivp->iv_state != IPVCC_ACTIVE) + continue; + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, + &uap->ua_dstatmsub, ivp); + } + + /* + * Restart retry timer + */ + UNIARP_TIMER(uap, UNIARP_ARP_RETRY); + } else { + /* + * Yes, then we're trying to find the ATM address for this + * IP address - so send another ATMARP_REQ to the arpserver + * (if it's up at the moment) + */ + if (uip->uip_arpstate == UIAS_CLIENT_ACTIVE) + (void) uniarp_arp_req(uip, &uap->ua_dstip); + + /* + * Restart retry timer + */ + UNIARP_TIMER(uap, UNIARP_ARP_RETRY); + } + + return; +} + + +/* + * Process an UNI ARP SVC entry aging timer expiration + * + * This function is called when an SVC arp entry's aging timer has expired. + * + * Called at splnet(). + * + * Arguments: + * uap pointer to atmarp table entry + * + * Returns: + * none + * + */ +static void +uniarp_svc_oldage(uap) + struct uniarp *uap; +{ + struct ipvcc *ivp, *inext; + struct uniip *uip = uap->ua_intf; + + + /* + * Permanent (manually installed) entries are never aged + */ + if (uap->ua_origin >= UAO_PERM) + return; + + /* + * If entry is valid and we're out of retrys, tell + * IP/ATM that the SVCs can't be used + */ + if ((uap->ua_flags & UAF_VALID) && (uap->ua_retry-- == 0)) { + uap->ua_flags |= UAF_LOCKED; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_INVALID); + } + uap->ua_flags &= ~(UAF_LOCKED | UAF_VALID); + uap->ua_origin = 0; + + /* + * Delete and free an unused entry + */ + if (uap->ua_ivp == NULL) { + UNIARP_CANCEL(uap); + UNIARP_DELETE(uap); + atm_free((caddr_t)uap); + return; + } + } + + /* + * We want to try and refresh this entry but we don't want + * to keep unused entries laying around forever. + */ + if (uap->ua_ivp || (uap->ua_flags & UAF_USED)) { + if (uip->uip_arpstate == UIAS_CLIENT_ACTIVE) { + /* + * If we are a client (and the server VCC is active), + * then we'll ask the server for a refresh + */ + (void) uniarp_arp_req(uip, &uap->ua_dstip); + } else { + /* + * Otherwise, solicit the each active VCC peer with + * an Inverse ATMARP + */ + for (ivp = uap->ua_ivp; ivp; ivp = ivp->iv_arpnext) { + if (ivp->iv_state != IPVCC_ACTIVE) + continue; + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, + &uap->ua_dstatmsub, ivp); + } + } + } + + /* + * Reset timeout + */ + if (uap->ua_flags & UAF_VALID) + uap->ua_aging = UNIARP_RETRY_AGE; + else + uap->ua_aging = UNIARP_REVALID_AGE; + + return; +} + + +/* + * Process an UNI ARP PVC entry aging timer expiration + * + * This function is called when a PVC arp entry's aging timer has expired. + * + * Called at splnet(). + * + * Arguments: + * uap pointer to atmarp table entry + * + * Returns: + * none + * + */ +static void +uniarp_pvc_oldage(uap) + struct uniarp *uap; +{ + struct ipvcc *ivp = uap->ua_ivp; + + /* + * If entry is valid and we're out of retrys, tell + * IP/ATM that PVC can't be used + */ + if ((uap->ua_flags & UAF_VALID) && (uap->ua_retry-- == 0)) { + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_INVALID); + uap->ua_flags &= ~UAF_VALID; + } + + /* + * Solicit peer with Inverse ATMARP + */ + (void) uniarp_inarp_req(uap->ua_intf, &uap->ua_dstatm, + &uap->ua_dstatmsub, ivp); + + /* + * Reset timeout + */ + if (uap->ua_flags & UAF_VALID) + uap->ua_aging = UNIARP_RETRY_AGE; + else + uap->ua_aging = UNIARP_REVALID_AGE; + + return; +} + + +/* + * Process a UNI ARP aging timer tick + * + * This function is called every UNIARP_AGING seconds, in order to age + * all the arp table entries. If an entry's timer is expired, then the + * uniarp old-age timeout function will be called for that entry. + * + * Called at splnet. + * + * Arguments: + * tip pointer to uniarp aging timer control block + * + * Returns: + * none + * + */ +void +uniarp_aging(tip) + struct atm_time *tip; +{ + struct uniarp *uap, *unext; + int i; + + + /* + * Schedule next timeout + */ + atm_timeout(&uniarp_timer, UNIARP_AGING, uniarp_aging); + + /* + * Run through arp table bumping each entry's aging timer. + * If an expired timer is found, process that entry. + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_aging && --uap->ua_aging == 0) + uniarp_svc_oldage(uap); + } + } + + /* + * Check out PVC aging timers too + */ + for (uap = uniarp_pvctab; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_aging && --uap->ua_aging == 0) + uniarp_pvc_oldage(uap); + } + + /* + * Only fully resolved SVC entries need aging, so there's no need + * to examine the 'no map' table + */ +} + diff --git a/sys/netatm/uni/uniarp_vcm.c b/sys/netatm/uni/uniarp_vcm.c new file mode 100644 index 0000000..9b1f211 --- /dev/null +++ b/sys/netatm/uni/uniarp_vcm.c @@ -0,0 +1,708 @@ +/* + * + * =================================== + * 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: uniarp_vcm.c,v 1.10 1998/06/29 22:15:46 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - Virtual Channel Management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_vcm.c,v 1.10 1998/06/29 22:15:46 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Local variables + */ +static struct attr_llc uniarp_llc = { + T_ATM_PRESENT, + { + T_ATM_LLC_SHARING, + 8, + {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06} + } +}; + +static struct t_atm_cause uniarp_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_TEMPORARY_FAILURE, + {0, 0, 0, 0} +}; + + +/* + * Process a new PVC requiring ATMARP support + * + * This function is called after IP/ATM has successfully opened a PVC which + * requires ATMARP support. We will send an InATMARP request over the PVC + * to elicit a response from the PVC's ATMARP peer informing us of its + * network address. This information will also be used by IP/ATM in order + * to complete its address-to-VC mapping table. + * + * Arguments: + * ivp pointer to PVC's IPVCC control block + * + * Returns: + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +uniarp_pvcopen(ivp) + struct ipvcc *ivp; +{ + struct uniip *uip; + struct uniarp *uap; + int s, err; + + ATM_DEBUG1("uniarp_pvcopen: ivp=0x%x\n", (int)ivp); + + ivp->iv_arpent = NULL; + + /* + * Check things out + */ + if ((ivp->iv_flags & IVF_LLC) == 0) + return (MAP_FAILED); + + /* + * Get uni interface + */ + uip = (struct uniip *)ivp->iv_ipnif->inf_isintf; + if (uip == NULL) + return (MAP_FAILED); + + /* + * Get an arp map entry + */ + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) + return (MAP_FAILED); + + /* + * Create our CM connection + */ + err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc, + ivp->iv_conn, &ivp->iv_arpconn); + if (err) { + /* + * We don't take no (or maybe) for an answer + */ + if (ivp->iv_arpconn) { + (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause); + ivp->iv_arpconn = NULL; + } + atm_free((caddr_t)uap); + return (MAP_FAILED); + } + + /* + * Get map entry set up + */ + s = splnet(); + uap->ua_dstatm.address_format = T_ATM_ABSENT; + uap->ua_dstatmsub.address_format = T_ATM_ABSENT; + uap->ua_intf = uip; + + /* + * Put ivp on arp entry chain + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + + /* + * Put arp entry on pvc chain + */ + LINK2TAIL(uap, struct uniarp, uniarp_pvctab, ua_next); + + /* + * Send Inverse ATMARP request + */ + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp); + + /* + * Start resend timer + */ + uap->ua_aging = UNIARP_REVALID_AGE; + + (void) splx(s); + return (MAP_PROCEEDING); +} + + +/* + * Process a new outgoing SVC requiring ATMARP support + * + * This function is called by the IP/ATM module to resolve a destination + * IP address to an ATM address in order to open an SVC to that destination. + * If a valid mapping is already in our cache, then we just tell the caller + * about it and that's that. Otherwise, we have to allocate a new arp entry + * and issue a query for the mapping. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * dst pointer to destination IP address + * + * Returns: + * MAP_VALID - Got the answer, returned via iv_arpent field. + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +uniarp_svcout(ivp, dst) + struct ipvcc *ivp; + struct in_addr *dst; +{ + struct uniip *uip; + struct uniarp *uap; + int s = splnet(); + + ATM_DEBUG2("uniarp_svcout: ivp=0x%x,dst=0x%x\n", (int)ivp, dst->s_addr); + + ivp->iv_arpent = NULL; + + /* + * Get uni interface + */ + uip = (struct uniip *)ivp->iv_ipnif->inf_isintf; + if (uip == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Lookup IP destination address + */ + UNIARP_LOOKUP(dst->s_addr, uap); + + if (uap) { + /* + * We've got an entry, verify interface + */ + if (uap->ua_intf != uip) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Chain this vcc onto entry + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + if (uap->ua_flags & UAF_VALID) { + /* + * Entry is valid, we're done + */ + (void) splx(s); + return (MAP_VALID); + } else { + /* + * We're already looking for this address + */ + (void) splx(s); + return (MAP_PROCEEDING); + } + } + + /* + * No info in the cache. If we're the server, then + * we're already authoritative, so just deny request. + * If we're a client but the server VCC isn't open we + * also deny the request. + */ + if (uip->uip_arpstate != UIAS_CLIENT_ACTIVE) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * We're a client with an open VCC to the server, get a new arp entry + */ + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Get entry set up + */ + uap->ua_dstip.s_addr = dst->s_addr; + uap->ua_dstatm.address_format = T_ATM_ABSENT; + uap->ua_dstatm.address_length = 0; + uap->ua_dstatmsub.address_format = T_ATM_ABSENT; + uap->ua_dstatmsub.address_length = 0; + uap->ua_intf = uip; + + /* + * Link ipvcc to arp entry for later notification + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + /* + * Add arp entry to table + */ + UNIARP_ADD(uap); + + /* + * Issue arp request for this address + */ + (void) uniarp_arp_req(uip, dst); + + /* + * Start retry timer + */ + UNIARP_TIMER(uap, UNIARP_ARP_RETRY); + + (void) splx(s); + return (MAP_PROCEEDING); +} + + +/* + * Process a new incoming SVC requiring ATMARP support + * + * This function is called by the IP/ATM module to resolve a caller's ATM + * address to its IP address for an incoming call in order to allow a + * bi-directional flow of IP packets on the SVC. If a valid mapping is + * already in our cache, then we will use it. Otherwise, we have to allocate + * a new arp entry and wait for the SVC to become active so that we can issue + * an InATMARP to the peer. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * dst pointer to caller's ATM address + * dstsub pointer to caller's ATM subaddress + * + * Returns: + * MAP_VALID - Got the answer, returned via iv_arpent field. + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +uniarp_svcin(ivp, dst, dstsub) + struct ipvcc *ivp; + Atm_addr *dst; + Atm_addr *dstsub; +{ + struct uniip *uip; + struct uniarp *uap; + int found = 0, i, s = splnet(); + + ATM_DEBUG1("uniarp_svcin: ivp=0x%x\n", (int)ivp); + + /* + * Clear ARP entry field + */ + ivp->iv_arpent = NULL; + + /* + * Check things out + */ + if ((ivp->iv_flags & IVF_LLC) == 0) + return (MAP_FAILED); + + /* + * Get uni interface + */ + uip = (struct uniip *)ivp->iv_ipnif->inf_isintf; + if (uip == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Make sure we're configured as a client or server + */ + if (uip->uip_arpstate == UIAS_NOTCONF) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * If we know the caller's ATM address, look it up + */ + uap = NULL; + if (dst->address_format != T_ATM_ABSENT) { + for (i = 0; (i < UNIARP_HASHSIZ) && (found == 0); i++) { + for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) { + if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) && + ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub)){ + found = 1; + break; + } + } + } + if (uap == NULL) { + for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) { + if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) && + ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub)) + break; + } + } + } + + if (uap) { + /* + * We've got an entry, verify interface + */ + if (uap->ua_intf != uip) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Chain the vcc onto this entry + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + if (uap->ua_flags & UAF_VALID) { + /* + * Entry is valid, we're done + */ + (void) splx(s); + return (MAP_VALID); + } else { + /* + * We're already looking for this address + */ + (void) splx(s); + return (MAP_PROCEEDING); + } + } + + /* + * No info in the cache - get a new arp entry + */ + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Get entry set up + */ + ATM_ADDR_COPY(dst, &uap->ua_dstatm); + ATM_ADDR_COPY(dstsub, &uap->ua_dstatmsub); + uap->ua_intf = uip; + + /* + * Link ipvcc to arp entry for later notification + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + /* + * Add arp entry to 'nomap' table + */ + LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next); + + (void) splx(s); + + /* + * Now we just wait for SVC to become active + */ + return (MAP_PROCEEDING); +} + + +/* + * Process ARP SVC activation notification + * + * This function is called by the IP/ATM module whenever a previously + * opened SVC has successfully been connected. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * + * Returns: + * 0 activation processing successful + * errno activation failed - reason indicated + * + */ +int +uniarp_svcactive(ivp) + struct ipvcc *ivp; +{ + struct ip_nif *inp; + struct uniip *uip; + struct uniarp *uap; + int err, s = splnet(); + + ATM_DEBUG1("uniarp_svcactive: ivp=0x%x\n", (int)ivp); + + inp = ivp->iv_ipnif; + uip = (struct uniip *)inp->inf_isintf; + uap = (struct uniarp *)ivp->iv_arpent; + + /* + * First, we need to create our CM connection + */ + err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc, + ivp->iv_conn, &ivp->iv_arpconn); + if (err) { + /* + * We don't take no (or maybe) for an answer + */ + if (ivp->iv_arpconn) { + (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause); + ivp->iv_arpconn = NULL; + } + return (err); + } + + /* + * Is this the client->server vcc?? + */ + if (uip->uip_arpsvrvcc == ivp) { + + /* + * Yep, go into the client registration phase + */ + uip->uip_arpstate = UIAS_CLIENT_REGISTER; + + /* + * To register ourselves, RFC1577 says we should wait + * around for the server to send us an InATMARP_Request. + * However, draft-1577+ just has us send an ATMARP_Request + * for our own address. To keep everyone happy, we'll go + * with both and see what works! + */ + (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr)); + + /* + * Start retry timer + */ + UNIIP_ARP_TIMER(uip, 1 * ATM_HZ); + + (void) splx(s); + return (0); + } + + /* + * Send an InATMARP_Request on this VCC to find out/notify who's at + * the other end. If we're the server, this will start off the + * RFC1577 registration procedure. If we're a client, then this + * SVC is for user data and it's pretty likely that both ends are + * going to be sending packets. So, if we're the caller, we'll be + * nice and let the callee know right away who we are. If we're the + * callee, let's find out asap the caller's IP address. + */ + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp); + + /* + * Start retry timer if entry isn't valid yet + */ + if (((uap->ua_flags & UAF_VALID) == 0) && + ((uap->ua_time.ti_flag & TIF_QUEUED) == 0)) + UNIARP_TIMER(uap, UNIARP_ARP_RETRY); + + (void) splx(s); + return (0); +} + + +/* + * Process VCC close + * + * This function is called just prior to IP/ATM closing a VCC which + * supports ATMARP. We'll sever our links to the VCC and then + * figure out how much more cleanup we need to do for now. + * + * Arguments: + * ivp pointer to VCC's IPVCC control block + * + * Returns: + * none + * + */ +void +uniarp_vcclose(ivp) + struct ipvcc *ivp; +{ + struct uniip *uip; + struct uniarp *uap; + int s; + + ATM_DEBUG1("uniarp_vcclose: ivp=0x%x\n", (int)ivp); + + /* + * Close our CM connection + */ + if (ivp->iv_arpconn) { + (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause); + ivp->iv_arpconn = NULL; + } + + /* + * Get atmarp entry + */ + if ((uap = (struct uniarp *)ivp->iv_arpent) == NULL) + return; + uip = uap->ua_intf; + + s = splnet(); + + /* + * If this is the arpserver VCC, then schedule ourselves to + * reopen the connection soon + */ + if (uip->uip_arpsvrvcc == ivp) { + uip->uip_arpsvrvcc = NULL; + uip->uip_arpstate = UIAS_CLIENT_POPEN; + UNIIP_ARP_CANCEL(uip); + UNIIP_ARP_TIMER(uip, 5 * ATM_HZ); + } + + /* + * Remove IP VCC from chain + */ + UNLINK(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + + /* + * SVCs and PVCs are handled separately + */ + if (ivp->iv_flags & IVF_SVC) { + /* + * If the mapping is currently valid or in use, or if there + * are other VCCs still using this mapping, we're done for now + */ + if ((uap->ua_flags & (UAF_VALID | UAF_LOCKED)) || + (uap->ua_origin >= UAO_PERM) || + (uap->ua_ivp != NULL)) { + (void) splx(s); + return; + } + + /* + * Unlink the entry + */ + if (uap->ua_dstip.s_addr == 0) { + UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next); + } else { + UNIARP_DELETE(uap); + } + } else { + /* + * Remove entry from pvc table + */ + UNLINK(uap, struct uniarp, uniarp_pvctab, ua_next); + } + + UNIARP_CANCEL(uap); + + /* + * Finally, free the entry + */ + atm_free((caddr_t)uap); + + (void) splx(s); + return; +} + + +/* + * Process ATMARP VCC Connected Notification + * + * Arguments: + * toku owner's connection token (ipvcc protocol block) + * + * Returns: + * none + * + */ +void +uniarp_connected(toku) + void *toku; +{ + + /* + * Since we only do atm_cm_addllc()'s on active connections, + * we should never get called here... + */ + panic("uniarp_connected"); +} + + +/* + * Process ATMARP VCC Cleared Notification + * + * Arguments: + * toku owner's connection token (ipvcc protocol block) + * cause pointer to cause code + * + * Returns: + * none + * + */ +void +uniarp_cleared(toku, cause) + void *toku; + struct t_atm_cause *cause; +{ + struct ipvcc *ivp = toku; + int s; + + s = splnet(); + + /* + * We're done with VCC + */ + ivp->iv_arpconn = NULL; + + /* + * If IP is finished with VCC, then we'll free it + */ + if (ivp->iv_state == IPVCC_FREE) + atm_free((caddr_t)ivp); + + (void) splx(s); +} + diff --git a/sys/netatm/uni/uniip.c b/sys/netatm/uni/uniip.c new file mode 100644 index 0000000..0039585 --- /dev/null +++ b/sys/netatm/uni/uniip.c @@ -0,0 +1,252 @@ +/* + * + * =================================== + * 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: uniip.c,v 1.6 1998/05/18 19:18:42 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI IP interface module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniip.c,v 1.6 1998/05/18 19:18:42 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Local functions + */ +static int uniip_ipact __P((struct ip_nif *)); +static int uniip_ipdact __P((struct ip_nif *)); + + +/* + * Global variables + */ +struct uniip *uniip_head = NULL; + +struct ip_serv uniip_ipserv = { + uniip_ipact, + uniip_ipdact, + uniarp_ioctl, + uniarp_pvcopen, + uniarp_svcout, + uniarp_svcin, + uniarp_svcactive, + uniarp_vcclose, + NULL, + {ATM_AAL5, ATM_ENC_LLC}, +}; + + +/* + * Local variables + */ +static struct sp_info uniip_pool = { + "uni ip pool", /* si_name */ + sizeof(struct uniip), /* si_blksiz */ + 2, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + + +/* + * Process module loading notification + * + * Called whenever the uni module is initializing. + * + * Arguments: + * none + * + * Returns: + * 0 initialization successful + * errno initialization failed - reason indicated + * + */ +int +uniip_start() +{ + int err; + + /* + * Tell arp to initialize stuff + */ + err = uniarp_start(); + + return (err); +} + + +/* + * Process module unloading notification + * + * Called whenever the uni module is about to be unloaded. All signalling + * instances will have been previously detached. All uniip resources + * must be freed now. + * + * Arguments: + * none + * + * Returns: + * 0 shutdown was successful + * errno shutdown failed - reason indicated + * + */ +int +uniip_stop() +{ + + /* + * All IP interfaces should be gone + */ + if (uniip_head) + return (EBUSY); + + /* + * Tell arp to stop + */ + uniarp_stop(); + + /* + * Free our storage pools + */ + atm_release_pool(&uniip_pool); + + return (0); +} + + +/* + * Process IP Network Interface Activation + * + * Called whenever an IP network interface becomes active. + * + * Called at splnet. + * + * Arguments: + * inp pointer to IP network interface + * + * Returns: + * 0 command successful + * errno command failed - reason indicated + * + */ +static int +uniip_ipact(inp) + struct ip_nif *inp; +{ + struct uniip *uip; + + /* + * Make sure we don't already have this interface + */ + for (uip = uniip_head; uip; uip = uip->uip_next) { + if (uip->uip_ipnif == inp) + return (EEXIST); + } + + /* + * Get a new interface control block + */ + uip = (struct uniip *)atm_allocate(&uniip_pool); + if (uip == NULL) + return (ENOMEM); + + /* + * Initialize and link up + */ + uip->uip_ipnif = inp; + LINK2TAIL(uip, struct uniip, uniip_head, uip_next); + + /* + * Link from IP world + */ + inp->inf_isintf = (caddr_t)uip; + + /* + * Tell arp about new interface + */ + uniarp_ipact(uip); + + return (0); +} + + +/* + * Process IP Network Interface Deactivation + * + * Called whenever an IP network interface becomes inactive. + * + * Called at splnet. + * + * Arguments: + * inp pointer to IP network interface + * + * Returns: + * 0 command successful + * errno command failed - reason indicated + * + */ +static int +uniip_ipdact(inp) + struct ip_nif *inp; +{ + struct uniip *uip; + + /* + * Get the appropriate IP interface block + */ + uip = (struct uniip *)inp->inf_isintf; + if (uip == NULL) + return (ENXIO); + + /* + * Let arp know about this + */ + uniarp_ipdact(uip); + + /* + * Free interface info + */ + UNLINK(uip, struct uniip, uniip_head, uip_next); + if (uip->uip_prefix != NULL) + KM_FREE(uip->uip_prefix, + uip->uip_nprefix * sizeof(struct uniarp_prf), M_DEVBUF); + atm_free((caddr_t)uip); + + return (0); +} + diff --git a/sys/netatm/uni/uniip_var.h b/sys/netatm/uni/uniip_var.h new file mode 100644 index 0000000..ea1eb8c --- /dev/null +++ b/sys/netatm/uni/uniip_var.h @@ -0,0 +1,318 @@ +/* + * + * =================================== + * 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: uniip_var.h,v 1.9 1998/07/13 00:00:39 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * IP interface control blocks + * + */ + +#ifndef _UNI_UNIIP_VAR_H +#define _UNI_UNIIP_VAR_H + +#ifdef ATM_KERNEL +/* + * UNI IP network interface structure. There will be one such structure for + * each IP network interface attached via a UNI signalling instance. + */ +struct uniip { + struct uniip *uip_next; /* Next attached IP interface */ + struct ip_nif *uip_ipnif; /* IP network interface */ + u_char uip_flags; /* Interface flags (see below) */ + + /* ATMARP (RFC1577) */ + u_char uip_arpstate; /* ARP interface state (see below) */ + struct arpmap uip_arpsvrmap; /* ATMARP server map info */ + struct ipvcc *uip_arpsvrvcc; /* ATMARP server's VCC */ + int uip_nprefix; /* Count of IP prefixes (server only) */ + struct uniarp_prf *uip_prefix; /* Array of IP prefixes (server only) */ + struct atm_time uip_arptime; /* ARP timer controls */ +}; +#define uip_arpsvrip uip_arpsvrmap.am_dstip +#define uip_arpsvratm uip_arpsvrmap.am_dstatm +#define uip_arpsvrsub uip_arpsvrmap.am_dstatmsub +#endif /* ATM_KERNEL */ + +/* + * UNI Interface Flags + */ +#define UIF_IFADDR 0x01 /* Interface address is set */ + +/* + * UNI ARP Interface States + */ +#define UIAS_NOTCONF 1 /* Not configured */ +#define UIAS_SERVER_ACTIVE 2 /* Server - active */ +#define UIAS_CLIENT_PADDR 3 /* Client - pending ATM address */ +#define UIAS_CLIENT_POPEN 4 /* Client - pending server vcc open */ +#define UIAS_CLIENT_REGISTER 5 /* Client - registering with server */ +#define UIAS_CLIENT_ACTIVE 6 /* Client - active */ + + +#ifdef ATM_KERNEL +/* + * Structure for allowable IP prefixes for ATMARP server registration + */ +struct uniarp_prf { + struct in_addr upf_addr; /* Prefix address */ + struct in_addr upf_mask; /* Prefix mask */ +}; + + +/* + * UNI ARP protocol constants + */ +#define UNIARP_AGING (60 * ATM_HZ) /* Aging timer tick */ +#define UNIARP_HASHSIZ 19 /* Hash table size */ +#define UNIARP_REGIS_REFRESH (15 * 60 * ATM_HZ) + /* Client registration refresh timer */ +#define UNIARP_REGIS_RETRY (60 * ATM_HZ) + /* Client registration retry timer */ +#define UNIARP_ARP_RETRY (3 * ATM_HZ) /* ARP command retry timer */ +#define UNIARP_CLIENT_AGE 12 /* Client validation timeout */ +#define UNIARP_CLIENT_RETRY 3 /* Client validation retrys */ +#define UNIARP_SERVER_AGE 17 /* Server validation timeout */ +#define UNIARP_SERVER_RETRY 3 /* Server validation retrys */ +#define UNIARP_RETRY_AGE 1 /* Retry timeout */ +#define UNIARP_REVALID_AGE 2 /* Revalidation timeout */ +#define UNIARP_MIN_REFRESH 10 /* Minimum entry refresh time */ + + +/* + * Structure for ATMARP mappings. Each of these structures will contain + * IP address to ATM hardware address mappings. There will be one such + * structure for each IP address and for each unresolved ATM address + * currently in use. + */ +struct uniarp { + struct arpmap ua_arpmap; /* Common entry header */ + struct uniip *ua_intf; /* Interface where we learned answer */ + struct uniarp *ua_next; /* Hash chain link */ + u_char ua_flags; /* Flags (see below) */ + u_char ua_origin; /* Source of mapping (see below) */ + u_char ua_retry; /* Retry counter */ + u_char ua_aging; /* Aging timeout value (minutes) */ + struct ipvcc *ua_ivp; /* Head of IP VCC chain */ + struct atm_time ua_time; /* Timer controls */ +}; +#define ua_dstip ua_arpmap.am_dstip +#define ua_dstatm ua_arpmap.am_dstatm +#define ua_dstatmsub ua_arpmap.am_dstatmsub +#endif /* ATM_KERNEL */ + +/* + * UNIARP Entry Flags + */ +#define UAF_VALID ARPF_VALID /* Entry is valid */ +#define UAF_REFRESH ARPF_REFRESH /* Entry has been refreshed */ +#define UAF_LOCKED 0x04 /* Entry is locked */ +#define UAF_USED 0x08 /* Entry has been used recently */ + +/* + * UNIARP Entry Origin + * + * The origin values are ranked according to the source precedence. + * Larger values are more preferred. + */ +#define UAO_LOCAL 100 /* Local address */ +#define UAO_PERM ARP_ORIG_PERM /* Permanently installed */ +#define UAO_REGISTER 40 /* Learned via client registration */ +#define UAO_SCSP 30 /* Learned via SCSP */ +#define UAO_LOOKUP 20 /* Learned via server lookup */ +#define UAO_PEER_RSP 15 /* Learned from peer - inarp rsp */ +#define UAO_PEER_REQ 10 /* Learned from peer - inarp req */ + +/* + * ATMARP/InATMARP Packet Format + */ +struct atmarp_hdr { + u_short ah_hrd; /* Hardware type (see below) */ + u_short ah_pro; /* Protocol type */ + u_char ah_shtl; /* Type/len of source ATM address */ + u_char ah_sstl; /* Type/len of source ATM subaddress */ + u_short ah_op; /* Operation code (see below) */ + u_char ah_spln; /* Length of source protocol address */ + u_char ah_thtl; /* Type/len of target ATM address */ + u_char ah_tstl; /* Type/len of target ATM subaddress */ + u_char ah_tpln; /* Length of target protocol address */ +#ifdef notdef + /* Variable size fields */ + u_char ah_sha[]; /* Source ATM address */ + u_char ah_ssa[]; /* Source ATM subaddress */ + u_char ah_spa[]; /* Source protocol address */ + u_char ah_tha[]; /* Target ATM subaddress */ + u_char ah_tsa[]; /* Target ATM address */ + u_char ah_tpa[]; /* Target protocol subaddress */ +#endif +}; + +/* + * Hardware types + */ +#define ARP_ATMFORUM 19 + +/* + * Operation types + */ +#define ARP_REQUEST 1 /* ATMARP request */ +#define ARP_REPLY 2 /* ATMARP response */ +#define INARP_REQUEST 8 /* InATMARP request */ +#define INARP_REPLY 9 /* InATMARP response */ +#define ARP_NAK 10 /* ATMARP negative ack */ + +/* + * Type/length fields + */ +#define ARP_TL_TMASK 0x40 /* Type mask */ +#define ARP_TL_NSAPA 0x00 /* Type = ATM Forum NSAPA */ +#define ARP_TL_E164 0x40 /* Type = E.164 */ +#define ARP_TL_LMASK 0x3f /* Length mask */ + + +#ifdef ATM_KERNEL +/* + * Timer macros + */ +#define UNIIP_ARP_TIMER(s, t) atm_timeout(&(s)->uip_arptime, (t), uniarp_iftimeout) +#define UNIIP_ARP_CANCEL(s) atm_untimeout(&(s)->uip_arptime) +#define UNIARP_TIMER(s, t) atm_timeout(&(s)->ua_time, (t), uniarp_timeout) +#define UNIARP_CANCEL(s) atm_untimeout(&(s)->ua_time) + + +/* + * Macros for manipulating UNIARP tables and entries + */ +#define UNIARP_HASH(ip) ((u_long)(ip) % UNIARP_HASHSIZ) + +#define UNIARP_ADD(ua) \ +{ \ + struct uniarp **h; \ + h = &uniarp_arptab[UNIARP_HASH((ua)->ua_dstip.s_addr)]; \ + LINK2TAIL((ua), struct uniarp, *h, ua_next); \ +} + +#define UNIARP_DELETE(ua) \ +{ \ + struct uniarp **h; \ + h = &uniarp_arptab[UNIARP_HASH((ua)->ua_dstip.s_addr)]; \ + UNLINK((ua), struct uniarp, *h, ua_next); \ +} + +#define UNIARP_LOOKUP(ip, ua) \ +{ \ + for ((ua) = uniarp_arptab[UNIARP_HASH(ip)]; \ + (ua); (ua) = (ua)->ua_next) { \ + if ((ua)->ua_dstip.s_addr == (ip)) \ + break; \ + } \ +} + + +/* + * Global UNIARP Statistics + */ +struct uniarp_stat { + u_long uas_rcvdrop; /* Input packets dropped */ +}; + + +/* + * External variables + */ +extern struct uniip *uniip_head; +extern struct ip_serv uniip_ipserv; +extern struct uniarp *uniarp_arptab[]; +extern struct uniarp *uniarp_nomaptab; +extern struct uniarp *uniarp_pvctab; +extern struct sp_info uniarp_pool; +extern struct atm_time uniarp_timer; +extern int uniarp_print; +extern Atm_endpoint uniarp_endpt; +extern struct uniarp_stat uniarp_stat; + + +/* + * Global function declarations + */ + /* uniarp.c */ +int uniarp_start __P((void)); +void uniarp_stop __P((void)); +void uniarp_ipact __P((struct uniip *)); +void uniarp_ipdact __P((struct uniip *)); +void uniarp_ifaddr __P((struct siginst *)); +void uniarp_iftimeout __P((struct atm_time *)); +int uniarp_ioctl __P((int, caddr_t, caddr_t)); +caddr_t uniarp_getname __P((void *)); + + /* uniarp_cache.c */ +int uniarp_cache_svc __P((struct uniip *, struct in_addr *, + Atm_addr *, Atm_addr *, u_int)); +void uniarp_cache_pvc __P((struct ipvcc *, struct in_addr *, + Atm_addr *, Atm_addr *)); +int uniarp_validate_ip __P((struct uniip *, struct in_addr *, + u_int)); + + /* uniarp_input.c */ +void uniarp_cpcs_data __P((void *, KBuffer *)); +void uniarp_pdu_print __P((struct ipvcc *, KBuffer *, char *)); + + /* uniarp_output.c */ +int uniarp_arp_req __P((struct uniip *, struct in_addr *)); +int uniarp_arp_rsp __P((struct uniip *, struct arpmap *, + struct in_addr *, Atm_addr *, + Atm_addr *, struct ipvcc *)); +int uniarp_arp_nak __P((struct uniip *, KBuffer *, struct ipvcc *)); +int uniarp_inarp_req __P((struct uniip *, Atm_addr *, + Atm_addr *, struct ipvcc *)); +int uniarp_inarp_rsp __P((struct uniip *, struct in_addr *, + Atm_addr *, Atm_addr *, struct ipvcc *)); + + /* uniarp_timer.c */ +void uniarp_timeout __P((struct atm_time *)); +void uniarp_aging __P((struct atm_time *)); + + /* uniarp_vcm.c */ +int uniarp_pvcopen __P((struct ipvcc *)); +int uniarp_svcout __P((struct ipvcc *, struct in_addr *)); +int uniarp_svcin __P((struct ipvcc *, Atm_addr *, Atm_addr *)); +int uniarp_svcactive __P((struct ipvcc *)); +void uniarp_vcclose __P((struct ipvcc *)); +void uniarp_connected __P((void *)); +void uniarp_cleared __P((void *, struct t_atm_cause *)); + + /* uniip.c */ +int uniip_start __P((void)); +int uniip_stop __P((void)); + + +#endif /* ATM_KERNEL */ + +#endif /* _UNI_UNIIP_VAR_H */ diff --git a/sys/netatm/uni/unisig.h b/sys/netatm/uni/unisig.h new file mode 100644 index 0000000..b69714d --- /dev/null +++ b/sys/netatm/uni/unisig.h @@ -0,0 +1,49 @@ +/* + * + * =================================== + * 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.h,v 1.2 1997/05/06 22:21:33 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Protocol control blocks + * + */ + +#ifndef _UNISIG_H +#define _UNISIG_H + +/* + * ATM Forum UNI 3.0/3.1 Signalling + */ +#define UNISIG_SIG_VPI 0 /* Signalling VPI */ +#define UNISIG_SIG_VCI 5 /* Signalling VCI */ + +#define STACK_SSCF "uni_sscf" + +#endif /* _UNISIG_H */ 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); +} diff --git a/sys/netatm/uni/unisig_decode.h b/sys/netatm/uni/unisig_decode.h new file mode 100644 index 0000000..dbd184a --- /dev/null +++ b/sys/netatm/uni/unisig_decode.h @@ -0,0 +1,87 @@ +/* + * + * =================================== + * 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.h,v 1.5 1998/08/26 23:29:21 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message formats + * + */ + +#ifndef _UNI_SIG_DECODE_H +#define _UNI_SIG_DECODE_H + + +/* + * Values specifying which IEs are required in messages + */ +#define IE_NA 0 +#define IE_MAND 1 +#define IE_OPT 2 + +/* + * Structure for information element decoding information + */ +struct ie_ent { + u_char ident; /* IE identifier */ + int min_len; /* Min. length */ + int max_len; /* Max. length */ + int p_idx; /* IE pointer index in msg */ + int (*decode) /* Decoding function */ + __P((struct usfmt *, struct ie_generic *)); +}; + +/* + * Macro to give the offset of a field in a generic IE structure + */ +#define IE_OFFSET(f) \ + ((int)&((struct ie_generic *) 0)->f) + +/* + * Macro to give the size of a field in a generic IE structure + */ +#define IE_FSIZE(f) \ + (sizeof(((struct ie_generic *) 0)->f)) + +#define IE_OFF_SIZE(f) IE_OFFSET(f),IE_FSIZE(f) + + +/* + * Structure to define a field-driven decoding table (for AAL + * parameters and ATM user cell rate IEs) + */ +struct ie_decode_tbl { + u_char ident; + int len; + int f_offs; + int f_size; +}; + +#endif /* _UNI_SIG_DECODE_H */ diff --git a/sys/netatm/uni/unisig_encode.c b/sys/netatm/uni/unisig_encode.c new file mode 100644 index 0000000..0920acc --- /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); +} diff --git a/sys/netatm/uni/unisig_if.c b/sys/netatm/uni/unisig_if.c new file mode 100644 index 0000000..784b6c5 --- /dev/null +++ b/sys/netatm/uni/unisig_if.c @@ -0,0 +1,1012 @@ +/* + * + * =================================== + * 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_if.c,v 1.12 1998/07/30 22:36:57 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * System interface module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_if.c,v 1.12 1998/07/30 22:36:57 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/uniip_var.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> + + +/* + * Global variables + */ +struct sp_info unisig_vcpool = { + "unisig vcc pool", /* si_name */ + sizeof(struct unisig_vccb), /* si_blksiz */ + 10, /* si_blkcnt */ + 50 /* si_maxallow */ +}; + +struct sp_info unisig_msgpool = { + "unisig message pool", /* si_name */ + sizeof(struct unisig_msg), /* si_blksiz */ + 10, /* si_blkcnt */ + 50 /* si_maxallow */ +}; + +struct sp_info unisig_iepool = { + "unisig ie pool", /* si_name */ + sizeof(struct ie_generic), /* si_blksiz */ + 10, /* si_blkcnt */ + 50 /* si_maxallow */ +}; + + +/* + * Local functions + */ +static int unisig_attach __P((struct sigmgr *, struct atm_pif *)); +static int unisig_detach __P((struct atm_pif *)); +static int unisig_setup __P((Atm_connvc *, int *)); +static int unisig_release __P((struct vccb *, int *)); +static int unisig_accept __P((struct vccb *, int *)); +static int unisig_reject __P((struct vccb *, int *)); +static int unisig_abort __P((struct vccb *)); +static int unisig_ioctl __P((int, caddr_t, caddr_t)); + + +/* + * Local variables + */ +static struct sigmgr unisig_mgr30 = { + NULL, + ATM_SIG_UNI30, + NULL, + unisig_attach, + unisig_detach, + unisig_setup, + unisig_accept, + unisig_reject, + unisig_release, + unisig_free, + unisig_ioctl +}; + +static struct sigmgr unisig_mgr31 = { + NULL, + ATM_SIG_UNI31, + NULL, + unisig_attach, + unisig_detach, + unisig_setup, + unisig_accept, + unisig_reject, + unisig_release, + unisig_free, + unisig_ioctl +}; + + +/* + * Initialize UNISIG processing + * + * This will be called during module loading. We'll just register + * the UNISIG protocol descriptor and wait for a UNISIG ATM interface + * to come online. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +int +unisig_start() +{ + int err = 0; + + /* + * Verify software version + */ + if (atm_version != ATM_VERSION) { + log(LOG_ERR, "version mismatch: unisig=%d.%d kernel=%d.%d\n", + ATM_VERS_MAJ(ATM_VERSION), + ATM_VERS_MIN(ATM_VERSION), + ATM_VERS_MAJ(atm_version), + ATM_VERS_MIN(atm_version)); + return (EINVAL); + } + + /* + * Register ourselves with system + */ + err = atm_sigmgr_register(&unisig_mgr30); + if (err) + goto done; + + err = atm_sigmgr_register(&unisig_mgr31); + +done: + return (err); +} + + +/* + * Halt UNISIG processing + * + * This should be called just prior to unloading the module from + * memory. All UNISIG interfaces must be deregistered before the + * protocol can be shutdown. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +int +unisig_stop() +{ + int err = 0; + int s = splnet(); + + + /* + * Any protocol instances still registered? + */ + if ((unisig_mgr30.sm_prinst != NULL) || + (unisig_mgr31.sm_prinst != NULL)) { + + /* Yes, can't stop now */ + err = EBUSY; + goto done; + } + + /* + * De-register from system + */ + (void) atm_sigmgr_deregister(&unisig_mgr30); + (void) atm_sigmgr_deregister(&unisig_mgr31); + + /* + * Free up our storage pools + */ + atm_release_pool(&unisig_vcpool); + atm_release_pool(&unisig_msgpool); + atm_release_pool(&unisig_iepool); + +done: + (void) splx(s); + return (err); +} + + +/* + * Attach a UNISIG-controlled interface + * + * Each ATM physical interface must be attached with the signalling + * manager for the interface's signalling protocol (via the + * atm_sigmgr_attach function). This function will handle the + * attachment for UNISIG-controlled interfaces. A new UNISIG protocol + * instance will be created and then we'll just sit around waiting for + * status or connection requests. + * + * Function must be called at splnet. + * + * Arguments: + * smp pointer to UNISIG signalling manager control block + * pip pointer to ATM physical interface control block + * + * Returns: + * 0 attach successful + * errno attach failed - reason indicated + * + */ +static int +unisig_attach(smp, pip) + struct sigmgr *smp; + struct atm_pif *pip; +{ + int err = 0, s; + struct unisig *usp = NULL; + + ATM_DEBUG2("unisig_attach: smp=%x, pip=%x\n", smp, pip); + + /* + * Allocate UNISIG protocol instance control block + */ + usp = (struct unisig *) + KM_ALLOC(sizeof(struct unisig), M_DEVBUF, M_NOWAIT); + if (usp == NULL) { + err = ENOMEM; + goto done; + } + KM_ZERO(usp, sizeof(struct unisig)); + + /* + * Set state in UNISIG protocol instance control block + */ + usp->us_state = UNISIG_NULL; + usp->us_proto = smp->sm_proto; + + /* + * Set initial call reference allocation value + */ + usp->us_cref = 1; + + /* + * Link instance into manager's chain + */ + LINK2TAIL((struct siginst *)usp, struct siginst, smp->sm_prinst, + si_next); + + /* + * Link in interface + */ + usp->us_pif = pip; + s = splimp(); + pip->pif_sigmgr = smp; + pip->pif_siginst = (struct siginst *) usp; + (void) splx(s); + + /* + * Clear our ATM address. The address will be set by user + * command or by registration via ILMI. + */ + usp->us_addr.address_format = T_ATM_ABSENT; + usp->us_addr.address_length = 0; + usp->us_subaddr.address_format = T_ATM_ABSENT; + usp->us_subaddr.address_length = 0; + + /* + * Set pointer to IP + */ + usp->us_ipserv = &uniip_ipserv; + + /* + * Kick-start the UNISIG protocol + */ + UNISIG_TIMER(usp, 0); + + /* + * Log the fact that we've attached + */ + log(LOG_INFO, "unisig: attached to interface %s%d\n", + pip->pif_name, pip->pif_unit); + +done: + /* + * Reset our work if attach fails + */ + if (err) { + if (usp) { + UNISIG_CANCEL(usp); + UNLINK((struct siginst *)usp, struct siginst, + smp->sm_prinst, si_next); + KM_FREE(usp, sizeof(struct unisig), M_DEVBUF); + } + s = splimp(); + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + (void) splx(s); + } + + return (err); +} + + +/* + * Detach a UNISIG-controlled interface + * + * Each ATM physical interface may be detached from its signalling + * manager (via the atm_sigmgr_detach function). This function will + * handle the detachment for all UNISIG-controlled interfaces. All + * circuits will be immediately terminated. + * + * Function must be called at splnet. + * + * Arguments: + * pip pointer to ATM physical interface control block + * + * Returns: + * 0 detach successful + * errno detach failed - reason indicated + * + */ +static int +unisig_detach(pip) + struct atm_pif *pip; +{ + struct unisig *usp; + int err; + + ATM_DEBUG1("unisig_detach: pip=0x%x\n", pip); + + /* + * Get UNISIG protocol instance + */ + usp = (struct unisig *)pip->pif_siginst; + + /* + * Return an error if we're already detaching + */ + if (usp->us_state == UNISIG_DETACH) { + return(EALREADY); + } + + /* + * Pass the detach event to the signalling manager + * state machine + */ + err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_DETACH, + (KBuffer *)0); + + /* + * Log the fact that we've detached + */ + if (!err) + log(LOG_INFO, "unisig: detached from interface %s%d\n", + pip->pif_name, pip->pif_unit); + + return (0); +} + + +/* + * Open a UNISIG ATM Connection + * + * All service user requests to open a VC connection (via + * atm_open_connection) over an ATM interface attached to the UNISIG + * signalling manager are handled here. + * + * Function will be called at splnet. + * + * Arguments: + * cvp pointer to user's requested connection parameters + * errp pointer to an int for extended error information + * + * Returns: + * CALL_PROCEEDING connection establishment is in progress + * CALL_FAILED connection establishment failed + * CALL_CONNECTED connection has been successfully established + * + */ +static int +unisig_setup(cvp, errp) + Atm_connvc *cvp; + int *errp; +{ + struct atm_pif *pip = cvp->cvc_attr.nif->nif_pif; + struct unisig *usp = (struct unisig *)pip->pif_siginst; + int rc = 0; + + ATM_DEBUG1("unisig_setup: cvp=0x%x\n", cvp); + + /* + * Intialize the returned error code + */ + *errp = 0; + + /* + * Open the connection + */ + switch (cvp->cvc_attr.called.addr.address_format) { + case T_ATM_PVC_ADDR: + /* + * Create a PVC + */ + *errp = unisig_open_vcc(usp, cvp); + rc = (*errp ? CALL_FAILED : CALL_CONNECTED); + break; + + case T_ATM_ENDSYS_ADDR: + case T_ATM_E164_ADDR: + + /* + * Create an SVC + */ + *errp = unisig_open_vcc(usp, cvp); + rc = (*errp ? CALL_FAILED : CALL_PROCEEDING); + break; + + default: + *errp = EPROTONOSUPPORT; + rc = CALL_FAILED; + } + + return (rc); +} + + +/* + * Close a UNISIG ATM Connection + * + * All service user requests to terminate a previously open VC + * connection (via the atm_close_connection function), which is running + * over an interface attached to the UNISIG signalling manager, are + * handled here. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * errp pointer to an int for extended error information + * + * Returns: + * CALL_PROCEEDING connection termination is in progress + * CALL_FAILED connection termination failed + * CALL_CLEARED connection has been successfully terminated + * + */ +static int +unisig_release(vcp, errp) + struct vccb *vcp; + int *errp; +{ + int rc = 0; + struct atm_pif *pip = vcp->vc_pif; + struct unisig *usp = (struct unisig *)pip->pif_siginst; + + ATM_DEBUG1("unisig_release: vcp=0x%x\n", vcp); + + /* + * Initialize returned error code + */ + *errp = 0; + + /* + * Validate the connection type (PVC or SVC) + */ + if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) { + *errp = EPROTONOSUPPORT; + return(CALL_FAILED); + } + + /* + * Close the VCCB + */ + *errp = unisig_close_vcc(usp, (struct unisig_vccb *)vcp); + + /* + * Set the return code + */ + if (*errp) { + rc = CALL_FAILED; + } else if (vcp->vc_sstate == UNI_NULL || + vcp->vc_sstate == UNI_FREE) { + rc = CALL_CLEARED; + } else { + rc = CALL_PROCEEDING; + } + + return (rc); +} + + +/* + * Accept a UNISIG Open from a remote host + * + * A user calls this routine (via the atm_accept_call function) + * after it is notified that an open request was received for it. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to user's VCCB + * errp pointer to an int for extended error information + * + * Returns: + * CALL_PROCEEDING connection establishment is in progress + * CALL_FAILED connection establishment failed + * CALL_CONNECTED connection has been successfully established + * + */ +static int +unisig_accept(vcp, errp) + struct vccb *vcp; + int *errp; +{ + struct unisig_vccb *uvp = (struct unisig_vccb *)vcp; + struct atm_pif *pip = uvp->uv_pif; + struct unisig *usp = (struct unisig *)pip->pif_siginst; + + ATM_DEBUG1("unisig_accept: vcp=0x%x\n", vcp); + + /* + * Initialize the returned error code + */ + *errp = 0; + + /* + * Return an error if we're detaching + */ + if (usp->us_state == UNISIG_DETACH) { + *errp = ENETDOWN; + goto free; + } + + /* + * Return an error if we lost the connection + */ + if (uvp->uv_sstate == UNI_FREE) { + *errp = ENETDOWN; + goto free; + } + + /* + * Pass the acceptance to the VC state machine + */ + *errp = unisig_vc_state(usp, uvp, UNI_VC_ACCEPT_CALL, + (struct unisig_msg *) 0); + if (*errp) + goto failed; + + return(CALL_PROCEEDING); + +failed: + /* + * On error, free the VCCB and return CALL_FAILED + */ + +free: + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq); + unisig_free((struct vccb *)uvp); + + return(CALL_FAILED); +} + + +/* + * Reject a UNISIG Open from a remote host + * + * A user calls this routine (via the atm_reject_call function) + * after it is notified that an open request was received for it. + * + * Function will be called at splnet. + * + * Arguments: + * uvp pointer to user's VCCB + * errp pointer to an int for extended error information + * + * Returns: + * CALL_CLEARED call request rejected + * CALL_FAILED call rejection failed + * + */ +static int +unisig_reject(vcp, errp) + struct vccb *vcp; + int *errp; +{ + struct unisig_vccb *uvp = (struct unisig_vccb *)vcp; + struct atm_pif *pip = uvp->uv_pif; + struct unisig *usp = (struct unisig *)pip->pif_siginst; + + ATM_DEBUG1("unisig_reject: uvp=0x%x\n", uvp); + + /* + * Initialize the returned error code + */ + *errp = 0; + + + /* + * Return an error if we're detaching + */ + if (usp->us_state == UNISIG_DETACH) { + *errp = ENETDOWN; + goto failed; + } + + /* + * Call the VC state machine + */ + *errp = unisig_vc_state(usp, uvp, UNI_VC_REJECT_CALL, + (struct unisig_msg *) 0); + if (*errp) + goto failed; + + return(CALL_CLEARED); + +failed: + /* + * On error, free the VCCB and return CALL_FAILED + */ + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq); + (void) unisig_free((struct vccb *)uvp); + return(CALL_FAILED); +} + + +/* + * Abort a UNISIG ATM Connection + * + * All (non-user) requests to abort a previously open VC connection (via + * the atm_abort_connection function), which is running over an + * interface attached to the UNISIG signalling manager, are handled here. + * The VCC owner will be notified of the request, in order to initiate + * termination of the connection. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * + * Returns: + * 0 connection release was successful + * errno connection release failed - reason indicated + * + */ +static int +unisig_abort(vcp) + struct vccb *vcp; +{ + + ATM_DEBUG1("unisig_abort: vcp=0x%x\n", (int)vcp); + + /* + * Only abort once + */ + if (vcp->vc_ustate == VCCU_ABORT) { + return (EALREADY); + } + + /* + * Cancel any timer that might be running + */ + UNISIG_VC_CANCEL(vcp); + + /* + * Set immediate timer to schedule connection termination + */ + vcp->vc_ustate = VCCU_ABORT; + UNISIG_VC_TIMER(vcp, 0); + + return (0); +} + + +/* + * Free UNISIG ATM connection resources + * + * All service user requests to free the resources of a closed VCC + * connection (via the atm_free_connection function), which is running + * over an interface attached to the UNISIG signalling manager, are + *handled here. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * + * Returns: + * 0 connection free was successful + * errno connection free failed - reason indicated + * + */ +int +unisig_free(vcp) + struct vccb *vcp; +{ + struct atm_pif *pip = vcp->vc_pif; + struct unisig *usp = (struct unisig *)pip->pif_siginst; + + ATM_DEBUG1("unisig_free: vcp = 0x%x\n", vcp); + + /* + * Make sure VCC has been closed + */ + if ((vcp->vc_ustate != VCCU_CLOSED && + vcp->vc_ustate != VCCU_ABORT) || + vcp->vc_sstate != UNI_FREE) { + ATM_DEBUG2("unisig_free: bad state, sstate=%d, ustate=%d\n", + vcp->vc_sstate, vcp->vc_ustate); + return(EEXIST); + } + + /* + * Remove VCCB from protocol queue + */ + DEQUEUE(vcp, struct vccb, vc_sigelem, usp->us_vccq); + + /* + * Free VCCB storage + */ + vcp->vc_ustate = VCCU_NULL; + vcp->vc_sstate = UNI_NULL; + atm_free((caddr_t)vcp); + + /* + * If we're detaching and this was the last VCC queued, + * get rid of the protocol instance + */ + if ((usp->us_state == UNISIG_DETACH) && + (Q_HEAD(usp->us_vccq, struct vccb) == NULL)) { + struct sigmgr *smp = pip->pif_sigmgr; + int s = splimp(); + + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + (void) splx(s); + + UNLINK((struct siginst *)usp, struct siginst, + smp->sm_prinst, si_next); + KM_FREE(usp, sizeof(struct unisig), M_DEVBUF); + } + + return (0); +} + + +/* + * UNISIG IOCTL support + * + * Function will be called at splnet. + * + * Arguments: + * code PF_ATM sub-operation code + * data pointer to code specific parameter data area + * arg1 pointer to code specific argument + * + * Returns: + * 0 request procesed + * errno error processing request - reason indicated + * + */ +static int +unisig_ioctl(code, data, arg1) + int code; + caddr_t data; + caddr_t arg1; +{ + struct atmdelreq *adp; + struct atminfreq *aip; + struct atmsetreq *asp; + struct unisig *usp; + struct unisig_vccb *uvp; + struct air_vcc_rsp rsp; + struct atm_pif *pip; + Atm_connection *cop; + u_int vpi, vci; + int err = 0, buf_len, i; + caddr_t buf_addr; + + ATM_DEBUG1("unisig_ioctl: code=%d\n", code); + + switch (code) { + + case AIOCS_DEL_PVC: + case AIOCS_DEL_SVC: + /* + * Delete a VCC + */ + adp = (struct atmdelreq *)data; + usp = (struct unisig *)arg1; + + /* + * Don't let a user close the UNISIG signalling VC + */ + vpi = adp->adr_pvc_vpi; + vci = adp->adr_pvc_vci; + if ((vpi == UNISIG_SIG_VPI && vci == UNISIG_SIG_VCI)) + return(EINVAL); + + /* + * Find requested VCC + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) { + if ((uvp->uv_vpi == vpi) && (uvp->uv_vci == vci)) + break; + } + if (uvp == NULL) + return (ENOENT); + + /* + * Check VCC type + */ + switch (code) { + case AIOCS_DEL_PVC: + if (!(uvp->uv_type & VCC_PVC)) { + return(EINVAL); + } + break; + case AIOCS_DEL_SVC: + if (!(uvp->uv_type & VCC_SVC)) { + return(EINVAL); + } + break; + } + + /* + * Schedule VCC termination + */ + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, + T_ATM_CAUSE_UNSPECIFIED_NORMAL); + err = unisig_abort((struct vccb *)uvp); + break; + + case AIOCS_INF_VCC: + /* + * Return VCC information + */ + aip = (struct atminfreq *)data; + usp = (struct unisig *)arg1; + + buf_addr = aip->air_buf_addr; + buf_len = aip->air_buf_len; + + /* + * Loop through the VCC queue + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) { + /* + * Make sure there's room in the user's buffer + */ + if (buf_len < sizeof(rsp)) { + err = ENOSPC; + break; + } + + /* + * Fill out the response struct for the VCC + */ + (void) sprintf(rsp.avp_intf, "%s%d", + usp->us_pif->pif_name, + usp->us_pif->pif_unit); + rsp.avp_vpi = uvp->uv_vpi; + rsp.avp_vci = uvp->uv_vci; + rsp.avp_type = uvp->uv_type; + rsp.avp_aal = uvp->uv_connvc->cvc_attr.aal.type; + rsp.avp_sig_proto = uvp->uv_proto; + cop = uvp->uv_connvc->cvc_conn; + if (cop) + rsp.avp_encaps = cop->co_mpx; + else + rsp.avp_encaps = 0; + rsp.avp_state = uvp->uv_sstate; + if (uvp->uv_connvc->cvc_flags & CVCF_CALLER) { + rsp.avp_daddr = uvp->uv_connvc->cvc_attr.called.addr; + } else { + rsp.avp_daddr = uvp->uv_connvc->cvc_attr.calling.addr; + } + rsp.avp_dsubaddr.address_format = T_ATM_ABSENT; + rsp.avp_dsubaddr.address_length = 0; + rsp.avp_ipdus = uvp->uv_ipdus; + rsp.avp_opdus = uvp->uv_opdus; + rsp.avp_ibytes = uvp->uv_ibytes; + rsp.avp_obytes = uvp->uv_obytes; + rsp.avp_ierrors = uvp->uv_ierrors; + rsp.avp_oerrors = uvp->uv_oerrors; + rsp.avp_tstamp = uvp->uv_tstamp; + KM_ZERO(rsp.avp_owners, + sizeof(rsp.avp_owners)); + for (i = 0; cop && i < sizeof(rsp.avp_owners); + cop = cop->co_next, + i += T_ATM_APP_NAME_LEN+1) { + strncpy(&rsp.avp_owners[i], + cop->co_endpt->ep_getname(cop->co_toku), + T_ATM_APP_NAME_LEN); + } + + /* + * Copy the response into the user's buffer + */ + if (err = copyout((caddr_t)&rsp, buf_addr, + sizeof(rsp))) + break; + buf_addr += sizeof(rsp); + buf_len -= sizeof(rsp); + } + + /* + * Update the buffer pointer and length + */ + aip->air_buf_addr = buf_addr; + aip->air_buf_len = buf_len; + break; + + case AIOCS_INF_ARP: + case AIOCS_INF_ASV: + case AIOCS_SET_ASV: + /* + * Get ARP table information or get/set ARP server address + */ + err = uniarp_ioctl(code, data, arg1); + break; + + case AIOCS_SET_PRF: + /* + * Set NSAP prefix + */ + asp = (struct atmsetreq *)data; + usp = (struct unisig *)arg1; + pip = usp->us_pif; + if (usp->us_addr.address_format != T_ATM_ABSENT) { + if (KM_CMP(asp->asr_prf_pref, usp->us_addr.address, + sizeof(asp->asr_prf_pref)) != 0) + err = EALREADY; + break; + } + usp->us_addr.address_format = T_ATM_ENDSYS_ADDR; + usp->us_addr.address_length = sizeof(Atm_addr_nsap); + KM_COPY(&pip->pif_macaddr, + ((Atm_addr_nsap *)usp->us_addr.address)->aan_esi, + sizeof(pip->pif_macaddr)); + KM_COPY((caddr_t) asp->asr_prf_pref, + &((Atm_addr_nsap *)usp->us_addr.address)->aan_afi, + sizeof(asp->asr_prf_pref)); + log(LOG_INFO, "uni: set address %s on interface %s\n", + unisig_addr_print(&usp->us_addr), + asp->asr_prf_intf); + + /* + * Pass event to signalling manager state machine + */ + err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_ADDR_SET, + (KBuffer *) NULL); + + /* + * Clean up if there was an error + */ + if (err) { + usp->us_addr.address_format = T_ATM_ABSENT; + usp->us_addr.address_length = 0; + break; + } + + /* + * Inform ARP code of new address + */ + uniarp_ifaddr((struct siginst *)usp); + break; + + default: + err = EOPNOTSUPP; + } + + return (err); +} diff --git a/sys/netatm/uni/unisig_mbuf.c b/sys/netatm/uni/unisig_mbuf.c new file mode 100644 index 0000000..84c78fe --- /dev/null +++ b/sys/netatm/uni/unisig_mbuf.c @@ -0,0 +1,485 @@ +/* + * + * =================================== + * 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_mbuf.c,v 1.6 1998/08/26 23:29:22 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message buffer handling routines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_mbuf.c,v 1.6 1998/08/26 23:29:22 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_mbuf.h> +#include <netatm/uni/unisig_msg.h> + + +/* + * Initialize a unisig formatting structure + * + * Arguments: + * usf pointer to a unisig formatting structure + * usp pointer to a unisig protocol instance + * buf pointer to a buffer chain (decode only) + * op operation code (encode or decode) + * headroom headroom to leave in first buffer + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_init(usf, usp, buf, op, headroom) + struct usfmt *usf; + struct unisig *usp; + KBuffer *buf; + int op; + int headroom; +{ + KBuffer *m; + + ATM_DEBUG3("usf_init: usf=0x%x, buf=0x%x, op=%d\n", + (int) usf, (int) buf, op); + + /* + * Check parameters + */ + if (!usf) + return(EINVAL); + + switch(op) { + + case USF_ENCODE: + /* + * Get a buffer + */ + KB_ALLOCPKT(m, USF_MIN_ALLOC, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return(ENOMEM); + KB_LEN(m) = 0; + if (headroom < KB_BFRLEN(m)) { + KB_HEADSET(m, headroom); + } + break; + + case USF_DECODE: + /* + * Verify buffer address + */ + if (!buf) + return(EINVAL); + m = buf; + break; + + default: + return(EINVAL); + } + + /* + * Save parameters in formatting structure + */ + usf->usf_m_addr = m; + usf->usf_m_base = m; + usf->usf_loc = 0; + usf->usf_op = op; + usf->usf_sig = usp; + + return(0); +} + + +/* + * Get or put the next byte of a signalling message + * + * Arguments: + * usf pointer to a unisig formatting structure + * c pointer to the byte to send from or receive into + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_byte(usf, c) + struct usfmt *usf; + u_char *c; +{ + u_char *mp; + KBuffer *m = usf->usf_m_addr, *m1; + int space; + + switch (usf->usf_op) { + + case USF_DECODE: + /* + * Make sure we're not past the end of the buffer + * (allowing for zero-length buffers) + */ + while (usf->usf_loc >= KB_LEN(m)) { + if (KB_NEXT(usf->usf_m_addr)) { + usf->usf_m_addr = m = KB_NEXT(usf->usf_m_addr); + usf->usf_loc = 0; + } else { + return(EMSGSIZE); + } + } + + /* + * Get the data from the buffer + */ + KB_DATASTART(m, mp, u_char *); + *c = mp[usf->usf_loc]; + usf->usf_loc++; + break; + + case USF_ENCODE: + /* + * If the current buffer is full, get another + */ + KB_TAILROOM(m, space); + if (space == 0) { + KB_ALLOC(m1, USF_MIN_ALLOC, KB_F_NOWAIT, KB_T_DATA); + if (m1 == NULL) + return(ENOMEM); + KB_LEN(m1) = 0; + KB_LINK(m1, m); + usf->usf_m_addr = m = m1; + usf->usf_loc = 0; + } + + /* + * Put the data into the buffer + */ + KB_DATASTART(m, mp, u_char *); + mp[usf->usf_loc] = *c; + KB_TAILADJ(m, 1); + usf->usf_loc++; + break; + + default: + /* + * Invalid operation code + */ + return(EINVAL); + } + + return(0); + +} + +/* + * Get or put a short integer + * + * Arguments: + * usf pointer to a unisig formatting structure + * s pointer to a short to send from or receive into + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_short(usf, s) + struct usfmt *usf; + u_short *s; + +{ + int rc; + union { + u_short value; + u_char b[sizeof(u_short)]; + } tval; + + tval.value = 0; + if (usf->usf_op == USF_ENCODE) + tval.value = htons(*s); + + if (rc = usf_byte(usf, &tval.b[0])) + return(rc); + if (rc = usf_byte(usf, &tval.b[1])) + return(rc); + + if (usf->usf_op == USF_DECODE) + *s = ntohs(tval.value); + + return(0); +} + + +/* + * Get or put a 3-byte integer + * + * Arguments: + * usf pointer to a unisig formatting structure + * i pointer to an integer to send from or receive into + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_int3(usf, i) + struct usfmt *usf; + u_int *i; + +{ + int j, rc; + union { + u_int value; + u_char b[sizeof(u_int)]; + } tval; + + tval.value = 0; + + if (usf->usf_op == USF_ENCODE) + tval.value = htonl(*i); + + for (j=0; j<3; j++) { + rc = usf_byte(usf, &tval.b[j+sizeof(u_int)-3]); + if (rc) + return(rc); + } + + if (usf->usf_op == USF_DECODE) + *i = ntohl(tval.value); + + return(rc); +} + + +/* + * Get or put an integer + * + * Arguments: + * usf pointer to a unisig formatting structure + * i pointer to an integer to send from or receive into + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_int(usf, i) + struct usfmt *usf; + u_int *i; + +{ + int j, rc; + union { + u_int value; + u_char b[sizeof(u_int)]; + } tval; + + if (usf->usf_op == USF_ENCODE) + tval.value = htonl(*i); + + for (j=0; j<4; j++) { + rc = usf_byte(usf, &tval.b[j+sizeof(u_int)-4]); + if (rc) + return(rc); + } + + if (usf->usf_op == USF_DECODE) + *i = ntohl(tval.value); + + return(rc); +} + + +/* + * Get or put an extented field + * + * An extented field consists of a string of bytes. All but the last + * byte of the field has the high-order bit set to zero. When decoding, + * this routine will read bytes until either the input is exhausted or + * a byte with a high-order one is found. Whe encoding, it will take an + * unsigned integer and write until the highest-order one bit has been + * written. + * + * Arguments: + * usf pointer to a unisig formatting structure + * i pointer to an integer to send from or receive into + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_ext(usf, i) + struct usfmt *usf; + u_int *i; + +{ + int j, rc; + u_char c, buff[sizeof(u_int)+1]; + u_int val; + union { + u_int value; + u_char b[sizeof(u_int)]; + } tval; + + switch(usf->usf_op) { + + case USF_ENCODE: + val = *i; + j = 0; + while (val) { + tval.value = htonl(val); + buff[j] = tval.b[sizeof(u_int)-1] & UNI_IE_EXT_MASK; + val >>= 7; + j++; + } + j--; + buff[0] |= UNI_IE_EXT_BIT; + for (; j>=0; j--) { + rc = usf_byte(usf, &buff[j]); + if (rc) + return(rc); + } + break; + + case USF_DECODE: + c = 0; + val = 0; + while (!(c & UNI_IE_EXT_BIT)) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + val = (val << 7) + (c & UNI_IE_EXT_MASK); + } + *i = val; + break; + + default: + return(EINVAL); + } + + return(0); +} + + +/* + * Count the bytes remaining to be decoded + * + * Arguments: + * usf pointer to a unisig formatting structure + * + * Returns: + * int the number of bytes in the buffer chain remaining to + * be decoded + * + */ +int +usf_count(usf) + struct usfmt *usf; +{ + int count; + KBuffer *m = usf->usf_m_addr; + + /* + * Return zero if we're not decoding + */ + if (usf->usf_op != USF_DECODE) + return (0); + + /* + * Calculate the length of data remaining in the current buffer + */ + count = KB_LEN(m) - usf->usf_loc; + + /* + * Loop through any remaining buffers, adding in their lengths + */ + while (KB_NEXT(m)) { + m = KB_NEXT(m); + count += KB_LEN(m); + } + + return(count); + +} + + +/* + * Get or put the next byte of a signalling message and return + * the byte's buffer address + * + * Arguments: + * usf pointer to a unisig formatting structure + * c pointer to the byte to send from or receive into + * bp address to store the byte's buffer address + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_byte_mark(usf, c, bp) + struct usfmt *usf; + u_char *c; + u_char **bp; +{ + u_char *mp; + int rc; + + /* + * First, get/put the data byte + */ + rc = usf_byte(usf, c); + if (rc) { + + /* + * Error encountered + */ + *bp = NULL; + return (rc); + } + + /* + * Now return the buffer address of that byte + */ + KB_DATASTART(usf->usf_m_addr, mp, u_char *); + *bp = &mp[usf->usf_loc - 1]; + + return (0); +} + diff --git a/sys/netatm/uni/unisig_mbuf.h b/sys/netatm/uni/unisig_mbuf.h new file mode 100644 index 0000000..f394047 --- /dev/null +++ b/sys/netatm/uni/unisig_mbuf.h @@ -0,0 +1,58 @@ +/* + * + * =================================== + * 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_mbuf.h,v 1.5 1998/08/26 23:29:22 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message buffer formats + * + */ + +#ifndef _UNI_SIG_MBUF_H +#define _UNI_SIG_MBUF_H + + +/* + * Structure for message encoding/decoding information. + */ +struct usfmt { + KBuffer *usf_m_addr; /* Current buffer */ + KBuffer *usf_m_base; /* First buffer in chain */ + int usf_loc; /* Offset in current buffer */ + int usf_op; /* Operation (see below) */ + struct unisig *usf_sig; /* UNI signalling instance */ +}; + +#define USF_ENCODE 1 +#define USF_DECODE 2 + +#define USF_MIN_ALLOC MHLEN /* Minimum encoding buffer size */ + +#endif /* _UNI_SIG_MBUF_H */ diff --git a/sys/netatm/uni/unisig_msg.c b/sys/netatm/uni/unisig_msg.c new file mode 100644 index 0000000..22bf469 --- /dev/null +++ b/sys/netatm/uni/unisig_msg.c @@ -0,0 +1,1002 @@ +/* + * + * =================================== + * 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_msg.c,v 1.10 1998/08/26 23:29:22 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message handling module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_msg.c,v 1.10 1998/08/26 23:29:22 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_print.h> + + +/* + * Local functions + */ +static void unisig_rcv_restart __P((struct unisig *, struct unisig_msg *)); +static void unisig_rcv_setup __P((struct unisig *, struct unisig_msg *)); + + +/* + * Local variables + */ +#ifdef DIAGNOSTIC +static int unisig_print_msg = 0; +#endif + + +/* + * Set a Cause IE based on information in an ATM attribute block + * + * Arguments: + * iep pointer to a cause IE + * msg pointer to message + * cause cause code for the error + * + * Returns: + * 0 message sent OK + * errno error encountered + * + */ +void +unisig_cause_from_attr(iep, aap) + struct ie_generic *iep; + Atm_attributes *aap; +{ + /* + * Copy cause info from attribute block to IE + */ + iep->ie_ident = UNI_IE_CAUS; + iep->ie_coding = aap->cause.v.coding_standard; + iep->ie_caus_loc = aap->cause.v.location; + iep->ie_caus_cause = aap->cause.v.cause_value; +} + + +/* + * Set a Cause IE based on information in a UNI signalling message + * + * Arguments: + * iep pointer to a cause IE + * msg pointer to message + * cause cause code for the error + * + * Returns: + * 0 message sent OK + * errno error encountered + * + */ +void +unisig_cause_from_msg(iep, msg, cause) + struct ie_generic *iep; + struct unisig_msg *msg; + int cause; +{ + struct ie_generic *ie1; + int i; + + /* + * Fill out the cause IE fixed fields + */ + iep->ie_ident = UNI_IE_CAUS; + iep->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + iep->ie_caus_cause = cause; + + /* + * Set diagnostics if indicated + */ + switch(cause) { + case UNI_IE_CAUS_IECONTENT: + iep->ie_caus_diag_len = 0; + for (i = 0, ie1 = msg->msg_ie_err; + ie1 && i < UNI_IE_CAUS_MAX_ID; + ie1 = ie1->ie_next) { + if (ie1->ie_err_cause == UNI_IE_CAUS_IECONTENT) { + iep->ie_caus_diagnostic[i] = + ie1->ie_ident; + iep->ie_caus_diag_len++; + i++; + } + } + break; + case UNI_IE_CAUS_REJECT: + iep->ie_caus_diag_len = 2; + iep->ie_caus_diagnostic[0] = UNI_IE_EXT_BIT + + (UNI_IE_CAUS_RR_USER << UNI_IE_CAUS_RR_SHIFT) + + UNI_IE_CAUS_RC_TRANS; + iep->ie_caus_diagnostic[1] = 0; + break; + case UNI_IE_CAUS_MISSING: + iep->ie_caus_diag_len = 0; + for (i = 0, ie1 = msg->msg_ie_err; + ie1 && i < UNI_IE_CAUS_MAX_ID; + ie1 = ie1->ie_next) { + if (ie1->ie_err_cause == UNI_IE_CAUS_MISSING) { + iep->ie_caus_diagnostic[i] = + ie1->ie_ident; + iep->ie_caus_diag_len++; + i++; + } + } + } +} + + +/* + * Send a UNISIG signalling message + * + * Called to send a Q.2931 message. This routine encodes the message + * and hands it to SSCF for transmission. + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * msg pointer to message + * + * Returns: + * 0 message sent OK + * errno error encountered + * + */ +int +unisig_send_msg(usp, msg) + struct unisig *usp; + struct unisig_msg *msg; +{ + int err = 0; + struct usfmt usf; + + ATM_DEBUG2("unisig_send_msg: msg=0x%x, type=%d\n", msg, + msg->msg_type); + + /* + * Make sure the network is up + */ + if (usp->us_state != UNISIG_ACTIVE) + return(ENETDOWN); + +#ifdef DIAGNOSTIC + /* + * Print the message we're sending. + */ + if (unisig_print_msg) + usp_print_msg(msg, UNISIG_MSG_OUT); +#endif + + /* + * Convert message to network order + */ + err = usf_init(&usf, usp, (KBuffer *) 0, USF_ENCODE, + usp->us_headout); + if (err) + return(err); + + err = usf_enc_msg(&usf, msg); + if (err) { + ATM_DEBUG1("unisig_send_msg: encode failed with %d\n", + err); + KB_FREEALL(usf.usf_m_base); + return(EIO); + } + +#ifdef DIAGNOSTIC + /* + * Print the converted message + */ + if (unisig_print_msg > 1) + unisig_print_mbuf(usf.usf_m_base); +#endif + + /* + * Send the message + */ + err = atm_cm_saal_data(usp->us_conn, usf.usf_m_base); + if (err) + KB_FREEALL(usf.usf_m_base); + + return(err); +} + + +/* + * Send a SETUP request + * + * Build and send a Q.2931 SETUP message. + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * uvp pointer to VCCB for which the request is being sent + * + * Returns: + * none + * + */ +int +unisig_send_setup(usp, uvp) + struct unisig *usp; + struct unisig_vccb *uvp; +{ + int err = 0; + struct unisig_msg *setup; + Atm_attributes *ap = &uvp->uv_connvc->cvc_attr; + + ATM_DEBUG1("unisig_send_setup: uvp=0x%x\n", (int) uvp); + + /* + * Make sure required connection attriutes are set + */ + if (ap->aal.tag != T_ATM_PRESENT || + ap->traffic.tag != T_ATM_PRESENT || + ap->bearer.tag != T_ATM_PRESENT || + ap->called.tag != T_ATM_PRESENT || + ap->qos.tag != T_ATM_PRESENT) { + err = EINVAL; + setup = NULL; + goto done; + } + + /* + * Get memory for a SETUP message + */ + setup = (struct unisig_msg *)atm_allocate(&unisig_msgpool); + if (setup == NULL) { + err = ENOMEM; + goto done; + } + + /* + * Fill in the SETUP message + */ + if (!uvp->uv_call_ref) + uvp->uv_call_ref = unisig_alloc_call_ref(usp); + setup->msg_call_ref = uvp->uv_call_ref; + setup->msg_type = UNI_MSG_SETU; + + /* + * Set IEs from connection attributes + */ + err = unisig_set_attrs(usp, setup, ap); + if (err) + goto done; + + /* + * Attach a Calling Party Number IE if the user didn't + * specify one in the attribute block + */ + if (ap->calling.tag != T_ATM_PRESENT) { + setup->msg_ie_cgad = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (setup->msg_ie_cgad == NULL) { + err = ENOMEM; + goto done; + } + setup->msg_ie_cgad->ie_ident = UNI_IE_CGAD; + ATM_ADDR_COPY(&usp->us_addr, + &setup->msg_ie_cgad->ie_cgad_addr); + ATM_ADDR_SEL_COPY(&usp->us_addr, + uvp->uv_nif ? uvp->uv_nif->nif_sel : 0, + &setup->msg_ie_cgad->ie_cgad_addr); + } + + /* + * Send the SETUP message + */ + err = unisig_send_msg(usp, setup); + +done: + if (setup) + unisig_free_msg(setup); + + return(err); +} + + +/* + * Send a RELEASE message + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * uvp pointer to VCCB for which the RELEASE is being sent + * msg pointer to UNI signalling message that the RELEASE + * responds to (may be NULL) + * cause the reason for the RELEASE; a value of + * T_ATM_ABSENT indicates that the cause code is + * in the VCC's ATM attributes block + * + * Returns: + * none + * + */ +int +unisig_send_release(usp, uvp, msg, cause) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; + int cause; +{ + int err = 0; + struct unisig_msg *rls_msg; + struct ie_generic *cause_ie; + + ATM_DEBUG2("unisig_send_release: usp=0x%x, uvp=0x%x\n", + (int) usp, (int) uvp); + + /* + * Get memory for a RELEASE message + */ + rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (rls_msg == NULL) { + return(ENOMEM); + } + cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (cause_ie == NULL) { + atm_free(rls_msg); + return(ENOMEM); + } + + /* + * Fill in the RELEASE message + */ + rls_msg->msg_call_ref = uvp->uv_call_ref; + rls_msg->msg_type = UNI_MSG_RLSE; + rls_msg->msg_type_flag = 0; + rls_msg->msg_type_action = 0; + rls_msg->msg_ie_caus = cause_ie; + + /* + * Fill out the cause IE + */ + cause_ie->ie_ident = UNI_IE_CAUS; + if (cause == T_ATM_ABSENT) { + unisig_cause_from_attr(cause_ie, + &uvp->uv_connvc->cvc_attr); + } else { + cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + unisig_cause_from_msg(cause_ie, msg, cause); + } + + /* + * Send the RELEASE + */ + err = unisig_send_msg(usp, rls_msg); + unisig_free_msg(rls_msg); + + return(err); +} + + +/* + * Send a RELEASE COMPLETE message + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * uvp pointer to VCCB for which the RELEASE is being sent. + * NULL indicates that a VCCB wasn't found for a call + * reference value. + * msg pointer to the message which triggered the send + * cause the cause code for the message; a value of + * T_ATM_ABSENT indicates that the cause code is + * in the VCC's ATM attributes block + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +unisig_send_release_complete(usp, uvp, msg, cause) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; + int cause; +{ + int err = 0; + struct unisig_msg *rls_cmp; + struct ie_generic *cause_ie; + + ATM_DEBUG4("unisig_send_release_complete usp=0x%x, uvp=0x%x, msg=0x%x, cause=%d\n", + (int) usp, (int) uvp, (int) msg, cause); + + /* + * Get memory for a RELEASE COMPLETE message + */ + rls_cmp = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (rls_cmp == NULL) { + return(ENOMEM); + } + cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (cause_ie == NULL) { + atm_free(rls_cmp); + return(ENOMEM); + } + + /* + * Fill in the RELEASE COMPLETE message + */ + if (uvp) { + rls_cmp->msg_call_ref = uvp->uv_call_ref; + } else if (msg) { + rls_cmp->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref); + } else { + rls_cmp->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL; + } + rls_cmp->msg_type = UNI_MSG_RLSC; + rls_cmp->msg_type_flag = 0; + rls_cmp->msg_type_action = 0; + rls_cmp->msg_ie_caus = cause_ie; + + /* + * Fill out the cause IE + */ + cause_ie->ie_ident = UNI_IE_CAUS; + if (cause == T_ATM_ABSENT) { + unisig_cause_from_attr(cause_ie, + &uvp->uv_connvc->cvc_attr); + } else { + cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + unisig_cause_from_msg(cause_ie, msg, cause); + } + + /* + * Send the RELEASE COMPLETE + */ + err = unisig_send_msg(usp, rls_cmp); + unisig_free_msg(rls_cmp); + + return(err); +} + + +/* + * Send a STATUS message + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * uvp pointer to VCCB for which the STATUS is being sent. + * NULL indicates that a VCCB wasn't found for a call + * reference value. + * msg pointer to the message which triggered the send + * cause the cause code to include in the message + * + * Returns: + * none + * + */ +int +unisig_send_status(usp, uvp, msg, cause) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; + int cause; +{ + int err = 0, i; + struct unisig_msg *stat_msg; + struct ie_generic *cause_ie, *clst_ie, *iep; + + ATM_DEBUG4("unisig_send_status: usp=0x%x, uvp=0x%x, msg=0x%x, cause=%d\n", + (int) usp, (int) uvp, (int) msg, cause); + + /* + * Get memory for a STATUS message + */ + stat_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (stat_msg == NULL) { + return(ENOMEM); + } + cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (cause_ie == NULL) { + atm_free(stat_msg); + return(ENOMEM); + } + clst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (clst_ie == NULL) { + atm_free(stat_msg); + atm_free(cause_ie); + return(ENOMEM); + } + + /* + * Fill in the STATUS message + */ + if (uvp) { + stat_msg->msg_call_ref = uvp->uv_call_ref; + } else if (msg) { + stat_msg->msg_call_ref = + EXTRACT_CREF(msg->msg_call_ref); + } else { + stat_msg->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL; + } + stat_msg->msg_type = UNI_MSG_STAT; + stat_msg->msg_type_flag = 0; + stat_msg->msg_type_action = 0; + stat_msg->msg_ie_clst = clst_ie; + stat_msg->msg_ie_caus = cause_ie; + + /* + * Fill out the call state IE + */ + clst_ie->ie_ident = UNI_IE_CLST; + clst_ie->ie_coding = 0; + clst_ie->ie_flag = 0; + clst_ie->ie_action = 0; + if (uvp) { + clst_ie->ie_clst_state = uvp->uv_sstate; + } else { + clst_ie->ie_clst_state = UNI_NULL; + } + + /* + * Fill out the cause IE + */ + cause_ie->ie_ident = UNI_IE_CAUS; + cause_ie->ie_coding = 0; + cause_ie->ie_flag = 0; + cause_ie->ie_action = 0; + cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + cause_ie->ie_caus_cause = cause; + switch (cause) { + case UNI_IE_CAUS_MTEXIST: + case UNI_IE_CAUS_STATE: + if (msg) { + cause_ie->ie_caus_diagnostic[0] = msg->msg_type; + } + break; + case UNI_IE_CAUS_MISSING: + case UNI_IE_CAUS_IECONTENT: + case UNI_IE_CAUS_IEEXIST: + for (i=0, iep=msg->msg_ie_err; + iep && i<UNI_MSG_IE_CNT; + i++, iep = iep->ie_next) { + if (iep->ie_err_cause == cause) { + cause_ie->ie_caus_diagnostic[i] = + iep->ie_ident; + } + } + } + + /* + * Send the STATUS message + */ + err = unisig_send_msg(usp, stat_msg); + unisig_free_msg(stat_msg); + + return(err); +} + + +/* + * Process a RESTART message + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * msg pointer to the RESTART message + * + * Returns: + * none + * + */ +static void +unisig_rcv_restart(usp, msg) + struct unisig *usp; + struct unisig_msg *msg; +{ + struct unisig_vccb *uvp, *uvnext; + struct unisig_msg *rsta_msg; + int s; + + ATM_DEBUG2("unisig_rcv_restart: usp=0x%x, msg=0x%x\n", + usp, msg); + + /* + * Check what class of VCCs we're supposed to restart + */ + if (msg->msg_ie_rsti->ie_rsti_class == UNI_IE_RSTI_IND_VC) { + /* + * Just restart the indicated VCC + */ + if (msg->msg_ie_cnid) { + uvp = unisig_find_vpvc(usp, + msg->msg_ie_cnid->ie_cnid_vpci, + msg->msg_ie_cnid->ie_cnid_vci, + 0); + if (uvp && uvp->uv_type & VCC_SVC) { + (void) unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } + } + } else { + /* + * Restart all VCCs + */ + s = splnet(); + for (uvp=Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp=uvnext) { + uvnext = Q_NEXT(uvp, struct unisig_vccb, + uv_sigelem); + if (uvp->uv_type & VCC_SVC) { + (void) unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } + } + (void) splx(s); + } + + /* + * Get memory for a RESTART ACKNOWLEDGE message + */ + rsta_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (rsta_msg == NULL) { + return; + } + + /* + * Fill out the message + */ + rsta_msg->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref); + rsta_msg->msg_type = UNI_MSG_RSTA; + rsta_msg->msg_type_flag = 0; + rsta_msg->msg_type_action = 0; + rsta_msg->msg_ie_rsti = msg->msg_ie_rsti; + if (msg->msg_ie_cnid) { + rsta_msg->msg_ie_cnid = msg->msg_ie_cnid; + } + + /* + * Send the message + */ + (void) unisig_send_msg(usp, rsta_msg); + rsta_msg->msg_ie_rsti = NULL; + rsta_msg->msg_ie_cnid = NULL; + unisig_free_msg(rsta_msg); + + return; +} + + +/* + * Process a SETUP message + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * msg pointer to the SETUP message + * + * Returns: + * none + * + */ +static void +unisig_rcv_setup(usp, msg) + struct unisig *usp; + struct unisig_msg *msg; +{ + struct unisig_vccb *uvp = NULL; + struct ie_generic *iep; + + ATM_DEBUG2("unisig_rcv_setup: usp=0x%x, msg=0x%x\n", usp, msg); + + /* + * If we already have a VCC with the call reference, + * ignore the SETUP message + */ + uvp = unisig_find_conn(usp, EXTRACT_CREF(msg->msg_call_ref)); + if (uvp) + return; + + /* + * If the call reference flag is incorrectly set, + * ignore the SETUP message + */ + if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT) + return; + + /* + * If there are missing mandatory IEs, send a + * RELEASE COMPLETE message and ignore the SETUP + */ + for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) { + if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) { + (void) unisig_send_release_complete(usp, + uvp, msg, UNI_IE_CAUS_MISSING); + return; + } + } + + /* + * If there are mandatory IEs with invalid content, send a + * RELEASE COMPLETE message and ignore the SETUP + */ + for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) { + if (iep->ie_err_cause == UNI_IE_CAUS_IECONTENT) { + (void) unisig_send_release_complete(usp, + uvp, msg, + UNI_IE_CAUS_IECONTENT); + return; + } + } + + /* + * Get a new VCCB for the connection + */ + uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool); + if (uvp == NULL) { + return; + } + + /* + * Put the VCCB on the UNISIG queue + */ + ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq); + + /* + * Set the state and call reference value + */ + uvp->uv_sstate = UNI_NULL; + uvp->uv_call_ref = EXTRACT_CREF(msg->msg_call_ref); + + /* + * Pass the VCCB and message to the VC state machine + */ + (void) unisig_vc_state(usp, uvp, UNI_VC_SETUP_MSG, msg); + + /* + * If the VCCB state is NULL, the open failed and the + * VCCB should be released + */ + if (uvp->uv_sstate == UNI_NULL) { + DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, + usp->us_vccq); + atm_free(uvp); + } + + return; +} + + +/* + * Process a UNISIG signalling message + * + * Called when a UNISIG message is received. The message is decoded + * and passed to the UNISIG state machine. Unrecognized and + * unexpected messages are logged. + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * m pointer to a buffer chain containing the UNISIG message + * + * Returns: + * none + * + */ +int +unisig_rcv_msg(usp, m) + struct unisig *usp; + KBuffer *m; +{ + int err; + u_int cref; + struct usfmt usf; + struct unisig_msg *msg = 0; + struct unisig_vccb *uvp = 0; + struct ie_generic *iep; + + ATM_DEBUG2("unisig_rcv_msg: bfr=0x%x, len=%d\n", (int)m, KB_LEN(m)); + +#ifdef NOTDEF + unisig_print_mbuf(m); +#endif + + /* + * Get storage for the message + */ + msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool); + if (msg == NULL) { + err = ENOMEM; + goto done; + } + + /* + * Convert the message from network order to internal format + */ + err = usf_init(&usf, usp, m, USF_DECODE, 0); + if (err) { + if (err == EINVAL) + panic("unisig_rcv_msg: invalid parameter\n"); + ATM_DEBUG1("unisig_rcv_msg: decode init failed with %d\n", + err); + goto done; + } + + err = usf_dec_msg(&usf, msg); + if (err) { + ATM_DEBUG1("unisig_rcv_msg: decode failed with %d\n", + err); + goto done; + } + +#ifdef DIAGNOSTIC + /* + * Debug--print some information about the message + */ + if (unisig_print_msg) + usp_print_msg(msg, UNISIG_MSG_IN); +#endif + + /* + * Get the call reference value + */ + cref = EXTRACT_CREF(msg->msg_call_ref); + + /* + * Any message with the global call reference value except + * RESTART, RESTART ACK, or STATUS is in error + */ + if (GLOBAL_CREF(cref) && + msg->msg_type != UNI_MSG_RSTR && + msg->msg_type != UNI_MSG_RSTA && + msg->msg_type != UNI_MSG_STAT) { + /* + * Send STATUS message indicating the error + */ + err = unisig_send_status(usp, (struct unisig_vccb *) 0, + msg, UNI_IE_CAUS_CREF); + goto done; + } + + /* + * Check for missing mandatory IEs. Checks for SETUP, + * RELEASE, and RELEASE COMPLETE are handled elsewhere. + */ + if (msg->msg_type != UNI_MSG_SETU && + msg->msg_type != UNI_MSG_RLSE && + msg->msg_type != UNI_MSG_RLSC) { + for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) { + if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) { + err = unisig_send_status(usp, + uvp, msg, + UNI_IE_CAUS_MISSING); + goto done; + } + } + } + + /* + * Find the VCCB associated with the message + */ + uvp = unisig_find_conn(usp, cref); + + /* + * Process the message based on its type + */ + switch(msg->msg_type) { + case UNI_MSG_CALP: + (void) unisig_vc_state(usp, uvp, + UNI_VC_CALLP_MSG, msg); + break; + case UNI_MSG_CONN: + (void) unisig_vc_state(usp, uvp, + UNI_VC_CONNECT_MSG, msg); + break; + case UNI_MSG_CACK: + (void) unisig_vc_state(usp, uvp, + UNI_VC_CNCTACK_MSG, msg); + break; + case UNI_MSG_SETU: + unisig_rcv_setup(usp, msg); + break; + case UNI_MSG_RLSE: + (void) unisig_vc_state(usp, uvp, + UNI_VC_RELEASE_MSG, msg); + break; + case UNI_MSG_RLSC: + /* + * Ignore a RELEASE COMPLETE with an unrecognized + * call reference value + */ + if (uvp) { + (void) unisig_vc_state(usp, uvp, + UNI_VC_RLSCMP_MSG, msg); + } + break; + case UNI_MSG_RSTR: + unisig_rcv_restart(usp, msg); + break; + case UNI_MSG_RSTA: + break; + case UNI_MSG_STAT: + (void) unisig_vc_state(usp, uvp, + UNI_VC_STATUS_MSG, msg); + break; + case UNI_MSG_SENQ: + (void) unisig_vc_state(usp, uvp, + UNI_VC_STATUSENQ_MSG, msg); + break; + case UNI_MSG_ADDP: + (void) unisig_vc_state(usp, uvp, + UNI_VC_ADDP_MSG, msg); + break; + case UNI_MSG_ADPA: + (void) unisig_vc_state(usp, uvp, + UNI_VC_ADDPACK_MSG, msg); + break; + case UNI_MSG_ADPR: + (void) unisig_vc_state(usp, uvp, + UNI_VC_ADDPREJ_MSG, msg); + break; + case UNI_MSG_DRPP: + (void) unisig_vc_state(usp, uvp, + UNI_VC_DROP_MSG, msg); + break; + case UNI_MSG_DRPA: + (void) unisig_vc_state(usp, uvp, + UNI_VC_DROPACK_MSG, msg); + break; + default: + /* + * Message size didn't match size received + */ + err = unisig_send_status(usp, uvp, msg, + UNI_IE_CAUS_MTEXIST); + } + +done: + /* + * Handle message errors that require a response + */ + switch(err) { + case EMSGSIZE: + /* + * Message size didn't match size received + */ + err = unisig_send_status(usp, uvp, msg, + UNI_IE_CAUS_LEN); + break; + } + + /* + * Free the incoming message (both buffer and internal format) + * if necessary. + */ + if (msg) + unisig_free_msg(msg); + if (m) + KB_FREEALL(m); + + return (err); +} diff --git a/sys/netatm/uni/unisig_msg.h b/sys/netatm/uni/unisig_msg.h new file mode 100644 index 0000000..4be0144 --- /dev/null +++ b/sys/netatm/uni/unisig_msg.h @@ -0,0 +1,953 @@ +/* + * + * =================================== + * 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_msg.h,v 1.8 1998/08/26 23:29:23 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message formatting blocks + * + */ + +#ifndef _UNI_SIG_MSG_H +#define _UNI_SIG_MSG_H + +#define UNI_MSG_DISC_Q93B 0x09 +#define UNI_MSG_MIN_LEN 9 + +/* + * Values for Q.2931 message type. + */ +#define UNI_MSG_CALP 0x02 +#define UNI_MSG_CONN 0x07 +#define UNI_MSG_CACK 0x0F +#define UNI_MSG_SETU 0x05 +#define UNI_MSG_RLSE 0x4D +#define UNI_MSG_RLSC 0x5A +#define UNI_MSG_RSTR 0x46 +#define UNI_MSG_RSTA 0x4E +#define UNI_MSG_STAT 0x7D +#define UNI_MSG_SENQ 0x75 +#define UNI_MSG_ADDP 0x80 +#define UNI_MSG_ADPA 0x81 +#define UNI_MSG_ADPR 0x82 +#define UNI_MSG_DRPP 0x83 +#define UNI_MSG_DRPA 0x84 + + +/* + * Values for information element identifier. + */ +#define UNI_IE_CAUS 0x08 +#define UNI_IE_CLST 0x14 +#define UNI_IE_EPRF 0x54 +#define UNI_IE_EPST 0x55 +#define UNI_IE_AALP 0x58 +#define UNI_IE_CLRT 0x59 +#define UNI_IE_CNID 0x5A +#define UNI_IE_QOSP 0x5C +#define UNI_IE_BHLI 0x5D +#define UNI_IE_BBCP 0x5E +#define UNI_IE_BLLI 0x5F +#define UNI_IE_BLSH 0x60 +#define UNI_IE_BNSH 0x61 +#define UNI_IE_BSDC 0x62 +#define UNI_IE_BRPI 0x63 +#define UNI_IE_CGAD 0x6C +#define UNI_IE_CGSA 0x6D +#define UNI_IE_CDAD 0x70 +#define UNI_IE_CDSA 0x71 +#define UNI_IE_TRNT 0x78 +#define UNI_IE_RSTI 0x79 + +/* + * Masks for information element extension in bit 8 + */ +#define UNI_IE_EXT_BIT 0x80 +#define UNI_IE_EXT_MASK 0x7F + + +/* + * Signalling message in internal format. + */ +#define UNI_MSG_IE_CNT 22 + +struct unisig_msg { + u_int msg_call_ref; + u_char msg_type; + u_char msg_type_flag; + u_char msg_type_action; + int msg_length; + struct ie_generic *msg_ie_vec[UNI_MSG_IE_CNT]; +}; + +#define UNI_MSG_CALL_REF_RMT 0x800000 +#define UNI_MSG_CALL_REF_MASK 0x7FFFFF +#define UNI_MSG_CALL_REF_GLOBAL 0 +#define UNI_MSG_CALL_REF_DUMMY 0x7FFFFF + +#define EXTRACT_CREF(x) \ + ((x) & UNI_MSG_CALL_REF_RMT ? (x) & UNI_MSG_CALL_REF_MASK : (x) | UNI_MSG_CALL_REF_RMT) +#define GLOBAL_CREF(x) ((x) & UNI_MSG_CALL_REF_MASK == UNI_MSG_CALL_REF_GLOBAL) +#define DUMMY_CREF(x) ((x) & UNI_MSG_CALL_REF_MASK == UNI_MSG_CALL_REF_DUMMY) + +#define UNI_MSG_TYPE_FLAG_MASK 1 +#define UNI_MSG_TYPE_FLAG_SHIFT 4 + +#define UNI_MSG_TYPE_ACT_CLEAR 0 +#define UNI_MSG_TYPE_ACT_DISC 1 +#define UNI_MSG_TYPE_ACT_RPRT 2 +#define UNI_MSG_TYPE_ACT_RSVD 3 +#define UNI_MSG_TYPE_ACT_MASK 3 + +#define UNI_MSG_IE_AALP 0 +#define UNI_MSG_IE_CLRT 1 +#define UNI_MSG_IE_BBCP 2 +#define UNI_MSG_IE_BHLI 3 +#define UNI_MSG_IE_BLLI 4 +#define UNI_MSG_IE_CLST 5 +#define UNI_MSG_IE_CDAD 6 +#define UNI_MSG_IE_CDSA 7 +#define UNI_MSG_IE_CGAD 8 +#define UNI_MSG_IE_CGSA 9 +#define UNI_MSG_IE_CAUS 10 +#define UNI_MSG_IE_CNID 11 +#define UNI_MSG_IE_QOSP 12 +#define UNI_MSG_IE_BRPI 13 +#define UNI_MSG_IE_RSTI 14 +#define UNI_MSG_IE_BLSH 15 +#define UNI_MSG_IE_BNSH 16 +#define UNI_MSG_IE_BSDC 17 +#define UNI_MSG_IE_TRNT 18 +#define UNI_MSG_IE_EPRF 19 +#define UNI_MSG_IE_EPST 20 +#define UNI_MSG_IE_ERR 21 + +#define msg_ie_aalp msg_ie_vec[UNI_MSG_IE_AALP] +#define msg_ie_clrt msg_ie_vec[UNI_MSG_IE_CLRT] +#define msg_ie_bbcp msg_ie_vec[UNI_MSG_IE_BBCP] +#define msg_ie_bhli msg_ie_vec[UNI_MSG_IE_BHLI] +#define msg_ie_blli msg_ie_vec[UNI_MSG_IE_BLLI] +#define msg_ie_clst msg_ie_vec[UNI_MSG_IE_CLST] +#define msg_ie_cdad msg_ie_vec[UNI_MSG_IE_CDAD] +#define msg_ie_cdsa msg_ie_vec[UNI_MSG_IE_CDSA] +#define msg_ie_cgad msg_ie_vec[UNI_MSG_IE_CGAD] +#define msg_ie_cgsa msg_ie_vec[UNI_MSG_IE_CGSA] +#define msg_ie_caus msg_ie_vec[UNI_MSG_IE_CAUS] +#define msg_ie_cnid msg_ie_vec[UNI_MSG_IE_CNID] +#define msg_ie_qosp msg_ie_vec[UNI_MSG_IE_QOSP] +#define msg_ie_brpi msg_ie_vec[UNI_MSG_IE_BRPI] +#define msg_ie_rsti msg_ie_vec[UNI_MSG_IE_RSTI] +#define msg_ie_blsh msg_ie_vec[UNI_MSG_IE_BLSH] +#define msg_ie_bnsh msg_ie_vec[UNI_MSG_IE_BNSH] +#define msg_ie_bsdc msg_ie_vec[UNI_MSG_IE_BSDC] +#define msg_ie_trnt msg_ie_vec[UNI_MSG_IE_TRNT] +#define msg_ie_eprf msg_ie_vec[UNI_MSG_IE_EPRF] +#define msg_ie_epst msg_ie_vec[UNI_MSG_IE_EPST] +#define msg_ie_err msg_ie_vec[UNI_MSG_IE_ERR] + + +/* + * Information element header. + */ +struct ie_hdr { + u_char ie_hdr_ident; + u_char ie_hdr_coding; + u_char ie_hdr_flag; + u_char ie_hdr_action; + int ie_hdr_length; + int ie_hdr_err_cause; + struct ie_generic *ie_hdr_next; +}; + +#define UNI_IE_HDR_LEN 4 + +#define UNI_IE_CODE_CCITT 0 +#define UNI_IE_CODE_STD 3 +#define UNI_IE_CODE_MASK 3 +#define UNI_IE_CODE_SHIFT 5 + +#define UNI_IE_FLAG_MASK 1 +#define UNI_IE_FLAG_SHIFT 4 + +#define UNI_IE_ACT_CLEAR 0 +#define UNI_IE_ACT_DIS 1 +#define UNI_IE_ACT_RPRT 2 +#define UNI_IE_ACT_DMSGIGN 5 +#define UNI_IE_ACT_DMSGRPRT 6 +#define UNI_IE_ACT_MASK 7 + + +/* + * ATM AAL parameters information element in internal format. + */ +struct ie_aalp { + int8_t ie_aal_type; + union { + struct aal_type_1_parm { + u_char subtype; + u_char cbr_rate; + u_short multiplier; + u_char clock_recovery; + u_char error_correction; + u_char struct_data_tran; + u_char partial_cells; + } type_1; + struct aal_type_4_parm { + int32_t fwd_max_sdu; + int32_t bkwd_max_sdu; + int32_t mid_range; + u_char mode; + u_char sscs_type; + } type_4; + struct aal_type_5_parm { + int32_t fwd_max_sdu; + int32_t bkwd_max_sdu; + u_char mode; + u_char sscs_type; + } type_5; + struct user_aal_type { + u_char aal_info[4]; + } type_user; + } aal_u; +}; + +#define UNI_IE_AALP_AT_AAL1 1 +#define UNI_IE_AALP_AT_AAL3 3 +#define UNI_IE_AALP_AT_AAL5 5 +#define UNI_IE_AALP_AT_AALU 16 + +#define UNI_IE_AALP_A1_ST_NULL 0 +#define UNI_IE_AALP_A1_ST_VCE 1 +#define UNI_IE_AALP_A1_ST_SCE 2 +#define UNI_IE_AALP_A1_ST_ACE 3 +#define UNI_IE_AALP_A1_ST_HQA 4 +#define UNI_IE_AALP_A1_ST_VID 5 + +#define UNI_IE_AALP_A1_CB_64 1 +#define UNI_IE_AALP_A1_CB_DS1 4 +#define UNI_IE_AALP_A1_CB_DS2 5 +#define UNI_IE_AALP_A1_CB_32064 6 +#define UNI_IE_AALP_A1_CB_DS3 7 +#define UNI_IE_AALP_A1_CB_97728 8 +#define UNI_IE_AALP_A1_CB_E1 16 +#define UNI_IE_AALP_A1_CB_E2 17 +#define UNI_IE_AALP_A1_CB_E3 18 +#define UNI_IE_AALP_A1_CB_139264 19 +#define UNI_IE_AALP_A1_CB_N64 64 + +#define UNI_IE_AALP_A1_CR_NULL 0 +#define UNI_IE_AALP_A1_CR_SRTS 1 +#define UNI_IE_AALP_A1_CR_ACR 2 + +#define UNI_IE_AALP_A1_EC_NULL 0 +#define UNI_IE_AALP_A1_EC_FEC 1 + +#define UNI_IE_AALP_A1_SD_NULL 0 +#define UNI_IE_AALP_A1_SD_SDT 1 + +#define UNI_IE_AALP_A3_R_MASK 1023 +#define UNI_IE_AALP_A3_R_SHIFT 16 + +#define UNI_IE_AALP_A5_M_MSG 1 +#define UNI_IE_AALP_A5_M_STR 2 + +#define UNI_IE_AALP_A5_ST_NULL 0 +#define UNI_IE_AALP_A5_ST_AO 1 +#define UNI_IE_AALP_A5_ST_NAO 2 +#define UNI_IE_AALP_A5_ST_FR 4 + + +/* + * ATM user cell rate information element in internal format. + */ +struct ie_clrt { + int32_t ie_fwd_peak; + int32_t ie_bkwd_peak; + int32_t ie_fwd_peak_01; + int32_t ie_bkwd_peak_01; + int32_t ie_fwd_sust; + int32_t ie_bkwd_sust; + int32_t ie_fwd_sust_01; + int32_t ie_bkwd_sust_01; + int32_t ie_fwd_burst; + int32_t ie_bkwd_burst; + int32_t ie_fwd_burst_01; + int32_t ie_bkwd_burst_01; + int8_t ie_best_effort; + int8_t ie_tm_options; +}; + +#define UNI_IE_CLRT_FWD_PEAK_ID 130 +#define UNI_IE_CLRT_BKWD_PEAK_ID 131 +#define UNI_IE_CLRT_FWD_PEAK_01_ID 132 +#define UNI_IE_CLRT_BKWD_PEAK_01_ID 133 +#define UNI_IE_CLRT_FWD_SUST_ID 136 +#define UNI_IE_CLRT_BKWD_SUST_ID 137 +#define UNI_IE_CLRT_FWD_SUST_01_ID 144 +#define UNI_IE_CLRT_BKWD_SUST_01_ID 145 +#define UNI_IE_CLRT_FWD_BURST_ID 160 +#define UNI_IE_CLRT_BKWD_BURST_ID 161 +#define UNI_IE_CLRT_FWD_BURST_01_ID 176 +#define UNI_IE_CLRT_BKWD_BURST_01_ID 177 +#define UNI_IE_CLRT_BEST_EFFORT_ID 190 +#define UNI_IE_CLRT_TM_OPTIONS_ID 191 + +#define UNI_IE_CLRT_TM_FWD_TAG 0x01 +#define UNI_IE_CLRT_TM_BKWD_TAG 0x02 + + +/* + * Broadband bearer capability information element in internal format. + */ +struct ie_bbcp { + int8_t ie_bearer_class; + int8_t ie_traffic_type; + int8_t ie_timing_req; + int8_t ie_clipping; + int8_t ie_conn_config; +}; + + +#define UNI_IE_BBCP_BC_BCOB_A 1 +#define UNI_IE_BBCP_BC_BCOB_C 3 +#define UNI_IE_BBCP_BC_BCOB_X 16 +#define UNI_IE_BBCP_BC_MASK 0x1F + +#define UNI_IE_BBCP_TT_NIND 0 +#define UNI_IE_BBCP_TT_CBR 1 +#define UNI_IE_BBCP_TT_VBR 2 +#define UNI_IE_BBCP_TT_MASK 3 +#define UNI_IE_BBCP_TT_SHIFT 2 + +#define UNI_IE_BBCP_TR_NIND 0 +#define UNI_IE_BBCP_TR_EER 1 +#define UNI_IE_BBCP_TR_EENR 2 +#define UNI_IE_BBCP_TR_RSVD 3 +#define UNI_IE_BBCP_TR_MASK 3 + +#define UNI_IE_BBCP_SC_NSUS 0 +#define UNI_IE_BBCP_SC_SUS 1 +#define UNI_IE_BBCP_SC_MASK 3 +#define UNI_IE_BBCP_SC_SHIFT 5 + +#define UNI_IE_BBCP_CC_PP 0 +#define UNI_IE_BBCP_CC_PM 1 +#define UNI_IE_BBCP_CC_MASK 3 + + +/* + * Broadband high layer information information element in internal + * format. + */ +struct ie_bhli { + int8_t ie_type; + u_char ie_info[8]; +}; + +#define UNI_IE_BHLI_TYPE_ISO 0 +#define UNI_IE_BHLI_TYPE_USER 1 +#define UNI_IE_BHLI_TYPE_HLP 2 +#define UNI_IE_BHLI_TYPE_VSA 3 + +#define UNI_IE_BHLI_HLP_LEN 4 +#define UNI_IE_BHLI_VSA_LEN 7 + + +/* + * Broadband low-layer information information element in internal + * format. + */ +struct ie_blli { + int8_t ie_l1_id; + int8_t ie_l2_id; + int8_t ie_l2_mode; + int8_t ie_l2_q933_use; + int8_t ie_l2_window; + int8_t ie_l2_user_proto; + int8_t ie_l3_id; + int8_t ie_l3_mode; + int8_t ie_l3_packet_size; + int8_t ie_l3_window; + int8_t ie_l3_user_proto; + int16_t ie_l3_ipi; + int8_t ie_l3_snap_id; + u_char ie_l3_oui[3]; + u_char ie_l3_pid[2]; +}; + +#define UNI_IE_BLLI_L1_ID 1 +#define UNI_IE_BLLI_L2_ID 2 +#define UNI_IE_BLLI_L3_ID 3 +#define UNI_IE_BLLI_LID_MASK 3 +#define UNI_IE_BLLI_LID_SHIFT 5 +#define UNI_IE_BLLI_LP_MASK 31 + +#define UNI_IE_BLLI_L2P_ISO1745 1 +#define UNI_IE_BLLI_L2P_Q921 2 +#define UNI_IE_BLLI_L2P_X25L 6 +#define UNI_IE_BLLI_L2P_X25M 7 +#define UNI_IE_BLLI_L2P_LAPB 8 +#define UNI_IE_BLLI_L2P_HDLC1 9 +#define UNI_IE_BLLI_L2P_HDLC2 10 +#define UNI_IE_BLLI_L2P_HDLC3 11 +#define UNI_IE_BLLI_L2P_LLC 12 +#define UNI_IE_BLLI_L2P_X75 13 +#define UNI_IE_BLLI_L2P_Q922 14 +#define UNI_IE_BLLI_L2P_USER 16 +#define UNI_IE_BLLI_L2P_ISO7776 17 + +#define UNI_IE_BLLI_L2MODE_NORM 1 +#define UNI_IE_BLLI_L2MODE_EXT 2 +#define UNI_IE_BLLI_L2MODE_SHIFT 5 +#define UNI_IE_BLLI_L2MODE_MASK 3 + +#define UNI_IE_BLLI_Q933_ALT 0 + +#define UNI_IE_BLLI_L3P_X25 6 +#define UNI_IE_BLLI_L3P_ISO8208 7 +#define UNI_IE_BLLI_L3P_ISO8878 8 +#define UNI_IE_BLLI_L3P_ISO8473 9 +#define UNI_IE_BLLI_L3P_T70 10 +#define UNI_IE_BLLI_L3P_ISO9577 11 +#define UNI_IE_BLLI_L3P_USER 16 + +#define UNI_IE_BLLI_L3MODE_NORM 1 +#define UNI_IE_BLLI_L3MODE_EXT 2 +#define UNI_IE_BLLI_L3MODE_SHIFT 5 +#define UNI_IE_BLLI_L3MODE_MASK 3 + +#define UNI_IE_BLLI_L3PS_16 4 +#define UNI_IE_BLLI_L3PS_32 5 +#define UNI_IE_BLLI_L3PS_64 6 +#define UNI_IE_BLLI_L3PS_128 7 +#define UNI_IE_BLLI_L3PS_256 8 +#define UNI_IE_BLLI_L3PS_512 9 +#define UNI_IE_BLLI_L3PS_1024 10 +#define UNI_IE_BLLI_L3PS_2048 11 +#define UNI_IE_BLLI_L3PS_4096 12 +#define UNI_IE_BLLI_L3PS_MASK 15 + +#define UNI_IE_BLLI_L3IPI_SHIFT 6 +#define UNI_IE_BLLI_L3IPI_SNAP 0x80 + + +/* + * Call state information element in internal format. + */ +struct ie_clst { + int8_t ie_state; +}; + +#define UNI_IE_CLST_STATE_U0 0 +#define UNI_IE_CLST_STATE_U1 1 +#define UNI_IE_CLST_STATE_U3 3 +#define UNI_IE_CLST_STATE_U6 6 +#define UNI_IE_CLST_STATE_U8 8 +#define UNI_IE_CLST_STATE_U9 9 +#define UNI_IE_CLST_STATE_U10 10 +#define UNI_IE_CLST_STATE_U11 11 +#define UNI_IE_CLST_STATE_U12 12 + +#define UNI_IE_CLST_STATE_N0 0 +#define UNI_IE_CLST_STATE_N1 1 +#define UNI_IE_CLST_STATE_N3 3 +#define UNI_IE_CLST_STATE_N6 6 +#define UNI_IE_CLST_STATE_N8 8 +#define UNI_IE_CLST_STATE_N9 9 +#define UNI_IE_CLST_STATE_N10 10 +#define UNI_IE_CLST_STATE_N11 11 +#define UNI_IE_CLST_STATE_N12 12 + +#define UNI_IE_CLST_GLBL_REST0 0x00 +#define UNI_IE_CLST_GLBL_REST1 0x3d +#define UNI_IE_CLST_GLBL_REST2 0x3e + +#define UNI_IE_CLST_STATE_MASK 0x3f + + +/* + * Called party number information element in internal format. + */ +struct ie_cdad { + int8_t ie_type; + int8_t ie_plan; + Atm_addr ie_addr; +}; + +#define UNI_IE_CDAD_TYPE_UNK 0 +#define UNI_IE_CDAD_TYPE_INTL 1 +#define UNI_IE_CDAD_TYPE_MASK 7 +#define UNI_IE_CDAD_TYPE_SHIFT 4 + +#define UNI_IE_CDAD_PLAN_E164 1 +#define UNI_IE_CDAD_PLAN_NSAP 2 +#define UNI_IE_CDAD_PLAN_MASK 15 + + +/* + * Called party subaddress information element in internal format. + */ +struct ie_cdsa { + Atm_addr ie_addr; +}; + +#define UNI_IE_CDSA_TYPE_NSAP 0 +#define UNI_IE_CDSA_TYPE_AESA 1 +#define UNI_IE_CDSA_TYPE_MASK 7 +#define UNI_IE_CDSA_TYPE_SHIFT 4 + + +/* + * Calling party number information element in internal format. + */ +struct ie_cgad { + int8_t ie_type; + int8_t ie_plan; + int8_t ie_pres_ind; + int8_t ie_screen_ind; + Atm_addr ie_addr; +}; + +#define UNI_IE_CGAD_TYPE_UNK 0 +#define UNI_IE_CGAD_TYPE_INTL 1 +#define UNI_IE_CGAD_TYPE_MASK 7 +#define UNI_IE_CGAD_TYPE_SHIFT 4 + +#define UNI_IE_CGAD_PLAN_E164 1 +#define UNI_IE_CGAD_PLAN_NSAP 2 +#define UNI_IE_CGAD_PLAN_MASK 15 + +#define UNI_IE_CGAD_PRES_ALLOW 0 +#define UNI_IE_CGAD_PRES_RSTR 1 +#define UNI_IE_CGAD_PRES_NNA 2 +#define UNI_IE_CGAD_PRES_RSVD 3 +#define UNI_IE_CGAD_PRES_MASK 3 +#define UNI_IE_CGAD_PRES_SHIFT 5 + +#define UNI_IE_CGAD_SCR_UNS 0 +#define UNI_IE_CGAD_SCR_UVP 1 +#define UNI_IE_CGAD_SCR_UVF 2 +#define UNI_IE_CGAD_SCR_NET 3 +#define UNI_IE_CGAD_SCR_MASK 3 + + +/* + * Calling party subaddress information element in internal format. + */ +struct ie_cgsa { + Atm_addr ie_addr; +}; + +#define UNI_IE_CGSA_TYPE_NSAP 0 +#define UNI_IE_CGSA_TYPE_AESA 1 +#define UNI_IE_CGSA_TYPE_MASK 7 +#define UNI_IE_CGSA_TYPE_SHIFT 4 + + +/* + * Cause information element in internal format. + */ +#define UNI_IE_CAUS_MAX_ID 24 +#define UNI_IE_CAUS_MAX_QOS_SUB 24 +struct ie_caus { + int8_t ie_loc; + int8_t ie_cause; + int8_t ie_diag_len; + u_int8_t ie_diagnostic[24]; +}; + +#define UNI_IE_CAUS_LOC_USER 0 +#define UNI_IE_CAUS_LOC_PRI_LCL 1 +#define UNI_IE_CAUS_LOC_PUB_LCL 2 +#define UNI_IE_CAUS_LOC_TRANSIT 3 +#define UNI_IE_CAUS_LOC_PUB_RMT 4 +#define UNI_IE_CAUS_LOC_PRI_RMT 5 +#define UNI_IE_CAUS_LOC_INTL 7 +#define UNI_IE_CAUS_LOC_BEYOND 10 +#define UNI_IE_CAUS_LOC_MASK 15 + +#define UNI_IE_CAUS_UN_NS_SHIFT 3 +#define UNI_IE_CAUS_UN_NS_MASK 1 + +#define UNI_IE_CAUS_UN_NA_SHIFT 2 +#define UNI_IE_CAUS_UN_NA_MASK 1 + +#define UNI_IE_CAUS_UN_CAU_MASK 3 + +#define UNI_IE_CAUS_RR_USER 0 +#define UNI_IE_CAUS_RR_IE 1 +#define UNI_IE_CAUS_RR_INSUFF 2 +#define UNI_IE_CAUS_RR_SHIFT 2 +#define UNI_IE_CAUS_RR_MASK 31 + +#define UNI_IE_CAUS_RC_UNK 0 +#define UNI_IE_CAUS_RC_PERM 1 +#define UNI_IE_CAUS_RC_TRANS 2 +#define UNI_IE_CAUS_RC_MASK 3 + +/* + * Cause codes from UNI 3.0, section 5.4.5.15 + */ +#define UNI_IE_CAUS_UNO 1 /* Unallocated number */ +#define UNI_IE_CAUS_NOTROUTE 2 /* No route to transit net */ +#define UNI_IE_CAUS_NODROUTE 3 /* No route to destination */ +#define UNI_IE_CAUS_BAD_VCC 10 /* VPI/VCI unacceptable */ +#define UNI_IE_CAUS_NORM 16 /* Normal call clearing */ +#define UNI_IE_CAUS_BUSY 17 /* User busy */ +#define UNI_IE_CAUS_NORSP 18 /* No user responding */ +#define UNI_IE_CAUS_REJECT 21 /* Call rejected */ +#define UNI_IE_CAUS_CHANGED 22 /* Number changed */ +#define UNI_IE_CAUS_CLIR 23 /* User rejects CLIR */ +#define UNI_IE_CAUS_DORDER 27 /* Dest out of order */ +#define UNI_IE_CAUS_INVNO 28 /* Invalid number format */ +#define UNI_IE_CAUS_SENQ 30 /* Rsp to Status Enquiry */ +#define UNI_IE_CAUS_NORM_UNSP 31 /* Normal, unspecified */ +#define UNI_IE_CAUS_NA_VCC 35 /* VCC not available */ +#define UNI_IE_CAUS_ASSIGN_VCC 36 /* VPCI/VCI assignment failure */ +#define UNI_IE_CAUS_NORDER 38 /* Network out of order */ +#define UNI_IE_CAUS_TEMP 41 /* Temporary failure */ +#define UNI_IE_CAUS_DISCARD 43 /* Access info discarded */ +#define UNI_IE_CAUS_NO_VCC 45 /* No VPI/VCI available */ +#define UNI_IE_CAUS_UNAVAIL 47 /* Resource unavailable */ +#define UNI_IE_CAUS_NO_QOS 49 /* QoS unavailable */ +#define UNI_IE_CAUS_NO_CR 51 /* User cell rate not avail */ +#define UNI_IE_CAUS_NO_BC 57 /* Bearer capability not auth */ +#define UNI_IE_CAUS_NA_BC 58 /* Bearer capability n/a */ +#define UNI_IE_CAUS_SERVICE 63 /* Service or opt not avail */ +#define UNI_IE_CAUS_NI_BC 65 /* Bearer cap not implemented */ +#define UNI_IE_CAUS_COMB 73 /* Unsupported combination */ +#define UNI_IE_CAUS_CREF 81 /* Invalid call reference */ +#define UNI_IE_CAUS_CEXIST 82 /* Channel does not exist */ +#define UNI_IE_CAUS_IDEST 88 /* Incompatible destination */ +#define UNI_IE_CAUS_ENDPT 89 /* Invalid endpoint reference */ +#define UNI_IE_CAUS_TRNET 91 /* Invalid transit net */ +#define UNI_IE_CAUS_APPEND 92 /* Too many pending add party */ +#define UNI_IE_CAUS_UAAL 93 /* AAL parms can't be supp */ +#define UNI_IE_CAUS_MISSING 96 /* Mandatory IE missing */ +#define UNI_IE_CAUS_MTEXIST 97 /* Message type nonexistent */ +#define UNI_IE_CAUS_IEEXIST 99 /* IE type nonexistent */ +#define UNI_IE_CAUS_IECONTENT 100 /* IE content invalid */ +#define UNI_IE_CAUS_STATE 101 /* Message incomp with state */ +#define UNI_IE_CAUS_TIMER 102 /* Recovery on timer expire */ +#define UNI_IE_CAUS_LEN 104 /* Incorrect message length */ +#define UNI_IE_CAUS_PROTO 111 /* Protocol error */ + + +/* + * Connection identifier information element in internal format. + */ +struct ie_cnid { + int8_t ie_vp_sig; + int8_t ie_pref_excl; + u_short ie_vpci; + u_short ie_vci; +}; + +#define UNI_IE_CNID_VPSIG_MASK 3 +#define UNI_IE_CNID_VPSIG_SHIFT 3 +#define UNI_IE_CNID_PREX_MASK 7 + +#define UNI_IE_CNID_MIN_VCI 32 + + +/* + * Quality of service parameter information element in internal format. + */ +struct ie_qosp { + int8_t ie_fwd_class; + int8_t ie_bkwd_class; +}; + +#define UNI_IE_QOSP_FWD_CLASS_0 0 +#define UNI_IE_QOSP_FWD_CLASS_1 1 +#define UNI_IE_QOSP_FWD_CLASS_2 2 +#define UNI_IE_QOSP_FWD_CLASS_3 3 +#define UNI_IE_QOSP_FWD_CLASS_4 4 + +#define UNI_IE_QOSP_BKWD_CLASS_0 0 +#define UNI_IE_QOSP_BKWD_CLASS_1 1 +#define UNI_IE_QOSP_BKWD_CLASS_2 2 +#define UNI_IE_QOSP_BKWD_CLASS_3 3 +#define UNI_IE_QOSP_BKWD_CLASS_4 4 + + +/* + * Broadband repeat indicator information element in internal format. + */ +struct ie_brpi { + int8_t ie_ind; +}; + +#define UNI_IE_BRPI_PRI_LIST 2 +#define UNI_IE_BRPI_IND_MASK 15 + + +/* + * Restart indicator information element in internal format. + */ +struct ie_rsti { + int8_t ie_class; +}; + +#define UNI_IE_RSTI_IND_VC 0 +#define UNI_IE_RSTI_ALL_VC 2 +#define UNI_IE_RSTI_CLASS_MASK 3 + + +/* + * Broadband locking shift information element in internal format. + */ +struct ie_blsh { + int8_t ie_dummy; +}; + + +/* + * Broadband non-locking shift information element in internal format. + */ +struct ie_bnsh { + int8_t ie_dummy; +}; + + +/* + * Broadband sending complete information element in internal format. + */ +struct ie_bsdc { + int8_t ie_ind; +}; + +#define UNI_IE_BSDC_IND 0x21 + + +/* + * Transit net selection information element in internal format. + */ +struct ie_trnt { + int8_t ie_id_type; + int8_t ie_id_plan; + u_char ie_id_len; + u_char ie_id[4]; +}; + +#define UNI_IE_TRNT_IDT_MASK 7 +#define UNI_IE_TRNT_IDT_SHIFT 4 +#define UNI_IE_TRNT_IDP_MASK 15 + +#define UNI_IE_TRNT_IDT_NATL 2 +#define UNI_IE_TRNT_IDP_CIC 1 + + +/* + * Endpoint reference information element in internal format. + */ +struct ie_eprf { + int8_t ie_type; + int16_t ie_id; +}; + +#define UNI_IE_EPRF_LDI 0 + + +/* + * Endpoint state information element in internal format. + */ +struct ie_epst { + int8_t ie_state; +}; + +#define UNI_IE_EPST_NULL 0 +#define UNI_IE_EPST_API 1 +#define UNI_IE_EPST_APR 6 +#define UNI_IE_EPST_DPI 11 +#define UNI_IE_EPST_DPR 12 +#define UNI_IE_EPST_ACTIVE 10 +#define UNI_IE_EPST_STATE_MASK 0x3F + + +/* + * Generic information element + */ +struct ie_generic { + struct ie_hdr ie_hdr; + union { + struct ie_aalp ie_aalp; + struct ie_clrt ie_clrt; + struct ie_bbcp ie_bbcp; + struct ie_bhli ie_bhli; + struct ie_blli ie_blli; + struct ie_clst ie_clst; + struct ie_cdad ie_cdad; + struct ie_cdsa ie_cdsa; + struct ie_cgad ie_cgad; + struct ie_cgsa ie_cgsa; + struct ie_caus ie_caus; + struct ie_cnid ie_cnid; + struct ie_qosp ie_qosp; + struct ie_brpi ie_brpi; + struct ie_rsti ie_rsti; + struct ie_blsh ie_blsh; + struct ie_bnsh ie_bnsh; + struct ie_bsdc ie_bsdc; + struct ie_trnt ie_trnt; + struct ie_eprf ie_eprf; + struct ie_epst ie_epst; + } ie_u; +}; + +#define ie_ident ie_hdr.ie_hdr_ident +#define ie_coding ie_hdr.ie_hdr_coding +#define ie_flag ie_hdr.ie_hdr_flag +#define ie_action ie_hdr.ie_hdr_action +#define ie_length ie_hdr.ie_hdr_length +#define ie_err_cause ie_hdr.ie_hdr_err_cause +#define ie_next ie_hdr.ie_hdr_next + +#define ie_aalp_aal_type ie_u.ie_aalp.ie_aal_type +#define ie_aalp_1_subtype ie_u.ie_aalp.aal_u.type_1.subtype +#define ie_aalp_1_cbr_rate ie_u.ie_aalp.aal_u.type_1.cbr_rate +#define ie_aalp_1_multiplier ie_u.ie_aalp.aal_u.type_1.multiplier +#define ie_aalp_1_clock_recovery ie_u.ie_aalp.aal_u.type_1.clock_recovery +#define ie_aalp_1_error_correction ie_u.ie_aalp.aal_u.type_1.error_correction +#define ie_aalp_1_struct_data_tran ie_u.ie_aalp.aal_u.type_1.struct_data_tran +#define ie_aalp_1_partial_cells ie_u.ie_aalp.aal_u.type_1.partial_cells + +#define ie_aalp_4_fwd_max_sdu ie_u.ie_aalp.aal_u.type_4.fwd_max_sdu +#define ie_aalp_4_bkwd_max_sdu ie_u.ie_aalp.aal_u.type_4.bkwd_max_sdu +#define ie_aalp_4_mid_range ie_u.ie_aalp.aal_u.type_4.mid_range +#define ie_aalp_4_mode ie_u.ie_aalp.aal_u.type_4.mode +#define ie_aalp_4_sscs_type ie_u.ie_aalp.aal_u.type_4.sscs_type + +#define ie_aalp_5_fwd_max_sdu ie_u.ie_aalp.aal_u.type_5.fwd_max_sdu +#define ie_aalp_5_bkwd_max_sdu ie_u.ie_aalp.aal_u.type_5.bkwd_max_sdu +#define ie_aalp_5_mode ie_u.ie_aalp.aal_u.type_5.mode +#define ie_aalp_5_sscs_type ie_u.ie_aalp.aal_u.type_5.sscs_type +#define ie_aalp_user_info ie_u.ie_aalp.aal_u.type_user.aal_info + +#define ie_clrt_fwd_peak ie_u.ie_clrt.ie_fwd_peak +#define ie_clrt_bkwd_peak ie_u.ie_clrt.ie_bkwd_peak +#define ie_clrt_fwd_peak_01 ie_u.ie_clrt.ie_fwd_peak_01 +#define ie_clrt_bkwd_peak_01 ie_u.ie_clrt.ie_bkwd_peak_01 +#define ie_clrt_fwd_sust ie_u.ie_clrt.ie_fwd_sust +#define ie_clrt_bkwd_sust ie_u.ie_clrt.ie_bkwd_sust +#define ie_clrt_fwd_sust_01 ie_u.ie_clrt.ie_fwd_sust_01 +#define ie_clrt_bkwd_sust_01 ie_u.ie_clrt.ie_bkwd_sust_01 +#define ie_clrt_fwd_burst ie_u.ie_clrt.ie_fwd_burst +#define ie_clrt_bkwd_burst ie_u.ie_clrt.ie_bkwd_burst +#define ie_clrt_fwd_burst_01 ie_u.ie_clrt.ie_fwd_burst_01 +#define ie_clrt_bkwd_burst_01 ie_u.ie_clrt.ie_bkwd_burst_01 +#define ie_clrt_best_effort ie_u.ie_clrt.ie_best_effort +#define ie_clrt_tm_options ie_u.ie_clrt.ie_tm_options + +#define ie_bbcp_bearer_class ie_u.ie_bbcp.ie_bearer_class +#define ie_bbcp_traffic_type ie_u.ie_bbcp.ie_traffic_type +#define ie_bbcp_timing_req ie_u.ie_bbcp.ie_timing_req +#define ie_bbcp_clipping ie_u.ie_bbcp.ie_clipping +#define ie_bbcp_conn_config ie_u.ie_bbcp.ie_conn_config + +#define ie_bhli_type ie_u.ie_bhli.ie_type +#define ie_bhli_info ie_u.ie_bhli.ie_info + +#define ie_blli_l1_id ie_u.ie_blli.ie_l1_id +#define ie_blli_l2_id ie_u.ie_blli.ie_l2_id +#define ie_blli_l2_mode ie_u.ie_blli.ie_l2_mode +#define ie_blli_l2_q933_use ie_u.ie_blli.ie_l2_q933_use +#define ie_blli_l2_window ie_u.ie_blli.ie_l2_window +#define ie_blli_l2_user_proto ie_u.ie_blli.ie_l2_user_proto +#define ie_blli_l3_id ie_u.ie_blli.ie_l3_id +#define ie_blli_l3_mode ie_u.ie_blli.ie_l3_mode +#define ie_blli_l3_packet_size ie_u.ie_blli.ie_l3_packet_size +#define ie_blli_l3_window ie_u.ie_blli.ie_l3_window +#define ie_blli_l3_user_proto ie_u.ie_blli.ie_l3_user_proto +#define ie_blli_l3_ipi ie_u.ie_blli.ie_l3_ipi +#define ie_blli_l3_snap_id ie_u.ie_blli.ie_l3_snap_id +#define ie_blli_l3_oui ie_u.ie_blli.ie_l3_oui +#define ie_blli_l3_pid ie_u.ie_blli.ie_l3_pid + +#define ie_clst_state ie_u.ie_clst.ie_state + +#define ie_cdad_type ie_u.ie_cdad.ie_type +#define ie_cdad_plan ie_u.ie_cdad.ie_plan +#define ie_cdad_addr ie_u.ie_cdad.ie_addr + +#define ie_cdsa_addr ie_u.ie_cdsa.ie_addr + +#define ie_cgad_type ie_u.ie_cgad.ie_type +#define ie_cgad_plan ie_u.ie_cgad.ie_plan +#define ie_cgad_pres_ind ie_u.ie_cgad.ie_pres_ind +#define ie_cgad_screen_ind ie_u.ie_cgad.ie_screen_ind +#define ie_cgad_addr ie_u.ie_cgad.ie_addr + +#define ie_cgsa_addr ie_u.ie_cgsa.ie_addr + +#define ie_caus_loc ie_u.ie_caus.ie_loc +#define ie_caus_cause ie_u.ie_caus.ie_cause +#define ie_caus_diag_len ie_u.ie_caus.ie_diag_len +#define ie_caus_diagnostic ie_u.ie_caus.ie_diagnostic + +#define ie_cnid_vp_sig ie_u.ie_cnid.ie_vp_sig +#define ie_cnid_pref_excl ie_u.ie_cnid.ie_pref_excl +#define ie_cnid_vpci ie_u.ie_cnid.ie_vpci +#define ie_cnid_vci ie_u.ie_cnid.ie_vci + +#define ie_qosp_fwd_class ie_u.ie_qosp.ie_fwd_class +#define ie_qosp_bkwd_class ie_u.ie_qosp.ie_bkwd_class + +#define ie_brpi_ind ie_u.ie_brpi.ie_ind + +#define ie_rsti_class ie_u.ie_rsti.ie_class + +#define ie_bsdc_ind ie_u.ie_bsdc.ie_ind + +#define ie_trnt_id_type ie_u.ie_trnt.ie_id_type +#define ie_trnt_id_plan ie_u.ie_trnt.ie_id_plan +#define ie_trnt_id_len ie_u.ie_trnt.ie_id_len +#define ie_trnt_id ie_u.ie_trnt.ie_id + +#define ie_eprf_type ie_u.ie_eprf.ie_type +#define ie_eprf_id ie_u.ie_eprf.ie_id + +#define ie_epst_state ie_u.ie_epst.ie_state + +/* + * Macro to add an IE to the end of a list of IEs + */ +#define MSG_IE_ADD(m, i, ind) \ + if (m->msg_ie_vec[ind]) { \ + struct ie_generic *_iep = msg->msg_ie_vec[ind]; \ + while (_iep->ie_next) { \ + _iep = _iep->ie_next; \ + } \ + _iep->ie_next = i; \ + } else { \ + m->msg_ie_vec[ind] = i; \ + } + +#endif /* _UNI_SIG_MSG_H */ diff --git a/sys/netatm/uni/unisig_print.c b/sys/netatm/uni/unisig_print.c new file mode 100644 index 0000000..f335ce4 --- /dev/null +++ b/sys/netatm/uni/unisig_print.c @@ -0,0 +1,877 @@ +/* + * + * =================================== + * 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_print.c,v 1.9 1998/08/26 23:29:23 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Print Q.2931 messages + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_print.c,v 1.9 1998/08/26 23:29:23 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_print.h> + + +/* + * Local declarations + */ +struct type_name { + char *name; + u_char type; +}; + + +/* + * Local functions + */ +static char * find_type __P((struct type_name *, u_char)); +static void usp_print_atm_addr __P((Atm_addr *)); +static void usp_print_ie __P((struct ie_generic *)); +static void usp_print_ie_aalp __P((struct ie_generic *)); +static void usp_print_ie_clrt __P((struct ie_generic *)); +static void usp_print_ie_bbcp __P((struct ie_generic *)); +static void usp_print_ie_bhli __P((struct ie_generic *)); +static void usp_print_ie_blli __P((struct ie_generic *)); +static void usp_print_ie_clst __P((struct ie_generic *)); +static void usp_print_ie_cdad __P((struct ie_generic *)); +static void usp_print_ie_cdsa __P((struct ie_generic *)); +static void usp_print_ie_cgad __P((struct ie_generic *)); +static void usp_print_ie_cgsa __P((struct ie_generic *)); +static void usp_print_ie_caus __P((struct ie_generic *)); +static void usp_print_ie_cnid __P((struct ie_generic *)); +static void usp_print_ie_qosp __P((struct ie_generic *)); +static void usp_print_ie_brpi __P((struct ie_generic *)); +static void usp_print_ie_rsti __P((struct ie_generic *)); +static void usp_print_ie_blsh __P((struct ie_generic *)); +static void usp_print_ie_bnsh __P((struct ie_generic *)); +static void usp_print_ie_bsdc __P((struct ie_generic *)); +static void usp_print_ie_trnt __P((struct ie_generic *)); +static void usp_print_ie_eprf __P((struct ie_generic *)); +static void usp_print_ie_epst __P((struct ie_generic *)); + + +/* + * Values for Q.2931 message type. + */ +static struct type_name msg_types[] = { + { "Call proceeding", 0x02 }, + { "Connect", 0x07 }, + { "Connect ACK", 0x0F }, + { "Setup", 0x05 }, + { "Release", 0x4D }, + { "Release complete", 0x5A }, + { "Restart", 0x46 }, + { "Restart ACK", 0x4E }, + { "Status", 0x7D }, + { "Status enquiry", 0x75 }, + { "Add party", 0x80 }, + { "Add party ACK", 0x81 }, + { "Add party reject", 0x82 }, + { "Drop party", 0x83 }, + { "Drop party ACK", 0x84 }, + {0, 0} +}; + + +/* + * Values for information element identifier. + */ +static struct type_name ie_types[] = { + { "Cause", 0x08 }, + { "Call state", 0x14 }, + { "Endpoint reference", 0x54 }, + { "Endpoint state", 0x55 }, + { "ATM AAL parameters", 0x58 }, + { "ATM user cell rate", 0x59 }, + { "Connection ID", 0x5A }, + { "QoS parameter", 0x5C }, + { "Broadband high layer info", 0x5D }, + { "Broadband bearer capability", 0x5E }, + { "Broadband low layer info", 0x5F }, + { "Broadband locking shift", 0x60 }, + { "Broadband non-locking shift", 0x61 }, + { "Broadband sending complete", 0x62 }, + { "Broadband repeat indicator", 0x63 }, + { "Calling party number", 0x6C }, + { "Calling party subaddress", 0x6D }, + { "Called party number", 0x70 }, + { "Called party subaddress", 0x71 }, + { "Transit net selection", 0x78 }, + { "Restart indicator", 0x79 }, + { 0, 0 } +}; + + +/* + * Search a name - type translation table + * + * Arguments: + * tbl a pointer to the table to search + * type the type to look for + * + * Returns: + * name a pointer to a character string with the name + * + */ +static char * +find_type(tbl, type) + struct type_name *tbl; + u_char type; +{ + while (type != tbl->type && tbl->name) + tbl++; + + if (tbl->name) + return(tbl->name); + else + return("-"); +} + + +/* + * Print an ATM address + * + * Arguments: + * p pointer to a Atm_address + * + * Returns: + * none + * + */ +static void +usp_print_atm_addr(p) + Atm_addr *p; +{ + char *cp; + + cp = unisig_addr_print(p); + printf("%s", cp); +} + + +/* + * Print a Q.2931 message structure + * + * Arguments: + * msg pointer to the message to print + * + * Returns: + * None + * + */ +void +usp_print_msg(msg, dir) + struct unisig_msg *msg; + int dir; +{ + char *name; + int i; + struct ie_generic *ie, *inxt; + + name = find_type(msg_types, msg->msg_type); + switch (dir) { + case UNISIG_MSG_IN: + printf("Received "); + break; + case UNISIG_MSG_OUT: + printf("Sent "); + break; + } + printf("message: %s (%x)\n", name, msg->msg_type); + printf(" Call reference: 0x%x\n", msg->msg_call_ref); +#ifdef LONG_PRINT + printf(" Message type flag: 0x%x\n", msg->msg_type_flag); + printf(" Message type action: 0x%x\n", msg->msg_type_action); + printf(" Message length: %d\n", msg->msg_length); + for (i=0; i<UNI_MSG_IE_CNT; i++) { + ie = msg->msg_ie_vec[i]; + while (ie) { + inxt = ie->ie_next; + usp_print_ie(ie); + ie = inxt; + } + } +#else + for (i=0; i<UNI_MSG_IE_CNT; i++) + { + ie = msg->msg_ie_vec[i]; + while (ie) { + inxt = ie->ie_next; + name = find_type(ie_types, ie->ie_ident); + if (ie->ie_ident == UNI_IE_CAUS || + ie->ie_ident == UNI_IE_RSTI || + ie->ie_ident == UNI_IE_CLST) { + usp_print_ie(ie); + } else { + printf(" Information element: %s (0x%x)\n", + name, ie->ie_ident); + } + ie = inxt; + } + } +#endif +} + + +/* + * Print a Q.2931 information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie(ie) + struct ie_generic *ie; +{ + char *name; + + while (ie) { + name = find_type(ie_types, ie->ie_ident); + printf(" Information element: %s (0x%x)\n", + name, ie->ie_ident); +#ifdef LONG_PRINT + printf(" Coding: 0x%x\n", + ie->ie_coding); + printf(" Flag: 0x%x\n", ie->ie_flag); + printf(" Action: 0x%x\n", + ie->ie_action); + printf(" Length: %d\n", ie->ie_length); +#endif + + switch (ie->ie_ident) { + case UNI_IE_AALP: + usp_print_ie_aalp(ie); + break; + case UNI_IE_CLRT: + usp_print_ie_clrt(ie); + break; + case UNI_IE_BBCP: + usp_print_ie_bbcp(ie); + break; + case UNI_IE_BHLI: + usp_print_ie_bhli(ie); + break; + case UNI_IE_BLLI: + usp_print_ie_blli(ie); + break; + case UNI_IE_CLST: + usp_print_ie_clst(ie); + break; + case UNI_IE_CDAD: + usp_print_ie_cdad(ie); + break; + case UNI_IE_CDSA: + usp_print_ie_cdsa(ie); + break; + case UNI_IE_CGAD: + usp_print_ie_cgad(ie); + break; + case UNI_IE_CGSA: + usp_print_ie_cgsa(ie); + break; + case UNI_IE_CAUS: + usp_print_ie_caus(ie); + break; + case UNI_IE_CNID: + usp_print_ie_cnid(ie); + break; + case UNI_IE_QOSP: + usp_print_ie_qosp(ie); + break; + case UNI_IE_BRPI: + usp_print_ie_brpi(ie); + break; + case UNI_IE_RSTI: + usp_print_ie_rsti(ie); + break; + case UNI_IE_BLSH: + usp_print_ie_blsh(ie); + break; + case UNI_IE_BNSH: + usp_print_ie_bnsh(ie); + break; + case UNI_IE_BSDC: + usp_print_ie_bsdc(ie); + break; + case UNI_IE_TRNT: + usp_print_ie_trnt(ie); + break; + case UNI_IE_EPRF: + usp_print_ie_eprf(ie); + break; + case UNI_IE_EPST: + usp_print_ie_epst(ie); + break; + } + ie = ie->ie_next; + } +} + + +/* + * Print an AAL parameters information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_aalp(ie) + struct ie_generic *ie; +{ + printf(" AAL type: %d\n", ie->ie_aalp_aal_type); + switch(ie->ie_aalp_aal_type) { + case UNI_IE_AALP_AT_AAL1: + printf(" Subtype: 0x%x\n", + ie->ie_aalp_1_subtype); + printf(" CBR rate: 0x%x\n", + ie->ie_aalp_1_cbr_rate); + printf(" Multiplier: 0x%x\n", + ie->ie_aalp_1_multiplier); + printf(" Clock rcvry: 0x%x\n", + ie->ie_aalp_1_clock_recovery); + printf(" Err corr: 0x%x\n", + ie->ie_aalp_1_error_correction); + printf(" Struct data: 0x%x\n", + ie->ie_aalp_1_struct_data_tran); + printf(" Partial cells: 0x%x\n", + ie->ie_aalp_1_partial_cells); + break; + case UNI_IE_AALP_AT_AAL3: + printf(" Fwd max SDU: %d\n", + ie->ie_aalp_4_fwd_max_sdu); + printf(" Bkwd max SDU: %d\n", + ie->ie_aalp_4_bkwd_max_sdu); + printf(" MID range: %d\n", + ie->ie_aalp_4_mid_range); + printf(" Mode: 0x%x\n", + ie->ie_aalp_4_mode); + printf(" SSCS type: 0x%x\n", + ie->ie_aalp_4_sscs_type); + break; + case UNI_IE_AALP_AT_AAL5: + printf(" Fwd max SDU: %d\n", + ie->ie_aalp_5_fwd_max_sdu); + printf(" Bkwd max SDU: %d\n", + ie->ie_aalp_5_bkwd_max_sdu); + printf(" Mode: 0x%x\n", + ie->ie_aalp_5_mode); + printf(" SSCS type: 0x%x\n", + ie->ie_aalp_5_sscs_type); + break; + case UNI_IE_AALP_AT_AALU: + printf(" User info: 0x%x %x %x %x\n", + ie->ie_aalp_user_info[0], + ie->ie_aalp_user_info[1], + ie->ie_aalp_user_info[2], + ie->ie_aalp_user_info[3]); + break; + } +} + + +/* + * Print a user cell rate information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_clrt(ie) + struct ie_generic *ie; +{ + printf(" Forward peak: %d\n", ie->ie_clrt_fwd_peak); + printf(" Backward peak: %d\n", ie->ie_clrt_bkwd_peak); + printf(" Fwd peak 01: %d\n", ie->ie_clrt_fwd_peak_01); + printf(" Bkwd peak 01: %d\n", ie->ie_clrt_bkwd_peak_01); + printf(" Fwd sust: %d\n", ie->ie_clrt_fwd_sust); + printf(" Bkwd sust: %d\n", ie->ie_clrt_bkwd_sust); + printf(" Fwd sust 01: %d\n", ie->ie_clrt_fwd_sust_01); + printf(" Bkwd sust 01: %d\n", ie->ie_clrt_bkwd_sust_01); + printf(" Fwd burst: %d\n", ie->ie_clrt_fwd_burst); + printf(" Bkwd burst: %d\n", ie->ie_clrt_bkwd_burst); + printf(" Fwd burst 01: %d\n", ie->ie_clrt_fwd_burst_01); + printf(" Bkwd burst 01: %d\n", + ie->ie_clrt_bkwd_burst_01); + printf(" Best effort: %d\n", ie->ie_clrt_best_effort); + printf(" TM optons: 0x%x\n", + ie->ie_clrt_tm_options); +} + + +/* + * Print a broadband bearer capability information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_bbcp(ie) + struct ie_generic *ie; +{ + printf(" Bearer class: 0x%x\n", + ie->ie_bbcp_bearer_class); + printf(" Traffic type: 0x%x\n", + ie->ie_bbcp_traffic_type); + printf(" Timing req: 0x%x\n", + ie->ie_bbcp_timing_req); + printf(" Clipping: 0x%x\n", ie->ie_bbcp_clipping); + printf(" Conn config: 0x%x\n", + ie->ie_bbcp_conn_config); +} + + +/* + * Print a broadband high layer information information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_bhli(ie) + struct ie_generic *ie; +{ + int i; + + printf(" Type: 0x%x\n", ie->ie_bhli_type); + printf(" HL info: 0x"); + for (i=0; i<ie->ie_length-1; i++) { + printf("%x ", ie->ie_bhli_info[i]); + } + printf("\n"); +} + + +/* + * Print a broadband low-layer information information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_blli(ie) + struct ie_generic *ie; +{ + printf(" Layer 1 ID: 0x%x\n", ie->ie_blli_l1_id); + printf(" Layer 2 ID: 0x%x\n", ie->ie_blli_l2_id); + printf(" Layer 2 mode: 0x%x\n", ie->ie_blli_l2_mode); + printf(" Layer 2 Q.933: 0x%x\n", + ie->ie_blli_l2_q933_use); + printf(" Layer 2 win: 0x%x\n", + ie->ie_blli_l2_window); + printf(" Layer 2 user: 0x%x\n", + ie->ie_blli_l2_user_proto); + printf(" Layer 3 ID: 0x%x\n", ie->ie_blli_l3_id); + printf(" Layer 3 mode: 0x%x\n", ie->ie_blli_l3_mode); + printf(" Layer 3 pkt: 0x%x\n", + ie->ie_blli_l3_packet_size); + printf(" Layer 3 win: 0x%x\n", + ie->ie_blli_l3_window); + printf(" Layer 3 user: 0x%x\n", + ie->ie_blli_l3_user_proto); + printf(" Layer 3 IPI: 0x%x\n", ie->ie_blli_l3_ipi); + printf(" Layer 3 SNAP: 0x%x\n", + ie->ie_blli_l3_snap_id); + printf(" Layer 3 OUI: 0x%x %x %x\n", + ie->ie_blli_l3_oui[0], + ie->ie_blli_l3_oui[1], + ie->ie_blli_l3_oui[2]); + printf(" Layer 3 PID: 0x%x %x\n", + ie->ie_blli_l3_pid[0], + ie->ie_blli_l3_pid[1]); +} + + +/* + * Print a call state information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_clst(ie) + struct ie_generic *ie; +{ + printf(" Call state: %d\n", + ie->ie_clst_state); +} + + +/* + * Print a called party number information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_cdad(ie) + struct ie_generic *ie; +{ + printf(" ATM addr: "); + usp_print_atm_addr(&ie->ie_cdad_addr); + printf("\n"); +} + + +/* + * Print a called party subaddress information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_cdsa(ie) + struct ie_generic *ie; +{ + printf(" ATM subaddr: "); + usp_print_atm_addr(&ie->ie_cdsa_addr); + printf("\n"); +} + + +/* + * Print a calling party number information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_cgad(ie) + struct ie_generic *ie; +{ + printf(" ATM addr: "); + usp_print_atm_addr(&ie->ie_cgad_addr); + printf("\n"); +} + + +/* + * Print a calling party subaddress information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_cgsa(ie) + struct ie_generic *ie; +{ + printf(" ATM subaddr: "); + usp_print_atm_addr(&ie->ie_cgsa_addr); + printf("\n"); +} + + +/* + * Print a cause information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_caus(ie) + struct ie_generic *ie; +{ + int i; + + printf(" Location: %d\n", ie->ie_caus_loc); + printf(" Cause: %d\n", ie->ie_caus_cause); + switch(ie->ie_caus_cause) { + case UNI_IE_CAUS_IECONTENT: + printf(" Flagged IEs: "); + for (i=0; ie->ie_caus_diagnostic[i]; i++) { + printf("0x%x ", ie->ie_caus_diagnostic[i]); + } + printf("\n"); + break; + case UNI_IE_CAUS_TIMER: + printf(" Timer ID: %c%c%c\n", + ie->ie_caus_diagnostic[0], + ie->ie_caus_diagnostic[1], + ie->ie_caus_diagnostic[2]); + break; + default: + printf(" Diag length: %d\n", + ie->ie_caus_diag_len); + printf(" Diagnostic: "); + for (i=0; i<ie->ie_caus_diag_len; i++) { + printf("0x%x ", ie->ie_caus_diagnostic[i]); + } + printf("\n"); + } +} + + +/* + * Print a connection identifier information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_cnid(ie) + struct ie_generic *ie; +{ + printf(" VP assoc sig: 0x%x\n", ie->ie_cnid_vp_sig); + printf(" Pref/excl: 0x%x\n", + ie->ie_cnid_pref_excl); + printf(" VPCI: %d\n", ie->ie_cnid_vpci); + printf(" VCI: %d\n", ie->ie_cnid_vci); +} + + +/* + * Print a quality of service parameter information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_qosp(ie) + struct ie_generic *ie; +{ + printf(" QoS fwd: 0x%x\n", + ie->ie_qosp_fwd_class); + printf(" QoS bkwd: 0x%x\n", + ie->ie_qosp_bkwd_class); +} + + +/* + * Print a broadband repeat indicator information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_brpi(ie) + struct ie_generic *ie; +{ + printf(" Indicator: 0x%x\n", ie->ie_brpi_ind); +} + + +/* + * Print a restart indicator information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_rsti(ie) + struct ie_generic *ie; +{ + printf(" Class: 0x%x\n", ie->ie_rsti_class); +} + + +/* + * Print a broadband locking shift information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_blsh(ie) + struct ie_generic *ie; +{ +} + + +/* + * Print a broadband non-locking shift information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_bnsh(ie) + struct ie_generic *ie; +{ +} + + +/* + * Print a broadband sending complete information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_bsdc(ie) + struct ie_generic *ie; +{ + printf(" Indication: 0x%x\n", ie->ie_bsdc_ind); +} + + +/* + * Print a transit net selection information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_trnt(ie) + struct ie_generic *ie; +{ +#ifdef NOTDEF + struct ie_generic ie_trnt_hdr; + u_char ie_trnt_id_type; + u_char ie_trnt_id_plan; + Atm_addr ie_trnt_id; +#endif +} + + +/* + * Print an endpoint reference information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_eprf(ie) + struct ie_generic *ie; +{ + printf(" Ref type: 0x%x\n", + ie->ie_eprf_type); + printf(" Endpt ref: 0x%x\n", + ie->ie_eprf_id); +} + + +/* + * Print an endpoint state information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_epst(ie) + struct ie_generic *ie; +{ + printf(" Endpt state: %d\n", + ie->ie_epst_state); +} diff --git a/sys/netatm/uni/unisig_print.h b/sys/netatm/uni/unisig_print.h new file mode 100644 index 0000000..5e906c8 --- /dev/null +++ b/sys/netatm/uni/unisig_print.h @@ -0,0 +1,47 @@ +/* + * + * =================================== + * 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_print.h,v 1.2 1997/05/06 22:22:27 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Protocol control blocks + * + */ + +#ifndef _UNISIG_PRINT_H +#define _UNISIG_PRINT_H + +/* + * Message direction for print routine + */ +#define UNISIG_MSG_IN 1 +#define UNISIG_MSG_OUT 2 + +#endif /* _UNISIG_PRINT_H */ diff --git a/sys/netatm/uni/unisig_proto.c b/sys/netatm/uni/unisig_proto.c new file mode 100644 index 0000000..914e76d --- /dev/null +++ b/sys/netatm/uni/unisig_proto.c @@ -0,0 +1,324 @@ +/* + * + * =================================== + * 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_proto.c,v 1.9 1998/08/26 23:29:23 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Protocol processing module. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_proto.c,v 1.9 1998/08/26 23:29:23 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> + + +/* + * Process a UNISIG timeout + * + * Called when a previously scheduled protocol instance control block + * timer expires. This routine passes a timeout event to the UNISIG + * signalling manager state machine. + * + * Called at splnet. + * + * Arguments: + * tip pointer to UNISIG timer control block + * + * Returns: + * none + * + */ +void +unisig_timer(tip) + struct atm_time *tip; +{ + struct unisig *usp; + + /* + * Back-off to UNISIG control block + */ + usp = (struct unisig *) + ((caddr_t)tip - (int)(&((struct unisig *)0)->us_time)); + + ATM_DEBUG2("unisig_timer: usp=0x%x,state=%d\n", + (int)usp, usp->us_state); + + /* + * Pass the timeout to the signalling manager state machine + */ + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_TIMEOUT, + (KBuffer *) 0); +} + + +/* + * Process a UNISIG VCC timeout + * + * Called when a previously scheduled UNISIG VCCB timer expires. + * Processing will based on the current VCC state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to vccb timer control block + * + * Returns: + * none + * + */ +void +unisig_vctimer(tip) + struct atm_time *tip; +{ + struct unisig *usp; + struct unisig_vccb *uvp; + + /* + * Get VCCB and UNISIG control block addresses + */ + uvp = (struct unisig_vccb *) ((caddr_t)tip - + (int)(&((struct vccb *)0)->vc_time)); + usp = (struct unisig *)uvp->uv_pif->pif_siginst; + + ATM_DEBUG3("unisig_vctimer: uvp=0x%x, sstate=%d, ustate=%d\n", + (int)uvp, uvp->uv_sstate, uvp->uv_ustate); + + /* + * Hand the timeout to the VC finite state machine + */ + if (uvp->uv_ustate == VCCU_ABORT) { + /* + * If we're aborting, this is an ABORT call + */ + (void) unisig_vc_state(usp, uvp, UNI_VC_ABORT_CALL, + (struct unisig_msg *) 0); + } else { + /* + * If we're not aborting, it's a timeout + */ + (void) unisig_vc_state(usp, uvp, UNI_VC_TIMEOUT, + (struct unisig_msg *) 0); + } +} + + +/* + * UNISIG SAAL Control Handler + * + * This is the module which receives data on the UNISIG signalling + * channel. Processing is based on the indication received from the + * SSCF and the protocol state. + * + * Arguments: + * cmd command code + * tok session token (pointer to UNISIG protocol control block) + * a1 argument 1 + * + * Returns: + * none + * + */ +void +unisig_saal_ctl(cmd, tok, a1) + int cmd; + void *tok; + void *a1; +{ + struct unisig *usp = tok; + + ATM_DEBUG4("unisig_upper: usp=0x%x,state=%d,cmd=%d,a1=0x%x,\n", + (u_long)usp, usp->us_state, cmd, (u_long)a1); + + /* + * Process command + */ + switch (cmd) { + + case SSCF_UNI_ESTABLISH_IND: + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_SSCF_EST_IND, + (KBuffer *) 0); + break; + + case SSCF_UNI_ESTABLISH_CNF: + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_SSCF_EST_CNF, + (KBuffer *) 0); + break; + + case SSCF_UNI_RELEASE_IND: + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_SSCF_RLS_IND, + (KBuffer *) 0); + break; + + case SSCF_UNI_RELEASE_CNF: + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_SSCF_RLS_CNF, + (KBuffer *) 0); + break; + + default: + log(LOG_ERR, + "unisig: unknown SAAL cmd: usp=0x%x, state=%d, cmd=%d\n", + (int)usp, usp->us_state, cmd); + } +} + + +/* + * UNISIG SAAL Data Handler + * + * This is the module which receives data on the UNISIG signalling + * channel. Processing is based on the protocol state. + * + * Arguments: + * tok session token (pointer to UNISIG protocol control block) + * m pointer to data + * + * Returns: + * none + * + */ +void +unisig_saal_data(tok, m) + void *tok; + KBuffer *m; +{ + struct unisig *usp = tok; + + ATM_DEBUG3("unisig_saal_data: usp=0x%x,state=%d,m=0x%x,\n", + (int)usp, usp->us_state, m); + + /* + * Pass data to signalling manager state machine + */ + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_SSCF_DATA_IND, + m); +} + + +/* + * Get Connection's Application/Owner Name + * + * Arguments: + * tok UNI signalling connection token (pointer to protocol instance) + * + * Returns: + * addr pointer to string containing our name + * + */ +caddr_t +unisig_getname(tok) + void *tok; +{ + struct unisig *usp = tok; + + if (usp->us_proto == ATM_SIG_UNI30) + return ("UNI3.0"); + else if (usp->us_proto == ATM_SIG_UNI31) + return ("UNI3.1"); + else if (usp->us_proto == ATM_SIG_UNI40) + return ("UNI4.0"); + else + return ("UNI"); +} + + +/* + * Process a VCC connection notification + * + * Should never be called. + * + * Arguments: + * tok user's connection token (unisig protocol block) + * + * Returns: + * none + * + */ +void +unisig_connected(tok) + void *tok; +{ + struct unisig *usp = tok; + + ATM_DEBUG2("unisig_connected: usp=0x%x,state=%d\n", + (u_long)usp, usp->us_state); + + /* + * Connected routine shouldn't ever get called for a PVC + */ + log(LOG_ERR, "unisig: connected notification, usp=0x%x\n", + (u_long)usp); +} + + +/* + * Process a VCC closed notification + * + * Called when UNISIG signalling channel is closed. + * + * Arguments: + * tok user's connection token (unisig protocol block) + * cp pointer to cause structure + * + * Returns: + * none + * + */ +void +unisig_cleared(tok, cp) + void *tok; + struct t_atm_cause *cp; +{ + struct unisig *usp = tok; + + ATM_DEBUG3("unisig_cleared: usp=0x%x, state=%d, cause=%d\n", + (u_long)usp, usp->us_state, cp->cause_value); + + /* + * VCC has been closed. Notify the signalling + * manager state machine. + */ + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_CALL_CLEARED, + (KBuffer *) 0); +} diff --git a/sys/netatm/uni/unisig_sigmgr_state.c b/sys/netatm/uni/unisig_sigmgr_state.c new file mode 100644 index 0000000..2fbbfca --- /dev/null +++ b/sys/netatm/uni/unisig_sigmgr_state.c @@ -0,0 +1,860 @@ +/* + * + * =================================== + * 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_sigmgr_state.c,v 1.10 1998/08/26 23:29:24 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Signalling manager finite state machine + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_sigmgr_state.c,v 1.10 1998/08/26 23:29:24 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.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> + +#include <netatm/uni/sscf_uni.h> + + +/* + * Local functions + */ +static int unisig_sigmgr_invalid __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act01 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act02 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act03 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act04 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act05 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act06 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act07 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act08 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act09 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act10 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act11 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act12 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act13 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act14 __P((struct unisig *, KBuffer *)); + + +/* + * State table. + */ +static int sigmgr_state_table[10][7] = { + /* 0 1 2 3 4 5 */ + { 1, 0, 0, 0, 0 }, /* 0 - Time out */ + { 0, 0, 3, 5, 0 }, /* 1 - SSCF estab ind */ + { 0, 0, 3, 5, 0 }, /* 2 - SSCF estab cnf */ + { 0, 0, 4, 6, 0 }, /* 3 - SSCF release ind */ + { 0, 0, 0, 6, 0 }, /* 4 - SSCF release cnf */ + { 0, 0, 0, 7, 0 }, /* 5 - SSCF data ind */ + { 0, 0, 2, 2, 0 }, /* 6 - SSCF unit data ind */ + { 0, 0, 8, 8, 8 }, /* 7 - Call cleared */ + { 14, 14, 14, 14, 0 }, /* 8 - Detach */ + { 13, 13, 0, 0, 0 } /* 9 - Address set */ +}; + +/* + * Action vector + */ +#define MAX_ACTION 15 +static int (*unisig_sigmgr_act_vec[MAX_ACTION]) + __P((struct unisig *, KBuffer *)) = { + unisig_sigmgr_invalid, + unisig_sigmgr_act01, + unisig_sigmgr_act02, + unisig_sigmgr_act03, + unisig_sigmgr_act04, + unisig_sigmgr_act05, + unisig_sigmgr_act06, + unisig_sigmgr_act07, + unisig_sigmgr_act08, + unisig_sigmgr_act09, + unisig_sigmgr_act10, + unisig_sigmgr_act11, + unisig_sigmgr_act12, + unisig_sigmgr_act13, + unisig_sigmgr_act14 +}; + + +/* + * ATM endpoint for UNI signalling channel + */ +static Atm_endpoint unisig_endpt = { + NULL, /* ep_next */ + ENDPT_UNI_SIG, /* ep_id */ + NULL, /* ep_ioctl */ + unisig_getname, /* ep_getname */ + unisig_connected, /* ep_connected */ + unisig_cleared, /* ep_cleared */ + NULL, /* ep_incoming */ + NULL, /* ep_addparty */ + NULL, /* ep_dropparty */ + NULL, /* ep_cpcs_ctl */ + NULL, /* ep_cpcs_data */ + unisig_saal_ctl, /* ep_saal_ctl */ + unisig_saal_data, /* ep_saal_data */ + NULL, /* ep_sscop_ctl */ + NULL /* ep_sscop_data */ +}; + + +/* + * ATM connection attributes for UNI signalling channel + */ +static Atm_attributes unisig_attr = { + NULL, /* nif */ + CMAPI_SAAL, /* api */ + UNI_VERS_3_0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, /* aal.tag */ + ATM_AAL5 /* aal.aal_type */ + }, + { /* traffic */ + T_ATM_PRESENT, /* traffic.tag */ + { /* traffic.v */ + { /* traffic.v.forward */ + T_ATM_ABSENT, /* PCR_high */ + 0, /* PCR_all */ + T_ATM_ABSENT, /* SCR_high */ + T_ATM_ABSENT, /* SCR_all */ + T_ATM_ABSENT, /* MBS_high */ + T_ATM_ABSENT, /* MBS_all */ + T_NO, /* tagging */ + }, + { /* traffic.v.backward */ + T_ATM_ABSENT, /* PCR_high */ + 0, /* PCR_all */ + T_ATM_ABSENT, /* SCR_high */ + T_ATM_ABSENT, /* SCR_all */ + T_ATM_ABSENT, /* MBS_high */ + T_ATM_ABSENT, /* MBS_all */ + T_NO, /* tagging */ + }, + T_YES, /* best_effort */ + } + }, + { /* bearer */ + T_ATM_PRESENT, /* bearer.tag */ + { /* bearer.v */ + T_ATM_CLASS_X, /* class */ + T_ATM_NULL, /* traffic_type */ + T_ATM_NO_END_TO_END, /* timing_req */ + T_NO, /* clipping */ + T_ATM_1_TO_1, /* conn_conf */ + } + }, + { /* bhli */ + T_ATM_ABSENT, /* bhli.tag */ + }, + { /* blli */ + T_ATM_ABSENT, /* blli.tag_l2 */ + T_ATM_ABSENT, /* blli.tag_l3 */ + }, + { /* llc */ + T_ATM_ABSENT, /* llc.tag */ + }, + { /* called */ + T_ATM_PRESENT, /* called.tag */ + }, + { /* calling */ + T_ATM_ABSENT, /* calling.tag */ + }, + { /* qos */ + T_ATM_PRESENT, /* qos.tag */ + { /* qos.v */ + T_ATM_NETWORK_CODING, /* coding_standard */ + { /* qos.v.forward */ + T_ATM_QOS_CLASS_0, /* class */ + }, + { /* qos.v.backward */ + T_ATM_QOS_CLASS_0, /* class */ + } + } + }, + { /* transit */ + T_ATM_ABSENT, /* transit.tag */ + }, + { /* cause */ + T_ATM_ABSENT, /* cause.tag */ + } +}; + + +/* + * Finite state machine for the UNISIG signalling manager + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * event indication of the event to be processed + * m pointer to a buffer with a message (optional) + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +unisig_sigmgr_state(usp, event, m) + struct unisig *usp; + int event; + KBuffer *m; +{ + int action, err = 0; + + /* + * Cancel any signalling manager timer + */ + UNISIG_CANCEL(usp); + + /* + * Select an action based on the incoming event and + * the signalling manager's state + */ + action = sigmgr_state_table[event][usp->us_state]; + ATM_DEBUG4("unisig_sigmgr_state: usp=0x%x, state=%d, event=%d, action=%d\n", + (u_int) usp, usp->us_state, event, action); + if (action >= MAX_ACTION || action < 0) { + panic("unisig_sigmgr_state: invalid action\n"); + } + + /* + * Perform the requested action + */ + err = unisig_sigmgr_act_vec[action](usp, m); + + return(err); +} + + +/* + * Signalling manager state machine action 0 + * + * Invalid action + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_invalid(usp, m) + struct unisig *usp; + KBuffer *m; +{ + log(LOG_ERR, "unisig_sigmgr_state: unexpected action\n"); + if (m) + KB_FREEALL(m); + return(0); +} + + +/* + * Signalling manager state machine action 1 + * + * The kickoff timer has expired at attach time; go to + * UNISIG_ADDR_WAIT state. + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act01(usp, m) + struct unisig *usp; + KBuffer *m; +{ + /* + * Set the new state + */ + usp->us_state = UNISIG_ADDR_WAIT; + + return(0); +} + + +/* + * Signalling manager state machine action 2 + * + * Ignore the event + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act02(usp, m) + struct unisig *usp; + KBuffer *m; +{ + /* + * Ignore event, discard message if present + */ + if (m) + KB_FREEALL(m); + + return(0); +} + + +/* + * Signalling manager state machine action 3 + * + * SSCF session on signalling channel has come up + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act03(usp, m) + struct unisig *usp; + KBuffer *m; +{ + struct unisig_vccb *uvp, *vnext; + + /* + * Log the activation + */ + log(LOG_INFO, "unisig: signalling channel active\n"); + + /* + * Go to ACTIVE state + */ + usp->us_state = UNISIG_ACTIVE; + + /* + * Notify the VC state machine that the channel is up + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); + uvp; uvp = vnext) { + vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB, + (struct unisig_msg *) 0); + } + + return(0); +} + + +/* + * Signalling manager state machine action 4 + * + * A SSCF release indication was received. Try to establish an + * SSCF session on the signalling PVC. + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act04(usp, m) + struct unisig *usp; + KBuffer *m; +{ + int err; + + /* + * Try to establish an SSCF session. + */ + err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ, + usp->us_conn, + (void *)0); + if (err) + panic("unisig_sigmgr_act04: SSCF_UNI_ESTABLISH_REQ"); + + return(0); +} + + +/* + * Signalling manager state machine action 5 + * + * SSCF session on signalling channel has been reset + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act05(usp, m) + struct unisig *usp; + KBuffer *m; +{ + struct unisig_vccb *uvp, *vnext; + + /* + * Log the reset + */ + log(LOG_INFO, "unisig: signalling channel reset\n"); + + /* + * Notify the VC state machine of the reset + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); + uvp; uvp = vnext) { + vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB, + (struct unisig_msg *) 0); + } + + return(0); +} + + +/* + * Signalling manager state machine action 6 + * + * SSCF session on signalling channel has been lost + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act06(usp, m) + struct unisig *usp; + KBuffer *m; +{ + struct unisig_vccb *uvp, *vnext; + + /* + * Log the fact that the session has been lost + */ + log(LOG_INFO, "unisig: signalling channel SSCF session lost\n"); + + /* + * Notify the VC state machine of the loss + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); + uvp; uvp = vnext) { + vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_FAIL, + (struct unisig_msg *) 0); + } + + /* + * Try to restart the SSCF session + */ + (void) unisig_sigmgr_act04(usp, (KBuffer *) 0); + + /* + * Go to INIT state + */ + usp->us_state = UNISIG_INIT; + + return(0); +} + + +/* + * Signalling manager state machine action 7 + * + * A Q.2931 signalling message has been received + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act07(usp, m) + struct unisig *usp; + KBuffer *m; +{ + int err; + + /* + * Pass the Q.2931 signalling message on + * to the VC state machine + */ + err = unisig_rcv_msg(usp, m); + + return(err); +} + + +/* + * Signalling manager state machine action 8 + * + * Process a CALL_CLOSED event for the signalling PVC + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act08(usp, m) + struct unisig *usp; + KBuffer *m; +{ + + /* + * Signalling manager is now incommunicado + */ + if (usp->us_state != UNISIG_DETACH) { + /* + * Log an error and set the state to NULL if + * we're not detaching + */ + log(LOG_ERR, "unisig: signalling channel closed\n"); + usp->us_state = UNISIG_NULL; + } + usp->us_conn = 0; + + return(0); +} + + +/* + * Signalling manager state machine action 9 + * + * Not used + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act09(usp, m) + struct unisig *usp; + KBuffer *m; +{ + log(LOG_ERR, "unisig_sigmgr_act09: unexpected action\n"); + if (m) + KB_FREEALL(m); + return (0); +} + + +/* + * Signalling manager state machine action 10 + * + * Not used + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act10(usp, m) + struct unisig *usp; + KBuffer *m; +{ + return(0); +} + + +/* + * Signalling manager state machine action 11 + * + * Not used + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act11(usp, m) + struct unisig *usp; + KBuffer *m; +{ + log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n"); + if (m) + KB_FREEALL(m); + return(0); +} + + +/* + * Signalling manager state machine action 12 + * + * Not used + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act12(usp, m) + struct unisig *usp; + KBuffer *m; +{ + log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n"); + if (m) + KB_FREEALL(m); + return(0); +} + + +/* + * Signalling manager state machine action 13 + * + * NSAP prefix has been set + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act13(usp, m) + struct unisig *usp; + KBuffer *m; +{ + int err; + Atm_addr_pvc *pvcp; + + /* + * Set UNI signalling channel connection attributes + */ + if (usp->us_proto == ATM_SIG_UNI30) + unisig_attr.api_init = UNI_VERS_3_0; + else + unisig_attr.api_init = UNI_VERS_3_1; + + unisig_attr.nif = usp->us_pif->pif_nif; + + unisig_attr.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU; + unisig_attr.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU; + unisig_attr.aal.v.aal5.SSCS_type = T_ATM_SSCS_SSCOP_REL; + + unisig_attr.called.tag = T_ATM_PRESENT; + unisig_attr.called.addr.address_format = T_ATM_PVC_ADDR; + unisig_attr.called.addr.address_length = sizeof(Atm_addr_pvc); + pvcp = (Atm_addr_pvc *)unisig_attr.called.addr.address; + ATM_PVC_SET_VPI(pvcp, UNISIG_SIG_VPI); + ATM_PVC_SET_VCI(pvcp, UNISIG_SIG_VCI); + unisig_attr.called.subaddr.address_format = T_ATM_ABSENT; + unisig_attr.called.subaddr.address_length = 0; + + unisig_attr.traffic.v.forward.PCR_all_traffic = + usp->us_pif->pif_pcr; + unisig_attr.traffic.v.backward.PCR_all_traffic = + usp->us_pif->pif_pcr; + + /* + * Create UNISIG signalling channel + */ + err = atm_cm_connect(&unisig_endpt, usp, &unisig_attr, + &usp->us_conn); + if (err) { + return(err); + } + + /* + * Establish the SSCF session + */ + err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ, + usp->us_conn, + (void *)0); + if (err) + panic("unisig_sigmgr_act13: SSCF_UNI_ESTABLISH_REQ"); + + /* + * Set the new state + */ + usp->us_state = UNISIG_INIT; + + return(0); +} + + +/* + * Signalling manager state machine action 14 + * + * Process a detach event + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act14(usp, m) + struct unisig *usp; + KBuffer *m; +{ + int err; + struct unisig_vccb *sig_vccb, *uvp, *vnext; + struct atm_pif *pip; + struct t_atm_cause cause; + + /* + * Locate the signalling channel's VCCB + */ + sig_vccb = (struct unisig_vccb *)0; + if (usp->us_conn && usp->us_conn->co_connvc) + sig_vccb = (struct unisig_vccb *) + usp->us_conn->co_connvc->cvc_vcc; + + /* + * Terminate all of our VCCs + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); + uvp; uvp = vnext) { + vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + + /* + * Don't close the signalling VCC yet + */ + if (uvp == sig_vccb) + continue; + + /* + * Close VCC and notify owner + */ + err = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } + + /* + * Set the signalling manager state + */ + usp->us_state = UNISIG_DETACH; + + /* + * Close the signalling channel + */ + if (usp->us_conn) { + cause.coding_standard = T_ATM_ITU_CODING; + cause.coding_standard = T_ATM_LOC_USER; + cause.coding_standard = T_ATM_CAUSE_UNSPECIFIED_NORMAL; + err = atm_cm_release(usp->us_conn, &cause); + if (err) + panic("unisig_sigmgr_act14: close failed\n"); + } + + /* + * Get rid of protocol instance if there are no VCCs queued + */ + pip = usp->us_pif; + if (Q_HEAD(usp->us_vccq, struct vccb) == NULL && + pip->pif_sigmgr) { + struct sigmgr *smp = pip->pif_sigmgr; + int s = splimp(); + + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + (void) splx(s); + + UNLINK((struct siginst *)usp, struct siginst, + smp->sm_prinst, si_next); + KM_FREE(usp, sizeof(struct unisig), M_DEVBUF); + } + + /* + * Otherwise, wait for protocol instance to be freed + * during unisig_free processing for the last queued VCC + */ + + return (0); +} diff --git a/sys/netatm/uni/unisig_subr.c b/sys/netatm/uni/unisig_subr.c new file mode 100644 index 0000000..f8dc067 --- /dev/null +++ b/sys/netatm/uni/unisig_subr.c @@ -0,0 +1,1276 @@ +/* + * + * =================================== + * 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_subr.c,v 1.12 1998/08/26 23:29:24 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_subr.c,v 1.12 1998/08/26 23:29:24 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> + + +/* + * External variables + */ +extern struct ie_aalp ie_aalp_absent; +extern struct ie_clrt ie_clrt_absent; +extern struct ie_bbcp ie_bbcp_absent; +extern struct ie_bhli ie_bhli_absent; +extern struct ie_blli ie_blli_absent; +extern struct ie_clst ie_clst_absent; +extern struct ie_cdad ie_cdad_absent; +extern struct ie_cdsa ie_cdsa_absent; +extern struct ie_cgad ie_cgad_absent; +extern struct ie_cgsa ie_cgsa_absent; +extern struct ie_caus ie_caus_absent; +extern struct ie_cnid ie_cnid_absent; +extern struct ie_qosp ie_qosp_absent; +extern struct ie_brpi ie_brpi_absent; +extern struct ie_rsti ie_rsti_absent; +extern struct ie_blsh ie_blsh_absent; +extern struct ie_bnsh ie_bnsh_absent; +extern struct ie_bsdc ie_bsdc_absent; +extern struct ie_trnt ie_trnt_absent; +extern struct ie_eprf ie_eprf_absent; +extern struct ie_epst ie_epst_absent; + + +/* + * Set a cause code in an ATM attribute block + * + * Arguments: + * aap pointer to attribute block + * cause cause code + * + * Returns: + * none + * + */ +void +unisig_set_cause_attr(aap, cause) + Atm_attributes *aap; + int cause; +{ + /* + * Set the fields in the attribute block + */ + aap->cause.tag = T_ATM_PRESENT; + aap->cause.v.coding_standard = T_ATM_ITU_CODING; + aap->cause.v.location = T_ATM_LOC_USER; + aap->cause.v.cause_value = cause; + KM_ZERO(aap->cause.v.diagnostics, + sizeof(aap->cause.v.diagnostics)); +} + + +/* + * Open a UNI VCC + * + * Called when a user wants to open a VC. This function will construct + * a VCCB and, if we are opening an SVC, call the Q.2931 VC state + * machine. The user will have to wait for a notify event to be sure + * the SVC is fully open. + * + * Must be called at splnet. + * + * Arguments: + * usp pointer to UNISIG protocol instance + * cvp pointer to connection parameters for the VCC + * + * Returns: + * 0 VCC creation successful + * errno VCC setup failed - reason indicated + * + */ +int +unisig_open_vcc(usp, cvp) + struct unisig *usp; + Atm_connvc *cvp; +{ + struct atm_pif *pip = usp->us_pif; + struct unisig_vccb *uvp; + Atm_addr_pvc *pvp; + int err, pvc; + + ATM_DEBUG2("unisig_open_vcc: usp=0x%x, cvp=0x%x\n", usp, cvp); + + /* + * Validate user parameters. AAL and encapsulation are + * checked by the connection manager + */ + + /* + * Check called party address(es) + */ + if(cvp->cvc_attr.called.tag != T_ATM_PRESENT || + cvp->cvc_attr.called.addr.address_format == + T_ATM_ABSENT) { + return(EINVAL); + } + switch (cvp->cvc_attr.called.addr.address_format) { + case T_ATM_PVC_ADDR: + /* + * Make sure VPI/VCI is valid + */ + pvc = 1; + pvp = (Atm_addr_pvc *)cvp->cvc_attr.called.addr.address; + if ((ATM_PVC_GET_VPI(pvp) > pip->pif_maxvpi) || + (ATM_PVC_GET_VCI(pvp) == 0) || + (ATM_PVC_GET_VCI(pvp) > pip->pif_maxvci)) { + return(ERANGE); + } + + /* + * Make sure VPI/VCI is not already in use + */ + if (unisig_find_vpvc(usp, + ATM_PVC_GET_VPI(pvp), + ATM_PVC_GET_VCI(pvp), 0)) { + return(EEXIST); + } + ATM_DEBUG2("unisig_open_vcc: VPI.VCI=%d.%d\n", + ATM_PVC_GET_VPI(pvp), + ATM_PVC_GET_VCI(pvp)); + break; + + case T_ATM_ENDSYS_ADDR: + /* + * Check signalling state + */ + pvc = 0; + pvp = NULL; + if (usp->us_state != UNISIG_ACTIVE) { + return(ENETDOWN); + } + + /* + * Make sure there's no subaddress + */ + if (cvp->cvc_attr.called.subaddr.address_format != + T_ATM_ABSENT) { + return(EINVAL); + } + break; + + case T_ATM_E164_ADDR: + /* + * Check signalling state + */ + pvc = 0; + pvp = NULL; + if (usp->us_state != UNISIG_ACTIVE) { + return(ENETDOWN); + } + + /* + * Check destination address format + */ + if (cvp->cvc_attr.called.subaddr.address_format != + T_ATM_ENDSYS_ADDR && + cvp->cvc_attr.called.subaddr.address_format != + T_ATM_ABSENT) { + return(EINVAL); + } + break; + + default: + return(EPROTONOSUPPORT); + } + + /* + * Check that this is for the same interface UNISIG uses + */ + if (!cvp->cvc_attr.nif || + cvp->cvc_attr.nif->nif_pif != usp->us_pif) { + return(EINVAL); + } + + /* + * Allocate control block for VCC + */ + uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool); + if (uvp == NULL) { + return(ENOMEM); + } + + /* + * Fill in VCCB + */ + if (pvc) { + uvp->uv_type = VCC_PVC | VCC_IN | VCC_OUT; + uvp->uv_vpi = ATM_PVC_GET_VPI(pvp); + uvp->uv_vci = ATM_PVC_GET_VCI(pvp); + uvp->uv_sstate = (usp->us_state == UNISIG_ACTIVE ? + UNI_PVC_ACTIVE : UNI_PVC_ACT_DOWN); + uvp->uv_ustate = VCCU_OPEN; + } else { + uvp->uv_type = VCC_SVC | VCC_IN | VCC_OUT; + uvp->uv_sstate = UNI_NULL; + uvp->uv_ustate = VCCU_POPEN; + } + uvp->uv_proto = usp->us_pif->pif_sigmgr->sm_proto; + uvp->uv_pif = usp->us_pif; + uvp->uv_nif = cvp->cvc_attr.nif; + uvp->uv_connvc = cvp; + uvp->uv_tstamp = time_second; + + /* + * Put VCCB on UNISIG queue + */ + ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq); + + /* + * Call the VC state machine if this is an SVC + */ + if (!pvc) { + err = unisig_vc_state(usp, uvp, UNI_VC_SETUP_CALL, + (struct unisig_msg *) 0); + if (err) { + /* + * On error, delete the VCCB + */ + DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, + usp->us_vccq); + atm_free((caddr_t)uvp); + return(err); + } + } + + /* + * Link VCCB to VCC connection block + */ + cvp->cvc_vcc = (struct vccb *) uvp; + + return(0); +} + + +/* + * Close a UNISIG VCC + * + * Called when a user wants to close a VCC. This function will clean + * up the VCCB and, for an SVC, send a close request. + * + * Must be called at splnet. + * + * Arguments: + * usp pointer to UNISIG protocol instance + * uvp pointer to VCCB for the VCC to be closed + * + * Returns: + * 0 VCC is now closed + * errno error encountered + */ +int +unisig_close_vcc(usp, uvp) + struct unisig *usp; + struct unisig_vccb *uvp; +{ + int err = 0; + + ATM_DEBUG2("unisig_close_vcc: uvp=0x%x, state=%d\n", uvp, + uvp->uv_sstate); + + /* + * Check that this is for the same interface UNISIG uses + */ + if (uvp->uv_pif != usp->us_pif) { + return (EINVAL); + } + + /* + * Mark the close time. + */ + uvp->uv_tstamp = time_second; + + /* + * Process based on the connection type + */ + if (uvp->uv_type & VCC_PVC) { + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + } else if (uvp->uv_type & VCC_SVC) { + /* + * Call the VC state machine + */ + uvp->uv_ustate = VCCU_CLOSED; + err = unisig_vc_state(usp, uvp, UNI_VC_RELEASE_CALL, + (struct unisig_msg *) 0); + } + + /* + * Wait for user to free resources + */ + return(err); +} + + +/* + * Clear a UNISIG VCC + * + * Called to internally clear a VCC. No external protocol is + * initiated, the VCC is just closed and the owner is notified. + * + * Must be called at splnet. + * + * Arguments: + * usp pointer to UNISIG protocol instance + * uvp pointer to VCCB for the VCC to be closed + * cause cause code giving the reason for the close + * + * Returns: + * 0 VCC is closed + * errno error encountered + */ +int +unisig_clear_vcc(usp, uvp, cause) + struct unisig *usp; + struct unisig_vccb *uvp; + int cause; +{ + u_char outstate; + + ATM_DEBUG3("unisig_clear_vcc: uvp=0x%x, state=%d, cause=%d\n", + (int)uvp, uvp->uv_sstate, cause); + + /* + * Check that this is for the same interface UNISIG uses + */ + if (uvp->uv_pif != usp->us_pif) { + return (EINVAL); + } + + /* + * Kill any possible timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Mark the close time. + */ + uvp->uv_tstamp = time_second; + + /* + * Close the VCC and notify the user + */ + outstate = uvp->uv_sstate; + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + if (outstate == UNI_ACTIVE || + outstate == UNI_CALL_INITIATED || + outstate == UNI_CALL_OUT_PROC || + outstate == UNI_CONNECT_REQUEST || + outstate == UNI_RELEASE_REQUEST || + outstate == UNI_RELEASE_IND || + outstate == UNI_SSCF_RECOV || + outstate == UNI_PVC_ACT_DOWN || + outstate == UNI_PVC_ACTIVE) { + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, cause); + atm_cm_cleared(uvp->uv_connvc); + } + + /* + * Wait for user to free resources + */ + return(0); +} + + +#ifdef NOTDEF +/* + * Reset the switch state + * + * Arguments: + * usp pointer to UNISIG protocol instance + * + * Returns: + * none + * + */ +void +unisig_switch_reset(usp, cause) + struct unisig *usp; + int cause; +{ + int s; + struct unisig_vccb *uvp, *vnext; + + ATM_DEBUG2("unisig_switch_reset: usp=0x%x, cause=%d\n", + usp, cause); + + /* + * Terminate all of our VCCs + */ + s = splnet(); + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp = vnext) { + vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + + if (uvp->uv_type & VCC_SVC) { + /* + * Close the SVC and notify the owner + */ + (void)unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } else if (uvp->uv_type & VCC_PVC) { + /* + * Notify PVC owner of the state change + */ + switch(cause) { + case UNI_DOWN: + uvp->uv_sstate = UNI_PVC_ACT_DOWN; + break; + case UNI_UP: + uvp->uv_sstate = UNI_PVC_ACTIVE; + break; + } + atm_cm_cleared(uvp->uv_connvc, cause); + } else { + log(LOG_ERR, "unisig: invalid VCC type: vccb=0x%x, type=%d\n", + uvp, uvp->uv_type); + } + } + (void) splx(s); +} +#endif + + +/* + * Copy connection parameters from UNI 3.0 message IEs into + * an attribute block + * + * Arguments: + * usp pointer to UNISIG protocol instance + * msg pointer to the SETUP message + * ap pointer to the attribute block + * + * Returns: + * none + * + */ +void +unisig_save_attrs(usp, msg, ap) + struct unisig *usp; + struct unisig_msg *msg; + Atm_attributes *ap; +{ + /* + * Sanity check + */ + if (!msg || !ap) + return; + + /* + * Save the AAL parameters (AAL 3/4 and AAL 5 only) + */ + if (msg->msg_ie_aalp) { + struct ie_generic *aalp = msg->msg_ie_aalp; + + switch(msg->msg_ie_aalp->ie_aalp_aal_type) { + case UNI_IE_AALP_AT_AAL3: + ap->aal.tag = T_ATM_PRESENT; + ap->aal.type = + msg->msg_ie_aalp->ie_aalp_aal_type; + ap->aal.v.aal4.forward_max_SDU_size = + msg->msg_ie_aalp->ie_aalp_4_fwd_max_sdu; + ap->aal.v.aal4.backward_max_SDU_size = + msg->msg_ie_aalp->ie_aalp_4_bkwd_max_sdu; + ap->aal.v.aal4.SSCS_type = + msg->msg_ie_aalp->ie_aalp_4_sscs_type; + if (aalp->ie_aalp_4_mid_range == T_ATM_ABSENT) { + ap->aal.v.aal4.mid_low = T_ATM_ABSENT; + ap->aal.v.aal4.mid_high = T_ATM_ABSENT; + } else { + if (usp->us_proto == ATM_SIG_UNI30) { + ap->aal.v.aal4.mid_low = 0; + ap->aal.v.aal4.mid_high = + aalp->ie_aalp_4_mid_range + & UNI_IE_AALP_A3_R_MASK; + } else { + ap->aal.v.aal4.mid_low = + (aalp->ie_aalp_4_mid_range >> + UNI_IE_AALP_A3_R_SHIFT) + & UNI_IE_AALP_A3_R_MASK; + ap->aal.v.aal4.mid_high = + aalp->ie_aalp_4_mid_range + & UNI_IE_AALP_A3_R_MASK; + } + } + break; + case UNI_IE_AALP_AT_AAL5: + ap->aal.tag = T_ATM_PRESENT; + ap->aal.type = + msg->msg_ie_aalp->ie_aalp_aal_type; + ap->aal.v.aal5.forward_max_SDU_size = + msg->msg_ie_aalp->ie_aalp_5_fwd_max_sdu; + ap->aal.v.aal5.backward_max_SDU_size = + msg->msg_ie_aalp->ie_aalp_5_bkwd_max_sdu; + ap->aal.v.aal5.SSCS_type = + msg->msg_ie_aalp->ie_aalp_5_sscs_type; + break; + } + } + + /* + * Save traffic descriptor attributes + */ + if (msg->msg_ie_clrt) { + ap->traffic.tag = T_ATM_PRESENT; + ap->traffic.v.forward.PCR_high_priority = + msg->msg_ie_clrt->ie_clrt_fwd_peak; + ap->traffic.v.forward.PCR_all_traffic = + msg->msg_ie_clrt->ie_clrt_fwd_peak_01; + ap->traffic.v.forward.SCR_high_priority = + msg->msg_ie_clrt->ie_clrt_fwd_sust; + ap->traffic.v.forward.SCR_all_traffic = + msg->msg_ie_clrt->ie_clrt_fwd_sust_01; + ap->traffic.v.forward.MBS_high_priority = + msg->msg_ie_clrt->ie_clrt_fwd_burst; + ap->traffic.v.forward.MBS_all_traffic = + msg->msg_ie_clrt->ie_clrt_fwd_burst_01; + ap->traffic.v.backward.PCR_high_priority = + msg->msg_ie_clrt->ie_clrt_bkwd_peak; + ap->traffic.v.backward.PCR_all_traffic = + msg->msg_ie_clrt->ie_clrt_bkwd_peak_01; + ap->traffic.v.backward.SCR_high_priority = + msg->msg_ie_clrt->ie_clrt_bkwd_sust; + ap->traffic.v.backward.SCR_all_traffic = + msg->msg_ie_clrt->ie_clrt_bkwd_sust_01; + ap->traffic.v.backward.MBS_high_priority = + msg->msg_ie_clrt->ie_clrt_bkwd_burst; + ap->traffic.v.backward.MBS_all_traffic = + msg->msg_ie_clrt->ie_clrt_bkwd_burst_01; + ap->traffic.v.best_effort = + msg->msg_ie_clrt->ie_clrt_best_effort; + if (msg->msg_ie_clrt->ie_clrt_tm_options == + T_ATM_ABSENT) { + ap->traffic.v.forward.tagging = T_NO; + ap->traffic.v.backward.tagging = T_NO; + } else { + ap->traffic.v.forward.tagging = + (msg->msg_ie_clrt->ie_clrt_tm_options & + UNI_IE_CLRT_TM_FWD_TAG) != 0; + ap->traffic.v.backward.tagging = + (msg->msg_ie_clrt->ie_clrt_tm_options & + UNI_IE_CLRT_TM_BKWD_TAG) != 0; + } + } + + /* + * Save broadband bearer attributes + */ + if (msg->msg_ie_bbcp) { + ap->bearer.tag = T_ATM_PRESENT; + ap->bearer.v.bearer_class = + msg->msg_ie_bbcp->ie_bbcp_bearer_class; + ap->bearer.v.traffic_type = + msg->msg_ie_bbcp->ie_bbcp_traffic_type; + ap->bearer.v.timing_requirements = + msg->msg_ie_bbcp->ie_bbcp_timing_req; + ap->bearer.v.clipping_susceptibility = + msg->msg_ie_bbcp->ie_bbcp_clipping; + ap->bearer.v.connection_configuration = + msg->msg_ie_bbcp->ie_bbcp_conn_config; + } + + /* + * Save broadband high layer attributes + */ + if (msg->msg_ie_bhli) { + ap->bhli.tag = T_ATM_PRESENT; + ap->bhli.v.ID_type = msg->msg_ie_bhli->ie_bhli_type; + switch(ap->bhli.v.ID_type) { + case T_ATM_ISO_APP_ID: + KM_COPY(msg->msg_ie_bhli->ie_bhli_info, + ap->bhli.v.ID.ISO_ID, + sizeof(ap->bhli.v.ID.ISO_ID)); + break; + case T_ATM_USER_APP_ID: + KM_COPY(msg->msg_ie_bhli->ie_bhli_info, + ap->bhli.v.ID.user_defined_ID, + sizeof(ap->bhli.v.ID.user_defined_ID)); + break; + case T_ATM_VENDOR_APP_ID: + KM_COPY(msg->msg_ie_bhli->ie_bhli_info, + ap->bhli.v.ID.vendor_ID.OUI, + sizeof(ap->bhli.v.ID.vendor_ID.OUI)); + KM_COPY(&msg->msg_ie_bhli->ie_bhli_info[sizeof(ap->bhli.v.ID.vendor_ID.OUI)-1], + ap->bhli.v.ID.vendor_ID.app_ID, + sizeof(ap->bhli.v.ID.vendor_ID.app_ID)); + break; + } + } + + /* + * Save Broadband low layer, user layer 2 and 3 attributes + */ + if (msg->msg_ie_blli) { + /* + * Layer 2 parameters + */ + switch(msg->msg_ie_blli->ie_blli_l2_id) { + case UNI_IE_BLLI_L2P_ISO1745: + case UNI_IE_BLLI_L2P_Q921: + case UNI_IE_BLLI_L2P_X25L: + case UNI_IE_BLLI_L2P_X25M: + case UNI_IE_BLLI_L2P_LAPB: + case UNI_IE_BLLI_L2P_HDLC1: + case UNI_IE_BLLI_L2P_HDLC2: + case UNI_IE_BLLI_L2P_HDLC3: + case UNI_IE_BLLI_L2P_LLC: + case UNI_IE_BLLI_L2P_X75: + case UNI_IE_BLLI_L2P_Q922: + case UNI_IE_BLLI_L2P_ISO7776: + ap->blli.tag_l2 = T_ATM_PRESENT; + ap->blli.v.layer_2_protocol.ID_type = + T_ATM_SIMPLE_ID; + ap->blli.v.layer_2_protocol.ID.simple_ID = + msg->msg_ie_blli->ie_blli_l2_id; + break; + case UNI_IE_BLLI_L2P_USER: + ap->blli.tag_l2 = T_ATM_PRESENT; + ap->blli.v.layer_2_protocol.ID_type = + T_ATM_USER_ID; + ap->blli.v.layer_2_protocol.ID.user_defined_ID = + msg->msg_ie_blli->ie_blli_l2_user_proto; + break; + default: + ap->blli.tag_l2 = T_ATM_ABSENT; + } + if (ap->blli.tag_l2 == T_ATM_PRESENT) { + ap->blli.v.layer_2_protocol.mode = + msg->msg_ie_blli->ie_blli_l2_mode; + ap->blli.v.layer_2_protocol.window_size = + msg->msg_ie_blli->ie_blli_l2_window; + } + + /* + * Layer 3 parameters + */ + switch(msg->msg_ie_blli->ie_blli_l3_id) { + case UNI_IE_BLLI_L3P_X25: + case UNI_IE_BLLI_L3P_ISO8208: + case UNI_IE_BLLI_L3P_ISO8878: + case UNI_IE_BLLI_L3P_ISO8473: + case UNI_IE_BLLI_L3P_T70: + ap->blli.tag_l3 = T_ATM_PRESENT; + ap->blli.v.layer_3_protocol.ID_type = + T_ATM_SIMPLE_ID; + ap->blli.v.layer_3_protocol.ID.simple_ID = + msg->msg_ie_blli->ie_blli_l3_id; + break; + case UNI_IE_BLLI_L3P_ISO9577: + ap->blli.tag_l3 = T_ATM_PRESENT; + ap->blli.v.layer_3_protocol.ID_type = + T_ATM_SIMPLE_ID; + ap->blli.v.layer_3_protocol.ID.simple_ID = + msg->msg_ie_blli->ie_blli_l3_id; + if (msg->msg_ie_blli->ie_blli_l3_ipi == + UNI_IE_BLLI_L3IPI_SNAP) { + KM_COPY(msg->msg_ie_blli->ie_blli_l3_oui, + ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI, + sizeof(ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI)); + KM_COPY(msg->msg_ie_blli->ie_blli_l3_pid, + ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID, + sizeof(ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID)); + } else { + ap->blli.v.layer_3_protocol.ID.IPI_ID = + msg->msg_ie_blli->ie_blli_l3_ipi; + } + break; + case UNI_IE_BLLI_L3P_USER: + ap->blli.tag_l3 = T_ATM_PRESENT; + ap->blli.v.layer_3_protocol.ID_type = + T_ATM_USER_ID; + ap->blli.v.layer_3_protocol.ID.user_defined_ID = + msg->msg_ie_blli->ie_blli_l3_user_proto; + break; + default: + ap->blli.tag_l3 = T_ATM_ABSENT; + } + if (ap->blli.tag_l3 == T_ATM_PRESENT) { + ap->blli.v.layer_3_protocol.mode = + msg->msg_ie_blli->ie_blli_l3_mode; + ap->blli.v.layer_3_protocol.packet_size = + msg->msg_ie_blli->ie_blli_l3_packet_size; + ap->blli.v.layer_3_protocol.window_size = + msg->msg_ie_blli->ie_blli_l3_window; + } + } + + /* + * Save the called party address and subaddress + */ + if (msg->msg_ie_cdad) { + ap->called.tag = T_ATM_PRESENT; + ATM_ADDR_COPY(&msg->msg_ie_cdad->ie_cdad_addr, + &ap->called.addr); + ap->called.subaddr.address_format = T_ATM_ABSENT; + ap->called.subaddr.address_length = 0; + } + if (msg->msg_ie_cdsa) { + ATM_ADDR_COPY(&msg->msg_ie_cdsa->ie_cdsa_addr, + &ap->called.subaddr); + } + + /* + * Save the calling party address and subaddress + */ + if (msg->msg_ie_cgad) { + ap->calling.tag = T_ATM_PRESENT; + ATM_ADDR_COPY(&msg->msg_ie_cgad->ie_cgad_addr, + &ap->calling.addr); + ap->calling.subaddr.address_format = T_ATM_ABSENT; + ap->calling.subaddr.address_length = 0; + } + + if (msg->msg_ie_cgsa) { + ATM_ADDR_COPY(&msg->msg_ie_cgsa->ie_cgsa_addr, + &ap->calling.subaddr); + } + + /* + * Save quality of service attributes + */ + if (msg->msg_ie_qosp) { + ap->qos.tag = T_ATM_PRESENT; + ap->qos.v.coding_standard = msg->msg_ie_qosp->ie_coding; + ap->qos.v.forward.qos_class = msg->msg_ie_qosp->ie_qosp_fwd_class; + ap->qos.v.forward.qos_class = + msg->msg_ie_qosp->ie_qosp_bkwd_class; + } + + /* + * Save transit network attributes + */ + if (msg->msg_ie_trnt) { + ap->transit.tag = T_ATM_PRESENT; + ap->transit.v.length = + MIN(msg->msg_ie_trnt->ie_trnt_id_len, + sizeof(ap->transit.v.network_id)); + KM_COPY(msg->msg_ie_trnt->ie_trnt_id, + ap->transit.v.network_id, + ap->transit.v.length); + } + + /* + * Save cause code + */ + if (msg->msg_ie_caus) { + ap->cause.tag = T_ATM_PRESENT; + ap->cause.v.coding_standard = + msg->msg_ie_caus->ie_coding; + ap->cause.v.location = + msg->msg_ie_caus->ie_caus_loc; + ap->cause.v.cause_value = + msg->msg_ie_caus->ie_caus_cause; + KM_ZERO(ap->cause.v.diagnostics, + sizeof(ap->cause.v.diagnostics)); +#ifdef NOTDEF + KM_COPY(msg->msg_ie_caus->ie_caus_diagnostic, + ap->transit.v.diagnostics, + MIN(sizeof(ap->transit.v.diagnostics), + msg->msg_ie_caus->ie_caus_diag_len)); +#endif + } +} + + +/* + * Copy connection parameters from an attribute block into + * UNI 3.0 message IEs + * + * Arguments: + * usp pointer to UNISIG protocol instance + * msg pointer to the SETUP message + * ap pointer to the attribute block + * + * Returns: + * 0 everything OK + * else error encountered + * + */ +int +unisig_set_attrs(usp, msg, ap) + struct unisig *usp; + struct unisig_msg *msg; + Atm_attributes *ap; +{ + int err = 0; + + /* + * Sanity check + */ + if (!msg || !ap) + return(EINVAL); + + /* + * Set the AAL parameters (AAL 3/4 and AAL 5 only) + */ + if (ap->aal.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_aalp) { + msg->msg_ie_aalp = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_aalp == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_aalp_absent, + &msg->msg_ie_aalp->ie_u.ie_aalp, + sizeof(ie_aalp_absent)); + msg->msg_ie_aalp->ie_ident = UNI_IE_AALP; + msg->msg_ie_aalp->ie_aalp_aal_type = ap->aal.type; + switch(ap->aal.type) { + case ATM_AAL3_4: + msg->msg_ie_aalp->ie_aalp_4_fwd_max_sdu = + ap->aal.v.aal4.forward_max_SDU_size; + msg->msg_ie_aalp->ie_aalp_4_bkwd_max_sdu = + ap->aal.v.aal4.backward_max_SDU_size; + msg->msg_ie_aalp->ie_aalp_4_mode = UNI_IE_AALP_A5_M_MSG; + msg->msg_ie_aalp->ie_aalp_4_sscs_type = + ap->aal.v.aal4.SSCS_type; + if (ap->aal.v.aal4.mid_low == T_ATM_ABSENT) { + msg->msg_ie_aalp->ie_aalp_4_mid_range = + T_ATM_ABSENT; + } else { + if (usp->us_proto == ATM_SIG_UNI30) { + msg->msg_ie_aalp->ie_aalp_4_mid_range = + ap->aal.v.aal4.mid_high & + UNI_IE_AALP_A3_R_MASK; + } else { + msg->msg_ie_aalp->ie_aalp_4_mid_range = + ((ap->aal.v.aal4.mid_low & + UNI_IE_AALP_A3_R_MASK) + << UNI_IE_AALP_A3_R_SHIFT) + | + (ap->aal.v.aal4.mid_high & + UNI_IE_AALP_A3_R_MASK); + } + } + break; + case ATM_AAL5: + msg->msg_ie_aalp->ie_aalp_5_fwd_max_sdu = + ap->aal.v.aal5.forward_max_SDU_size; + msg->msg_ie_aalp->ie_aalp_5_bkwd_max_sdu = + ap->aal.v.aal5.backward_max_SDU_size; + msg->msg_ie_aalp->ie_aalp_5_mode = + UNI_IE_AALP_A5_M_MSG; + msg->msg_ie_aalp->ie_aalp_5_sscs_type = + ap->aal.v.aal5.SSCS_type; + break; + } + } + + /* + * Set traffic descriptor attributes + */ + if (ap->traffic.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_clrt) { + msg->msg_ie_clrt = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_clrt == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_clrt_absent, + &msg->msg_ie_clrt->ie_u.ie_clrt, + sizeof(ie_clrt_absent)); + msg->msg_ie_clrt->ie_ident = UNI_IE_CLRT; + msg->msg_ie_clrt->ie_clrt_fwd_peak = + ap->traffic.v.forward.PCR_high_priority; + msg->msg_ie_clrt->ie_clrt_fwd_peak_01 = + ap->traffic.v.forward.PCR_all_traffic; + msg->msg_ie_clrt->ie_clrt_fwd_sust = + ap->traffic.v.forward.SCR_high_priority; + msg->msg_ie_clrt->ie_clrt_fwd_sust_01 = + ap->traffic.v.forward.SCR_all_traffic; + msg->msg_ie_clrt->ie_clrt_fwd_burst = + ap->traffic.v.forward.MBS_high_priority; + msg->msg_ie_clrt->ie_clrt_fwd_burst_01 = + ap->traffic.v.forward.MBS_all_traffic; + msg->msg_ie_clrt->ie_clrt_bkwd_peak = + ap->traffic.v.backward.PCR_high_priority; + msg->msg_ie_clrt->ie_clrt_bkwd_peak_01 = + ap->traffic.v.backward.PCR_all_traffic; + msg->msg_ie_clrt->ie_clrt_bkwd_sust = + ap->traffic.v.backward.SCR_high_priority; + msg->msg_ie_clrt->ie_clrt_bkwd_sust_01 = + ap->traffic.v.backward.SCR_all_traffic; + msg->msg_ie_clrt->ie_clrt_bkwd_burst = + ap->traffic.v.backward.MBS_high_priority; + msg->msg_ie_clrt->ie_clrt_bkwd_burst_01 = + ap->traffic.v.backward.MBS_all_traffic; + msg->msg_ie_clrt->ie_clrt_best_effort = + ap->traffic.v.best_effort; + msg->msg_ie_clrt->ie_clrt_tm_options = 0; + if (ap->traffic.v.forward.tagging) { + msg->msg_ie_clrt->ie_clrt_tm_options |= + UNI_IE_CLRT_TM_FWD_TAG; + } + if (ap->traffic.v.backward.tagging) { + msg->msg_ie_clrt->ie_clrt_tm_options |= + UNI_IE_CLRT_TM_BKWD_TAG; + } + if (msg->msg_ie_clrt->ie_clrt_tm_options == 0) { + msg->msg_ie_clrt->ie_clrt_tm_options = + T_ATM_ABSENT; + } + } + + /* + * Set broadband bearer attributes + */ + if (ap->bearer.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_bbcp) { + msg->msg_ie_bbcp = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_bbcp == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_bbcp_absent, + &msg->msg_ie_bbcp->ie_u.ie_bbcp, + sizeof(ie_bbcp_absent)); + msg->msg_ie_bbcp->ie_ident = UNI_IE_BBCP; + msg->msg_ie_bbcp->ie_bbcp_bearer_class = + ap->bearer.v.bearer_class; + msg->msg_ie_bbcp->ie_bbcp_traffic_type = + ap->bearer.v.traffic_type; + msg->msg_ie_bbcp->ie_bbcp_timing_req = + ap->bearer.v.timing_requirements; + msg->msg_ie_bbcp->ie_bbcp_clipping = + ap->bearer.v.clipping_susceptibility; + msg->msg_ie_bbcp->ie_bbcp_conn_config = + ap->bearer.v.connection_configuration; + } + + /* + * Set broadband high layer attributes + */ + if (ap->bhli.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_bhli) { + msg->msg_ie_bhli = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_bhli == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_bhli_absent, + &msg->msg_ie_bhli->ie_u.ie_bhli, + sizeof(ie_bhli_absent)); + msg->msg_ie_bhli->ie_ident = UNI_IE_BHLI; + msg->msg_ie_bhli->ie_bhli_type = ap->bhli.v.ID_type; + switch (ap->bhli.v.ID_type) { + case T_ATM_ISO_APP_ID: + KM_COPY(ap->bhli.v.ID.ISO_ID, + msg->msg_ie_bhli->ie_bhli_info, + sizeof(ap->bhli.v.ID.ISO_ID)); + break; + case T_ATM_USER_APP_ID: + KM_COPY(ap->bhli.v.ID.user_defined_ID, + msg->msg_ie_bhli->ie_bhli_info, + sizeof(ap->bhli.v.ID.user_defined_ID)); + break; + case T_ATM_VENDOR_APP_ID: + KM_COPY(ap->bhli.v.ID.vendor_ID.OUI, + msg->msg_ie_bhli->ie_bhli_info, + sizeof(ap->bhli.v.ID.vendor_ID.OUI)); + KM_COPY(ap->bhli.v.ID.vendor_ID.app_ID, + &msg->msg_ie_bhli->ie_bhli_info[sizeof(ap->bhli.v.ID.vendor_ID.OUI)-1], + sizeof(ap->bhli.v.ID.vendor_ID.app_ID)); + break; + } + } + + /* + * Set Broadband low layer, user layer 2 and 3 attributes + */ + if (ap->blli.tag_l2 == T_ATM_PRESENT || + ap->blli.tag_l3 == T_ATM_PRESENT) { + if (!msg->msg_ie_blli) { + msg->msg_ie_blli = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_blli == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_blli_absent, + &msg->msg_ie_blli->ie_u.ie_blli, + sizeof(ie_blli_absent)); + msg->msg_ie_blli->ie_ident = UNI_IE_BLLI; + + if (ap->blli.tag_l2 == T_ATM_PRESENT) { + switch(ap->blli.v.layer_2_protocol.ID_type) { + case T_ATM_SIMPLE_ID: + msg->msg_ie_blli->ie_blli_l2_id = + ap->blli.v.layer_2_protocol.ID.simple_ID; + break; + case T_ATM_USER_ID: + msg->msg_ie_blli->ie_blli_l2_user_proto = + ap->blli.v.layer_2_protocol.ID.user_defined_ID; + break; + } + if (ap->blli.v.layer_2_protocol.ID_type != + T_ATM_ABSENT) { + msg->msg_ie_blli->ie_blli_l2_mode = + ap->blli.v.layer_2_protocol.mode; + msg->msg_ie_blli->ie_blli_l2_window = + ap->blli.v.layer_2_protocol.window_size; + } + } + + if (ap->blli.tag_l3 == T_ATM_PRESENT) { + switch (ap->blli.v.layer_3_protocol.ID_type) { + case T_ATM_SIMPLE_ID: + msg->msg_ie_blli->ie_blli_l3_id = + ap->blli.v.layer_3_protocol.ID.simple_ID; + break; + + case T_ATM_IPI_ID: + msg->msg_ie_blli->ie_blli_l3_id = + UNI_IE_BLLI_L3P_ISO9577; + msg->msg_ie_blli->ie_blli_l3_ipi = + ap->blli.v.layer_3_protocol.ID.IPI_ID; + break; + + case T_ATM_SNAP_ID: + msg->msg_ie_blli->ie_blli_l3_id = + UNI_IE_BLLI_L3P_ISO9577; + msg->msg_ie_blli->ie_blli_l3_ipi = + UNI_IE_BLLI_L3IPI_SNAP; + KM_COPY(ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI, + msg->msg_ie_blli->ie_blli_l3_oui, + sizeof(msg->msg_ie_blli->ie_blli_l3_oui)); + KM_COPY(ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID, + msg->msg_ie_blli->ie_blli_l3_pid, + sizeof(msg->msg_ie_blli->ie_blli_l3_pid)); + break; + + case T_ATM_USER_ID: + msg->msg_ie_blli->ie_blli_l3_id = + UNI_IE_BLLI_L3P_USER; + msg->msg_ie_blli->ie_blli_l3_user_proto = + ap->blli.v.layer_3_protocol.ID.user_defined_ID; + break; + } + if (ap->blli.v.layer_3_protocol.ID_type + != T_ATM_ABSENT) { + msg->msg_ie_blli->ie_blli_l3_mode = + ap->blli.v.layer_3_protocol.mode; + msg->msg_ie_blli->ie_blli_l3_packet_size = + ap->blli.v.layer_3_protocol.packet_size; + msg->msg_ie_blli->ie_blli_l3_window = + ap->blli.v.layer_3_protocol.window_size; + } + } + } + + /* + * Set the called party address and subaddress + */ + if (ap->called.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_cdad) { + msg->msg_ie_cdad = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_cdad == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_cdad_absent, + &msg->msg_ie_cdad->ie_u.ie_cdad, + sizeof(ie_cdad_absent)); + msg->msg_ie_cdad->ie_ident = UNI_IE_CDAD; + ATM_ADDR_COPY(&ap->called.addr, + &msg->msg_ie_cdad->ie_cdad_addr); + + if (ap->called.subaddr.address_format != T_ATM_ABSENT) { + if (!msg->msg_ie_cdsa) { + msg->msg_ie_cdsa = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_cdsa == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_cdsa_absent, + &msg->msg_ie_cdsa->ie_u.ie_cdsa, + sizeof(ie_cdsa_absent)); + msg->msg_ie_cdsa->ie_ident = UNI_IE_CDSA; + ATM_ADDR_COPY(&ap->called.subaddr, + &msg->msg_ie_cdsa->ie_cdsa_addr); + } + } + + /* + * Set the calling party address and subaddress + */ + + if (ap->calling.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_cgad) { + msg->msg_ie_cgad = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_cgad == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_cgad_absent, + &msg->msg_ie_cgad->ie_u.ie_cgad, + sizeof(ie_cgad_absent)); + msg->msg_ie_cgsa->ie_ident = UNI_IE_CGSA; + ATM_ADDR_COPY(&ap->calling.addr, + &msg->msg_ie_cgad->ie_cgad_addr); + + if (ap->calling.subaddr.address_format != + T_ATM_ABSENT) { + if (!msg->msg_ie_cgsa) { + msg->msg_ie_cgsa = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_cgsa == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_cgsa_absent, + &msg->msg_ie_cgsa->ie_u.ie_cgsa, + sizeof(ie_cgsa_absent)); + msg->msg_ie_cgsa->ie_ident = UNI_IE_CGSA; + ATM_ADDR_COPY(&ap->calling.subaddr, + &msg->msg_ie_cgsa->ie_cgsa_addr); + } + } + + /* + * Set quality of service attributes + */ + if (ap->qos.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_qosp) { + msg->msg_ie_qosp = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_qosp == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_qosp_absent, + &msg->msg_ie_qosp->ie_u.ie_qosp, + sizeof(ie_qosp_absent)); + msg->msg_ie_qosp->ie_ident = UNI_IE_QOSP; + if (usp->us_proto == ATM_SIG_UNI30) + msg->msg_ie_qosp->ie_coding = UNI_IE_CODE_STD; + else if ((ap->qos.v.forward.qos_class == + T_ATM_QOS_CLASS_0) || + (ap->qos.v.backward.qos_class == + T_ATM_QOS_CLASS_0)) + msg->msg_ie_qosp->ie_coding = UNI_IE_CODE_CCITT; + else + msg->msg_ie_qosp->ie_coding = ap->qos.v.coding_standard; + msg->msg_ie_qosp->ie_qosp_fwd_class = + ap->qos.v.forward.qos_class; + msg->msg_ie_qosp->ie_qosp_bkwd_class = + ap->qos.v.backward.qos_class; + } + + /* + * Set transit network attributes + */ + if (ap->transit.tag == T_ATM_PRESENT && + ap->transit.v.length != 0) { + if (!msg->msg_ie_trnt) { + msg->msg_ie_trnt = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_trnt == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_trnt_absent, + &msg->msg_ie_trnt->ie_u.ie_trnt, + sizeof(ie_trnt_absent)); + msg->msg_ie_trnt->ie_ident = UNI_IE_TRNT; + msg->msg_ie_trnt->ie_trnt_id_type = + UNI_IE_TRNT_IDT_NATL; + msg->msg_ie_trnt->ie_trnt_id_plan = + UNI_IE_TRNT_IDP_CIC; + KM_COPY(ap->transit.v.network_id, + msg->msg_ie_trnt->ie_trnt_id, + ap->transit.v.length); + } + + /* + * Set cause code + */ + if (ap->cause.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_caus) { + msg->msg_ie_caus = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_caus == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_caus_absent, + &msg->msg_ie_caus->ie_u.ie_caus, + sizeof(ie_caus_absent)); + msg->msg_ie_caus->ie_ident = UNI_IE_CAUS; + msg->msg_ie_caus->ie_coding = + ap->cause.v.coding_standard; + msg->msg_ie_caus->ie_caus_loc = + ap->cause.v.location; + msg->msg_ie_caus->ie_caus_cause = + ap->cause.v.cause_value; + + /* + * Don't copy the diagnostics from the attribute + * block, as there's no way to tell how much of + * the diagnostic field is relevant + */ + msg->msg_ie_caus->ie_caus_diag_len = 0; + } + +done: + return(err); +} diff --git a/sys/netatm/uni/unisig_util.c b/sys/netatm/uni/unisig_util.c new file mode 100644 index 0000000..ec4fbd0 --- /dev/null +++ b/sys/netatm/uni/unisig_util.c @@ -0,0 +1,389 @@ +/* + * + * =================================== + * 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_util.c,v 1.9 1998/08/26 23:29:24 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Protocol processing module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_util.c,v 1.9 1998/08/26 23:29:24 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> + + +/* + * Free a UNISIG signalling message + * + * Free the passed message and any IEs that are attached to it + * + * Arguments: + * msg pointer to UNISIG protocol instance + * + * Returns: + * none + * + */ +void +unisig_free_msg(msg) + struct unisig_msg *msg; +{ + int i; + struct ie_generic *ie, *ienxt; + + ATM_DEBUG1("unisig_free_msg: msg=0x%x\n", msg); + + /* + * First free all the IEs + */ + for (i=0; i<UNI_MSG_IE_CNT; i++) { + ie = msg->msg_ie_vec[i]; + while (ie) { + ienxt = ie->ie_next; + atm_free(ie); + ie = ienxt; + } + } + + /* + * Finally, free the message structure itself + */ + atm_free(msg); +} + + +/* + * Verify a VCCB + * + * Search UNISIG's VCCB queue to verify that a VCCB belongs to UNISIG. + * + * Arguments: + * usp pointer to UNISIG protocol instance + * svp pointer to a VCCB + * + * Returns: + * TRUE the VCCB belongs to UNISIG + * FALSE the VCCB doesn't belong to UNISIG + * + */ +int +unisig_verify_vccb(usp, uvp) + struct unisig *usp; + struct unisig_vccb *uvp; + +{ + struct unisig_vccb *utp, *uvnext; + + for (utp = Q_HEAD(usp->us_vccq, struct unisig_vccb); + utp; utp = uvnext){ + uvnext = Q_NEXT(utp, struct unisig_vccb, uv_sigelem); + if (uvp == utp) { + return(TRUE); + } + } + return(FALSE); +} + + +/* + * Find a connection + * + * Find a VCCB given the call reference + * + * Arguments: + * usp pointer to UNISIG protocol instance + * cref the call reference to search for + * + * Returns: + * 0 there is no such VCCB + * uvp the address of the VCCB + * + */ +struct unisig_vccb * +unisig_find_conn(usp, cref) + struct unisig *usp; + u_int cref; + +{ + struct unisig_vccb *uvp, *uvnext; + + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp = uvnext){ + uvnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + if (uvp->uv_call_ref == cref) + break; + } + return(uvp); +} + + +/* + * Find a VCCB + * + * Find a VCCB given the VPI and VCI. + * + * Arguments: + * usp pointer to UNISIG protocol instance + * vpi the VPI to search for + * vci the VCI to search for + * dir the direction of the VCC (VCC_IN, VCC_OUT, or both). + * If dir is set to zero, return the address of any VCCB + * with the given VPI/VCI, regardless of direction. + * + * Returns: + * 0 there is no such VCCB + * uvp the address of the VCCB + * + */ +struct unisig_vccb * +unisig_find_vpvc(usp, vpi, vci, dir) + struct unisig *usp; + int vpi, vci; + u_char dir; + +{ + struct unisig_vccb *uvp, *uvnext; + + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp = uvnext){ + uvnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + if (uvp->uv_vpi == vpi && + uvp->uv_vci == vci && + (uvp->uv_type & dir) == dir) + break; + } + return(uvp); +} + + +/* + * Allocate a call reference value + * + * Arguments: + * usp pointer to UNISIG protocol instance + * + * Returns: + * 0 call reference not available + * cref the call reference value + * + */ +int +unisig_alloc_call_ref(usp) + struct unisig *usp; + +{ + int cref; + + /* + * Get the next call reference value + */ + cref = usp->us_cref; + + /* + * Make sure it hasn't got too large + */ + if (cref >= UNI_MSG_CALL_REF_DUMMY) { + /* XXX */ + log(LOG_ERR, "uni: call reference limit reached\n"); + return(0); + } + + /* + * Bump the call reference value + */ + usp->us_cref++; + + return(cref); +} + + +/* + * Print an ATM address + * + * Convert an ATM address into an ASCII string suitable for printing. + * + * Arguments: + * p pointer to an ATM address + * + * Returns: + * the address of a string with the ASCII representation of the + * address. This routine returns the address of a statically- + * allocated buffer, so if repeated calls to this routine are made, + * each call will destroy the result of the previous call. + * + */ +char * +unisig_addr_print(p) + Atm_addr *p; +{ + int i; + char *fp, *op, t_buff[16]; + u_char *cp; + static char strbuff[256]; + + static char nf_DCC[] = "0xX.XX.X.XXX.XX.XX.XX.XXXXXX.X"; + static char nf_ICD[] = "0xX.XX.X.XXX.XX.XX.XX.XXXXXX.X"; + static char nf_E164[] = "0xX.XXXXXXXX.XX.XX.XXXXXX.X"; + + union { + int w; + char c[4]; + } u1, u2; + + /* + * Clear the print buffer + */ + KM_ZERO(strbuff, sizeof(strbuff)); + + /* + * Select appropriate printing format + */ + switch(p->address_format) { + case T_ATM_ENDSYS_ADDR: + /* + * Select format by NSAP type + */ + switch(((Atm_addr_nsap *)p->address)->aan_afi) { + default: + case AFI_DCC: + fp = nf_DCC; + break; + case AFI_ICD: + fp = nf_ICD; + break; + case AFI_E164: + fp = nf_E164; + break; + } + + /* + * Loop through the format string, converting the NSAP + * to ASCII + */ + cp = (u_char *) p->address; + op = strbuff; + while (*fp) { + if (*fp == 'X') { + /* + * If format character is an 'X', put a + * two-digit hex representation of the + * NSAP byte in the output buffer + */ + sprintf(t_buff, "%x", *cp + 512); + strcpy(op, &t_buff[strlen(t_buff)-2]); + op++; op++; + cp++; + } else { + /* + * If format character isn't an 'X', + * just copy it to the output buffer + */ + *op = *fp; + op++; + } + fp++; + } + + break; + + case T_ATM_E164_ADDR: + /* + * Print the IA5 characters of the E.164 address + */ + for(i=0; i<p->address_length; i++) { + sprintf(&strbuff[strlen(strbuff)], "%c\0", + ((Atm_addr_e164 *)p->address)->aae_addr[i]); + } + break; + + case T_ATM_SPANS_ADDR: + /* + * Get address into integers + */ + u1.c[0] = ((Atm_addr_spans *)p->address)->aas_addr[0]; + u1.c[1] = ((Atm_addr_spans *)p->address)->aas_addr[1]; + u1.c[2] = ((Atm_addr_spans *)p->address)->aas_addr[2]; + u1.c[3] = ((Atm_addr_spans *)p->address)->aas_addr[3]; + u2.c[0] = ((Atm_addr_spans *)p->address)->aas_addr[4]; + u2.c[1] = ((Atm_addr_spans *)p->address)->aas_addr[5]; + u2.c[2] = ((Atm_addr_spans *)p->address)->aas_addr[6]; + u2.c[3] = ((Atm_addr_spans *)p->address)->aas_addr[7]; + + /* + * Print the address as two words xxxxx.yyyyyyyy + */ + sprintf(strbuff, "%x.%x", u1.w, u2.w); + break; + + case T_ATM_ABSENT: + default: + strcpy(strbuff, "-"); + } + + return(strbuff); +} + + +/* + * Print the contents of a message buffer chain + * + * Arguments: + * m pointer to a buffer + * + * Returns: + * none + * + */ +void +unisig_print_mbuf(m) + KBuffer *m; +{ + int i; + caddr_t cp; + + printf("unisig_print_mbuf:\n"); + while (m) { + KB_DATASTART(m, cp, caddr_t); + for (i = 0; i < KB_LEN(m); i++) { + if (i == 0) + printf(" bfr=0x%x: ", (int)m); + printf("%x ", (u_char)*cp++); + } + printf("<end_bfr>\n"); + m = KB_NEXT(m); + } +} diff --git a/sys/netatm/uni/unisig_var.h b/sys/netatm/uni/unisig_var.h new file mode 100644 index 0000000..1e3d01a7 --- /dev/null +++ b/sys/netatm/uni/unisig_var.h @@ -0,0 +1,321 @@ +/* + * + * =================================== + * 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_var.h,v 1.12 1998/07/24 20:24:34 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Protocol control blocks + * + */ + +#ifndef _UNISIG_VAR_H +#define _UNISIG_VAR_H + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifdef ATM_KERNEL +/* + * Structure containing state information for each UNI protocol + * instance. There will be one instance for each ATM device interface + * using the UNI signalling manager. + */ +struct unisig { + struct siginst us_inst; /* Header */ + struct atm_time us_time; /* Timer controls */ + void (*us_lower) /* Lower command handler */ + __P((int, void *, int, int)); + Atm_connection *us_conn; /* Signalling connection */ + int us_cref; /* Call reference allocation */ + u_int us_retry; /* Protocol retry count */ + u_short us_headout; /* Headroom on sig ch output */ + u_char us_proto; /* Signalling version */ +}; + +#define us_next us_inst.si_next +#define us_pif us_inst.si_pif +#define us_addr us_inst.si_addr +#define us_subaddr us_inst.si_subaddr +#define us_vccq us_inst.si_vccq +#define us_state us_inst.si_state +#define us_ipserv us_inst.si_ipserv +#endif /* ATM_KERNEL */ + +/* + * Signalling manager states + */ +#define UNISIG_NULL 0 +#define UNISIG_ADDR_WAIT 1 +#define UNISIG_INIT 2 +#define UNISIG_ACTIVE 3 +#define UNISIG_DETACH 4 + +/* + * Signalling manager events + */ +#define UNISIG_SIGMGR_TIMEOUT 0 +#define UNISIG_SIGMGR_SSCF_EST_IND 1 +#define UNISIG_SIGMGR_SSCF_EST_CNF 2 +#define UNISIG_SIGMGR_SSCF_RLS_IND 3 +#define UNISIG_SIGMGR_SSCF_RLS_CNF 4 +#define UNISIG_SIGMGR_SSCF_DATA_IND 5 +#define UNISIG_SIGMGR_SSCF_UDATA_IND 6 +#define UNISIG_SIGMGR_CALL_CLEARED 7 +#define UNISIG_SIGMGR_DETACH 8 +#define UNISIG_SIGMGR_ADDR_SET 9 + +/* + * Signalling manager timer values + */ +#define UNISIG_SSCF_TIMEOUT (3 * ATM_HZ) + + +#ifdef ATM_KERNEL +/* + * UNI Virtual Channel Connection control block. All information + * regarding the state of a UNI-controlled VCC will be recorded here. + * There will be one UNI VCC control block for each UNI-controlled + * VCC. + */ +struct unisig_vccb { + struct vccb vcp_hdr; /* Generic VCCB */ + u_short uv_retry; /* Xmit retry count */ + u_int uv_call_ref; /* Q.2931 call reference */ +}; + +#define uv_type vcp_hdr.vc_type +#define uv_proto vcp_hdr.vc_proto +#define uv_sstate vcp_hdr.vc_sstate +#define uv_ustate vcp_hdr.vc_ustate +#define uv_pif vcp_hdr.vc_pif +#define uv_nif vcp_hdr.vc_nif +#define uv_sigelem vcp_hdr.vc_sigelem +#define uv_time vcp_hdr.vc_time +#define uv_vpi vcp_hdr.vc_vpi +#define uv_vci vcp_hdr.vc_vci +#define uv_connvc vcp_hdr.vc_connvc +#define uv_ipdus vcp_hdr.vc_ipdus +#define uv_opdus vcp_hdr.vc_opdus +#define uv_ibytes vcp_hdr.vc_ibytes +#define uv_obytes vcp_hdr.vc_obytes +#define uv_ierrors vcp_hdr.vc_ierrors +#define uv_oerrors vcp_hdr.vc_oerrors +#define uv_tstamp vcp_hdr.vc_tstamp +#endif /* ATM_KERNEL */ + +/* + * UNI VCC protocol states. Taken from The ATM Forum UNI 3.0 (section + * 5.2.1.1) + */ +#define UNI_NULL 0 /* No call exists */ +#define UNI_CALL_INITIATED 1 /* Initiating call */ +#define UNI_CALL_OUT_PROC 3 /* Outgoing call proceeding */ +#define UNI_CALL_DELIVERED 4 /* Not supported */ +#define UNI_CALL_PRESENT 6 /* Call coming in */ +#define UNI_CALL_RECEIVED 7 /* Not supported */ +#define UNI_CONNECT_REQUEST 8 /* Call coming in */ +#define UNI_CALL_IN_PROC 9 /* Incoming call proceeding */ +#define UNI_ACTIVE 10 /* Call is established */ +#define UNI_RELEASE_REQUEST 11 /* Clearing call */ +#define UNI_RELEASE_IND 12 /* Network disconnecting */ + +/* + * Additional states required for internal management of VCCs + */ +#define UNI_SSCF_RECOV 13 /* Signalling chan recovery */ +#define UNI_FREE 14 /* Waiting for user to free */ +#define UNI_PVC_ACTIVE 15 /* PVC Active */ +#define UNI_PVC_ACT_DOWN 16 /* PVC Active - i/f down */ + +/* + * UNI VCC events + */ +#define UNI_VC_TIMEOUT 0 /* Timer expired */ +#define UNI_VC_CALLP_MSG 1 /* CALL PROCEEDING message */ +#define UNI_VC_CONNECT_MSG 2 /* CONNECT message */ +#define UNI_VC_CNCTACK_MSG 3 /* CONNECT ACK message */ +#define UNI_VC_SETUP_MSG 4 /* SETUP message */ +#define UNI_VC_RELEASE_MSG 5 /* RELEASE message */ +#define UNI_VC_RLSCMP_MSG 6 /* RELEASE COMPLETE message */ +#define UNI_VC_STATUS_MSG 7 /* STATUS message */ +#define UNI_VC_STATUSENQ_MSG 8 /* STATUS ENQ message */ +#define UNI_VC_ADDP_MSG 9 /* ADD PARTY message */ +#define UNI_VC_ADDPACK_MSG 10 /* ADD PARTY ACK message */ +#define UNI_VC_ADDPREJ_MSG 11 /* ADD PARTY REJ message */ +#define UNI_VC_DROP_MSG 12 /* DROP PARTY message */ +#define UNI_VC_DROPACK_MSG 13 /* DROP PARTY ACK message */ +#define UNI_VC_SETUP_CALL 14 /* Setup routine called */ +#define UNI_VC_ACCEPT_CALL 15 /* Accept call routine called */ +#define UNI_VC_REJECT_CALL 16 /* Reject call routine called */ +#define UNI_VC_RELEASE_CALL 17 /* Release routine called */ +#define UNI_VC_ABORT_CALL 18 /* Abort routine called */ +#define UNI_VC_SAAL_FAIL 19 /* Signalling AAL failed */ +#define UNI_VC_SAAL_ESTAB 20 /* Signalling AAL back up */ + + +#ifdef ATM_KERNEL +/* + * UNI Timer Values. These values (except for T317) are taken from + * The ATM Forum UNI 3.0 (section 5.7.2). + */ +#define UNI_T303 (4 * ATM_HZ) +#define UNI_T308 (30 * ATM_HZ) +#define UNI_T309 (10 * ATM_HZ) +#define UNI_T310 (10 * ATM_HZ) +#define UNI_T313 (4 * ATM_HZ) +#define UNI_T316 (120 * ATM_HZ) +#define UNI_T317 (60 * ATM_HZ) +#define UNI_T322 (4 * ATM_HZ) +#define UNI_T398 (4 * ATM_HZ) +#define UNI_T399 (14 * ATM_HZ) + + +/* + * Timer macros + */ +#define UNISIG_TIMER(s, t) atm_timeout(&(s)->us_time, (t), unisig_timer) +#define UNISIG_CANCEL(s) atm_untimeout(&(s)->us_time) +#define UNISIG_VC_TIMER(v, t) atm_timeout(&(v)->vc_time, (t), unisig_vctimer) +#define UNISIG_VC_CANCEL(v) atm_untimeout(&(v)->vc_time) + + +/* + * Global function declarations + */ +struct usfmt; +struct unisig_msg; + + /* unisig_decode.c */ +int usf_dec_msg __P((struct usfmt *, struct unisig_msg *)); + + /* unisig_encode.c */ +int usf_enc_msg __P((struct usfmt *, struct unisig_msg *)); + + /* unisig_if.c */ +int unisig_start __P((void)); +int unisig_stop __P((void)); +int unisig_free __P((struct vccb *)); + + /* unisig_mbuf.c */ +int usf_init __P((struct usfmt *, struct unisig *, KBuffer *, int, int)); +int usf_byte __P((struct usfmt *, u_char *)); +int usf_short __P((struct usfmt *, u_short *)); +int usf_int3 __P((struct usfmt *, u_int *)); +int usf_int __P((struct usfmt *, u_int *)); +int usf_ext __P((struct usfmt *, u_int *)); +int usf_count __P((struct usfmt *)); +int usf_byte_mark __P((struct usfmt *, u_char *, u_char **)); + + /* unisig_msg.c */ +struct ie_generic; +void unisig_cause_from_attr __P((struct ie_generic *, + Atm_attributes *)); +void unisig_cause_from_msg __P((struct ie_generic *, + struct unisig_msg *, int)); +int unisig_send_msg __P((struct unisig *, + struct unisig_msg *)); +int unisig_send_setup __P((struct unisig *, + struct unisig_vccb *)); +int unisig_send_release __P((struct unisig *, + struct unisig_vccb *, + struct unisig_msg *, + int)); +int unisig_send_release_complete __P((struct unisig *, + struct unisig_vccb *, + struct unisig_msg *, + int)); +int unisig_send_status __P((struct unisig *, + struct unisig_vccb *, + struct unisig_msg *, + int)); +int unisig_rcv_msg __P((struct unisig *, KBuffer *)); + + /* unisig_print.c */ +void usp_print_msg __P((struct unisig_msg *, int)); + + /* unisig_proto.c */ +void unisig_timer __P((struct atm_time *)); +void unisig_vctimer __P((struct atm_time *)); +void unisig_saal_ctl __P((int, void *, void *)); +void unisig_saal_data __P((void *, KBuffer *)); +caddr_t unisig_getname __P((void *)); +void unisig_connected __P((void *)); +void unisig_cleared __P((void *, struct t_atm_cause *)); + + /* unisig_sigmgr_state.c */ +int unisig_sigmgr_state __P((struct unisig *, int, + KBuffer *)); + + /* unisig_subr.c */ +void unisig_set_cause_attr __P((Atm_attributes *, int)); +int unisig_open_vcc __P((struct unisig *, Atm_connvc *)); +int unisig_close_vcc __P((struct unisig *, + struct unisig_vccb *)); +int unisig_clear_vcc __P((struct unisig *, + struct unisig_vccb *, int)); +void unisig_switch_reset __P((struct unisig *, int)); +void unisig_save_attrs __P((struct unisig *, struct unisig_msg *, + Atm_attributes *)); +int unisig_set_attrs __P((struct unisig *, struct unisig_msg *, + Atm_attributes *)); + + /* unisig_util.c */ +void unisig_free_msg __P((struct unisig_msg *)); +int unisig_verify_vccb __P((struct unisig *, + struct unisig_vccb *)); +struct unisig_vccb * + unisig_find_conn __P((struct unisig *, u_int)); +struct unisig_vccb * + unisig_find_vpvc __P((struct unisig *, int, int, + u_char)); +int unisig_alloc_call_ref __P((struct unisig *)); +char * unisig_addr_print __P((Atm_addr *)); +void unisig_print_mbuf __P((KBuffer *)); +void unisig_print_buffer __P((KBuffer *)); + + /* unisig_vc_state.c */ +int unisig_vc_state __P((struct unisig *, + struct unisig_vccb *, + int, + struct unisig_msg *)); + + +/* + * External variables + */ +extern struct sp_info unisig_vcpool; +extern struct sp_info unisig_msgpool; +extern struct sp_info unisig_iepool; + +#endif /* ATM_KERNEL */ + +#endif /* _UNISIG_VAR_H */ diff --git a/sys/netatm/uni/unisig_vc_state.c b/sys/netatm/uni/unisig_vc_state.c new file mode 100644 index 0000000..cfd7635 --- /dev/null +++ b/sys/netatm/uni/unisig_vc_state.c @@ -0,0 +1,2223 @@ +/* + * + * =================================== + * 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_vc_state.c,v 1.11 1998/08/06 18:16:29 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * VC state machine + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_vc_state.c,v 1.11 1998/08/06 18:16:29 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 unisig_vc_invalid __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act01 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act02 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act03 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act04 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act05 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act06 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act07 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act08 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act09 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act10 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act11 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act12 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act13 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act14 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act15 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act16 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act17 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act18 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act19 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act20 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act21 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act22 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act23 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act24 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act25 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act26 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act27 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act28 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act29 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act30 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act31 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_clear_call __P((struct unisig *, + struct unisig_vccb *, + struct unisig_msg *, + int)); + + +/* + * State table + */ +static int unisig_vc_states[21][17] = { +/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */ +{ 0, 2, 99, 5, 99, 99, 0, 99, 12, 99, 0, 14, 0, 3, 0, 0, 0 }, +{ 29, 4, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 6, 99, 6, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 10, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 8, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 7, 99, 15, 99, 99, 15, 99, 15, 99, 15, 16, 17, 0, 0, 0, 0 }, +{ 19, 3, 99, 3, 99, 99, 3, 99, 3, 99, 3, 13, 3, 0, 0, 0, 0 }, +{ 21, 21, 99, 21, 99, 99, 21, 99, 21, 99, 21, 21, 21, 0, 0, 0, 0 }, +{ 22, 22, 99, 22, 99, 99, 22, 99, 22, 99, 22, 22, 22, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 23, 17, 17, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 1, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 }, +{ 99, 25, 99, 25, 99, 99, 9, 99, 25, 99, 25, 25, 25, 25, 31, 25, 25 }, +{ 99, 25, 99, 25, 99, 99, 11, 99, 25, 99, 25, 25, 25, 25, 19, 25, 25 }, +{ 99, 12, 99, 12, 99, 99, 25, 99, 12, 99, 12, 19, 19, 30, 19, 99, 99 }, +{ 99, 12, 99, 12, 99, 99, 12, 99, 12, 99, 12, 3, 3, 3, 24, 26, 26 }, +{ 99, 3, 99, 3, 99, 99, 30, 99, 3, 99, 18, 3, 3, 0, 19, 27, 19 }, +{ 99, 7, 99, 7, 99, 99, 30, 99, 7, 99, 19, 19, 19, 20, 19, 19, 28 } +}; + + +/* + * Action vector + * + * A given state, action pair selects an action number from the + * state table. This vector holds the address of the action routine + * for each action number. + */ +#define MAX_ACTION 32 +static int (*unisig_vc_act_vec[MAX_ACTION]) + __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)) = { + unisig_vc_invalid, + unisig_vc_act01, + unisig_vc_act02, + unisig_vc_act03, + unisig_vc_act04, + unisig_vc_act05, + unisig_vc_act06, + unisig_vc_act07, + unisig_vc_act08, + unisig_vc_act09, + unisig_vc_act10, + unisig_vc_act11, + unisig_vc_act12, + unisig_vc_act13, + unisig_vc_act14, + unisig_vc_act15, + unisig_vc_act16, + unisig_vc_act17, + unisig_vc_act18, + unisig_vc_act19, + unisig_vc_act20, + unisig_vc_act21, + unisig_vc_act22, + unisig_vc_act23, + unisig_vc_act24, + unisig_vc_act25, + unisig_vc_act26, + unisig_vc_act27, + unisig_vc_act28, + unisig_vc_act29, + unisig_vc_act30, + unisig_vc_act31 +}; + + +/* + * Process an event on a VC + * + * Arguments: + * usp pointer to the UNISIG instance + * uvp pointer to the VCCB for the affected VCC + * event a numeric indication of which event has occured + * msg pointer to a signalling message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +unisig_vc_state(usp, uvp, event, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + int event; + struct unisig_msg *msg; +{ + int action, rc, state; + + /* + * Select an action from the state table + */ + if (uvp) + state = uvp->uv_sstate; + else + state = UNI_NULL; + action = unisig_vc_states[event][state]; + if (action >= MAX_ACTION || action < 0) + panic("unisig_vc_state: invalid action\n"); + + /* + * Perform the requested action + */ + ATM_DEBUG4("unisig_vc_state: uvp=0x%x, state=%d, event=%d, action=%d\n", + (int) uvp, state, event, action); + rc = unisig_vc_act_vec[action](usp, uvp, msg); + + return(rc); +} + + +/* + * VC state machine action 0 + * Unexpected action - log an error message + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection (may + be null) + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_invalid(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + log(LOG_ERR, "unisig_vc_state: unexpected action\n"); + return(EINVAL); +} + + +/* + * VC state machine action 1 + * Setup handler called + * + * Send SETUP, start timer T303, go to UNI_CALL_INITIATED state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act01(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Send the setup message + */ + rc = unisig_send_setup(usp, uvp); + if (rc) + return(rc); + + /* + * Set timer T303 + */ + uvp->uv_retry = 0; + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T303); + + /* + * Set the new state + */ + uvp->uv_sstate = UNI_CALL_INITIATED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} + + +/* + * VC state machine action 2 + * Timeout while waiting for CALL PROCEEDING or CONNECT + * + * If this is the second expiration, clear the call. Otherwise, + * retransmit the SETUP message and restart T303. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act02(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc = 0; + + if (uvp->uv_retry) { + /* + * Clear the call + */ + rc = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NO_ROUTE_TO_DESTINATION); + } else { + uvp->uv_retry++; + (void) unisig_send_setup(usp, uvp); + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T303); + } + + return(rc); +} + + +/* + * VC state machine action 3 + * + * Clear the call internally + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act03(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Clear the VCCB + */ + rc = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER); + + return(rc); +} + + +/* + * VC state machine action 4 + * Received CALL PROCEEDING + * + * Start timer T310, go to UNI_CALL_OUT_PROC + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act04(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int cause, rc, vpi, vci; + struct atm_pif *pip = usp->us_pif; + struct ie_generic *iep; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Make sure a Connection ID is part of the message + */ + if (msg->msg_ie_cnid) { + vpi = msg->msg_ie_cnid->ie_cnid_vpci; + vci = msg->msg_ie_cnid->ie_cnid_vci; + } else { + iep = (struct ie_generic *)atm_allocate(&unisig_iepool); + if (!iep) + return(ENOMEM); + iep->ie_ident = UNI_IE_CNID; + iep->ie_err_cause = UNI_IE_CAUS_MISSING; + MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR); + cause = UNI_IE_CAUS_MISSING; + ATM_DEBUG0("unisig_vc_act04: no CNID in Call Proc\n"); + goto response04; + } + + /* + * Make sure we can handle the specified VPI and VCI + */ + if (vpi > pip->pif_maxvpi || vci > pip->pif_maxvci || + vci < UNI_IE_CNID_MIN_VCI) { + cause = UNI_IE_CAUS_BAD_VCC; + ATM_DEBUG0("unisig_vc_act04: VPI/VCI invalid\n"); + goto response04; + } + + /* + * Make sure the specified VPI and VCI are not in use + */ + if (unisig_find_vpvc(usp, vpi, vci, VCC_OUT)) { + cause = UNI_IE_CAUS_NA_VCC; + ATM_DEBUG0("unisig_vc_act04: VPI/VCI in use\n"); + goto response04; + } + + /* + * Start timer T310 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T310); + + /* + * Save the specified VPI and VCI + */ + uvp->uv_vpi = vpi; + uvp->uv_vci = vci; + + /* + * Set the state + */ + uvp->uv_sstate = UNI_CALL_OUT_PROC; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); + +response04: + /* + * Initiate call clearing + */ + rc = unisig_vc_clear_call(usp, uvp, msg, cause); + + return(rc); +} + + +/* + * VC state machine action 5 + * Timeout in UNI_CALL_OUT_PROC + * + * Clear call towards network + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act05(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + struct unisig_msg *rls_msg; + struct ie_generic *cause_ie; + + /* + * Send a RELEASE message + */ + rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (rls_msg == NULL) + return(ENOMEM); + cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (cause_ie == NULL) { + atm_free(rls_msg); + return(ENOMEM); + } + + /* + * Fill out the RELEASE message + */ + rls_msg->msg_call_ref = uvp->uv_call_ref; + rls_msg->msg_type = UNI_MSG_RLSE; + rls_msg->msg_type_flag = 0; + rls_msg->msg_type_action = 0; + rls_msg->msg_ie_caus = cause_ie; + + /* + * Fill out the cause IE + */ + cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + cause_ie->ie_caus_cause = UNI_IE_CAUS_TIMER; + KM_COPY("310", cause_ie->ie_caus_diagnostic, 3); + + /* + * Send the RELEASE message. + */ + rc = unisig_send_msg(usp, rls_msg); + unisig_free_msg(rls_msg); + + /* + * Start timer T308 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308); + + /* + * Set the new state + */ + uvp->uv_sstate = UNI_RELEASE_REQUEST; + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(rc); +} + + +/* + * VC state machine action 6 + * Received CONNECT + * + * Send CONNECT ACK, go to UNI_ACTIVE state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act06(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int cause, rc, vci, vpi; + struct atm_pif *pip = usp->us_pif; + struct unisig_msg *cack_msg; + struct ie_generic *iep; + Atm_attributes *ap; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + ap = &uvp->uv_connvc->cvc_attr; + + /* + * See if a VPI/VCI is specified + */ + if (msg->msg_ie_cnid) { + /* + * Yes--VPI/VCI must be the first specification or must + * match what was specified before + */ + vpi = msg->msg_ie_cnid->ie_cnid_vpci; + vci = msg->msg_ie_cnid->ie_cnid_vci; + if ((uvp->uv_vpi || uvp->uv_vci) && + (vpi != uvp->uv_vpi || + vci != uvp->uv_vci)) { + cause = UNI_IE_CAUS_BAD_VCC; + ATM_DEBUG0("unisig_vc_act06: VPI/VCI invalid\n"); + goto response06; + } + + /* + * Specified VPI/VCI must be within range + */ + if (vpi > pip->pif_maxvpi || vci > pip->pif_maxvci || + vci < UNI_IE_CNID_MIN_VCI) { + cause = UNI_IE_CAUS_BAD_VCC; + ATM_DEBUG0("unisig_vc_act06: VPI/VCI invalid\n"); + goto response06; + } + uvp->uv_vpi = vpi; + uvp->uv_vci = vci; + } else { + /* + * No--VPI/VCI must have been specified earlier + */ + if (!uvp->uv_vpi || !uvp->uv_vci) { + iep = (struct ie_generic *)atm_allocate( + &unisig_iepool); + if (!iep) + return(ENOMEM); + iep->ie_ident = UNI_IE_CNID; + iep->ie_err_cause = UNI_IE_CAUS_MISSING; + MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR); + cause = UNI_IE_CAUS_MISSING; + ATM_DEBUG0("unisig_vc_act06: CNID missing\n"); + goto response06; + } + } + + /* + * Handle AAL parameters negotiation + */ + if (msg->msg_ie_aalp) { + struct ie_generic *aalp = msg->msg_ie_aalp; + + /* + * AAL parameters must have been sent in SETUP + */ + if ((ap->aal.tag != T_ATM_PRESENT) || + (ap->aal.type != aalp->ie_aalp_aal_type)) { + cause = UNI_IE_CAUS_IECONTENT; + goto response06; + } + + switch (aalp->ie_aalp_aal_type) { + + case UNI_IE_AALP_AT_AAL3: + /* + * Maximum SDU size negotiation + */ + if (aalp->ie_aalp_4_fwd_max_sdu == T_ATM_ABSENT) + break; + if ((ap->aal.v.aal4.forward_max_SDU_size < + aalp->ie_aalp_4_fwd_max_sdu) || + (ap->aal.v.aal4.backward_max_SDU_size < + aalp->ie_aalp_4_bkwd_max_sdu)) { + cause = UNI_IE_CAUS_IECONTENT; + goto response06; + } else { + ap->aal.v.aal4.forward_max_SDU_size = + aalp->ie_aalp_4_fwd_max_sdu; + ap->aal.v.aal4.backward_max_SDU_size = + aalp->ie_aalp_4_bkwd_max_sdu; + } + break; + + case UNI_IE_AALP_AT_AAL5: + /* + * Maximum SDU size negotiation + */ + if (aalp->ie_aalp_5_fwd_max_sdu == T_ATM_ABSENT) + break; + if ((ap->aal.v.aal5.forward_max_SDU_size < + aalp->ie_aalp_5_fwd_max_sdu) || + (ap->aal.v.aal5.backward_max_SDU_size < + aalp->ie_aalp_5_bkwd_max_sdu)) { + cause = UNI_IE_CAUS_IECONTENT; + goto response06; + } else { + ap->aal.v.aal5.forward_max_SDU_size = + aalp->ie_aalp_5_fwd_max_sdu; + ap->aal.v.aal5.backward_max_SDU_size = + aalp->ie_aalp_5_bkwd_max_sdu; + } + break; + } + } + + /* + * Get memory for a CONNECT ACK message + */ + cack_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (cack_msg == NULL) + return(ENOMEM); + + /* + * Fill out the CONNECT ACK message + */ + cack_msg->msg_call_ref = uvp->uv_call_ref; + cack_msg->msg_type = UNI_MSG_CACK; + cack_msg->msg_type_flag = 0; + cack_msg->msg_type_action = 0; + + /* + * Send the CONNECT ACK message + */ + rc = unisig_send_msg(usp, cack_msg); + unisig_free_msg(cack_msg); + + /* + * Set the new state + */ + uvp->uv_sstate = UNI_ACTIVE; + uvp->uv_ustate = VCCU_OPEN; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Notify the user that the connection is now active + */ + atm_cm_connected(uvp->uv_connvc); + + return(0); + +response06: + /* + * Initiate call clearing + */ + rc = unisig_vc_clear_call(usp, uvp, msg, cause); + + return(rc); +} + + +/* + * VC state machine action 7 + * Abort routine called or signalling SAAL session reset while in + * one of the call setup states + * + * Clear the call, send RELEASE COMPLETE, notify the user. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act07(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Send a RELEASE COMPLETE message rejecting the connection + */ + rc = unisig_send_release_complete(usp, uvp, msg, + UNI_IE_CAUS_TEMP); + + /* + * Clear the call VCCB + */ + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Notify the user + */ + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + atm_cm_cleared(uvp->uv_connvc); + + return(rc); +} + + +/* + * VC state machine action 8 + * Received SETUP + * + * Check call paramaters, notify user that a call has been received, + * set UNI_CALL_PRESENT state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act08(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int cause = 0, rc, vpi, vci; + struct atm_pif *pip = usp->us_pif; + struct atm_nif *nip; + Atm_addr_nsap *nap; + Atm_attributes attr; + + ATM_DEBUG3("unisig_vc_act08: usp=0x%x, uvp=0x%x, msg=0x%x\n", + (int) usp, (int) uvp, (int) msg); + + /* + * Make sure that the called address is the right format + */ + if (msg->msg_ie_cdad->ie_cdad_plan != UNI_IE_CDAD_PLAN_NSAP) { + cause = UNI_IE_CAUS_IECONTENT; + ATM_DEBUG0("unisig_vc_act08: bad address format\n"); + goto response08; + } + + /* + * Make sure that the called address is ours + */ + nap = (Atm_addr_nsap *) msg->msg_ie_cdad->ie_cdad_addr.address; + if (bcmp(usp->us_addr.address, nap, /* XXX */ + sizeof(Atm_addr_nsap)-1)) { + cause = UNI_IE_CAUS_IECONTENT; + ATM_DEBUG0("unisig_vc_act08: address not mine\n"); + goto response08; + } + + /* + * Find the right NIF for the given selector byte + */ + nip = pip->pif_nif; + while (nip && nip->nif_sel != nap->aan_sel) { + nip = nip->nif_pnext; + } + if (!nip) { + cause = UNI_IE_CAUS_IECONTENT; + ATM_DEBUG0("unisig_vc_act08: bad selector byte\n"); + goto response08; + } + + /* + * See if we can handle the specified encapsulation + */ + if (msg->msg_ie_blli->ie_blli_l2_id != UNI_IE_BLLI_L2P_LLC && + (msg->msg_ie_blli->ie_blli_l2_id != 0 || + msg->msg_ie_blli->ie_blli_l3_id != + UNI_IE_BLLI_L3P_ISO9577)) { + cause = UNI_IE_CAUS_UNAVAIL; + ATM_DEBUG0("unisig_vc_act08: bad encapsulation\n"); + goto response08; + } + + /* + * See if we recognize the specified AAL + */ + if (msg->msg_ie_aalp->ie_aalp_aal_type != UNI_IE_AALP_AT_AAL3 && + msg->msg_ie_aalp->ie_aalp_aal_type != + UNI_IE_AALP_AT_AAL5) { + cause = UNI_IE_CAUS_UAAL; + ATM_DEBUG0("unisig_vc_act08: bad AAL\n"); + goto response08; + } + + /* + * Should verify that we can handle requested + * connection QOS + */ + + /* + * Make sure the specified VPI/VCI is valid + */ + vpi = msg->msg_ie_cnid->ie_cnid_vpci; + vci = msg->msg_ie_cnid->ie_cnid_vci; + if (vpi > pip->pif_maxvpi || + vci > pip->pif_maxvci || + vci < UNI_IE_CNID_MIN_VCI) { + cause = UNI_IE_CAUS_BAD_VCC; + ATM_DEBUG0("unisig_vc_act08: VPI/VCI invalid\n"); + goto response08; + } + + /* + * Make sure the specified VPI/VCI isn't in use already + */ + if (unisig_find_vpvc(usp, vpi, vci, VCC_IN)) { + cause = UNI_IE_CAUS_NA_VCC; + ATM_DEBUG0("unisig_vc_act08: VPI/VCI in use\n"); + goto response08; + } + + /* + * Make sure it's a point-to-point connection + */ + if (msg->msg_ie_bbcp->ie_bbcp_conn_config != + UNI_IE_BBCP_CC_PP) { + cause = UNI_IE_CAUS_NI_BC; + ATM_DEBUG0("unisig_vc_act08: conn not pt-pt\n"); + goto response08; + } + + /* + * Fill in the VCCB fields that we can at this point + */ + uvp->uv_type = VCC_SVC | VCC_IN | VCC_OUT; + uvp->uv_proto = pip->pif_sigmgr->sm_proto; + uvp->uv_sstate = UNI_CALL_PRESENT; + uvp->uv_ustate = VCCU_POPEN; + uvp->uv_pif = pip; + uvp->uv_nif = nip; + uvp->uv_vpi = msg->msg_ie_cnid->ie_cnid_vpci; + uvp->uv_vci = msg->msg_ie_cnid->ie_cnid_vci; + uvp->uv_tstamp = time_second; + + /* + * Copy the connection attributes from the SETUP message + * to an attribute block + */ + KM_ZERO(&attr, sizeof(attr)); + attr.nif = nip; + attr.aal.tag = T_ATM_ABSENT; + attr.traffic.tag = T_ATM_ABSENT; + attr.bearer.tag = T_ATM_ABSENT; + attr.bhli.tag = T_ATM_ABSENT; + attr.blli.tag_l2 = T_ATM_ABSENT; + attr.blli.tag_l3 = T_ATM_ABSENT; + attr.llc.tag = T_ATM_ABSENT; + attr.called.tag = T_ATM_ABSENT; + attr.calling.tag = T_ATM_ABSENT; + attr.qos.tag = T_ATM_ABSENT; + attr.transit.tag = T_ATM_ABSENT; + attr.cause.tag = T_ATM_ABSENT; + unisig_save_attrs(usp, msg, &attr); + + /* + * Notify the connection manager of the new VCC + */ + ATM_DEBUG0("unisig_vc_act08: notifying user of connection\n"); + rc = atm_cm_incoming((struct vccb *)uvp, &attr); + if (rc) + goto response08; + + /* + * Wait for the connection recipient to issue an accept + * or reject + */ + return(0); + +response08: + ATM_DEBUG1("unisig_vc_act08: reject with cause=%d\n", cause); + + /* + * Clear the VCCB state + */ + uvp->uv_sstate = UNI_NULL; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Some problem was detected with the request. Send a Q.2931 + * message rejecting the connection. + */ + rc = unisig_send_release_complete(usp, uvp, msg, cause); + + return(rc); +} + + +/* + * VC state machine action 9 + * Accept routine called by user + * + * Send CONNECT, start timer T313, go to UNI_CONNECT_REQUEST state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act09(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + struct unisig_msg *conn_msg; + + conn_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (conn_msg == NULL) + return(ENOMEM); + + /* + * Fill out the response + */ + conn_msg->msg_call_ref = uvp->uv_call_ref; + conn_msg->msg_type = UNI_MSG_CONN; + conn_msg->msg_type_flag = 0; + conn_msg->msg_type_action = 0; + + /* + * Send the CONNECT message. If the send fails, the other + * side will eventually time out and close the connection. + */ + rc = unisig_send_msg(usp, conn_msg); + unisig_free_msg(conn_msg); + if (rc) { + return(rc); + } + + /* + * Start timer T313 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T313); + + /* + * Set the new state + */ + uvp->uv_sstate = UNI_CONNECT_REQUEST; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} + + +/* + * VC state machine action 10 + * Received CONNECT ACK + * + * Go to UNI_ACTIVE state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act10(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Set the state + */ + uvp->uv_sstate = UNI_ACTIVE; + uvp->uv_ustate = VCCU_OPEN; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Notify the user that the call is up + */ + atm_cm_connected(uvp->uv_connvc); + + return (0); +} + + +/* + * VC state machine action 11 + * Reject handler called + * + * Send RELEASE COMPLETE, clear the call + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act11(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Send a RELEASE COMPLETE message + */ + rc = unisig_send_release_complete(usp, uvp, msg, + UNI_IE_CAUS_REJECT); + + /* + * Clear the call VCCB + */ + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(rc); +} + + +/* + * VC state machine action 12 + * Release or abort routine called + * + * Send RELEASE, start timer T308, go to UNI_RELEASE_REQUEST state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act12(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Send the RELEASE message + */ + rc = unisig_vc_clear_call(usp, uvp, (struct unisig_msg *)0, + T_ATM_ABSENT); + + return(rc); +} + + +/* + * VC state machine action 13 + * RELEASE COMPLETE received + * + * Clear the call + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act13(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Set the state + */ + uvp->uv_sstate = UNI_FREE; + if (uvp->uv_ustate != VCCU_ABORT) + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Notify the user that the call is now closed + */ + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + atm_cm_cleared(uvp->uv_connvc); + + return(0); +} + + +/* + * VC state machine action 14 + * Timer expired while waiting for RELEASE COMPLETE + * + * If this is the second expiration, just clear the call. Otherwise, + * retransmit the RELEASE message and restart timer T308. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act14(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Check the retry count + */ + if (uvp->uv_retry) { + /* + * Clear the connection + */ + rc = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } else { + /* + * Increment the retry count + */ + uvp->uv_retry++; + + /* + * Resend the RELEASE message + */ + rc = unisig_send_release(usp, uvp, + (struct unisig_msg *)0, T_ATM_ABSENT); + if (rc) + return(rc); + + /* + * Restart timer T308 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308); + } + + return(0); +} + + +/* + * VC state machine action 15 + * RELEASE received in UNI_ACTIVE state + * + * Send RELEASE COMPLETE, go to UNI_FREE, notify the user + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act15(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int cause, rc; + struct ie_generic *iep; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * If there was no Cause IE, flag an error + */ + if (!msg->msg_ie_caus) { + cause = UNI_IE_CAUS_MISSING; + for (iep=msg->msg_ie_err; iep; iep=iep->ie_next) { + if (iep->ie_ident == UNI_IE_CAUS && + iep->ie_err_cause == + UNI_IE_CAUS_IECONTENT) { + cause = UNI_IE_CAUS_IECONTENT; + } + } + if (cause == UNI_IE_CAUS_MISSING) { + iep = (struct ie_generic *)atm_allocate( + &unisig_iepool); + if (!iep) + return(ENOMEM); + iep->ie_ident = UNI_IE_CNID; + iep->ie_err_cause = UNI_IE_CAUS_MISSING; + MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR); + } + } else { + cause = UNI_IE_CAUS_NORM_UNSP; + } + + /* + * Send a RELEASE COMPLETE message + */ + rc = unisig_send_release_complete(usp, uvp, msg, cause); + + /* + * Set the state + */ + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Notify the user that the call is cleared + */ + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + atm_cm_cleared(uvp->uv_connvc); + + return(rc); +} + + +/* + * VC state machine action 16 + * RELEASE received in UNI_RELEASE_REQUEST state + * + * Clear the call + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act16(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Clear the VCCB + */ + rc = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + + return(rc); +} + + +/* + * VC state machine action 17 + * Protocol error + * + * Send a STATUS message with cause 101, "message not compatible with + * call state" + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act17(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + ATM_DEBUG3("unisig_vc_perror: usp=0x%x, uvp=0x%x, msg=0x%x\n", + (int) usp, (int) uvp, (int) msg); + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Send a STATUS message + */ + rc = unisig_send_status(usp, uvp, msg, UNI_IE_CAUS_STATE); + + return(rc ? rc : EINVAL); +} + + +/* + * VC state machine action 18 + * Signalling AAL connection has been lost + * + * Start timer T309. If the timer expires before the SAAL connection + * comes back, the VCC will be cleared. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act18(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Start timer T309 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T309); + + /* + * Set new state + */ + uvp->uv_sstate = UNI_SSCF_RECOV; + + return(0); +} + + +/* + * VC state machine action 19 + * Ignore the event + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act19(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + return(0); +} + + +/* + * VC state machine action 20 + * SSCF establish indication in UNI_SSCF_RECOV state -- signalling + * AAL has come up after an outage + * + * Send STATUS ENQ to make sure we're in compatible state with other end + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act20(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + struct unisig_msg *stat_msg; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Get memory for a STATUS ENQUIRY message + */ + stat_msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool); + if (stat_msg == NULL) + return(ENOMEM); + + /* + * Fill out the message + */ + stat_msg->msg_call_ref = uvp->uv_call_ref; + stat_msg->msg_type = UNI_MSG_SENQ; + stat_msg->msg_type_flag = 0; + stat_msg->msg_type_action = 0; + + /* + * Send the STATUS ENQUIRY message + */ + rc = unisig_send_msg(usp, stat_msg); + unisig_free_msg(stat_msg); + + /* + * Return to active state + */ + uvp->uv_sstate = UNI_ACTIVE; + + return(rc); +} + + +/* + * VC state machine action 21 + * STATUS received + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection (may + * be NULL) + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act21(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int cause, rc; + + /* + * Ignore a STATUS message with the global call reference + */ + if (GLOBAL_CREF(msg->msg_call_ref)) { + return(0); + } + + /* + * If the network thinks we're in NULL state, clear the VCC + */ + if (msg->msg_ie_clst->ie_clst_state == UNI_NULL) { + if (uvp) { + (void)unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER); + } + return(0); + } + + /* + * If we are in NULL state, send a RELEASE COMPLETE + */ + if (!uvp || (uvp->uv_sstate == UNI_FREE) || + (uvp->uv_sstate == UNI_NULL)) { + rc = unisig_send_release_complete(usp, + uvp, msg, UNI_IE_CAUS_STATE); + return(rc); + } + + /* + * If the reported state doesn't match our state, close the VCC + * unless we're in UNI_RELEASE_REQUEST or UNI_RELEASE_IND + */ + if (msg->msg_ie_clst->ie_clst_state != uvp->uv_sstate) { + if (uvp->uv_sstate == UNI_RELEASE_REQUEST || + uvp->uv_sstate == UNI_RELEASE_IND) { + return(0); + } + rc = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } + + /* + * States match, check for an error on one of our messages + */ + cause = msg->msg_ie_caus->ie_caus_cause; + if (cause == UNI_IE_CAUS_MISSING || + cause == UNI_IE_CAUS_MTEXIST || + cause == UNI_IE_CAUS_IEEXIST || + cause == UNI_IE_CAUS_IECONTENT || + cause == UNI_IE_CAUS_STATE) { + ATM_DEBUG2("unisig_vc_act21: error %d on message 0x%x\n", + cause, + msg->msg_ie_caus->ie_caus_diagnostic[0]); + if (uvp) { + (void)unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_INVALID_INFO_ELEMENT_CONTENTS); + } + } + + return(0); +} + + +/* + * VC state machine action 22 + * Received STATUS ENQ + * + * Send STATUS with cause 30 "response to STATUS ENQUIRY" and + * current state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection (may + * be NULL) + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act22(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + struct unisig_msg *status; + struct ie_generic *callst_ie, *cause_ie; + + ATM_DEBUG3("unisig_vc_perror: usp=0x%x, uvp=0x%x, msg=0x%x\n", + (int) usp, (int) uvp, (int) msg); + + /* + * Get memory for a STATUS message + */ + status = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (status == NULL) + return(ENOMEM); + callst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (callst_ie == NULL) { + atm_free(status); + return(ENOMEM); + } + cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (cause_ie == NULL) { + atm_free(status); + atm_free(callst_ie); + return(ENOMEM); + } + + /* + * Fill out the response + */ + if (uvp) { + status->msg_call_ref = uvp->uv_call_ref; + } else if (msg) { + if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT) + status->msg_call_ref = msg->msg_call_ref & + UNI_MSG_CALL_REF_MASK; + else + status->msg_call_ref = msg->msg_call_ref | + UNI_MSG_CALL_REF_RMT; + } else { + status->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL; + } + status->msg_type = UNI_MSG_STAT; + status->msg_type_flag = 0; + status->msg_type_action = 0; + status->msg_ie_clst = callst_ie; + status->msg_ie_caus = cause_ie; + + /* + * Fill out the call state IE + */ + callst_ie->ie_ident = UNI_IE_CLST; + callst_ie->ie_coding = 0; + callst_ie->ie_flag = 0; + callst_ie->ie_action = 0; + if (uvp) { + switch(uvp->uv_sstate) { + case UNI_FREE: + callst_ie->ie_clst_state = UNI_NULL; + break; + default: + callst_ie->ie_clst_state = uvp->uv_sstate; + } + } else { + callst_ie->ie_clst_state = UNI_NULL; + } + + /* + * Fill out the cause IE + */ + cause_ie->ie_ident = UNI_IE_CAUS; + cause_ie->ie_coding = 0; + cause_ie->ie_flag = 0; + cause_ie->ie_action = 0; + cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + cause_ie->ie_caus_cause = UNI_IE_CAUS_SENQ; + + /* + * Send the STATUS message + */ + rc = unisig_send_msg(usp, status); + unisig_free_msg(status); + return(rc); +} + + +/* + * VC state machine action 23 + * Received ADD PARTY + * + * We don't support multipoint connections, so send an ADD PARTY REJECT + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act23(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + struct unisig_msg *apr_msg; + + /* + * Get memory for the ADD PARTY REJECT message + */ + apr_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (apr_msg == NULL) + return(ENOMEM); + + /* + * Fill out the message + */ + if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT) + apr_msg->msg_call_ref = msg->msg_call_ref & + UNI_MSG_CALL_REF_MASK; + else + apr_msg->msg_call_ref = msg->msg_call_ref | + UNI_MSG_CALL_REF_RMT; + apr_msg->msg_type = UNI_MSG_ADPR; + apr_msg->msg_type_flag = 0; + apr_msg->msg_type_action = 0; + + /* + * Use the endpoint reference IE from the received message + */ + apr_msg->msg_ie_eprf = msg->msg_ie_eprf; + + /* + * Send the ADD PARTY REJECT message + */ + rc = unisig_send_msg(usp, apr_msg); + apr_msg->msg_ie_eprf = NULL; + unisig_free_msg(apr_msg); + + return(rc); +} + + +/* + * VC state machine action 24 + * User error + * + * Return EALREADY + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act24(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + return(EALREADY); +} + + +/* + * VC state machine action 25 + * User error + * + * Return EINVAL + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act25(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + return(EINVAL); +} + + +/* + * VC state machine action 26 + * PVC abort + * + * The abort handler was called to abort a PVC. Clear the VCCB and + * notify the user. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act26(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Close the VCCB + */ + rc = unisig_close_vcc(usp, uvp); + if (rc) + return(rc); + + /* + * Notify the user + */ + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + atm_cm_cleared(uvp->uv_connvc); + + return(0); +} + + +/* + * VC state machine action 27 + * Signalling AAL failure + * + * Change PVC state to UNI_PVC_ACT_DOWN. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act27(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Set the state + */ + uvp->uv_sstate = UNI_PVC_ACT_DOWN; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} + + +/* + * VC state machine action 28 + * Signalling AAL established + * + * Set PVC state to UNI_PVC_ACTIVE. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act28(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Set the state + */ + uvp->uv_sstate = UNI_PVC_ACTIVE; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} + + +/* + * VC state machine action 29 + * Protocol error + * + * Send a RELEASE COMPLETE message with cause 81, "invalid call + * reference value" + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection (may + * be NULL) + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act29(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Send a RELEASE COMPLETE message + */ + rc = unisig_send_release_complete(usp, uvp, msg, + UNI_IE_CAUS_CREF); + + return(rc); +} + + +/* + * VC state machine action 30 + * Release routine called while SSCF session down, or SSCF session + * reset or lost while in UNI_CALL_PRESENT + * + * Go to UNI_FREE state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act30(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Clear the call state + */ + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} + + +/* + * VC state machine action 31 + * Accept handler called in UNI_FREE state. + * + * The call was in UNI_CALL_PRESENT state when it was closed because + * of an SSCF failure. Return an error indication. The accept + * handler will free the VCCB and return the proper code to the + * caller. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act31(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + return(ENETDOWN); +} + + +/* + * Initiate clearing a call by sending a RELEASE message. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to UNI signalling message that the RELEASE + * responds to (may be NULL) + * cause the reason for clearing the call; a value of + * T_ATM_ABSENT indicates that the cause code is + * in the VCC's ATM attributes block + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_clear_call(usp, uvp, msg, cause) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; + int cause; +{ + int rc; + + /* + * Clear the retry count + */ + uvp->uv_retry = 0; + + /* + * Make sure the ATM attributes block has a valid cause code, + * if needed + */ + if (cause == T_ATM_ABSENT && + uvp->uv_connvc->cvc_attr.cause.tag != + T_ATM_PRESENT) { + uvp->uv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT; + uvp->uv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + uvp->uv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + uvp->uv_connvc->cvc_attr.cause.v.cause_value = + usp->us_proto == ATM_SIG_UNI30 ? + T_ATM_CAUSE_UNSPECIFIED_NORMAL : + T_ATM_CAUSE_NORMAL_CALL_CLEARING; + } + + /* + * Send a RELEASE message + */ + rc = unisig_send_release(usp, uvp, msg, cause); + if (rc) + return(rc); + + /* + * Start timer T308 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308); + + /* + * Set the VCCB state + */ + uvp->uv_sstate = UNI_RELEASE_REQUEST; + if (uvp->uv_ustate != VCCU_ABORT) + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} |