diff options
Diffstat (limited to 'sys/netatm/spans/spans_msg.c')
-rw-r--r-- | sys/netatm/spans/spans_msg.c | 1633 |
1 files changed, 1633 insertions, 0 deletions
diff --git a/sys/netatm/spans/spans_msg.c b/sys/netatm/spans/spans_msg.c new file mode 100644 index 000000000000..0dc5df9d4416 --- /dev/null +++ b/sys/netatm/spans/spans_msg.c @@ -0,0 +1,1633 @@ +/* + * + * =================================== + * 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: spans_msg.c,v 1.8 1998/08/26 23:29:09 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS signalling message processing. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_msg.c,v 1.8 1998/08/26 23:29:09 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <rpc/rpc.h> +#include "spans_xdr.h" +#include <netatm/spans/spans_var.h> + +/* + * External functions + */ +void xdrmbuf_init __P((XDR *, KBuffer *, enum xdr_op)); + +/* + * Local functions + */ +static void spans_host_link __P((struct spans *, long)); +static void spans_status_ind __P((struct spans *, spans_msg *)); +static void spans_status_rsp __P((struct spans *, spans_msg *)); +static void spans_open_req __P((struct spans *, spans_msg *)); +static void spans_open_rsp __P((struct spans *, spans_msg *)); +static void spans_close_req __P((struct spans *, spans_msg *)); +static void spans_close_rsp __P((struct spans *, spans_msg *)); +static void spans_multi_req __P((struct spans *, spans_msg *)); +static void spans_add_req __P((struct spans *, spans_msg *)); +static void spans_join_req __P((struct spans *, spans_msg *)); +static void spans_leave_req __P((struct spans *, spans_msg *)); +static void spans_vcir_ind __P((struct spans *, spans_msg *)); +static void spans_query_req __P((struct spans *, spans_msg *)); + + +/* + * Called to set status when a status message comes in from a host + * connected back-to-back with us. Check the epoch and, if it has + * changed, set the appropriate state and save updated state + * information. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * host_epoch epoch of host at far end of link + * + * Returns: + * 0 message sent OK + * errno error encountered + * + */ +static void +spans_host_link(spp, host_epoch) + struct spans *spp; + long host_epoch; +{ + struct atm_pif *pip = spp->sp_pif; + + /* + * There's a host at the other end of the link. If its + * epoch has changed, clean up our state and save the + * new information. + */ + if (spp->sp_s_epoch != host_epoch) { + spp->sp_s_epoch = host_epoch; + spans_switch_reset(spp, SPANS_UNI_UP); + spp->sp_addr.address_format = T_ATM_SPANS_ADDR; + spp->sp_addr.address_length = sizeof(spans_addr); + KM_COPY(&pip->pif_macaddr.ma_data[2], + &spp->sp_addr.address[4], + 4); + log(LOG_INFO, + "spans: using SPANS address of %s on interface %s%d\n", + spans_addr_print((spans_addr *)spp->sp_addr.address), + pip->pif_name, + pip->pif_unit); + } +} + +/* + * Send a SPANS signalling message + * + * Called to send a SPANS message. This routine gets a buffer, performs + * XDR processing, and hands the message to the AAL for transmission. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to status message + * + * Returns: + * 0 message sent OK + * errno error encountered + * + */ +int +spans_send_msg(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + int err = 0; + KBuffer *m; + XDR xdrs; + +#ifdef NOTDEF + ATM_DEBUG2("spans_send_msg: msg=0x%x, type=%d\n", msg, + msg->sm_type); + if (msg->sm_type != SPANS_STAT_REQ && + msg->sm_type != SPANS_STAT_IND && + msg->sm_type != SPANS_STAT_RSP) { + printf("spans_send_msg: sending "); + spans_print_msg(msg); + } +#endif + + /* + * If the signalling channel has been closed, don't do anything + */ + if (!spp->sp_conn) + return(ECONNABORTED); + + /* + * Get a buffer + */ + KB_ALLOCPKT(m, sizeof(spans_msg), KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) { + /* No buffer available */ + return(ENOBUFS); + } + + /* + * Convert message to network order + */ + KB_LEN(m) = KB_BFRLEN(m); + xdrmbuf_init(&xdrs, m, XDR_ENCODE); + if (!xdr_spans_msg(&xdrs, msg)) { + log(LOG_ERR, "spans_send_msg: XDR encode failed\n"); + KB_LEN(m) = XDR_GETPOS(&xdrs); + spans_dump_buffer(m); + KB_FREEALL(m); + return(EIO); + } + KB_LEN(m) = XDR_GETPOS(&xdrs); + + /* + * Send the message + */ + err = atm_cm_cpcs_data(spp->sp_conn, m); + if (err) + KB_FREEALL(m); + + return(err); +} + + +/* + * Send an open request + * + * Build and send an open request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * svp pointer to VCCB for which the request is being sent + * + * Returns: + * none + * + */ +int +spans_send_open_req(spp, svp) + struct spans *spp; + struct spans_vccb *svp; +{ + spans_msg *req; + int err = 0; + + ATM_DEBUG1("spans_send_open_req: svp=0x%x\n", svp); + + /* + * Get memory for a request message + */ + req = (spans_msg *)atm_allocate(&spans_msgpool); + if (req == NULL) { + err = ENOBUFS; + goto done; + } + + /* + * Fill in the request + */ + req->sm_vers = SPANS_VERS_1_0; + req->sm_type = SPANS_OPEN_REQ; + req->sm_open_req.opreq_conn = svp->sv_conn; + req->sm_open_req.opreq_aal = svp->sv_spans_aal; + req->sm_open_req.opreq_desrsrc = svp->sv_spans_qos; + req->sm_open_req.opreq_minrsrc.rsc_peak = 0; + req->sm_open_req.opreq_minrsrc.rsc_mean = 0; + req->sm_open_req.opreq_minrsrc.rsc_burst = 0; + req->sm_open_req.opreq_vpvc.vpf_valid = FALSE; + + /* + * Send the request + */ + err = spans_send_msg(spp, req); + atm_free(req); + +done: + return(err); +} + + +/* + * Send an open response + * + * Build and send a response to an open request or open indication. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * svp pointer to VCCB for which the response is being sent + * result result code to include in the response + * + * Returns: + * none + * + */ +int +spans_send_open_rsp(spp, svp, result) + struct spans *spp; + struct spans_vccb *svp; + spans_result result; +{ + spans_msg *rsp; + int rc; + + ATM_DEBUG2("spans_send_open_rsp: svp=0x%x, result=%d\n", svp, + result); + + /* + * Get memory for a response message + */ + rsp = (spans_msg *)atm_allocate(&spans_msgpool); + if (rsp == NULL) + return(ENOBUFS); + + /* + * Fill in the response + */ + rsp->sm_vers = SPANS_VERS_1_0; + rsp->sm_type = SPANS_OPEN_RSP; + rsp->sm_open_rsp.oprsp_conn = svp->sv_conn; + rsp->sm_open_rsp.oprsp_result = result; + rsp->sm_open_rsp.oprsp_rsrc = svp->sv_spans_qos; + rsp->sm_open_rsp.oprsp_vpvc = + SPANS_PACK_VPIVCI(svp->sv_vpi, svp->sv_vci); + + /* + * Send the response + */ + rc = spans_send_msg(spp, rsp); + atm_free(rsp); + + return(rc); +} + + +/* + * Send a close request + * + * Called to send a close request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * svp pointer to VCCB for which the close is being sent + * + * Returns: + * none + * + */ +int +spans_send_close_req(spp, svp) + struct spans *spp; + struct spans_vccb *svp; +{ + spans_msg *req; + int err = 0; + + ATM_DEBUG1("spans_send_close_req: svp=0x%x\n", svp); + + /* + * Get memory for a close request + */ + req = (spans_msg *)atm_allocate(&spans_msgpool); + if (req == NULL) { + err = ENOBUFS; + goto done; + } + + /* + * Fill in the request + */ + req->sm_vers = SPANS_VERS_1_0; + if (svp->sv_type & VCC_OUT) { + req->sm_type = SPANS_CLOSE_REQ; + } else if (svp->sv_type & VCC_IN) { + req->sm_type = SPANS_RCLOSE_REQ; + } else { + err = EINVAL; + ATM_DEBUG1( + "spans_send_close_req: invalid VCCB type 0x%x\n", + svp->sv_type); + goto done; + } + req->sm_close_req.clreq_conn = svp->sv_conn; + + /* + * Send the close request + */ + err = spans_send_msg(spp, req); + +done: + if (req) + atm_free(req); + + return(err); +} + + + +/* + * Process a status indication or status request + * + * Called when a status indication or status request is received. + * Processing will be based on the current SPANS state. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the status message + * + * Returns: + * none + * + */ +static void +spans_status_ind(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_msg *rsp_msg; + struct atm_pif *pip = spp->sp_pif; + + /* + * Reset the probe count. + */ + spp->sp_probe_ct = 0; + + switch (spp->sp_state) { + case SPANS_PROBE: + /* + * Interface just came up, update signalling state + */ + spp->sp_state = SPANS_ACTIVE; + break; + + case SPANS_ACTIVE: + break; + + default: + log(LOG_ERR, "spans: received status msg in state %d\n", + spp->sp_state); + } + + /* + * Process the message + */ + switch (msg->sm_type) { + + case SPANS_STAT_REQ: + /* + * Handle a request from a host at the other end of + * the link. + */ + spans_host_link(spp, msg->sm_stat_req.streq_es_epoch); + break; + + case SPANS_STAT_IND: + + /* + * There's a switch at the other end of the link. If + * its epoch has changed, reset the SPANS state and save + * the new information. + */ + if (spp->sp_s_epoch != + msg->sm_stat_ind.stind_sw_epoch) { + spans_switch_reset(spp, SPANS_UNI_UP); + spp->sp_s_epoch = + msg->sm_stat_ind.stind_sw_epoch; + spp->sp_addr.address_format = T_ATM_SPANS_ADDR; + spp->sp_addr.address_length = + sizeof(spans_addr); + spans_addr_copy(&msg->sm_stat_ind.stind_es_addr, + spp->sp_addr.address); + log(LOG_INFO, + "spans: received SPANS address %s from switch for interface %s%d\n", + spans_addr_print((spans_addr *)spp->sp_addr.address), + pip->pif_name, + pip->pif_unit); + } + break; + + default: + ATM_DEBUG1("spans_status_ind: Invalid message type %d\n", + msg->sm_type); + return; + } + + /* + * Respond to the status request or indication with a + * status response + */ + rsp_msg = (spans_msg *)atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_STAT_RSP; + rsp_msg->sm_stat_rsp.strsp_es_epoch = spp->sp_h_epoch; + spans_addr_copy(spp->sp_addr.address, + &rsp_msg->sm_stat_rsp.strsp_es_addr); + spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + + +/* + * Process a status response + * + * Called when a status response is received. + * Processing will be based on the current SPANS state. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the status response message + * + * Returns: + * none + * + */ +static void +spans_status_rsp(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + + /* + * Reset the probe count. + */ + spp->sp_probe_ct = 0; + + switch (spp->sp_state) { + case SPANS_PROBE: + /* + * Interface just came up, update signalling state + */ + spp->sp_state = SPANS_ACTIVE; + break; + + case SPANS_ACTIVE: + break; + + default: + log(LOG_ERR, "spans: received status msg in state %d\n", + spp->sp_state); + } + + /* + * Process the message + */ + spans_host_link(spp, msg->sm_stat_req.streq_es_epoch); +} + + +/* + * Process an open indication or open request + * + * Called when an open indication or open request is received. + * Processing will be based on the state of the requested connection. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the open message + * + * Returns: + * none + * + */ +static void +spans_open_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_result result = SPANS_OK; + spans_msg *rsp_msg; + struct spans_vccb *svp = NULL; + struct atm_pif *pip; + spans_vpvc vpvc; + int err = 0, vpi, vci; + Aal_t aal; + Atm_attributes call_attrs; + + ATM_DEBUG2("spans_open_req: spp=0x%x, msg=0x%x\n", spp, msg); + + /* + * See if the connection is new + */ + if (svp = spans_find_conn(spp, &msg->sm_open_req.opreq_conn)) { + /* + * We already have a VCCB that matches the connection in + * the request + */ + vpi = SPANS_EXTRACT_VPI(msg->sm_open_req.opreq_vpvc.vpf_vpvc); + vci = SPANS_EXTRACT_VCI(msg->sm_open_req.opreq_vpvc.vpf_vpvc); + if (msg->sm_open_req.opreq_aal == svp->sv_spans_aal && + (!msg->sm_open_req.opreq_vpvc.vpf_valid || + (vpi == svp->sv_vpi && + vci == svp->sv_vci))) { + /* + * VCCB already exists, process depending on + * state + */ + switch (svp->sv_sstate) { + case SPANS_VC_R_POPEN: + /* I'm still thinking about it */ + return; + case SPANS_VC_OPEN: + /* Retransmit the open_rsp */ + break; + case SPANS_VC_POPEN: + case SPANS_VC_CLOSE: + case SPANS_VC_ABORT: + ATM_DEBUG0("spans_open_req: bad VCCB state\n"); + result = SPANS_FAIL; + break; + } + } else { + /* + * VCCB is for same connection, but other + * parameters don't match + */ + ATM_DEBUG0("spans_open_req: VCCB confusion\n"); + result = SPANS_FAIL; + } + svp = NULL; + goto response; + } + + /* + * Verify that the request is for our ATM addres + */ + if (spans_addr_cmp(spp->sp_addr.address, + &msg->sm_open_req.opreq_conn.con_dst)) { + ATM_DEBUG0("spans_open_req: bad destination\n"); + result = SPANS_BADDEST; + goto response; + } + + /* + * See if we recognize the specified AAL + */ + if (!spans_get_local_aal(msg->sm_open_req.opreq_aal, &aal)) { + ATM_DEBUG0("spans_open_req: bad AAL\n"); + result = SPANS_FAIL; + goto response; + } + + /* + * Should verify that we can handle requested connection QOS + */ + + /* + * Select a VPI/VCI for the new connection + */ + if (msg->sm_open_req.opreq_vpvc.vpf_valid) { + /* + * Requestor asked for a certain VPI/VCI. Make sure we + * aren't already using the pair that was asked for. + */ + vpi = SPANS_EXTRACT_VPI(msg->sm_open_req.opreq_vpvc.vpf_vpvc); + vci = SPANS_EXTRACT_VCI(msg->sm_open_req.opreq_vpvc.vpf_vpvc); + if (spans_find_vpvc(spp, vci, vpi, VCC_IN)) { + ATM_DEBUG0("spans_open_req: VPI, VCI busy\n"); + result = SPANS_NOVPVC; + goto response; + } + vpvc = msg->sm_open_req.opreq_vpvc.vpf_vpvc; + } else { + /* + * Allocate a VPI/VCI for this end of the VCC + */ + vpvc = spans_alloc_vpvc(spp); + if (vpvc == 0) { + ATM_DEBUG0("spans_open_req: no VPI, VCI available\n"); + result = SPANS_NOVPVC; + goto response; + } + } + + /* + * Get a new VCCB for the connection + */ + svp = (struct spans_vccb *)atm_allocate(&spans_vcpool); + if (svp == NULL) { + ATM_DEBUG0("spans_open_req: VCCB pool empty\n"); + result = SPANS_NORSC; + goto response; + } + + /* + * Find the physical interface structure + */ + pip = spp->sp_pif; + + /* + * Fill in the VCCB fields that we can at this point + */ + svp->sv_type = VCC_SVC | VCC_IN; + svp->sv_proto = ATM_SIG_SPANS; + svp->sv_sstate = SPANS_VC_R_POPEN; + svp->sv_ustate = VCCU_POPEN; + svp->sv_pif = pip; + svp->sv_nif = pip->pif_nif; + svp->sv_conn = msg->sm_open_req.opreq_conn; + svp->sv_spans_qos = msg->sm_open_req.opreq_desrsrc; + svp->sv_spans_aal = msg->sm_open_req.opreq_aal; + svp->sv_tstamp = time_second; + + svp->sv_vpi = SPANS_EXTRACT_VPI(vpvc); + svp->sv_vci = SPANS_EXTRACT_VCI(vpvc); + + /* + * Put the VCCB on the SPANS queue + */ + ENQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq); + + /* + * Set up the ATM attributes block + */ + KM_ZERO(&call_attrs, sizeof(call_attrs)); + call_attrs.nif = svp->sv_nif; + call_attrs.api = CMAPI_CPCS; + + call_attrs.aal.tag = T_ATM_PRESENT; + call_attrs.aal.type = aal; + switch(aal) { + case ATM_AAL3_4: + call_attrs.aal.v.aal4.forward_max_SDU_size = + ATM_NIF_MTU; + call_attrs.aal.v.aal4.backward_max_SDU_size = + ATM_NIF_MTU; + call_attrs.aal.v.aal4.SSCS_type = + T_ATM_NULL; + call_attrs.aal.v.aal4.mid_low = 0; + call_attrs.aal.v.aal4.mid_high = 1023; + break; + case ATM_AAL5: + call_attrs.aal.v.aal5.forward_max_SDU_size = + ATM_NIF_MTU; + call_attrs.aal.v.aal5.backward_max_SDU_size = + ATM_NIF_MTU; + call_attrs.aal.v.aal5.SSCS_type = + T_ATM_NULL; + break; + } + + call_attrs.traffic.tag = T_ATM_PRESENT; + call_attrs.traffic.v.forward.PCR_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.forward.PCR_all_traffic = + msg->sm_open_req.opreq_desrsrc.rsc_peak * + 1000 / 53; + call_attrs.traffic.v.forward.SCR_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.forward.SCR_all_traffic = T_ATM_ABSENT; + call_attrs.traffic.v.forward.MBS_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.forward.MBS_all_traffic = T_ATM_ABSENT; + call_attrs.traffic.v.forward.tagging = T_NO; + call_attrs.traffic.v.backward.PCR_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.backward.PCR_all_traffic = + call_attrs.traffic.v.forward.PCR_all_traffic; + call_attrs.traffic.v.backward.SCR_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.backward.SCR_all_traffic = T_ATM_ABSENT; + call_attrs.traffic.v.backward.MBS_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.backward.MBS_all_traffic = T_ATM_ABSENT; + call_attrs.traffic.v.backward.tagging = T_NO; + call_attrs.traffic.v.best_effort = T_YES; + + call_attrs.bearer.tag = T_ATM_PRESENT; + call_attrs.bearer.v.bearer_class = T_ATM_CLASS_X; + call_attrs.bearer.v.traffic_type = T_ATM_NULL; + call_attrs.bearer.v.timing_requirements = T_ATM_NULL; + call_attrs.bearer.v.clipping_susceptibility = T_NO; + call_attrs.bearer.v.connection_configuration = T_ATM_1_TO_1; + + + call_attrs.bhli.tag = T_ATM_ABSENT; + call_attrs.blli.tag_l2 = T_ATM_ABSENT; + call_attrs.blli.tag_l3 = T_ATM_ABSENT; + call_attrs.llc.tag = T_ATM_ABSENT; + + call_attrs.called.tag = T_ATM_PRESENT; + spans_addr_copy(&msg->sm_open_req.opreq_conn.con_dst, + call_attrs.called.addr.address); + call_attrs.called.addr.address_format = T_ATM_SPANS_ADDR; + call_attrs.called.addr.address_length = sizeof(spans_addr); + call_attrs.called.subaddr.address_format = T_ATM_ABSENT; + call_attrs.called.subaddr.address_length = 0; + + call_attrs.calling.tag = T_ATM_PRESENT; + spans_addr_copy(&msg->sm_open_req.opreq_conn.con_src, + call_attrs.calling.addr.address); + call_attrs.calling.addr.address_format = T_ATM_SPANS_ADDR; + call_attrs.calling.addr.address_length = sizeof(spans_addr); + call_attrs.calling.subaddr.address_format = T_ATM_ABSENT; + call_attrs.calling.subaddr.address_length = 0; + + call_attrs.qos.tag = T_ATM_PRESENT; + call_attrs.qos.v.coding_standard = T_ATM_NETWORK_CODING; + call_attrs.qos.v.forward.qos_class = T_ATM_QOS_CLASS_0; + call_attrs.qos.v.backward.qos_class = T_ATM_QOS_CLASS_0; + + call_attrs.transit.tag = T_ATM_ABSENT; + call_attrs.cause.tag = T_ATM_ABSENT; + + /* + * Notify the connection manager that it has a new channel + */ + err = atm_cm_incoming((struct vccb *)svp, &call_attrs); + if (err) { + ATM_DEBUG0("spans_open_req: atm_cm_incoming returned error\n"); + result = SPANS_FAIL; + goto response; + } + + /* + * Wait for the connection recipient to issue an accept + */ + return; + +response: + /* + * Clean up the VCCB and the atm_conn block if we got them + */ + if (svp) { + DEQUEUE(svp, struct spans_vccb, sv_sigelem, + spp->sp_vccq); + atm_free(svp); + } + + /* + * Some problem was detected with the request. Send a SPANS + * message rejecting the connection. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_OPEN_RSP; + rsp_msg->sm_open_rsp.oprsp_conn = msg->sm_open_req.opreq_conn; + rsp_msg->sm_open_rsp.oprsp_result = result; + rsp_msg->sm_open_rsp.oprsp_vpvc = 0; + + /* + * Send the Open Response + */ + spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process an open response or open confirmation + * + * Called when an open response or open confirmation is received. + * Processing will be based on the state of the requested connection and + * the status returned. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the open response or confirmation message + * + * Returns: + * none + * + */ +static void +spans_open_rsp(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + struct spans_vccb *svp; + + ATM_DEBUG2("spans_open_rsp: spp=0x%x, msg=0x%x\n", spp, msg); + + /* + * Locate the VCCB for the connection + */ + svp = spans_find_conn(spp, &msg->sm_open_rsp.oprsp_conn); + if (svp == NULL) + return; + + /* + * Check the connection state + */ + if ((svp->sv_sstate != SPANS_VC_POPEN && + svp->sv_sstate != SPANS_VC_R_POPEN) || + svp->sv_ustate != VCCU_POPEN) { + ATM_DEBUG2( + "spans_open_rsp: invalid VCCB state, sstate=%d, ustate=%d\n", + svp->sv_sstate, svp->sv_ustate); + return; + } + + /* + * Cancel the retransmission timer + */ + SPANS_VC_CANCEL((struct vccb *) svp); + + /* + * Check the result + */ + switch (msg->sm_open_rsp.oprsp_result) { + + case SPANS_OK: + /* + * Save the assigned VPI and VCI + */ + svp->sv_vpi = SPANS_EXTRACT_VPI(msg->sm_open_rsp.oprsp_vpvc); + svp->sv_vci = SPANS_EXTRACT_VCI(msg->sm_open_rsp.oprsp_vpvc); + + /* + * Update the VCC state and notify the VCC owner + */ + svp->sv_sstate = SPANS_VC_OPEN; + svp->sv_ustate = VCCU_OPEN; + svp->sv_tstamp = time_second; + atm_cm_connected(svp->sv_connvc); + break; + + case SPANS_FAIL: + case SPANS_NOVPVC: + case SPANS_NORSC: + case SPANS_BADDEST: + /* + * Close out the VCCB and notify the user + */ + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_ustate = VCCU_CLOSED; + svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT; + svp->sv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + svp->sv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + svp->sv_connvc->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_CALL_REJECTED; + KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics, + sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + break; + + default: + log(LOG_ERR, "spans: unknown result %d in open rsp\n", + msg->sm_open_rsp.oprsp_result); + break; + } +} + + +/* + * Process a close request from the network + * + * Called when a close request, close indication, rclose request, or + * rclose indication is received. Processing will be based on the + * state of the connection. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the close request message + * + * Returns: + * none + * + */ +static void +spans_close_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + struct spans_vccb *svp; + spans_result result; + spans_msg *rsp_msg; + u_char outstate; + Atm_connvc *cvp; + + ATM_DEBUG2("spans_close_req: spp=0x%x, msg=0x%x\n", spp, msg); + + /* + * Locate the VCCB for the connection + */ + svp = spans_find_conn(spp, &msg->sm_close_req.clreq_conn); + if (svp == NULL) { + result = SPANS_BADDEST; + goto response; + } + + /* + * Check the connection type + */ + if (!(svp->sv_type & VCC_SVC)) { + result = SPANS_FAIL; + goto response; + } + + /* + * Check the connection state + */ + switch (svp->sv_sstate) { + case SPANS_VC_OPEN: + case SPANS_VC_R_POPEN: + case SPANS_VC_POPEN: + /* + * VCC is open or opening--continue + */ + break; + case SPANS_VC_CLOSE: + case SPANS_VC_FREE: + case SPANS_VC_ABORT: + /* + * We're already closing--give a response, since this + * is probably a retransmission + */ + result = SPANS_OK; + goto response; + case SPANS_VC_NULL: + result = SPANS_FAIL; + goto response; + } + + /* + * Cancel the retransmission timer + */ + SPANS_VC_CANCEL((struct vccb *) svp); + + /* + * Close out the VCCB and notify the user + */ + outstate = svp->sv_sstate; + svp->sv_ustate = VCCU_CLOSED; + svp->sv_sstate = SPANS_VC_FREE; + cvp = svp->sv_connvc; + switch (outstate) { + case SPANS_VC_R_POPEN: + spans_free((struct vccb *)svp); + /* FALLTHRU */ + + case SPANS_VC_POPEN: + case SPANS_VC_OPEN: + cvp->cvc_attr.cause.tag = T_ATM_PRESENT; + cvp->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + cvp->cvc_attr.cause.v.location = T_ATM_LOC_USER; + cvp->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_NORMAL_CALL_CLEARING; + KM_ZERO(cvp->cvc_attr.cause.v.diagnostics, + sizeof(cvp->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + break; + } + + result = SPANS_OK; + +response: + /* + * Respond to the SPANS_CLOSE_IND with a SPANS_CLOSE_RSP + */ + rsp_msg = (spans_msg *)atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + rsp_msg->sm_vers = SPANS_VERS_1_0; + if (msg->sm_type == SPANS_RCLOSE_REQ || + msg->sm_type == SPANS_RCLOSE_IND) { + rsp_msg->sm_type = SPANS_RCLOSE_RSP; + } else { + rsp_msg->sm_type = SPANS_CLOSE_RSP; + } + rsp_msg->sm_close_rsp.clrsp_conn = msg->sm_close_req.clreq_conn; + rsp_msg->sm_close_rsp.clrsp_result = result; + spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process a close response or close confirmation + * + * Called when an close response or close confirmation is received. + * Processing will be based on the state of the requested connection and + * the returned status. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the close response or confirmation message + * + * Returns: + * none + * + */ +static void +spans_close_rsp(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + struct spans_vccb *svp; + + ATM_DEBUG2("spans_close_rsp: spp=0x%x, msg=0x%x\n", spp, msg); + + /* + * Locate the VCCB for the connection + */ + svp = spans_find_conn(spp, &msg->sm_close_rsp.clrsp_conn); + if (svp == NULL) { + return; + } + + /* + * Check the VCCB state + */ + if (svp->sv_sstate != SPANS_VC_CLOSE) { + return; + } + + /* + * Cancel the retransmission timer + */ + SPANS_VC_CANCEL((struct vccb *) svp); + + /* + * Check the response from the remote end + */ + switch (msg->sm_close_rsp.clrsp_result) { + + case SPANS_OK: + /* + * Mark the VCCB as closed and notify the owner + */ + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT; + svp->sv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + svp->sv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + svp->sv_connvc->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_NORMAL_CALL_CLEARING; + KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics, + sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + break; + + case SPANS_NOVPVC: + case SPANS_BADDEST: + case SPANS_FAIL: + case SPANS_NORSC: + /* + * Mark the VCCB as closed and notify the owner + */ + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT; + svp->sv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + svp->sv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + svp->sv_connvc->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_UNSPECIFIED_NORMAL; + KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics, + sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + break; + + default: + log(LOG_ERR, "spans: unknown result %d in close rsp\n", + msg->sm_close_rsp.clrsp_result); + break; + } +} + + +/* + * Process a multi request or multi indication + * + * Called when a multi response or multi confirmation is received. We + * don't support multicast channels, so we just reject the request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the multi request or indication message + * + * Returns: + * none + * + */ +static void +spans_multi_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_msg *rsp_msg; + + /* + * Get memory for a SPANS_MULTI_RSP message. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response. + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_MULTI_RSP; + rsp_msg->sm_multi_rsp.mursp_conn = msg->sm_multi_req.mureq_conn; + rsp_msg->sm_multi_rsp.mursp_result = SPANS_FAIL; + rsp_msg->sm_multi_rsp.mursp_rsrc = msg->sm_multi_req.mureq_desrsrc; + rsp_msg->sm_multi_rsp.mursp_vpvc = 0; + + /* + * Send the response and free the message. + */ + (void) spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process an add request or add indication + * + * Called when an add response or add confirmation is received. We + * don't support multicast channels, so we just reject the request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the add request or indication message + * + * Returns: + * none + * + */ +static void +spans_add_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_msg *rsp_msg; + + /* + * Get memory for a SPANS_ADD_RSP message. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response. + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_ADD_RSP; + rsp_msg->sm_add_rsp.adrsp_conn = msg->sm_add_req.adreq_desconn; + rsp_msg->sm_add_rsp.adrsp_result = SPANS_FAIL; + rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_peak = 0; + rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_mean = 0; + rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_burst = 0; + + /* + * Send the response and free the message. + */ + (void) spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process a join request + * + * Called when an join request is received. We don't support group + * addresses, so we just reject the request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the join request message + * + * Returns: + * none + * + */ +static void +spans_join_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_msg *rsp_msg; + + /* + * Get memory for a SPANS_JOIN_CNF message. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response. + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_JOIN_CNF; + spans_addr_copy(&msg->sm_join_req.jnreq_addr, + &rsp_msg->sm_join_cnf.jncnf_addr); + rsp_msg->sm_join_cnf.jncnf_result = SPANS_FAIL; + + /* + * Send the response and free the message. + */ + (void) spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process a leave request + * + * Called when an leave request is received. We don't support group + * addresses, so we just reject the request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the leave request message + * + * Returns: + * none + * + */ +static void +spans_leave_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_msg *rsp_msg; + + /* + * Get memory for a SPANS_LEAVE_CNF message. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response. + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_LEAVE_CNF; + spans_addr_copy(&msg->sm_leave_req.lvreq_addr, + &rsp_msg->sm_leave_cnf.lvcnf_addr); + rsp_msg->sm_leave_cnf.lvcnf_result = SPANS_FAIL; + + /* + * Send the response and free the message. + */ + (void) spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process a VCI range indication + * + * Called when a VCI range indication is received. Adjust the VCI + * bounds if they have changed. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the VCI range indication message + * + * Returns: + * none + * + */ +static void +spans_vcir_ind(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + /* + * Adjust the limits if they have changed + */ + if (msg->sm_vcir_ind.vrind_min != spp->sp_min_vci) { + spp->sp_min_vci = + (msg->sm_vcir_ind.vrind_min < + SPANS_MIN_VCI ? + SPANS_MIN_VCI : + msg->sm_vcir_ind.vrind_min); + } + if (msg->sm_vcir_ind.vrind_max != spp->sp_max_vci) { + spp->sp_max_vci = + (msg->sm_vcir_ind.vrind_max > + SPANS_MAX_VCI ? + SPANS_MAX_VCI : + msg->sm_vcir_ind.vrind_max); + } +} + + +/* + * Process a query request + * + * Called when a query request is received. Respond with the + * appropriate query response. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the VCI range indication message + * + * Returns: + * none + * + */ +static void +spans_query_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + struct spans_vccb *svp = NULL; + spans_msg *rsp_msg; + + ATM_DEBUG1("spans_query_req: msg=0x%x\n", msg); + + /* + * Ignore an end-to-end query + */ + if (msg->sm_query_req.qyreq_type == SPANS_QUERY_END_TO_END) { + return; + } + + /* + * Get memory for a SPANS_QUERY_RSP message. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response. + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_QUERY_RSP; + rsp_msg->sm_query_rsp.qyrsp_conn = msg->sm_query_req.qyreq_conn; + rsp_msg->sm_query_rsp.qyrsp_type = msg->sm_query_req.qyreq_type; + rsp_msg->sm_query_rsp.qyrsp_data = 0; + + /* + * Get the state of the requested connection + */ + svp = spans_find_conn(spp, &msg->sm_query_req.qyreq_conn); + if (svp) { + switch(svp->sv_sstate) { + case SPANS_VC_NULL: + case SPANS_VC_FREE: + rsp_msg->sm_query_rsp.qyrsp_state = + SPANS_CONN_CLOSED; + break; + case SPANS_VC_OPEN: + rsp_msg->sm_query_rsp.qyrsp_state = + SPANS_CONN_OPEN; + break; + case SPANS_VC_POPEN: + case SPANS_VC_R_POPEN: + rsp_msg->sm_query_rsp.qyrsp_state = + SPANS_CONN_OPEN_PEND; + break; + case SPANS_VC_CLOSE: + case SPANS_VC_ABORT: + rsp_msg->sm_query_rsp.qyrsp_state = + SPANS_CONN_CLOSE_PEND; + break; + case SPANS_VC_ACTIVE: + case SPANS_VC_ACT_DOWN: + /* + * VCCB is for a PVC (shouldn't happen) + */ + atm_free(rsp_msg); + return; + } + } else { + /* + * No VCCB found--connection doesn't exist + */ + rsp_msg->sm_query_rsp.qyrsp_state = SPANS_CONN_CLOSED; + } + + /* + * Send the response and free the message. + */ + (void) spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process a SPANS signalling message + * + * Called when a SPANS message is received. The message is converted + * into internal format with XDR and decoded by calling the appropriate + * mesage handling routine. Unrecognized and unexpected messages are + * logged. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * m pointer to a buffer chain containing the SPANS message + * + * Returns: + * none + * + */ +void +spans_rcv_msg(spp, m) + struct spans *spp; + KBuffer *m; +{ + XDR xdrs; + spans_msg *msg; + + /* + * Get storage for the message + */ + msg = (spans_msg *)atm_allocate(&spans_msgpool); + if (msg == NULL) { + return; + } + + /* + * Convert the message from network order to internal format + */ + xdrmbuf_init(&xdrs, m, XDR_DECODE); + if (!xdr_spans_msg(&xdrs, msg)) { + log(LOG_ERR, "spans_rcv_msg: XDR decode failed\n"); + spans_dump_buffer(m); + goto done; + } + +#ifdef NOTDEF + /* + * Debug--print some information about the message + */ + if (msg->sm_type != SPANS_STAT_REQ && + msg->sm_type != SPANS_STAT_IND && + msg->sm_type != SPANS_STAT_RSP) { + printf("spans_rcv_msg: got "); + spans_print_msg(msg); + } +#endif + + /* + * Verify the message sm_vers + */ + if (msg->sm_vers != SPANS_VERS_1_0) { + log(LOG_ERR, "spans: invalid message version 0x%x\n", + msg->sm_vers); + } + + /* + * Ignore the message if SPANS isn't up yet + */ + if (spp->sp_state != SPANS_ACTIVE && + (spp->sp_state != SPANS_PROBE || + (msg->sm_type != SPANS_STAT_REQ && + msg->sm_type != SPANS_STAT_RSP && + msg->sm_type != SPANS_STAT_IND))) { + goto done; + } + + /* + * Process the message based on its type + */ + switch(msg->sm_type) { + case SPANS_STAT_REQ: + spans_status_ind(spp, msg); + break; + case SPANS_STAT_IND: + spans_status_ind(spp, msg); + break; + case SPANS_STAT_RSP: + spans_status_rsp(spp, msg); + break; + case SPANS_OPEN_REQ: + spans_open_req(spp, msg); + break; + case SPANS_OPEN_IND: + spans_open_req(spp, msg); + break; + case SPANS_OPEN_RSP: + spans_open_rsp(spp, msg); + break; + case SPANS_OPEN_CNF: + spans_open_rsp(spp, msg); + break; + case SPANS_CLOSE_REQ: + spans_close_req(spp, msg); + break; + case SPANS_CLOSE_IND: + spans_close_req(spp, msg); + break; + case SPANS_CLOSE_RSP: + spans_close_rsp(spp, msg); + break; + case SPANS_CLOSE_CNF: + spans_close_rsp(spp, msg); + break; + case SPANS_RCLOSE_REQ: + spans_close_req(spp, msg); + break; + case SPANS_RCLOSE_IND: + spans_close_req(spp, msg); + break; + case SPANS_RCLOSE_RSP: + spans_close_rsp(spp, msg); + break; + case SPANS_RCLOSE_CNF: + spans_close_rsp(spp, msg); + break; + case SPANS_MULTI_REQ: + spans_multi_req(spp, msg); + break; + case SPANS_MULTI_IND: + spans_multi_req(spp, msg); + break; + case SPANS_MULTI_RSP: + log(LOG_ERR, + "spans: unexpected message (multi_rsp)\n"); + break; + case SPANS_MULTI_CNF: + log(LOG_ERR, + "spans: unexpected message (multi_conf)\n"); + break; + case SPANS_ADD_REQ: + spans_add_req(spp, msg); + break; + case SPANS_ADD_IND: + spans_add_req(spp, msg); + break; + case SPANS_ADD_RSP: + log(LOG_ERR, + "spans: unexpected message (add_rsp)\n"); + break; + case SPANS_ADD_CNF: + log(LOG_ERR, "spans: unexpected message (add_conf)\n"); + break; + case SPANS_JOIN_REQ: + spans_join_req(spp, msg); + break; + case SPANS_JOIN_CNF: + log(LOG_ERR, "spans: unexpected message (join_conf)\n"); + break; + case SPANS_LEAVE_REQ: + spans_leave_req(spp, msg); + break; + case SPANS_LEAVE_CNF: + log(LOG_ERR, + "spans: unexpected message (leave_conf)\n"); + break; + case SPANS_VCIR_IND: + spans_vcir_ind(spp, msg); + break; + case SPANS_QUERY_REQ: + spans_query_req(spp, msg); + break; + case SPANS_QUERY_RSP: + log(LOG_ERR, + "spans: unexpected message (query_rsp)\n"); + break; + default: + log(LOG_ERR, "spans: unknown SPANS message type %d\n", + msg->sm_type); + } + +done: + /* + * Free the incoming message (both buffer and internal format) if + * necessary. + */ + if (msg) + atm_free(msg); + if (m) + KB_FREEALL(m); +} |