summaryrefslogtreecommitdiffstats
path: root/sys/netatm/uni/sscop_sigcpcs.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/uni/sscop_sigcpcs.c')
-rw-r--r--sys/netatm/uni/sscop_sigcpcs.c2311
1 files changed, 2311 insertions, 0 deletions
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;
+}
+
OpenPOWER on IntegriCloud