/* * * =================================== * 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. * * @(#) $FreeBSD$ * */ /* * Server Cache Synchronization Protocol (SCSP) Support * ---------------------------------------------------- * * SCSP-ATMARP server interface: SCSP/ATMARP interface code * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../scspd/scsp_msg.h" #include "../scspd/scsp_if.h" #include "../scspd/scsp_var.h" #include "atmarp_var.h" #ifndef lint __RCSID("@(#) $FreeBSD$"); #endif /* * Send the cache for a LIS to SCSP * * * Arguments: * aip pointer to interface block * * Returns: * 0 cache sent to SCSP OK * errno reason for failure * */ int atmarp_scsp_cache(aip, msg) Atmarp_intf *aip; Scsp_if_msg *msg; { int i, len, rc = 0; Atmarp *aap; Scsp_if_msg *smp = (Scsp_if_msg *)0; Scsp_atmarp_msg *sap; /* * Figure out how big the message needs to be */ len = sizeof(Scsp_if_msg_hdr); for (i = 0; i < ATMARP_HASHSIZ; i++) { for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) { len += sizeof(Scsp_atmarp_msg); } } /* * Get memory for the cache message */ smp = calloc(1, len); if (smp == NULL) atmarp_mem_err("atmarp_scsp_cache: len"); /* * Set header fields in SCSP message */ smp->si_type = SCSP_CACHE_RSP; smp->si_proto = SCSP_PROTO_ATMARP; smp->si_len = len; smp->si_tok = msg->si_tok; /* * Loop through the cache, adding each entry to the SCSP * Cache Response message */ sap = &smp->si_atmarp; for (i = 0; i < ATMARP_HASHSIZ; i++) { for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) { sap->sa_state = SCSP_ASTATE_NEW; sap->sa_cpa = aap->aa_dstip; ATM_ADDR_COPY(&aap->aa_dstatm, &sap->sa_cha); ATM_ADDR_COPY(&aap->aa_dstatmsub, &sap->sa_csa); sap->sa_key = aap->aa_key; sap->sa_oid = aap->aa_oid; sap->sa_seq = aap->aa_seq; sap++; } } /* * Send the message to SCSP */ rc = atmarp_scsp_out(aip, (char *)smp, len); /* * Free the message */ if (smp) free(smp); return(rc); } /* * Answer a reqeust for information about a cache entry * * Arguments: * aap pointer to entry * state entry's new state * * Returns: * 0 success * errno reason for failure * */ int atmarp_scsp_solicit(aip, smp) Atmarp_intf *aip; Scsp_if_msg *smp; { int i, rc = 0; Atmarp *aap; Scsp_if_msg *rsp = (Scsp_if_msg *)0; /* * Search the interface's ATMARP cache for an entry with * the specified cache key and origin ID */ for (i = 0; i < ATMARP_HASHSIZ; i++) { for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) { if (KEY_EQUAL(&aap->aa_key, &smp->si_sum.ss_key) && OID_EQUAL(&aap->aa_oid, &smp->si_sum.ss_oid)) break; } if (aap) break; } /* * Get storage for a Solicit Response */ rsp = calloc(1, sizeof(Scsp_if_msg)); if (rsp == NULL) atmarp_mem_err("atmarp_scsp_solicit: sizeof(Scsp_if_msg)"); /* * Fill out the Solicit Rsp */ rsp->si_type = SCSP_SOLICIT_RSP; rsp->si_proto = smp->si_proto; rsp->si_tok = smp->si_tok; if (aap) { /* * Copy fields from the ATMARP entry to the SCSP * Update Request message */ rsp->si_rc = SCSP_RSP_OK; rsp->si_len = sizeof(Scsp_if_msg_hdr) + sizeof(Scsp_atmarp_msg); rsp->si_atmarp.sa_state = SCSP_ASTATE_UPD; rsp->si_atmarp.sa_cpa = aap->aa_dstip; ATM_ADDR_COPY(&aap->aa_dstatm, &rsp->si_atmarp.sa_cha); ATM_ADDR_COPY(&aap->aa_dstatmsub, &rsp->si_atmarp.sa_csa); rsp->si_atmarp.sa_key = aap->aa_key; rsp->si_atmarp.sa_oid = aap->aa_oid; rsp->si_atmarp.sa_seq = aap->aa_seq; } else { /* * Entry not found--set return code */ rsp->si_rc = SCSP_RSP_NOT_FOUND; rsp->si_len = smp->si_len; rsp->si_sum = smp->si_sum; } /* * Send the message to SCSP */ rc = atmarp_scsp_out(aip, (char *)rsp, rsp->si_len); free(rsp); return(rc); } /* * Send a cache update to SCSP * * Arguments: * aap pointer to entry * state entry's new state * * Returns: * 0 success * errno reason for failure * */ int atmarp_scsp_update(aap, state) Atmarp *aap; int state; { int rc = 0; Atmarp_intf *aip = aap->aa_intf; Scsp_if_msg *smp = (Scsp_if_msg *)0; /* * Make sure the connection to SCSP is active */ if (aip->ai_state == AI_STATE_NULL) { return(0); } /* * Get memory for the cache message */ smp = calloc(1, sizeof(Scsp_if_msg)); if (smp == NULL) atmarp_mem_err("atmarp_scsp_update: sizeof(Scsp_if_msg)"); /* * Set header fields in SCSP message */ smp->si_type = SCSP_UPDATE_REQ; smp->si_proto = SCSP_PROTO_ATMARP; smp->si_len = sizeof(Scsp_if_msg_hdr) + sizeof(Scsp_atmarp_msg); /* * Copy fields from the ATMARP entry to the SCSP * Update Request message */ smp->si_atmarp.sa_state = state; smp->si_atmarp.sa_cpa = aap->aa_dstip; ATM_ADDR_COPY(&aap->aa_dstatm, &smp->si_atmarp.sa_cha); ATM_ADDR_COPY(&aap->aa_dstatmsub, &smp->si_atmarp.sa_csa); smp->si_atmarp.sa_key = aap->aa_key; smp->si_atmarp.sa_oid = aap->aa_oid; smp->si_atmarp.sa_seq = aap->aa_seq; /* * Send the message to SCSP */ rc = atmarp_scsp_out(aap->aa_intf, (char *)smp, smp->si_len); free(smp); return(rc); } /* * Respond to a Cache Update Indication from SCSP * * * Arguments: * aip pointer to interface control block * smp pointer to message from SCSP * * Returns: * 0 Message processed OK * errno Reason for failure * */ int atmarp_scsp_update_in(aip, smp) Atmarp_intf *aip; Scsp_if_msg *smp; { int accept, rc; Atmarp *aap; /* * Look up the entry */ ATMARP_LOOKUP(aip, smp->si_atmarp.sa_cpa.s_addr, aap); /* * Whether we accept the request depends on whether we * already have an entry for it */ if (!aap) { /* * We don't have this entry--accept it */ accept = 1; } else { /* * We do have an entry for this host--check the * origin ID */ if (bcmp(&aip->ai_ip_addr.s_addr, smp->si_atmarp.sa_oid.id, SCSP_ATMARP_ID_LEN) == 0) { /* * The received entry originated with us-- * reject it */ accept = 0; } else if (bcmp(&aip->ai_ip_addr.s_addr, aap->aa_oid.id, SCSP_ATMARP_ID_LEN) == 0) { /* * We originated the entry we currently have-- * only accept the new one if SCSP has higher * priority than the existing entry */ accept = aap->aa_origin < UAO_SCSP; } else { /* * Accept the entry if it is more up-to-date * than the existing entry */ accept = KEY_EQUAL(&aap->aa_key, &smp->si_atmarp.sa_key) && OID_EQUAL(&aap->aa_oid, &smp->si_atmarp.sa_oid) && (aap->aa_seq < smp->si_atmarp.sa_seq); } } /* * Add the entry to the cache, if appropriate */ if (accept) { if (!aap) { /* * Copy info from SCSP to a new cache entry */ aap = calloc(1, sizeof(Atmarp)); if (aap == NULL) atmarp_mem_err("atmarp_scsp_update_in: sizeof(Atmarp)"); aap->aa_dstip = smp->si_atmarp.sa_cpa; aap->aa_dstatm = smp->si_atmarp.sa_cha; aap->aa_dstatmsub = smp->si_atmarp.sa_csa; aap->aa_key = smp->si_atmarp.sa_key; aap->aa_oid = smp->si_atmarp.sa_oid; aap->aa_seq = smp->si_atmarp.sa_seq; aap->aa_intf = aip; aap->aa_origin = UAO_SCSP; /* * Add the new entry to our cache */ ATMARP_ADD(aip, aap); } else { /* * Update the existing entry */ aap->aa_dstip = smp->si_atmarp.sa_cpa; aap->aa_dstatm = smp->si_atmarp.sa_cha; aap->aa_dstatmsub = smp->si_atmarp.sa_csa; aap->aa_key = smp->si_atmarp.sa_key; aap->aa_oid = smp->si_atmarp.sa_oid; aap->aa_seq = smp->si_atmarp.sa_seq; aap->aa_origin = UAO_SCSP; } /* * Send the updated entry to the kernel */ if (atmarp_update_kernel(aap) == 0) rc = SCSP_RSP_OK; else rc = SCSP_RSP_REJ; } else { rc = SCSP_RSP_REJ; } /* * Turn the received message into a response */ smp->si_type = SCSP_UPDATE_RSP; smp->si_rc = rc; /* * Send the message to SCSP */ rc = atmarp_scsp_out(aip, (char *)smp, smp->si_len); return(rc); } /* * Read and process a message from SCSP * * * Arguments: * aip interface for read * * Returns: * 0 success * errno reason for failure * */ int atmarp_scsp_read(aip) Atmarp_intf *aip; { int len, rc = 0; char *buff = (char *)0; Scsp_if_msg *smp; Scsp_if_msg_hdr msg_hdr; /* * Read the header of the message from SCSP */ len = read(aip->ai_scsp_sock, (char *)&msg_hdr, sizeof(msg_hdr)); if (len == -1) { rc = errno; goto read_fail; } else if (len != sizeof(msg_hdr)) { rc = EMSGSIZE; goto read_fail; } /* * Get a buffer that will hold the message */ buff = malloc(msg_hdr.sh_len); if (buff == NULL) atmarp_mem_err("atmarp_scsp_read: msg_hdr.sh_len"); bcopy(&msg_hdr, buff, sizeof(msg_hdr)); /* * Read the rest of the message, if there is more than * just a header */ len = msg_hdr.sh_len - sizeof(msg_hdr); if (len > 0) { len = read(aip->ai_scsp_sock, buff + sizeof(msg_hdr), len); if (len == -1) { rc = errno; goto read_fail; } else if (len != msg_hdr.sh_len - sizeof(msg_hdr)) { rc = EMSGSIZE; goto read_fail; } } /* * Handle the message based on its type */ smp = (Scsp_if_msg *)buff; switch(smp->si_type) { case SCSP_CFG_RSP: if (smp->si_rc != SCSP_RSP_OK) { rc = EINVAL; goto read_fail; } break; case SCSP_CACHE_IND: rc = atmarp_scsp_cache(aip, smp); break; case SCSP_SOLICIT_IND: rc = atmarp_scsp_solicit(aip, smp); break; case SCSP_UPDATE_IND: rc = atmarp_scsp_update_in(aip, smp); break; case SCSP_UPDATE_RSP: /* * Ignore Update Responses */ break; default: atmarp_log(LOG_ERR, "Unexpected SCSP message received"); return(EOPNOTSUPP); } free(buff); return(rc); read_fail: if (buff) free(buff); /* * Error on socket to SCSP--close the socket and set the state * so that we know to retry when the cache timer fires. */ atmarp_scsp_close(aip); return(rc); } /* * Send a message to SCSP * * * Arguments: * aip pointer to ATMARP interface to send message on * buff pointer to message buffer * len length of message * * Returns: * 0 message sent * errno reason for failure * */ int atmarp_scsp_out(aip, buff, len) Atmarp_intf *aip; char *buff; int len; { int rc; /* * Send the message to SCSP */ rc = write(aip->ai_scsp_sock, buff, len); if (rc == len) return(0); /* * Error on write--close the socket to SCSP, clean up and * set the state so that we know to retry when the cache * timer fires. */ atmarp_scsp_close(aip); /* * Set the return code */ if (rc < 0) { rc = errno; } else { rc = EFAULT; } return(rc); } /* * Set up a socket and connect to SCSP * * Arguments: * aip pointer to interface block * * Returns: * 0 success, ai_scsp_sock is set * errno reason for failure * * */ int atmarp_scsp_connect(aip) Atmarp_intf *aip; { int len, rc, sd; char *sn; Scsp_if_msg cfg_msg; static struct sockaddr local_addr = { #if (defined(BSD) && (BSD >= 199103)) sizeof(struct sockaddr), /* sa_len */ #endif AF_UNIX, /* sa_family */ ATMARP_SOCK_PREFIX /* sa_data */ }; static struct sockaddr scsp_addr = { #if (defined(BSD) && (BSD >= 199103)) sizeof(struct sockaddr), /* sa_len */ #endif AF_UNIX, /* sa_family */ SCSPD_SOCK_NAME /* sa_data */ }; /* * Construct a name for the socket */ strncpy(local_addr.sa_data, ATMARP_SOCK_PREFIX, sizeof(local_addr.sa_data)); (void)strncat(local_addr.sa_data, aip->ai_intf, sizeof(local_addr.sa_data)); sn = strdup(local_addr.sa_data); if (!sn) atmarp_mem_err("atmarp_scsp_connect: strdup"); /* * Clean up any old socket */ rc = unlink(sn); if (rc < 0 && errno != ENOENT) return(errno); /* * Open a socket to SCSP */ sd = socket(PF_UNIX, SOCK_STREAM, 0); if (sd == -1) { free(sn); return(errno); } if (sd > atmarp_max_socket) { atmarp_max_socket = sd; } /* * Set non-blocking I/O */ #ifdef sun rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); #else rc = fcntl(sd, F_SETFL, O_NONBLOCK); #endif if (rc == -1) { rc = errno; goto scsp_connect_fail; } /* * Bind the local socket address */ rc = bind(sd, &local_addr, sizeof(local_addr)); if (rc) { rc = errno; goto scsp_connect_fail; } /* * Connect to SCSP */ rc = connect(sd, &scsp_addr, sizeof(scsp_addr)); if (rc) { rc = errno; goto scsp_connect_fail; } /* * Save socket information in interface control block */ aip->ai_scsp_sock = sd; aip->ai_scsp_sockname = sn; aip->ai_state = AI_STATE_UP; /* * Send configuration information to SCSP */ bzero(&cfg_msg, sizeof(cfg_msg)); cfg_msg.si_type = SCSP_CFG_REQ; cfg_msg.si_proto = SCSP_PROTO_ATMARP; strcpy(cfg_msg.si_cfg.atmarp_netif, aip->ai_intf); len =sizeof(Scsp_if_msg_hdr) + strlen(aip->ai_intf) + 1; cfg_msg.si_len = len; rc = atmarp_scsp_out(aip, (char *)&cfg_msg, len); if (rc) { return(rc); } return(0); scsp_connect_fail: (void)close(sd); aip->ai_scsp_sock = -1; free(sn); aip->ai_scsp_sockname = NULL; aip->ai_state = AI_STATE_NULL; return(rc); } /* * Close a socket connection to SCSP * * Arguments: * aip pointer to interface block for connection to be closed * * Returns: * none * * */ void atmarp_scsp_close(aip) Atmarp_intf *aip; { /* * Close and unlink the SCSP socket */ (void)close(aip->ai_scsp_sock); aip->ai_scsp_sock = -1; (void)unlink(aip->ai_scsp_sockname); free(aip->ai_scsp_sockname); aip->ai_scsp_sockname = NULL; aip->ai_state = AI_STATE_NULL; return; } /* * Disconnect an interface from SCSP * * Arguments: * aip pointer to interface block for connection to be closed * * Returns: * 0 success, ai_scsp_sock is set * errno reason for failure * * */ int atmarp_scsp_disconnect(aip) Atmarp_intf *aip; { int i; Atmarp *aap; /* * Close and unlink the SCSP socket */ atmarp_scsp_close(aip); /* * Free the ATMARP cache associated with the interface */ for (i = 0; i < ATMARP_HASHSIZ; i++) { for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) free(aap); aip->ai_arptbl[i] = (Atmarp *)0; } return(0); }