summaryrefslogtreecommitdiffstats
path: root/sys/netatm/uni/sscop_sigcpcs.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
committerphk <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
commitc3dd1fa899d435ea4bf79897f646a93cb80c94ac (patch)
tree98dfbc96e3c6aa7ff1f322855f6484c4e609819d /sys/netatm/uni/sscop_sigcpcs.c
parent9ed6892f4808d56de443849229e151f8f7ad43b0 (diff)
downloadFreeBSD-src-c3dd1fa899d435ea4bf79897f646a93cb80c94ac.zip
FreeBSD-src-c3dd1fa899d435ea4bf79897f646a93cb80c94ac.tar.gz
Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc. This software was developed with the support of the Defense Advanced Research Projects Agency (DARPA).
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