aboutsummaryrefslogtreecommitdiff
path: root/sys/netatm/uni/sscop_upper.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/uni/sscop_upper.c')
-rw-r--r--sys/netatm/uni/sscop_upper.c412
1 files changed, 412 insertions, 0 deletions
diff --git a/sys/netatm/uni/sscop_upper.c b/sys/netatm/uni/sscop_upper.c
new file mode 100644
index 000000000000..be9556deaa2f
--- /dev/null
+++ b/sys/netatm/uni/sscop_upper.c
@@ -0,0 +1,412 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: sscop_upper.c,v 1.6 1998/08/26 23:29:20 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP - CPCS SAP interface processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscop_upper.c,v 1.6 1998/08/26 23:29:20 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Local functions
+ */
+static caddr_t sscop_pdu_receive __P((KBuffer *, struct sscop *, int *));
+
+
+/*
+ * Local variables
+ */
+static union {
+ struct bgn_pdu t_bgn;
+ struct bgak_pdu t_bgak;
+ struct end_pdu t_end;
+ struct endak_q2110_pdu t_endak_q2110;
+ struct endak_qsaal_pdu t_endak_qsaal;
+ struct rs_pdu t_rs;
+ struct rsak_q2110_pdu t_rsak_q2110;
+ struct rsak_qsaal_pdu t_rsak_qsaal;
+ struct bgrej_pdu t_bgrej;
+ struct sd_pdu t_sd;
+ struct sdp_pdu t_sdp;
+ struct er_pdu t_er;
+ struct poll_pdu t_poll;
+ struct stat_pdu t_stat;
+ struct ustat_pdu t_ustat;
+ struct ud_pdu t_ud;
+ struct md_pdu t_md;
+ struct erak_pdu t_erak;
+} sscop_trailer;
+
+
+/*
+ * PDU length validation table
+ */
+struct pdulen {
+ int min;
+ int max;
+};
+
+static struct pdulen qsaal_pdulen[] = {
+ {0, 0},
+ {sizeof(struct bgn_pdu), sizeof(struct bgn_pdu)},
+ {sizeof(struct bgak_pdu), sizeof(struct bgak_pdu)},
+ {sizeof(struct end_pdu), sizeof(struct end_pdu)},
+ {sizeof(struct endak_qsaal_pdu),sizeof(struct endak_qsaal_pdu)},
+ {sizeof(struct rs_pdu), sizeof(struct rs_pdu)},
+ {sizeof(struct rsak_qsaal_pdu), sizeof(struct rsak_qsaal_pdu)},
+ {sizeof(struct bgrej_pdu), sizeof(struct bgrej_pdu)},
+ {sizeof(struct sd_pdu), sizeof(struct sd_pdu) + PDU_MAX_INFO},
+ {sizeof(struct sdp_pdu), sizeof(struct sdp_pdu) + PDU_MAX_INFO},
+ {sizeof(struct poll_pdu), sizeof(struct poll_pdu)},
+ {sizeof(struct stat_pdu), sizeof(struct stat_pdu) + PDU_MAX_STAT},
+ {sizeof(struct ustat_pdu), sizeof(struct ustat_pdu)},
+ {sizeof(struct ud_pdu), sizeof(struct ud_pdu) + PDU_MAX_INFO},
+ {sizeof(struct md_pdu), sizeof(struct md_pdu) + PDU_MAX_INFO},
+ {0, 0}
+};
+
+static struct pdulen q2110_pdulen[] = {
+ {0, 0},
+ {sizeof(struct bgn_pdu), sizeof(struct bgn_pdu) + PDU_MAX_UU},
+ {sizeof(struct bgak_pdu), sizeof(struct bgak_pdu) + PDU_MAX_UU},
+ {sizeof(struct end_pdu), sizeof(struct end_pdu) + PDU_MAX_UU},
+ {sizeof(struct endak_q2110_pdu),sizeof(struct endak_q2110_pdu)},
+ {sizeof(struct rs_pdu), sizeof(struct rs_pdu) + PDU_MAX_UU},
+ {sizeof(struct rsak_q2110_pdu), sizeof(struct rsak_q2110_pdu)},
+ {sizeof(struct bgrej_pdu), sizeof(struct bgrej_pdu) + PDU_MAX_UU},
+ {sizeof(struct sd_pdu), sizeof(struct sd_pdu) + PDU_MAX_INFO},
+ {sizeof(struct er_pdu), sizeof(struct er_pdu)},
+ {sizeof(struct poll_pdu), sizeof(struct poll_pdu)},
+ {sizeof(struct stat_pdu), sizeof(struct stat_pdu) + PDU_MAX_STAT},
+ {sizeof(struct ustat_pdu), sizeof(struct ustat_pdu)},
+ {sizeof(struct ud_pdu), sizeof(struct ud_pdu) + PDU_MAX_INFO},
+ {sizeof(struct md_pdu), sizeof(struct md_pdu) + PDU_MAX_INFO},
+ {sizeof(struct erak_pdu), sizeof(struct erak_pdu)}
+};
+
+
+/*
+ * PDUs with Pad Length Fields
+ */
+static u_char qsaal_padlen[] = {
+ 0, /* --- */
+ 0, /* BGN */
+ 0, /* BGAK */
+ 0, /* END */
+ 0, /* ENDAK */
+ 0, /* RS */
+ 0, /* RSAK */
+ 0, /* BGREJ */
+ 1, /* SD */
+ 1, /* SDP */
+ 0, /* POLL */
+ 0, /* STAT */
+ 0, /* USTAT */
+ 1, /* UD */
+ 1, /* MD */
+ 0 /* --- */
+};
+
+static u_char q2110_padlen[] = {
+ 0, /* --- */
+ 1, /* BGN */
+ 1, /* BGAK */
+ 1, /* END */
+ 0, /* ENDAK */
+ 1, /* RS */
+ 0, /* RSAK */
+ 1, /* BGREJ */
+ 1, /* SD */
+ 0, /* ER */
+ 0, /* POLL */
+ 0, /* STAT */
+ 0, /* USTAT */
+ 1, /* UD */
+ 1, /* MD */
+ 0 /* ERAK */
+};
+
+
+/*
+ * SSCOP Upper Stack Command Handler
+ *
+ * This function will receive all of the stack commands issued from the
+ * layer below SSCOP (ie. CPCS). Currently, only incoming PDUs will be
+ * received here. The appropriate processing function will be determined
+ * based on the received PDU type and the current sscop control block state.
+ *
+ * Arguments:
+ * cmd stack command code
+ * tok session token
+ * arg1 command specific argument
+ * arg2 command specific argument
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_upper(cmd, tok, arg1, arg2)
+ int cmd;
+ void *tok;
+ int arg1;
+ int arg2;
+{
+ struct sscop *sop = (struct sscop *)tok;
+ void (**ptab) __P((struct sscop *, KBuffer *, caddr_t));
+ void (*func) __P((struct sscop *, KBuffer *, caddr_t));
+ caddr_t trlr;
+ int type;
+
+ ATM_DEBUG5("sscop_upper: cmd=0x%x, sop=0x%x, state=%d, arg1=0x%x, arg2=0x%x\n",
+ cmd, (int)sop, sop->so_state, arg1, arg2);
+
+ switch (cmd) {
+
+ case CPCS_UNITDATA_SIG:
+ /*
+ * Decode/validate received PDU
+ */
+ trlr = sscop_pdu_receive((KBuffer *)arg1, sop, &type);
+ if (trlr == NULL) {
+ return;
+ }
+
+ /*
+ * Validate sscop state
+ */
+ if (sop->so_state > SOS_MAXSTATE) {
+ log(LOG_ERR,
+ "sscop_upper: invalid state sop=0x%x, state=%d\n",
+ (int)sop, sop->so_state);
+ KB_FREEALL((KBuffer *)arg1);
+ return;
+ }
+
+ /*
+ * Call event processing function
+ */
+ ptab = sop->so_vers == SSCOP_VERS_QSAAL ?
+ sscop_qsaal_pdutab[type]:
+ sscop_q2110_pdutab[type];
+ func = ptab[sop->so_state];
+ if (func == NULL) {
+ log(LOG_ERR,
+ "sscop_upper: unsupported pdu=%d, state=%d\n",
+ type, sop->so_state);
+ break;
+ }
+ (*func)(sop, (KBuffer *)arg1, trlr);
+ break;
+
+ default:
+ log(LOG_ERR, "sscop_upper: unknown cmd 0x%x, sop=0x%x\n",
+ cmd, (int)sop);
+ }
+
+ return;
+}
+
+
+/*
+ * Decode and Validate Received PDU
+ *
+ * This function will process all received SSCOP PDUs. The PDU type will be
+ * determined and PDU format validation will be performed. If the PDU is
+ * successfully decoded and validated, the buffer chain will have the PDU
+ * trailer removed, but any resultant zero-length buffers will NOT be freed.
+ * If the PDU fails validation, then the buffer chain will be freed.
+ *
+ * Arguments:
+ * m pointer to PDU buffer chain
+ * sop pointer to sscop connection block
+ * typep address to store PDU type
+ *
+ * Returns:
+ * addr pointer to (contiguous) PDU trailer
+ * 0 invalid PDU, buffer chain freed
+ *
+ */
+static caddr_t
+sscop_pdu_receive(m, sop, typep)
+ KBuffer *m;
+ struct sscop *sop;
+ int *typep;
+{
+ KBuffer *m0, *ml, *mn;
+ caddr_t cp, tp;
+ int len, tlen, type, plen;
+
+ /*
+ * Calculate PDU length and find the last two buffers in the chain
+ */
+ len = 0;
+ for (m0 = m, ml = mn = NULL; m0; m0 = KB_NEXT(m0)) {
+ len += KB_LEN(m0);
+ mn = ml;
+ ml = m0;
+ }
+
+ /*
+ * Make sure we've got a minimum sized PDU
+ */
+ if (len < PDU_MIN_LEN)
+ goto badpdu;
+
+ /*
+ * Get PDU type field
+ */
+ if (KB_LEN(ml) >= PDU_MIN_LEN) {
+ KB_DATAEND(ml, tp, caddr_t);
+ tp -= PDU_MIN_LEN;
+ } else {
+ KB_DATAEND(mn, tp, caddr_t);
+ tp -= (PDU_MIN_LEN - KB_LEN(ml));
+ }
+ *typep = type = *tp & PT_TYPE_MASK;
+
+ /*
+ * Check up on PDU length
+ */
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ if ((len < (tlen = qsaal_pdulen[type].min)) ||
+ (len > qsaal_pdulen[type].max) ||
+ (len & PDU_LEN_MASK))
+ goto badpdu;
+ } else {
+ if ((len < (tlen = q2110_pdulen[type].min)) ||
+ (len > q2110_pdulen[type].max) ||
+ (len & PDU_LEN_MASK))
+ goto badpdu;
+ }
+
+ /*
+ * Get a contiguous, aligned PDU trailer and adjust buffer
+ * controls to remove trailer
+ */
+ if (KB_LEN(ml) >= tlen) {
+ /*
+ * Trailer is contained in last buffer
+ */
+ KB_TAILADJ(ml, -tlen);
+ KB_DATAEND(ml, cp, caddr_t);
+ if ((int)cp & PDU_ADDR_MASK) {
+ /*
+ * Trailer not aligned in buffer, use local memory
+ */
+ KM_COPY(cp, (caddr_t)&sscop_trailer, tlen);
+ cp = (caddr_t)&sscop_trailer;
+ }
+ } else {
+ /*
+ * Trailer is split across buffers, use local memory
+ */
+ caddr_t cp1;
+ int off = tlen - KB_LEN(ml);
+
+ cp = (caddr_t)&sscop_trailer;
+
+ /*
+ * Ensure trailer is within last two buffers
+ */
+ if ((mn == NULL) || (KB_LEN(mn) < off))
+ goto badpdu;
+
+ KB_DATASTART(ml, cp1, caddr_t);
+ KM_COPY(cp1, cp + off, KB_LEN(ml));
+ KB_LEN(ml) = 0;
+ KB_TAILADJ(mn, -off);
+ KB_DATAEND(mn, cp1, caddr_t);
+ KM_COPY(cp1, cp, off);
+ }
+
+ /*
+ * Get possible PDU Pad Length
+ */
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ if (qsaal_padlen[type])
+ plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT;
+ else
+ plen = 0;
+ } else {
+ if (q2110_padlen[type])
+ plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT;
+ else
+ plen = 0;
+ }
+
+ /*
+ * Perform Pad Length adjustments
+ */
+ if (plen) {
+ if (KB_LEN(ml) >= plen) {
+ /*
+ * All pad bytes in last buffer
+ */
+ KB_TAILADJ(ml, -plen);
+ } else {
+ /*
+ * Pad bytes split between buffers
+ */
+ plen -= KB_LEN(ml);
+ if ((mn == NULL) || (KB_LEN(mn) < plen))
+ goto badpdu;
+ KB_LEN(ml) = 0;
+ KB_TAILADJ(mn, -plen);
+ }
+ }
+
+ return (cp);
+
+badpdu:
+ /*
+ * This MAA Error is only supposed to be for a PDU length violation,
+ * but we use it for any PDU format error.
+ */
+ sscop_maa_error(sop, 'U');
+ sscop_pdu_print(sop, m, "badpdu received");
+ KB_FREEALL(m);
+ return (NULL);
+}
+