aboutsummaryrefslogtreecommitdiff
path: root/sys/netatm/spans/spans_msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/spans/spans_msg.c')
-rw-r--r--sys/netatm/spans/spans_msg.c1633
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);
+}