1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-25 11:37:56 +00:00
freebsd/sys/netatm/uni/sscop_upper.c
Poul-Henning Kamp 1820df7a2d 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).
1998-09-15 08:23:17 +00:00

413 lines
9.7 KiB
C

/*
*
* ===================================
* HARP | Host ATM Research Platform
* ===================================
*
*
* This Host ATM Research Platform ("HARP") file (the "Software") is
* made available by Network Computing Services, Inc. ("NetworkCS")
* "AS IS". NetworkCS does not provide maintenance, improvements or
* support of any kind.
*
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
* In no event shall NetworkCS be responsible for any damages, including
* but not limited to consequential damages, arising from or relating to
* any use of the Software or related support.
*
* Copyright 1994-1998 Network Computing Services, Inc.
*
* Copies of this Software may be made, however, the above copyright
* notice must be reproduced on all copies.
*
* @(#) $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);
}