freebsd-dev/sys/netatm/uni/sscop.c
2003-02-19 05:47:46 +00:00

419 lines
7.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.
*
* @(#) $FreeBSD$
*
*/
/*
* ATM Forum UNI Support
* ---------------------
*
* Service Specific Connection Oriented Protocol (SSCOP)
*
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/syslog.h>
#include <net/if.h>
#include <netatm/port.h>
#include <netatm/queue.h>
#include <netatm/atm.h>
#include <netatm/atm_sys.h>
#include <netatm/atm_sap.h>
#include <netatm/atm_cm.h>
#include <netatm/atm_if.h>
#include <netatm/atm_vc.h>
#include <netatm/atm_stack.h>
#include <netatm/atm_pcb.h>
#include <netatm/atm_var.h>
#include <netatm/uni/sscop.h>
#include <netatm/uni/sscop_misc.h>
#include <netatm/uni/sscop_pdu.h>
#include <netatm/uni/sscop_var.h>
#include <vm/uma.h>
#ifndef lint
__RCSID("@(#) $FreeBSD$");
#endif
/*
* Global variables
*/
int sscop_vccnt = 0;
struct sscop *sscop_head = NULL;
struct sscop_stat sscop_stat = {0};
struct atm_time sscop_timer = {0, 0};
uma_zone_t sscop_zone;
/*
* Local functions
*/
static int sscop_inst(struct stack_defn **, Atm_connvc *);
/*
* Local variables
*/
static struct stack_defn sscop_service = {
NULL,
SAP_SSCOP,
0,
sscop_inst,
sscop_lower,
sscop_upper,
0
};
static struct t_atm_cause sscop_cause = {
T_ATM_ITU_CODING,
T_ATM_LOC_USER,
T_ATM_CAUSE_TEMPORARY_FAILURE,
{0, 0, 0, 0}
};
static u_char sscop_maa_log[MAA_ERROR_COUNT] = {
1, /* A */
1, /* B */
1, /* C */
1, /* D */
1, /* E */
1, /* F */
1, /* G */
1, /* H */
1, /* I */
1, /* J */
1, /* K */
1, /* L */
1, /* M */
0, /* N */
0, /* O */
0, /* P */
1, /* Q */
1, /* R */
1, /* S */
1, /* T */
1, /* U */
0, /* V */
0, /* W */
0, /* X */
1 /* INVAL */
};
/*
* Initialize SSCOP processing
*
* This will be called during module loading. We will register our stack
* service and wait for someone to talk to us.
*
* Arguments:
* none
*
* Returns:
* 0 initialization was successful
* errno initialization failed - reason indicated
*
*/
int
sscop_start()
{
int err = 0;
sscop_zone = uma_zcreate("sscop", sizeof(struct sscop), NULL, NULL,
NULL, NULL, UMA_ALIGN_PTR, 0);
if (sscop_zone == NULL)
panic("sscop_start: uma_zcreate");
uma_zone_set_max(sscop_zone, 100);
/*
* Register stack service
*/
if ((err = atm_stack_register(&sscop_service)) != 0)
goto done;
/*
* Start up timer
*/
atm_timeout(&sscop_timer, ATM_HZ/SSCOP_HZ, sscop_timeout);
done:
return (err);
}
/*
* Terminate SSCOP processing
*
* This will be called just prior to unloading the module from memory. All
* signalling instances should have been terminated by now, so we just free
* up all of our resources.
*
* Called at splnet.
*
* Arguments:
* none
*
* Returns:
* 0 termination was successful
* errno termination failed - reason indicated
*
*/
int
sscop_stop()
{
int err = 0;
/*
* Any connections still exist?? If so, we can't bail just yet.
*/
if (sscop_vccnt)
return (EBUSY);
/*
* Stop our timer
*/
(void)atm_untimeout(&sscop_timer);
/*
* Deregister the stack service
*/
(void)atm_stack_deregister(&sscop_service);
uma_zdestroy(sscop_zone);
return (err);
}
/*
* SSCOP Stack Instantiation
*
* Called at splnet.
*
* Arguments:
* ssp pointer to array of stack definition pointers for connection
* ssp[0] points to upper layer's stack service definition
* ssp[1] points to this layer's stack service definition
* ssp[2] points to lower layer's stack service definition
* cvp pointer to connection vcc for this stack
*
* Returns:
* 0 instantiation successful
* errno instantiation failed - reason indicated
*
*/
static int
sscop_inst(ssp, cvp)
struct stack_defn **ssp;
Atm_connvc *cvp;
{
struct stack_defn *sdp_up = ssp[0],
*sdp_me = ssp[1],
*sdp_low = ssp[2];
struct sscop *sop;
int err;
ATM_DEBUG2("sscop_inst: ssp=%p, cvp=%p\n", ssp, cvp);
/*
* Validate lower SAP
*/
if ((sdp_low->sd_sap & SAP_CLASS_MASK) != SAP_CPCS)
return (EINVAL);
/*
* Allocate our control block
*/
sop = uma_zalloc(sscop_zone, M_WAITOK);
if (sop == NULL)
return (ENOMEM);
sop->so_state = SOS_INST;
sop->so_connvc = cvp;
sop->so_toku = sdp_up->sd_toku;
sop->so_upper = sdp_up->sd_upper;
/*
* Store my token into service definition
*/
sdp_me->sd_toku = sop;
/*
* Update and save input buffer headroom
*/
HEADIN(cvp, sizeof(struct pdu_hdr), 0);
/* sop->so_headin = cvp->cvc_attr.headin; */
/*
* Pass instantiation down the stack
*/
err = sdp_low->sd_inst(ssp + 1, cvp);
if (err) {
/*
* Lower layer instantiation failed, free our resources
*/
uma_zfree(sscop_zone, sop);
return (err);
}
/*
* Link in connection block
*/
LINK2TAIL(sop, struct sscop, sscop_head, so_next);
sscop_vccnt++;
sscop_stat.sos_connects++;
/*
* Save and update output buffer headroom
*/
sop->so_headout = cvp->cvc_attr.headout;
HEADOUT(cvp, sizeof(struct pdu_hdr), 0);
/*
* Save lower layer's interface info
*/
sop->so_lower = sdp_low->sd_lower;
sop->so_tokl = sdp_low->sd_toku;
/*
* Initialize version (until INIT received)
*/
sop->so_vers = SSCOP_VERS_Q2110;
return (0);
}
/*
* Report Management Error
*
* Called to report an error to the layer management entity.
*
* Arguments:
* sop pointer to sscop control block
* code error code
*
* Returns:
* none
*
*/
void
sscop_maa_error(sop, code)
struct sscop *sop;
int code;
{
int i;
/*
* Validate error code
*/
if ((code < MAA_ERROR_MIN) ||
(code > MAA_ERROR_MAX))
code = MAA_ERROR_INVAL;
i = code - MAA_ERROR_MIN;
/*
* Bump statistics counters
*/
sscop_stat.sos_maa_error[i]++;
/*
* Log error message
*/
if (sscop_maa_log[i] != 0) {
struct vccb *vcp = sop->so_connvc->cvc_vcc;
struct atm_pif *pip = vcp->vc_pif;
log(LOG_ERR,
"sscop_maa_error: intf=%s%d vpi=%d vci=%d code=%c state=%d\n",
pip->pif_name, pip->pif_unit,
vcp->vc_vpi, vcp->vc_vci, code, sop->so_state);
}
}
/*
* Abort an SSCOP connection
*
* Called when an unrecoverable or "should never happen" error occurs.
* We log a message, send an END PDU to our peer and request the signalling
* manager to abort the connection.
*
* Arguments:
* sop pointer to sscop control block
* msg pointer to error message
*
* Returns:
* none
*
*/
void
sscop_abort(sop, msg)
struct sscop *sop;
char *msg;
{
Atm_connvc *cvp = sop->so_connvc;
/*
* Log and count error
*/
log(LOG_ERR, "%s", msg);
sscop_stat.sos_aborts++;
/*
* Send an END PDU as a courtesy to peer
*/
(void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
/*
* Set termination state
*/
sop->so_state = SOS_TERM;
/*
* Flush all of our queues
*/
sscop_xmit_drain(sop);
sscop_rcvr_drain(sop);
/*
* Tell Connection Manager to abort this connection
*/
(void) atm_cm_abort(cvp, &sscop_cause);
}