1560 lines
30 KiB
C
1560 lines
30 KiB
C
/*
|
|
*
|
|
* ===================================
|
|
* HARP | Host ATM Research Platform
|
|
* ===================================
|
|
*
|
|
*
|
|
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
|
* made available by Network Computing Services, Inc. ("NetworkCS")
|
|
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
|
* support of any kind.
|
|
*
|
|
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
|
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
|
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
|
* In no event shall NetworkCS be responsible for any damages, including
|
|
* but not limited to consequential damages, arising from or relating to
|
|
* any use of the Software or related support.
|
|
*
|
|
* Copyright 1994-1998 Network Computing Services, Inc.
|
|
*
|
|
* Copies of this Software may be made, however, the above copyright
|
|
* notice must be reproduced on all copies.
|
|
*
|
|
* @(#) $FreeBSD$
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* ATM Forum UNI Support
|
|
* ---------------------
|
|
*
|
|
* ITU-T Q.SAAL1 - Process CPCS-signals (SSCOP PDUs)
|
|
*
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/socketvar.h>
|
|
#include <net/if.h>
|
|
#include <netatm/port.h>
|
|
#include <netatm/queue.h>
|
|
#include <netatm/atm.h>
|
|
#include <netatm/atm_sys.h>
|
|
#include <netatm/atm_sap.h>
|
|
#include <netatm/atm_cm.h>
|
|
#include <netatm/atm_if.h>
|
|
#include <netatm/atm_stack.h>
|
|
#include <netatm/atm_pcb.h>
|
|
#include <netatm/atm_var.h>
|
|
|
|
#include <netatm/uni/sscop.h>
|
|
#include <netatm/uni/sscop_misc.h>
|
|
#include <netatm/uni/sscop_pdu.h>
|
|
#include <netatm/uni/sscop_var.h>
|
|
|
|
#ifndef lint
|
|
__RCSID("@(#) $FreeBSD$");
|
|
#endif
|
|
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
|