freebsd-skq/sys/netatm/uni/unisig_sigmgr_state.c
2002-03-20 08:00:54 +00:00

873 lines
18 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 3.0/3.1 Signalling Manager
* ----------------------------------------
*
* Signalling manager finite state machine
*
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/malloc.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_sigmgr.h>
#include <netatm/atm_stack.h>
#include <netatm/atm_pcb.h>
#include <netatm/atm_var.h>
#include <netatm/uni/uni.h>
#include <netatm/uni/unisig.h>
#include <netatm/uni/unisig_var.h>
#ifndef lint
__RCSID("@(#) $FreeBSD$");
#endif
/*
* Local functions
*/
static int unisig_sigmgr_invalid(struct unisig *, KBuffer *);
static int unisig_sigmgr_act01(struct unisig *, KBuffer *);
static int unisig_sigmgr_act02(struct unisig *, KBuffer *);
static int unisig_sigmgr_act03(struct unisig *, KBuffer *);
static int unisig_sigmgr_act04(struct unisig *, KBuffer *);
static int unisig_sigmgr_act05(struct unisig *, KBuffer *);
static int unisig_sigmgr_act06(struct unisig *, KBuffer *);
static int unisig_sigmgr_act07(struct unisig *, KBuffer *);
static int unisig_sigmgr_act08(struct unisig *, KBuffer *);
static int unisig_sigmgr_act09(struct unisig *, KBuffer *);
static int unisig_sigmgr_act10(struct unisig *, KBuffer *);
static int unisig_sigmgr_act11(struct unisig *, KBuffer *);
static int unisig_sigmgr_act12(struct unisig *, KBuffer *);
static int unisig_sigmgr_act13(struct unisig *, KBuffer *);
static int unisig_sigmgr_act14(struct unisig *, KBuffer *);
/*
* State table.
*/
static int sigmgr_state_table[10][7] = {
/* 0 1 2 3 4 5 */
{ 1, 0, 0, 0, 0 }, /* 0 - Time out */
{ 0, 0, 3, 5, 0 }, /* 1 - SSCF estab ind */
{ 0, 0, 3, 5, 0 }, /* 2 - SSCF estab cnf */
{ 0, 0, 4, 6, 0 }, /* 3 - SSCF release ind */
{ 0, 0, 0, 6, 0 }, /* 4 - SSCF release cnf */
{ 0, 0, 0, 7, 0 }, /* 5 - SSCF data ind */
{ 0, 0, 2, 2, 0 }, /* 6 - SSCF unit data ind */
{ 0, 0, 8, 8, 8 }, /* 7 - Call cleared */
{ 14, 14, 14, 14, 0 }, /* 8 - Detach */
{ 13, 13, 0, 0, 0 } /* 9 - Address set */
};
/*
* Action vector
*/
#define MAX_ACTION 15
static int (*unisig_sigmgr_act_vec[MAX_ACTION])
(struct unisig *, KBuffer *) = {
unisig_sigmgr_invalid,
unisig_sigmgr_act01,
unisig_sigmgr_act02,
unisig_sigmgr_act03,
unisig_sigmgr_act04,
unisig_sigmgr_act05,
unisig_sigmgr_act06,
unisig_sigmgr_act07,
unisig_sigmgr_act08,
unisig_sigmgr_act09,
unisig_sigmgr_act10,
unisig_sigmgr_act11,
unisig_sigmgr_act12,
unisig_sigmgr_act13,
unisig_sigmgr_act14
};
/*
* ATM endpoint for UNI signalling channel
*/
static Atm_endpoint unisig_endpt = {
NULL, /* ep_next */
ENDPT_UNI_SIG, /* ep_id */
NULL, /* ep_ioctl */
unisig_getname, /* ep_getname */
unisig_connected, /* ep_connected */
unisig_cleared, /* ep_cleared */
NULL, /* ep_incoming */
NULL, /* ep_addparty */
NULL, /* ep_dropparty */
NULL, /* ep_cpcs_ctl */
NULL, /* ep_cpcs_data */
unisig_saal_ctl, /* ep_saal_ctl */
unisig_saal_data, /* ep_saal_data */
NULL, /* ep_sscop_ctl */
NULL /* ep_sscop_data */
};
/*
* ATM connection attributes for UNI signalling channel
*/
static Atm_attributes unisig_attr = {
NULL, /* nif */
CMAPI_SAAL, /* api */
UNI_VERS_3_0, /* api_init */
0, /* headin */
0, /* headout */
{ /* aal */
T_ATM_PRESENT, /* aal.tag */
ATM_AAL5 /* aal.aal_type */
},
{ /* traffic */
T_ATM_PRESENT, /* traffic.tag */
{ /* traffic.v */
{ /* traffic.v.forward */
T_ATM_ABSENT, /* PCR_high */
0, /* PCR_all */
T_ATM_ABSENT, /* SCR_high */
T_ATM_ABSENT, /* SCR_all */
T_ATM_ABSENT, /* MBS_high */
T_ATM_ABSENT, /* MBS_all */
T_NO, /* tagging */
},
{ /* traffic.v.backward */
T_ATM_ABSENT, /* PCR_high */
0, /* PCR_all */
T_ATM_ABSENT, /* SCR_high */
T_ATM_ABSENT, /* SCR_all */
T_ATM_ABSENT, /* MBS_high */
T_ATM_ABSENT, /* MBS_all */
T_NO, /* tagging */
},
T_YES, /* best_effort */
}
},
{ /* bearer */
T_ATM_PRESENT, /* bearer.tag */
{ /* bearer.v */
T_ATM_CLASS_X, /* class */
T_ATM_NULL, /* traffic_type */
T_ATM_NO_END_TO_END, /* timing_req */
T_NO, /* clipping */
T_ATM_1_TO_1, /* conn_conf */
}
},
{ /* bhli */
T_ATM_ABSENT, /* bhli.tag */
},
{ /* blli */
T_ATM_ABSENT, /* blli.tag_l2 */
T_ATM_ABSENT, /* blli.tag_l3 */
},
{ /* llc */
T_ATM_ABSENT, /* llc.tag */
},
{ /* called */
T_ATM_PRESENT, /* called.tag */
},
{ /* calling */
T_ATM_ABSENT, /* calling.tag */
},
{ /* qos */
T_ATM_PRESENT, /* qos.tag */
{ /* qos.v */
T_ATM_NETWORK_CODING, /* coding_standard */
{ /* qos.v.forward */
T_ATM_QOS_CLASS_0, /* class */
},
{ /* qos.v.backward */
T_ATM_QOS_CLASS_0, /* class */
}
}
},
{ /* transit */
T_ATM_ABSENT, /* transit.tag */
},
{ /* cause */
T_ATM_ABSENT, /* cause.tag */
}
};
/*
* Finite state machine for the UNISIG signalling manager
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* event indication of the event to be processed
* m pointer to a buffer with a message (optional)
*
* Returns:
* 0 success
* errno error encountered
*
*/
int
unisig_sigmgr_state(usp, event, m)
struct unisig *usp;
int event;
KBuffer *m;
{
int action, err = 0;
/*
* Cancel any signalling manager timer
*/
UNISIG_CANCEL(usp);
/*
* Select an action based on the incoming event and
* the signalling manager's state
*/
action = sigmgr_state_table[event][usp->us_state];
ATM_DEBUG4("unisig_sigmgr_state: usp=%p, state=%d, event=%d, action=%d\n",
usp, usp->us_state, event, action);
if (action >= MAX_ACTION || action < 0) {
panic("unisig_sigmgr_state: invalid action\n");
}
/*
* Perform the requested action
*/
err = unisig_sigmgr_act_vec[action](usp, m);
return(err);
}
/*
* Signalling manager state machine action 0
*
* Invalid action
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_invalid(usp, m)
struct unisig *usp;
KBuffer *m;
{
log(LOG_ERR, "unisig_sigmgr_state: unexpected action\n");
if (m)
KB_FREEALL(m);
return(0);
}
/*
* Signalling manager state machine action 1
*
* The kickoff timer has expired at attach time; go to
* UNISIG_ADDR_WAIT state.
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act01(usp, m)
struct unisig *usp;
KBuffer *m;
{
/*
* Set the new state
*/
usp->us_state = UNISIG_ADDR_WAIT;
return(0);
}
/*
* Signalling manager state machine action 2
*
* Ignore the event
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act02(usp, m)
struct unisig *usp;
KBuffer *m;
{
/*
* Ignore event, discard message if present
*/
if (m)
KB_FREEALL(m);
return(0);
}
/*
* Signalling manager state machine action 3
*
* SSCF session on signalling channel has come up
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act03(usp, m)
struct unisig *usp;
KBuffer *m;
{
struct unisig_vccb *uvp, *vnext;
/*
* Log the activation
*/
log(LOG_INFO, "unisig: signalling channel active\n");
/*
* Go to ACTIVE state
*/
usp->us_state = UNISIG_ACTIVE;
/*
* Notify the VC state machine that the channel is up
*/
for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
uvp; uvp = vnext) {
vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
(void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB,
(struct unisig_msg *) 0);
}
return(0);
}
/*
* Signalling manager state machine action 4
*
* A SSCF release indication was received. Try to establish an
* SSCF session on the signalling PVC.
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act04(usp, m)
struct unisig *usp;
KBuffer *m;
{
int err;
/*
* Try to establish an SSCF session.
*/
err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ,
usp->us_conn,
(void *)0);
if (err)
panic("unisig_sigmgr_act04: SSCF_UNI_ESTABLISH_REQ");
return(0);
}
/*
* Signalling manager state machine action 5
*
* SSCF session on signalling channel has been reset
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act05(usp, m)
struct unisig *usp;
KBuffer *m;
{
struct unisig_vccb *uvp, *vnext;
/*
* Log the reset
*/
log(LOG_INFO, "unisig: signalling channel reset\n");
/*
* Notify the VC state machine of the reset
*/
for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
uvp; uvp = vnext) {
vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
(void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB,
(struct unisig_msg *) 0);
}
return(0);
}
/*
* Signalling manager state machine action 6
*
* SSCF session on signalling channel has been lost
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act06(usp, m)
struct unisig *usp;
KBuffer *m;
{
struct unisig_vccb *uvp, *vnext;
/*
* Log the fact that the session has been lost
*/
log(LOG_INFO, "unisig: signalling channel SSCF session lost\n");
/*
* Notify the VC state machine of the loss
*/
for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
uvp; uvp = vnext) {
vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
(void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_FAIL,
(struct unisig_msg *) 0);
}
/*
* Try to restart the SSCF session
*/
(void) unisig_sigmgr_act04(usp, (KBuffer *) 0);
/*
* Go to INIT state
*/
usp->us_state = UNISIG_INIT;
return(0);
}
/*
* Signalling manager state machine action 7
*
* A Q.2931 signalling message has been received
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act07(usp, m)
struct unisig *usp;
KBuffer *m;
{
int err;
/*
* Pass the Q.2931 signalling message on
* to the VC state machine
*/
err = unisig_rcv_msg(usp, m);
return(err);
}
/*
* Signalling manager state machine action 8
*
* Process a CALL_CLOSED event for the signalling PVC
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act08(usp, m)
struct unisig *usp;
KBuffer *m;
{
/*
* Signalling manager is now incommunicado
*/
if (usp->us_state != UNISIG_DETACH) {
/*
* Log an error and set the state to NULL if
* we're not detaching
*/
log(LOG_ERR, "unisig: signalling channel closed\n");
usp->us_state = UNISIG_NULL;
}
usp->us_conn = 0;
return(0);
}
/*
* Signalling manager state machine action 9
*
* Not used
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act09(usp, m)
struct unisig *usp;
KBuffer *m;
{
log(LOG_ERR, "unisig_sigmgr_act09: unexpected action\n");
if (m)
KB_FREEALL(m);
return (0);
}
/*
* Signalling manager state machine action 10
*
* Not used
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act10(usp, m)
struct unisig *usp;
KBuffer *m;
{
return(0);
}
/*
* Signalling manager state machine action 11
*
* Not used
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act11(usp, m)
struct unisig *usp;
KBuffer *m;
{
log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n");
if (m)
KB_FREEALL(m);
return(0);
}
/*
* Signalling manager state machine action 12
*
* Not used
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act12(usp, m)
struct unisig *usp;
KBuffer *m;
{
log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n");
if (m)
KB_FREEALL(m);
return(0);
}
/*
* Signalling manager state machine action 13
*
* NSAP prefix has been set
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act13(usp, m)
struct unisig *usp;
KBuffer *m;
{
int err;
Atm_addr_pvc *pvcp;
/*
* Set UNI signalling channel connection attributes
*/
if (usp->us_proto == ATM_SIG_UNI30)
unisig_attr.api_init = UNI_VERS_3_0;
else
unisig_attr.api_init = UNI_VERS_3_1;
unisig_attr.nif = usp->us_pif->pif_nif;
unisig_attr.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU;
unisig_attr.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU;
unisig_attr.aal.v.aal5.SSCS_type = T_ATM_SSCS_SSCOP_REL;
unisig_attr.called.tag = T_ATM_PRESENT;
unisig_attr.called.addr.address_format = T_ATM_PVC_ADDR;
unisig_attr.called.addr.address_length = sizeof(Atm_addr_pvc);
pvcp = (Atm_addr_pvc *)unisig_attr.called.addr.address;
ATM_PVC_SET_VPI(pvcp, UNISIG_SIG_VPI);
ATM_PVC_SET_VCI(pvcp, UNISIG_SIG_VCI);
unisig_attr.called.subaddr.address_format = T_ATM_ABSENT;
unisig_attr.called.subaddr.address_length = 0;
unisig_attr.traffic.v.forward.PCR_all_traffic =
usp->us_pif->pif_pcr;
unisig_attr.traffic.v.backward.PCR_all_traffic =
usp->us_pif->pif_pcr;
/*
* Create UNISIG signalling channel
*/
err = atm_cm_connect(&unisig_endpt, usp, &unisig_attr,
&usp->us_conn);
if (err) {
return(err);
}
/*
* Establish the SSCF session
*/
err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ,
usp->us_conn,
(void *)0);
if (err)
panic("unisig_sigmgr_act13: SSCF_UNI_ESTABLISH_REQ");
/*
* Set the new state
*/
usp->us_state = UNISIG_INIT;
return(0);
}
/*
* Signalling manager state machine action 14
*
* Process a detach event
*
* Arguments:
* usp pointer to the UNISIG protocol control block
* m buffer pointer (may be NULL)
*
* Returns:
* 0 success
* errno error encountered
*
*/
static int
unisig_sigmgr_act14(usp, m)
struct unisig *usp;
KBuffer *m;
{
int err;
struct unisig_vccb *sig_vccb, *uvp, *vnext;
struct atm_pif *pip;
struct t_atm_cause cause;
/*
* Locate the signalling channel's VCCB
*/
sig_vccb = (struct unisig_vccb *)0;
if (usp->us_conn && usp->us_conn->co_connvc)
sig_vccb = (struct unisig_vccb *)
usp->us_conn->co_connvc->cvc_vcc;
/*
* Terminate all of our VCCs
*/
for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
uvp; uvp = vnext) {
vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
/*
* Don't close the signalling VCC yet
*/
if (uvp == sig_vccb)
continue;
/*
* Close VCC and notify owner
*/
err = unisig_clear_vcc(usp, uvp,
T_ATM_CAUSE_NORMAL_CALL_CLEARING);
}
/*
* Close the signalling channel
*/
if (usp->us_conn) {
cause.coding_standard = T_ATM_ITU_CODING;
cause.coding_standard = T_ATM_LOC_USER;
cause.coding_standard = T_ATM_CAUSE_UNSPECIFIED_NORMAL;
err = atm_cm_release(usp->us_conn, &cause);
if (err)
panic("unisig_sigmgr_act14: close failed\n");
}
/*
* Get rid of protocol instance if there are no VCCs queued
*/
pip = usp->us_pif;
if (Q_HEAD(usp->us_vccq, struct vccb) == NULL &&
pip->pif_sigmgr) {
struct sigmgr *smp = pip->pif_sigmgr;
int s = splimp();
pip->pif_sigmgr = NULL;
pip->pif_siginst = NULL;
(void) splx(s);
UNLINK((struct siginst *)usp, struct siginst,
smp->sm_prinst, si_next);
KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
} else {
/*
* Otherwise, set new signalling manager state and
* wait for protocol instance to be freed during
* unisig_free processing for the last queued VCC
*/
usp->us_state = UNISIG_DETACH;
}
return (0);
}