diff options
Diffstat (limited to 'sys/netatm/uni/unisig_sigmgr_state.c')
-rw-r--r-- | sys/netatm/uni/unisig_sigmgr_state.c | 860 |
1 files changed, 860 insertions, 0 deletions
diff --git a/sys/netatm/uni/unisig_sigmgr_state.c b/sys/netatm/uni/unisig_sigmgr_state.c new file mode 100644 index 0000000..2fbbfca --- /dev/null +++ b/sys/netatm/uni/unisig_sigmgr_state.c @@ -0,0 +1,860 @@ +/* + * + * =================================== + * 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: unisig_sigmgr_state.c,v 1.10 1998/08/26 23:29:24 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Signalling manager finite state machine + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_sigmgr_state.c,v 1.10 1998/08/26 23:29:24 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> +#include <netatm/uni/unisig_mbuf.h> +#include <netatm/uni/unisig_decode.h> + +#include <netatm/uni/sscf_uni.h> + + +/* + * Local functions + */ +static int unisig_sigmgr_invalid __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act01 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act02 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act03 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act04 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act05 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act06 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act07 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act08 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act09 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act10 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act11 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act12 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act13 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act14 __P((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]) + __P((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=0x%x, state=%d, event=%d, action=%d\n", + (u_int) 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); + } + + /* + * Set the signalling manager state + */ + usp->us_state = UNISIG_DETACH; + + /* + * 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); + } + + /* + * Otherwise, wait for protocol instance to be freed + * during unisig_free processing for the last queued VCC + */ + + return (0); +} |