diff options
Diffstat (limited to 'sys/netatm/uni/sscop_upper.c')
-rw-r--r-- | sys/netatm/uni/sscop_upper.c | 412 |
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); +} + |