diff options
Diffstat (limited to 'usr.sbin/atm/scspd/scsp_msg.c')
-rw-r--r-- | usr.sbin/atm/scspd/scsp_msg.c | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/usr.sbin/atm/scspd/scsp_msg.c b/usr.sbin/atm/scspd/scsp_msg.c new file mode 100644 index 0000000..bed2918 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_msg.c @@ -0,0 +1,611 @@ +/* + * + * =================================== + * 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: scsp_msg.c,v 1.6 1998/08/21 18:08:24 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP message-handling routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_msg.c,v 1.6 1998/08/21 18:08:24 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + +/* + * Copy CSAS records into a CA record + * + * Arguments: + * dcsp pointer to DCS block for DCS + * cap pointer to CA record for CSASs + * + * + * Returns: + * none + * + */ +static void +scsp_ca_csas_setup(dcsp, cap) + Scsp_dcs *dcsp; + Scsp_ca *cap; +{ + int csas_len, len, mtu; + Scsp_server *ssp = dcsp->sd_server; + Scsp_cse *csep, *next_csep; + Scsp_csa *csap; + + /* + * Loop through pending CSAS records + */ + len = sizeof(struct scsp_nhdr) + sizeof(struct scsp_nmcp) + + ssp->ss_lsid.id_len + + dcsp->sd_dcsid.id_len; + csas_len = sizeof(struct scsp_ncsa) + + dcsp->sd_server->ss_id_len + + dcsp->sd_server->ss_ckey_len; + mtu = dcsp->sd_server->ss_mtu; + for (csep = dcsp->sd_ca_csas; + csep && (len < mtu - csas_len); + csep = next_csep) { + next_csep = csep->sc_next; + csap = scsp_cse2csas(csep); + LINK2TAIL(csap, Scsp_csa, cap->ca_csa_rec, next); + len += csas_len; + UNLINK(csep, Scsp_cse, dcsp->sd_ca_csas, sc_next); + UM_FREE(csep); + cap->ca_mcp.rec_cnt++; + } +} + + +/* + * Process CSA records from a CSU Request that may be in response to + * CSAS records sent in a CSUS + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message + * + * Returns: + * none + * + */ +void +scsp_csus_ack(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + Scsp_csu_msg *csusp; + Scsp_csa *csap, *csasp, *next_csasp; + + /* + * If this isn't a CSU Request, or there's no outstanding CSUS, + * or the outstanding CSUS has already been satisfied, just + * return + */ + if (!msg || msg->sc_msg_type != SCSP_CSU_REQ_MSG || + !dcsp->sd_csus_rexmt_msg || + !dcsp->sd_csus_rexmt_msg->sc_csu_msg || + !dcsp->sd_csus_rexmt_msg->sc_csu_msg->csu_csa_rec) + return; + + + /* + * Loop through the CSASs in the CSUS message, checking for + * each in the CSA records of the received CSU Request + */ + csusp = dcsp->sd_csus_rexmt_msg->sc_csu_msg; + for (csasp = csusp->csu_csa_rec; csasp; csasp = next_csasp) { + next_csasp = csasp->next; + for (csap = msg->sc_csu_msg->csu_csa_rec; + csap; csap = csap->next) { + /* + * If the records match, unlink and free the + * CSAS from the CSUS + */ + if (scsp_cmp_key(&csap->key, &csasp->key) == 0 && + scsp_cmp_key(&csap->key, &csasp->key) == 0 && + scsp_cmp_id(&csap->oid, &csasp->oid) == 0 && + csap->seq >= csasp->seq) { + UNLINK(csasp, Scsp_csa, + csusp->csu_csa_rec, + next); + SCSP_FREE_CSA(csasp); + dcsp->sd_csus_rexmt_msg->sc_csu_msg->csu_mcp.rec_cnt--; + break; + } + } + } + + if (csusp->csu_csa_rec == (Scsp_csa *)0) { + /* + * All CSASs in the CSUS message have been + * answered. Stop the timer and free the + * saved message. + */ + HARP_CANCEL(&dcsp->sd_csus_rexmt_t); + scsp_free_msg(dcsp->sd_csus_rexmt_msg); + dcsp->sd_csus_rexmt_msg = (Scsp_msg *)0; + + /* + * If the CRL isn't empty, send another CSUS + */ + if (dcsp->sd_crl) { + (void)scsp_send_csus(dcsp); + } + } +} + + +/* + * Send a CA message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * + * Returns: + * 0 message sent OK + * else errno indicating reason for failure + * + */ +int +scsp_send_ca(dcsp) + Scsp_dcs *dcsp; +{ + int rc; + Scsp_msg *ca_msg; + Scsp_ca *cap; + Scsp_server *ssp = dcsp->sd_server; + + /* + * Get memory for a CA message + */ + ca_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!ca_msg) { + scsp_mem_err("scsp_send_ca: sizeof(Scsp_msg)"); + } + cap = (Scsp_ca *)UM_ALLOC(sizeof(Scsp_ca)); + if (!cap) { + scsp_mem_err("scsp_send_ca: sizeof(Scsp_ca)"); + } + UM_ZERO(ca_msg, sizeof(Scsp_msg)); + UM_ZERO(cap, sizeof(Scsp_ca)); + + /* + * Fill out constant fields + */ + ca_msg->sc_msg_type = SCSP_CA_MSG; + ca_msg->sc_ca = cap; + cap->ca_seq = dcsp->sd_ca_seq; + cap->ca_mcp.pid = ssp->ss_pid; + cap->ca_mcp.sgid = ssp->ss_sgid; + cap->ca_mcp.sid = ssp->ss_lsid; + cap->ca_mcp.rid = dcsp->sd_dcsid; + + /* + * Fill out state-dependent fields + */ + switch(dcsp->sd_ca_state) { + case SCSP_CAFSM_NEG: + cap->ca_m = 1; + cap->ca_i = 1; + cap->ca_o = 1; + break; + case SCSP_CAFSM_MASTER: + cap->ca_m = 1; + cap->ca_i = 0; + scsp_ca_csas_setup(dcsp, cap); + cap->ca_o = dcsp->sd_ca_csas != (Scsp_cse *)0; + break; + case SCSP_CAFSM_SLAVE: + cap->ca_m = 0; + cap->ca_i = 0; + scsp_ca_csas_setup(dcsp, cap); + cap->ca_o = dcsp->sd_ca_csas != (Scsp_cse *)0; + break; + default: + scsp_log(LOG_ERR, "Invalid state in scsp_send_ca"); + abort(); + } + + /* + * Send the CA message and save a pointer to it in case + * it needs to be retransmitted + */ + rc = scsp_send_msg(dcsp, ca_msg); + if (rc == 0) { + dcsp->sd_ca_rexmt_msg = ca_msg; + } else { + scsp_free_msg(ca_msg); + } + + return(rc); +} + + +/* + * Send a CSU Solicit message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * + * Returns: + * 0 message sent OK + * else errno indicating reason for failure + * + */ +int +scsp_send_csus(dcsp) + Scsp_dcs *dcsp; +{ + int csas_len, len, mtu, rc; + Scsp_msg *csus_msg; + Scsp_csu_msg *csusp; + Scsp_csa *csasp, *next_csasp; + Scsp_server *ssp = dcsp->sd_server; + + /* + * If we have a mesage saved for retransmission, use it. + * If not, get memory for a new one. + */ + if (dcsp->sd_csus_rexmt_msg) { + csus_msg = dcsp->sd_csus_rexmt_msg; + csusp = csus_msg->sc_csu_msg; + } else { + /* + * Get memory for a CSUS message + */ + csus_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!csus_msg) { + scsp_mem_err("scsp_send_csus: sizeof(Scsp_msg)"); + } + csusp = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csusp) { + scsp_mem_err("scsp_send_csus: sizeof(Scsp_csu_msg)"); + } + UM_ZERO(csus_msg, sizeof(Scsp_msg)); + UM_ZERO(csusp, sizeof(Scsp_csu_msg)); + + /* + * Fill out constant fields + */ + csus_msg->sc_msg_type = SCSP_CSUS_MSG; + csus_msg->sc_csu_msg = csusp; + csusp->csu_mcp.pid = ssp->ss_pid; + csusp->csu_mcp.sgid = ssp->ss_sgid; + csusp->csu_mcp.sid = ssp->ss_lsid; + csusp->csu_mcp.rid = dcsp->sd_dcsid; + } + + /* + * Move CSAS records from CRL into message + */ + mtu = dcsp->sd_server->ss_mtu; + csas_len = sizeof(struct scsp_ncsa) + ssp->ss_id_len + + ssp->ss_ckey_len; + len = sizeof(struct scsp_nhdr) + sizeof(struct scsp_nmcp) + + 2 * ssp->ss_id_len + + csas_len * (csusp->csu_mcp.rec_cnt + 1); + for (csasp = dcsp->sd_crl; + csasp && ((len + csas_len) < mtu); + csasp = next_csasp, len += csas_len) { + next_csasp = csasp->next; + csusp->csu_mcp.rec_cnt++; + UNLINK(csasp, Scsp_csa, dcsp->sd_crl, next); + LINK2TAIL(csasp, Scsp_csa, csusp->csu_csa_rec, next); + csasp->hops = 1; + } + + /* + * Send the CSUS message and save a pointer to it in case + * it needs to be retransmitted + */ + rc = scsp_send_msg(dcsp, csus_msg); + if (rc == 0) { + /* + * Success--Save a pointer to the message and + * start the CSUS retransmit timer + */ + dcsp->sd_csus_rexmt_msg = csus_msg; + HARP_TIMER(&dcsp->sd_csus_rexmt_t, + dcsp->sd_csus_rexmt_int, + scsp_csus_retran_timeout); + } else { + /* + * Error--free the CSUS message + */ + scsp_free_msg(csus_msg); + } + + return(rc); +} + + +/* + * Send a CSU Request message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * csap pointer to CSAs to include + * + * Returns: + * 0 message sent OK + * else errno indicating reason for failure + * + */ +int +scsp_send_csu_req(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + int rc; + Scsp_server *ssp = dcsp->sd_server; + Scsp_csa *cnt_csap; + Scsp_msg *csu_msg; + Scsp_csu_msg *csup; + Scsp_csu_rexmt *rxp; + + /* + * Return if CSA list is empty + */ + if (!csap) + return(0); + + /* + * Get memory for a CSU Req message + */ + csu_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!csu_msg) { + scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_msg)"); + } + csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csup) { + scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_csu_msg)"); + } + UM_ZERO(csu_msg, sizeof(Scsp_msg)); + UM_ZERO(csup, sizeof(Scsp_csu_msg)); + + /* + * Get memory for a CSU Req retransmission queue entry + */ + rxp = (Scsp_csu_rexmt *)UM_ALLOC(sizeof(Scsp_csu_rexmt)); + if (!rxp) { + scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_csu_rexmt)"); + } + UM_ZERO(rxp, sizeof(Scsp_csu_rexmt)); + + /* + * Fill out constant fields + */ + csu_msg->sc_msg_type = SCSP_CSU_REQ_MSG; + csu_msg->sc_csu_msg = csup; + csup->csu_mcp.pid = ssp->ss_pid; + csup->csu_mcp.sgid = ssp->ss_sgid; + csup->csu_mcp.sid = ssp->ss_lsid; + csup->csu_mcp.rid = dcsp->sd_dcsid; + + /* + * Put the CSA list into the message + */ + csup->csu_csa_rec = csap; + for (cnt_csap = csap; cnt_csap; cnt_csap = cnt_csap->next) { + csup->csu_mcp.rec_cnt++; + } + + /* + * Send the CSU Request + */ + rc = scsp_send_msg(dcsp, csu_msg); + if (rc) { + scsp_free_msg(csu_msg); + return(rc); + } + UM_FREE(csu_msg); + UM_FREE(csup); + + /* + * Save the CSA entries on the CSU Request retransmission + * queue and start the retransmission timer + */ + rxp->sr_dcs = dcsp; + rxp->sr_csa = csap; + HARP_TIMER(&rxp->sr_t, dcsp->sd_csu_rexmt_int, + scsp_csu_req_retran_timeout); + LINK2TAIL(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt, sr_next); + + return(0); +} + + +/* + * Send a CSU Reply message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * csap pointer to CSAs to include + * + * Returns: + * 0 message sent OK + * errno reason for failure + * + */ +int +scsp_send_csu_reply(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + int rc; + Scsp_server *ssp = dcsp->sd_server; + Scsp_csa *csap1; + Scsp_msg *csu_msg; + Scsp_csu_msg *csup; + + /* + * Return if CSA list is empty + */ + if (!csap) + return(0); + + /* + * Get memory for a CSU Reply message + */ + csu_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!csu_msg) { + scsp_mem_err("scsp_send_csu_reply: sizeof(Scsp_msg)"); + } + csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csup) { + scsp_mem_err("scsp_send_csu_reply: sizeof(Scsp_csu_msg)"); + } + UM_ZERO(csu_msg, sizeof(Scsp_msg)); + UM_ZERO(csup, sizeof(Scsp_csu_msg)); + + /* + * Fill out constant fields + */ + csu_msg->sc_msg_type = SCSP_CSU_REPLY_MSG; + csu_msg->sc_csu_msg = csup; + csup->csu_mcp.pid = ssp->ss_pid; + csup->csu_mcp.sgid = ssp->ss_sgid; + csup->csu_mcp.sid = ssp->ss_lsid; + csup->csu_mcp.rid = dcsp->sd_dcsid; + + /* + * Put the CSA list into the message. Convert the CSAs into + * CSASs by freeing the protocol-specific portion. + */ + csup->csu_csa_rec = csap; + for (csap1 = csap; csap1; csap1 = csap1->next) { + switch(dcsp->sd_server->ss_pid) { + /* + * We currently only support ATMARP + */ + case SCSP_PROTO_ATMARP: + if (csap1->atmarp_data) { + UM_FREE(csap1->atmarp_data); + csap1->atmarp_data = + (Scsp_atmarp_csa *)0; + } + break; + } + csup->csu_mcp.rec_cnt++; + } + + /* + * Send the CSU Reply + */ + rc = scsp_send_msg(dcsp, csu_msg); + scsp_free_msg(csu_msg); + + return(rc); +} + + +/* + * Send a Hello message + * + * Arguments: + * dcsp pointer to DCS control block + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_send_hello(dcsp) + Scsp_dcs *dcsp; +{ + int rc; + Scsp_msg *hello; + Scsp_hello *hp; + + /* + * Get memory for a Hello message + */ + hello = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!hello) { + scsp_mem_err("scsp_send_hello: sizeof(Scsp_msg)"); + } + UM_ZERO(hello, sizeof(Scsp_msg)); + hp = (Scsp_hello *)UM_ALLOC(sizeof(Scsp_hello)); + if (!hp) { + scsp_mem_err("scsp_send_hello: sizeof(Scsp_hello)"); + } + UM_ZERO(hp, sizeof(Scsp_hello)); + + /* + * Set up the Hello message + */ + hello->sc_msg_type = SCSP_HELLO_MSG; + hello->sc_hello = hp; + hp->hello_int = SCSP_HELLO_Interval; + hp->dead_factor = SCSP_HELLO_DF; + hp->family_id = dcsp->sd_server->ss_fid; + hp->hello_mcp.pid = dcsp->sd_server->ss_pid; + hp->hello_mcp.sgid = dcsp->sd_server->ss_sgid; + hp->hello_mcp.flags = 0; + hp->hello_mcp.rec_cnt = 0; + hp->hello_mcp.sid = dcsp->sd_server->ss_lsid; + hp->hello_mcp.rid = dcsp->sd_dcsid; + + /* + * Send and free the message + */ + rc = scsp_send_msg(dcsp, hello); + scsp_free_msg(hello); + + return(rc); +} |