diff options
Diffstat (limited to 'usr.sbin/atm/scspd/scsp_subr.c')
-rw-r--r-- | usr.sbin/atm/scspd/scsp_subr.c | 1123 |
1 files changed, 1123 insertions, 0 deletions
diff --git a/usr.sbin/atm/scspd/scsp_subr.c b/usr.sbin/atm/scspd/scsp_subr.c new file mode 100644 index 0000000..c14195b --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_subr.c @@ -0,0 +1,1123 @@ +/* + * + * =================================== + * 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_subr.c,v 1.5 1998/08/13 20:11:16 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP subroutines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_subr.c,v 1.5 1998/08/13 20:11:16 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.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_sigmgr.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> +#include <netatm/uni/unisig_var.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * Hash an SCSP cache key + * + * Arguments: + * ckp pointer to an SCSP cache key structure + * + * Returns: + * hashed value + * + */ +int +scsp_hash(ckp) + Scsp_ckey *ckp; +{ + int i, j, h; + + /* + * Turn cache key into a positive integer + */ + h = 0; + for (i = ckp->key_len-1, j = 0; + i > 0, j < sizeof(int); + i--, j++) + h = (h << 8) + ckp->key[i]; + h = abs(h); + + /* + * Return the hashed value + */ + return(h % SCSP_HASHSZ); +} + + +/* + * Compare two SCSP IDs + * + * Arguments: + * id1p pointer to an SCSP ID structure + * id2p pointer to an SCSP ID structure + * + * Returns: + * < 0 id1 is less than id2 + * 0 id1 and id2 are equal + * > 0 id1 is greater than id2 + * + */ +int +scsp_cmp_id(id1p, id2p) + Scsp_id *id1p; + Scsp_id *id2p; +{ + int diff, i; + + /* + * Compare the two IDs, byte for byte + */ + for (i = 0; i < id1p->id_len && i < id2p->id_len; i++) { + diff = id1p->id[i] - id2p->id[i]; + if (diff) { + return(diff); + } + } + + /* + * IDs are equal. If lengths differ, the longer ID is + * greater than the shorter. + */ + return(id1p->id_len - id2p->id_len); +} + + +/* + * Compare two SCSP cache keys + * + * Arguments: + * ck1p pointer to an SCSP cache key structure + * ck2p pointer to an SCSP cache key structure + * + * Returns: + * < 0 ck1 is less than ck2 + * 0 ck1 and ck2 are equal + * > 0 ck1 is greater than ck2 + * + */ +int +scsp_cmp_key(ck1p, ck2p) + Scsp_ckey *ck1p; + Scsp_ckey *ck2p; +{ + int diff, i; + + /* + * Compare the two keys, byte for byte + */ + for (i = 0; i < ck1p->key_len && i < ck2p->key_len; i++) { + diff = ck1p->key[i] - ck2p->key[i]; + if (diff) + return(diff); + } + + /* + * Keys are equal. If lengths differ, the longer key is + * greater than the shorter. + */ + return(ck1p->key_len - ck2p->key_len); +} + + +/* + * Check whether the host system is an ATMARP server for + * the LIS associated with a given interface + * + * Arguments: + * netif pointer to the network interface name + * + * Returns: + * 1 host is a server + * 0 host is not a server + * + */ +int +scsp_is_atmarp_server(netif) + char *netif; +{ + int rc; + int buf_len = sizeof(struct air_asrv_rsp); + struct atminfreq air; + struct air_asrv_rsp *asrv_info; + + /* + * Get interface information from the kernel + */ + strcpy(air.air_int_intf, netif); + air.air_opcode = AIOCS_INF_ASV; + buf_len = do_info_ioctl(&air, buf_len); + if (buf_len < 0) + return(0); + + /* + * Check the interface's ATMARP server address + */ + asrv_info = (struct air_asrv_rsp *) air.air_buf_addr; + rc = (asrv_info->asp_addr.address_format == T_ATM_ABSENT) && + (asrv_info->asp_subaddr.address_format == + T_ATM_ABSENT); + UM_FREE(asrv_info); + return(rc); +} + + +/* + * Make a copy of a cache summary entry + * + * Arguments: + * csep pointer to CSE entry to copy + * + * Returns: + * 0 copy failed + * else pointer to new CSE entry + * + */ +Scsp_cse * +scsp_dup_cse(csep) + Scsp_cse *csep; +{ + Scsp_cse *dupp; + + /* + * Allocate memory for the duplicate + */ + dupp = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse)); + if (!dupp) { + scsp_mem_err("scsp_dup_cse: sizeof(Scsp_cse)"); + } + + /* + * Copy data to the duplicate + */ + UM_COPY(csep, dupp, sizeof(Scsp_cse)); + dupp->sc_next = (Scsp_cse *)0; + + return(dupp); +} + + +/* + * Make a copy of a CSA or CSAS record + * + * Arguments: + * csap pointer to CSE entry to copy + * + * Returns: + * 0 copy failed + * else pointer to new CSA or CSAS record + * + */ +Scsp_csa * +scsp_dup_csa(csap) + Scsp_csa *csap; +{ + Scsp_csa *dupp; + Scsp_atmarp_csa *adp; + + /* + * Allocate memory for the duplicate + */ + dupp = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa)); + if (!dupp) { + scsp_mem_err("scsp_dup_csa: sizeof(Scsp_csa)"); + } + + /* + * Copy data to the duplicate + */ + UM_COPY(csap, dupp, sizeof(Scsp_csa)); + dupp->next = (Scsp_csa *)0; + + /* + * Copy protocol-specific data, if it's present + */ + if (csap->atmarp_data) { + adp = (Scsp_atmarp_csa *)UM_ALLOC(sizeof(Scsp_atmarp_csa)); + if (!adp) { + scsp_mem_err("scsp_dup_csa: sizeof(Scsp_atmarp_csa)"); + } + UM_COPY(csap->atmarp_data, adp, sizeof(Scsp_atmarp_csa)); + dupp->atmarp_data = adp; + } + + return(dupp); +} + + +/* + * Copy a cache summary entry into a CSAS + * + * Arguments: + * csep pointer to CSE entry to copy + * + * Returns: + * 0 copy failed + * else pointer to CSAS record summarizing the entry + * + */ +Scsp_csa * +scsp_cse2csas(csep) + Scsp_cse *csep; +{ + Scsp_csa *csap; + + /* + * Allocate memory for the duplicate + */ + csap = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa)); + if (!csap) { + scsp_mem_err("scsp_cse2csas: sizeof(Scsp_csa)"); + } + UM_ZERO(csap, sizeof(Scsp_csa)); + + /* + * Copy data to the CSAS entry + */ + csap->seq = csep->sc_seq; + csap->key = csep->sc_key; + csap->oid = csep->sc_oid; + + return(csap); +} + + +/* + * Copy an ATMARP cache entry into a cache summary entry + * + * Arguments: + * aap pointer to ATMARP cache entry to copy + * + * Returns: + * 0 copy failed + * else pointer to CSE record summarizing the entry + * + */ +Scsp_cse * +scsp_atmarp2cse(aap) + Scsp_atmarp_msg *aap; +{ + Scsp_cse *csep; + + /* + * Allocate memory for the duplicate + */ + csep = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse)); + if (!csep) { + scsp_mem_err("scsp_atmarp2cse: sizeof(Scsp_cse)"); + } + UM_ZERO(csep, sizeof(Scsp_cse)); + + /* + * Copy data to the CSE entry + */ + csep->sc_seq = aap->sa_seq; + csep->sc_key = aap->sa_key; + csep->sc_oid = aap->sa_oid; + + return(csep); +} + + +/* + * Clean up a DCS block. This routine is called to clear out any + * lingering state information when the CA FSM reverts to an 'earlier' + * state (Down or Master/Slave Negotiation). + * + * Arguments: + * dcsp pointer to a DCS control block for the neighbor + * + * Returns: + * none + * + */ +void +scsp_dcs_cleanup(dcsp) + Scsp_dcs *dcsp; +{ + Scsp_cse *csep, *ncsep; + Scsp_csa *csap, *next_csap; + Scsp_csu_rexmt *rxp, *rx_next; + + /* + * Free any CSAS entries waiting to be sent + */ + for (csep = dcsp->sd_ca_csas; csep; csep = ncsep) { + ncsep = csep->sc_next; + UNLINK(csep, Scsp_cse, dcsp->sd_ca_csas, sc_next); + UM_FREE(csep); + } + + /* + * Free any entries on the CRL + */ + for (csap = dcsp->sd_crl; csap; csap = next_csap) { + next_csap = csap->next; + UNLINK(csap, Scsp_csa, dcsp->sd_crl, next); + SCSP_FREE_CSA(csap); + } + + /* + * Free any saved CA message and cancel the CA + * retransmission timer + */ + if (dcsp->sd_ca_rexmt_msg) { + scsp_free_msg(dcsp->sd_ca_rexmt_msg); + dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0; + } + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + + /* + * Free any saved CSU Solicit message and cancel the CSUS + * retransmission timer + */ + if (dcsp->sd_csus_rexmt_msg) { + scsp_free_msg(dcsp->sd_csus_rexmt_msg); + dcsp->sd_csus_rexmt_msg = (Scsp_msg *)0; + } + HARP_CANCEL(&dcsp->sd_csus_rexmt_t); + + /* + * Free any entries on the CSU Request retransmission queue + */ + for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = rx_next) { + rx_next = rxp->sr_next; + HARP_CANCEL(&rxp->sr_t); + for (csap = rxp->sr_csa; csap; csap = next_csap) { + next_csap = csap->next; + SCSP_FREE_CSA(csap); + } + UNLINK(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt, + sr_next); + UM_FREE(rxp); + } +} + + +/* + * Delete an SCSP DCS block and any associated information + * + * Arguments: + * dcsp pointer to a DCS control block to delete + * + * Returns: + * none + * + */ +void +scsp_dcs_delete(dcsp) + Scsp_dcs *dcsp; +{ + Scsp_cse *csep, *next_cse; + Scsp_csu_rexmt *rxp, *next_rxp; + Scsp_csa *csap, *next_csa; + + /* + * Cancel any pending DCS timers + */ + HARP_CANCEL(&dcsp->sd_open_t); + HARP_CANCEL(&dcsp->sd_hello_h_t); + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + HARP_CANCEL(&dcsp->sd_csus_rexmt_t); + + /* + * Unlink the DCS block from the server block + */ + UNLINK(dcsp, Scsp_dcs, dcsp->sd_server->ss_dcs, sd_next); + + /* + * Close the VCC to the DCS, if one is open + */ + if (dcsp->sd_sock != -1) { + (void)close(dcsp->sd_sock); + } + + /* + * Free any saved CA message + */ + if (dcsp->sd_ca_rexmt_msg) { + scsp_free_msg(dcsp->sd_ca_rexmt_msg); + } + + /* + * Free any pending CSAs waiting for cache alignment + */ + for (csep = dcsp->sd_ca_csas; csep; csep = next_cse) { + next_cse = csep->sc_next; + UM_FREE(csep); + } + + /* + * Free anything on the cache request list + */ + for (csap = dcsp->sd_crl; csap; csap = next_csa) { + next_csa = csap->next; + SCSP_FREE_CSA(csap); + } + + /* + * Free any saved CSUS message + */ + if (dcsp->sd_csus_rexmt_msg) { + scsp_free_msg(dcsp->sd_csus_rexmt_msg); + } + + /* + * Free anything on the CSU Request retransmit queue + */ + for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = next_rxp) { + /* + * Cancel the retransmit timer + */ + HARP_CANCEL(&rxp->sr_t); + + /* + * Free the CSAs to be retransmitted + */ + for (csap = rxp->sr_csa; csap; csap = next_csa) { + next_csa = csap->next; + SCSP_FREE_CSA(csap); + } + + /* + * Free the CSU Req retransmission control block + */ + next_rxp = rxp->sr_next; + UM_FREE(rxp); + } + + /* + * Free the DCS block + */ + UM_FREE(dcsp); +} + + +/* + * Shut down a server. This routine is called when a connection to + * a server is lost. It will clear the server's state without deleting + * the server. + * + * Arguments: + * ssp pointer to a server control block + * + * Returns: + * none + * + */ +void +scsp_server_shutdown(ssp) + Scsp_server *ssp; +{ + int i; + Scsp_dcs *dcsp; + Scsp_cse *csep; + + /* + * Trace the shutdown + */ + if (scsp_trace_mode & (SCSP_TRACE_IF_MSG | SCSP_TRACE_CFSM)) { + scsp_trace("Server %s being shut down\n", + ssp->ss_name); + } + + /* + * Terminate up all the DCS connections and clean + * up the control blocks + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + if (dcsp->sd_sock != -1) { + (void)close(dcsp->sd_sock); + dcsp->sd_sock = -1; + } + HARP_CANCEL(&dcsp->sd_open_t); + HARP_CANCEL(&dcsp->sd_hello_h_t); + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + scsp_dcs_cleanup(dcsp); + dcsp->sd_hello_state = SCSP_HFSM_DOWN; + dcsp->sd_ca_state = SCSP_CAFSM_DOWN; + dcsp->sd_client_state = SCSP_CIFSM_NULL; + } + + /* + * Clean up the server control block + */ + if (ssp->ss_sock != -1) { + (void)close(ssp->ss_sock); + ssp->ss_sock = -1; + } + if (ssp->ss_dcs_lsock != -1) { + (void)close(ssp->ss_dcs_lsock); + ssp->ss_dcs_lsock = -1; + } + ssp->ss_state = SCSP_SS_NULL; + + /* + * Free the entries in the server's summary cache + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + while (ssp->ss_cache[i]) { + csep = ssp->ss_cache[i]; + UNLINK(csep, Scsp_cse, ssp->ss_cache[i], + sc_next); + UM_FREE(csep); + } + } +} + + +/* + * Delete an SCSP server block and any associated information + * + * Arguments: + * ssp pointer to a server control block to delete + * + * Returns: + * none + * + */ +void +scsp_server_delete(ssp) + Scsp_server *ssp; +{ + int i; + Scsp_dcs *dcsp, *next_dcs; + Scsp_cse *csep, *next_cse; + + /* + * Unlink the server block from the chain + */ + UNLINK(ssp, Scsp_server, scsp_server_head, ss_next); + + /* + * Free the DCS blocks associated with the server + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = next_dcs) { + next_dcs = dcsp->sd_next; + scsp_dcs_delete(dcsp); + } + + /* + * Free the entries in the server's summary cache + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + for (csep = ssp->ss_cache[i]; csep; csep = next_cse) { + next_cse = csep->sc_next; + UM_FREE(csep); + } + } + + /* + * Free the server block + */ + UM_FREE(ssp->ss_name); + UM_FREE(ssp); +} + + +/* + * Get informtion about a server from the kernel + * + * Arguments: + * ssp pointer to the server block + * + * Returns: + * 0 server info is OK + * errno server is not ready + * + */ +int +scsp_get_server_info(ssp) + Scsp_server *ssp; +{ + int i, len, mtu, rc, sel; + struct atminfreq air; + struct air_netif_rsp *netif_rsp = (struct air_netif_rsp *)0; + struct air_int_rsp *intf_rsp = (struct air_int_rsp *)0; + struct air_cfg_rsp *cfg_rsp = (struct air_cfg_rsp *)0; + struct sockaddr_in *ip_addr; + struct sockaddr_in subnet_mask; + Atm_addr_nsap *anp; + + /* + * Make sure we're the server for the interface + */ + if (!scsp_is_atmarp_server(ssp->ss_intf)) { + rc = EINVAL; + goto server_info_done; + } + + /* + * Get the IP address and physical interface name + * associated with the network interface + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_NIF; + strcpy(air.air_netif_intf, ssp->ss_intf); + len = do_info_ioctl(&air, sizeof(struct air_netif_rsp)); + if (len <= 0) { + rc = EIO; + goto server_info_done; + } + netif_rsp = (struct air_netif_rsp *)air.air_buf_addr; + + ip_addr = (struct sockaddr_in *)&netif_rsp->anp_proto_addr; + if (ip_addr->sin_family != AF_INET || + ip_addr->sin_addr.s_addr == 0) { + rc = EADDRNOTAVAIL; + goto server_info_done; + } + + /* + * Get the MTU for the network interface + */ + mtu = get_mtu(ssp->ss_intf); + if (mtu < 0) { + rc = EIO; + goto server_info_done; + } + + /* + * Get the ATM address associated with the + * physical interface + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_INT; + strcpy(air.air_int_intf, netif_rsp->anp_phy_intf); + len = do_info_ioctl(&air, sizeof(struct air_int_rsp)); + if (len <= 0) { + rc = EIO; + goto server_info_done; + } + intf_rsp = (struct air_int_rsp *)air.air_buf_addr; + + /* + * Make sure we're running UNI signalling + */ + if (intf_rsp->anp_sig_proto != ATM_SIG_UNI30 && + intf_rsp->anp_sig_proto != ATM_SIG_UNI31 && + intf_rsp->anp_sig_proto != ATM_SIG_UNI40) { + rc = EINVAL; + goto server_info_done; + } + + /* + * Check the physical interface's state + */ + if (intf_rsp->anp_sig_state != UNISIG_ACTIVE) { + rc = EHOSTDOWN; + goto server_info_done; + } + + /* + * Make sure the interface's address is valid + */ + if (intf_rsp->anp_addr.address_format != T_ATM_ENDSYS_ADDR && + !(intf_rsp->anp_addr.address_format == + T_ATM_E164_ADDR && + intf_rsp->anp_subaddr.address_format == + T_ATM_ENDSYS_ADDR)) { + rc = EINVAL; + goto server_info_done; + } + + /* + * Find the selector byte value for the interface + */ + for (i=0; i<strlen(ssp->ss_intf); i++) { + if (ssp->ss_intf[i] >= '0' && + ssp->ss_intf[i] <= '9') + break; + } + sel = atoi(&ssp->ss_intf[i]); + + /* + * Get configuration information associated with the + * physical interface + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_CFG; + strcpy(air.air_int_intf, netif_rsp->anp_phy_intf); + len = do_info_ioctl(&air, sizeof(struct air_cfg_rsp)); + if (len <= 0) { + rc = EIO; + goto server_info_done; + } + cfg_rsp = (struct air_cfg_rsp *)air.air_buf_addr; + + /* + * Update the server entry + */ + UM_COPY(&ip_addr->sin_addr, ssp->ss_lsid.id, ssp->ss_id_len); + ssp->ss_lsid.id_len = ssp->ss_id_len; + ssp->ss_mtu = mtu + 8; + ATM_ADDR_COPY(&intf_rsp->anp_addr, &ssp->ss_addr); + ATM_ADDR_COPY(&intf_rsp->anp_subaddr, &ssp->ss_subaddr); + if (ssp->ss_addr.address_format == T_ATM_ENDSYS_ADDR) { + anp = (Atm_addr_nsap *)ssp->ss_addr.address; + anp->aan_sel = sel; + } else if (ssp->ss_addr.address_format == T_ATM_E164_ADDR && + ssp->ss_subaddr.address_format == + T_ATM_ENDSYS_ADDR) { + anp = (Atm_addr_nsap *)ssp->ss_subaddr.address; + anp->aan_sel = sel; + } + ssp->ss_media = cfg_rsp->acp_cfg.ac_media; + rc = 0; + + /* + * Free dynamic data + */ +server_info_done: + if (netif_rsp) + UM_FREE(netif_rsp); + if (intf_rsp) + UM_FREE(intf_rsp); + if (cfg_rsp) + UM_FREE(cfg_rsp); + + return(rc); +} + + +/* + * Process a CA message + * + * Arguments: + * dcsp pointer to a DCS control block for the neighbor + * cap pointer to the CA part of the received message + * + * Returns: + * none + * + */ +void +scsp_process_ca(dcsp, cap) + Scsp_dcs *dcsp; + Scsp_ca *cap; +{ + Scsp_csa *csap, *next_csap; + Scsp_cse *csep; + Scsp_server *ssp = dcsp->sd_server; + + /* + * Process CSAS records from the CA message + */ + for (csap = cap->ca_csa_rec; csap; csap = next_csap) { + next_csap = csap->next; + SCSP_LOOKUP(ssp, &csap->key, csep); + if (!csep || scsp_cmp_id(&csap->oid, + &csep->sc_oid) == 0 && + csap->seq > csep->sc_seq) { + /* + * CSAS entry not in cache or more + * up to date than cache, add it to CRL + */ + UNLINK(csap, Scsp_csa, cap->ca_csa_rec, next); + LINK2TAIL(csap, Scsp_csa, dcsp->sd_crl, next); + } + } +} + + +/* + * Process a Cache Response message from a server + * + * Arguments: + * ssp pointer to the server block + * smp pointer to the message + * + * Returns: + * none + * + */ +void +scsp_process_cache_rsp(ssp, smp) + Scsp_server *ssp; + Scsp_if_msg *smp; +{ + int len; + Scsp_atmarp_msg *aap; + Scsp_cse *csep; + + /* + * Loop through the message, processing each cache entry + */ + len = smp->si_len; + len -= sizeof(Scsp_if_msg_hdr); + aap = &smp->si_atmarp; + while (len > 0) { + switch(smp->si_proto) { + case SCSP_ATMARP_PROTO: + /* + * If we already have an entry with this key, + * delete it + */ + SCSP_LOOKUP(ssp, &aap->sa_key, csep); + if (csep) { + SCSP_DELETE(ssp, csep); + UM_FREE(csep); + } + + /* + * Copy the data from the server to a cache + * summary entry + */ + csep = scsp_atmarp2cse(aap); + + /* + * Point past this entry + */ + len -= sizeof(Scsp_atmarp_msg); + aap++; + break; + case SCSP_NHRP_PROTO: + /* + * Not implemented yet + */ + return; + } + + /* + * Add the new summary entry to the cache + */ + SCSP_ADD(ssp, csep); + } +} + + +/* + * Propagate a CSA to all the DCSs in the server group except + * the one the CSA was received from + * + * Arguments: + * dcsp pointer to a the DCS the CSA came from + * csap pointer to a the CSA + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_propagate_csa(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + int rc, ret_rc = 0; + Scsp_server *ssp = dcsp->sd_server; + Scsp_dcs *dcsp1; + Scsp_csa *csap1; + + /* + * Check the hop count in the CSA + */ + if (csap->hops <= 1) + return(0); + + /* + * Pass the cache entry on to the server's other DCSs + */ + for (dcsp1 = ssp->ss_dcs; dcsp1; dcsp1 = dcsp1->sd_next) { + /* + * Skip this DCS if it's the one we got + * the entry from + */ + if (dcsp1 == dcsp) + continue; + + /* + * Copy the CSA + */ + csap1 = scsp_dup_csa(csap); + + /* + * Decrement the hop count + */ + csap1->hops--; + + /* + * Send the copy of the CSA to the CA FSM for the DCS + */ + rc = scsp_cafsm(dcsp1, SCSP_CAFSM_CACHE_UPD, + (void *) csap1); + if (rc) + ret_rc = rc; + } + + return(ret_rc); +} + + +/* + * Update SCSP's cache given a CSA or CSAS + * + * Arguments: + * dcsp pointer to a DCS + * csap pointer to a CSA + * + * Returns: + * none + * + */ +void +scsp_update_cache(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + Scsp_cse *csep; + + /* + * Check whether we already have this in the cache + */ + SCSP_LOOKUP(dcsp->sd_server, &csap->key, csep); + + /* + * If we don't already have it and it's not being deleted, + * build a new cache summary entry + */ + if (!csep && !csap->null) { + /* + * Get memory for a new entry + */ + csep = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse)); + if (!csep) { + scsp_mem_err("scsp_update_cache: sizeof(Scsp_cse)"); + } + UM_ZERO(csep, sizeof(Scsp_cse)); + + /* + * Fill out the new cache summary entry + */ + csep->sc_seq = csap->seq; + csep->sc_key = csap->key; + csep->sc_oid = csap->oid; + + /* + * Add the new entry to the cache + */ + SCSP_ADD(dcsp->sd_server, csep); + } + + /* + * Update or delete the entry + */ + if (csap->null) { + /* + * The null flag is set--delete the entry + */ + if (csep) { + SCSP_DELETE(dcsp->sd_server, csep); + UM_FREE(csep); + } + } else { + /* + * Update the existing entry + */ + csep->sc_seq = csap->seq; + csep->sc_oid = csap->oid; + } +} + + +/* + * Reconfigure SCSP + * + * Called as the result of a SIGHUP interrupt. Reread the + * configuration file and solicit the cache from the server. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +scsp_reconfigure() +{ + int rc; + Scsp_server *ssp; + + /* + * Log a message saying we're reconfiguring + */ + scsp_log(LOG_ERR, "Reconfiguring ..."); + + /* + * Re-read the configuration file + */ + rc = scsp_config(scsp_config_file); + if (rc) { + scsp_log(LOG_ERR, "Found %d error%s in configuration file", + rc, ((rc == 1) ? "" : "s")); + exit(1); + } + + /* + * If a connection to a server is open, get the cache from + * the server + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (ssp->ss_sock != -1) { + rc = scsp_send_cache_ind(ssp); + } + } +} |