diff options
Diffstat (limited to 'sys/netatm/uni/uniarp_cache.c')
-rw-r--r-- | sys/netatm/uni/uniarp_cache.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/sys/netatm/uni/uniarp_cache.c b/sys/netatm/uni/uniarp_cache.c new file mode 100644 index 0000000..6c9537e --- /dev/null +++ b/sys/netatm/uni/uniarp_cache.c @@ -0,0 +1,420 @@ +/* + * + * =================================== + * 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: uniarp_cache.c,v 1.8 1998/08/26 23:29:20 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - ARP cache processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_cache.c,v 1.8 1998/08/26 23:29:20 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Add data to the arp table cache + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * ip pointer to IP address structure + * atm pointer to ATM address structure + * atmsub pointer to ATM subaddress structure + * origin source of arp information + * + * Returns: + * 0 cache successfully updated + * else updated failed - reason indicated + * + */ +int +uniarp_cache_svc(uip, ip, atm, atmsub, origin) + struct uniip *uip; + struct in_addr *ip; + Atm_addr *atm; + Atm_addr *atmsub; + u_int origin; +{ + struct ip_nif *inp; + struct ipvcc *ivp, *inext, *itail; + struct uniarp *nouap, *ipuap; + char abuf[64]; + +#ifdef DIAGNOSTIC + strncpy(abuf, unisig_addr_print(atmsub), sizeof(abuf)); + ATM_DEBUG4("cache_svc: ip=%s, atm=(%s,%s), origin=%d\n", + inet_ntoa(*ip), unisig_addr_print(atm), abuf, origin); +#endif + + /* + * Get interface info + */ + inp = uip->uip_ipnif; + + /* + * Find both cached entry and 'nomap' entries for this data. + */ + UNIARP_LOOKUP(ip->s_addr, ipuap); + for (nouap = uniarp_nomaptab; nouap; nouap = nouap->ua_next) { + if (ATM_ADDR_EQUAL(atm, &nouap->ua_dstatm) && + ATM_ADDR_EQUAL(atmsub, &nouap->ua_dstatmsub) && + (nouap->ua_intf == uip)) + break; + } + + /* + * If there aren't any entries yet, create one + */ + if ((ipuap == NULL) && (nouap == NULL)) { + ipuap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (ipuap == NULL) + return (ENOMEM); + ipuap->ua_dstip.s_addr = ip->s_addr; + ipuap->ua_dstatm.address_format = T_ATM_ABSENT; + ipuap->ua_dstatmsub.address_format = T_ATM_ABSENT; + ipuap->ua_intf = uip; + UNIARP_ADD(ipuap); + } + + /* + * If there's no cached mapping, then make the 'nomap' entry + * the new cached entry. + */ + if (ipuap == NULL) { + UNLINK(nouap, struct uniarp, uniarp_nomaptab, ua_next); + nouap->ua_dstip.s_addr = ip->s_addr; + ipuap = nouap; + nouap = NULL; + UNIARP_ADD(ipuap); + } + + /* + * We need to check the consistency of the new data with any + * cached data. So taking the easy case first, if there isn't + * an ATM address in the cache then we can skip all these checks. + */ + if (ipuap->ua_dstatm.address_format != T_ATM_ABSENT) { + /* + * See if the new data conflicts with what's in the cache + */ + if (ATM_ADDR_EQUAL(atm, &ipuap->ua_dstatm) && + ATM_ADDR_EQUAL(atmsub, &ipuap->ua_dstatmsub) && + (uip == ipuap->ua_intf)) { + /* + * No conflicts here + */ + goto dataok; + } + + /* + * Data conflict...how we deal with this depends on + * the origins of the conflicting data + */ + if (origin == ipuap->ua_origin) { + /* + * The new data has equal precedence - if there are + * any VCCs using this entry, then we reject this + * "duplicate IP address" update. + */ + if (ipuap->ua_ivp != NULL) { + strncpy(abuf, unisig_addr_print(atmsub), + sizeof(abuf)); + log(LOG_WARNING, + "uniarp: duplicate IP address %s from %s,%s\n", + inet_ntoa(*ip), unisig_addr_print(atm), + abuf); + return (EACCES); + } + + } else if (origin > ipuap->ua_origin) { + /* + * New data's origin has higher precedence, + * so accept the new mapping and notify IP/ATM + * that a mapping change has occurred. IP/ATM will + * close any VCC's which aren't waiting for this map. + */ + ipuap->ua_flags |= UAF_LOCKED; + for (ivp = ipuap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_CHANGED); + } + ipuap->ua_flags &= ~UAF_LOCKED; + } else { + /* + * New data is of lesser origin precedence, + * so we just reject the update attempt. + */ + return (EACCES); + } + + strncpy(abuf, unisig_addr_print(atmsub), sizeof(abuf)); + log(LOG_WARNING, + "uniarp: ATM address for %s changed to %s,%s\n", + inet_ntoa(*ip), unisig_addr_print(atm), abuf); + } + + /* + * Update the cache entry with the new data + */ + ATM_ADDR_COPY(atm, &ipuap->ua_dstatm); + ATM_ADDR_COPY(atmsub, &ipuap->ua_dstatmsub); + ipuap->ua_intf = uip; + +dataok: + /* + * Update cache data origin + */ + ipuap->ua_origin = MAX(ipuap->ua_origin, origin); + + /* + * Ok, now act on this new/updated cache data + */ + ipuap->ua_flags |= UAF_LOCKED; + + /* + * Save pointer to last VCC currently on cached entry chain that + * will need to be notified of the map becoming valid + */ + itail = NULL; + if ((ipuap->ua_flags & UAF_VALID) == 0) { + + for (itail = ipuap->ua_ivp; itail && itail->iv_arpnext; + itail = itail->iv_arpnext) { + } + } + + /* + * If there was a 'nomap' entry for this mapping, then we need to + * announce the new mapping to them first. + */ + if (nouap) { + + /* + * Move the VCCs from this entry to the cache entry and + * let them know there's a valid mapping now + */ + for (ivp = nouap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + + UNLINK(ivp, struct ipvcc, nouap->ua_ivp, iv_arpnext); + + LINK2TAIL(ivp, struct ipvcc, ipuap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)ipuap; + + (*inp->inf_arpnotify)(ivp, MAP_VALID); + } + + /* + * Unlink and free the 'nomap' entry + */ + UNLINK(nouap, struct uniarp, uniarp_nomaptab, ua_next); + UNIARP_CANCEL(nouap); + atm_free((caddr_t)nouap); + } + + /* + * Now, if this entry wasn't valid, notify the remaining VCCs + */ + if (itail) { + + for (ivp = ipuap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_VALID); + if (ivp == itail) + break; + } + } + ipuap->ua_flags &= ~UAF_LOCKED; + + /* + * We now have a valid cache entry, so cancel any retry timer + * and reset the aging timeout + */ + UNIARP_CANCEL(ipuap); + if ((ipuap->ua_origin == UAO_REGISTER) && (origin != UAO_REGISTER)) { + if (((ipuap->ua_flags & UAF_VALID) == 0) || + (ipuap->ua_aging <= + UNIARP_SERVER_AGE - UNIARP_MIN_REFRESH)) { + ipuap->ua_flags |= UAF_REFRESH; + ipuap->ua_aging = UNIARP_SERVER_AGE; + ipuap->ua_retry = UNIARP_SERVER_RETRY; + } + } else { + if (uip->uip_arpstate == UIAS_SERVER_ACTIVE) { + ipuap->ua_aging = UNIARP_SERVER_AGE; + ipuap->ua_retry = UNIARP_SERVER_RETRY; + } else { + ipuap->ua_aging = UNIARP_CLIENT_AGE; + ipuap->ua_retry = UNIARP_CLIENT_RETRY; + } + ipuap->ua_flags |= UAF_REFRESH; + } + ipuap->ua_flags |= UAF_VALID; + ipuap->ua_flags &= ~UAF_USED; + return (0); +} + + +/* + * Process ARP data from a PVC + * + * The arp table cache is never updated with PVC information. + * + * Called at splnet. + * + * Arguments: + * ivp pointer to input PVC's IPVCC control block + * ip pointer to IP address structure + * atm pointer to ATM address structure + * atmsub pointer to ATM subaddress structure + * + * Returns: + * none + * + */ +void +uniarp_cache_pvc(ivp, ip, atm, atmsub) + struct ipvcc *ivp; + struct in_addr *ip; + Atm_addr *atm; + Atm_addr *atmsub; +{ + struct ip_nif *inp; + struct uniarp *uap; + +#ifdef DIAGNOSTIC + char buf[64]; + int vpi = 0, vci = 0; + + if ((ivp->iv_conn) && (ivp->iv_conn->co_connvc)) { + vpi = ivp->iv_conn->co_connvc->cvc_vcc->vc_vpi; + vci = ivp->iv_conn->co_connvc->cvc_vcc->vc_vci; + } + strncpy(buf, unisig_addr_print(atmsub), sizeof(buf)); + ATM_DEBUG5("cache_pvc: vcc=(%d,%d), ip=%s, atm=(%s,%s)\n", + vpi, vci, inet_ntoa(*ip), unisig_addr_print(atm), buf); +#endif + + /* + * Get PVC info + */ + inp = ivp->iv_ipnif; + uap = (struct uniarp *)ivp->iv_arpent; + + /* + * See if IP address for PVC has changed + */ + if (uap->ua_dstip.s_addr != ip->s_addr) { + if (uap->ua_dstip.s_addr != 0) + (*inp->inf_arpnotify)(ivp, MAP_CHANGED); + uap->ua_dstip.s_addr = ip->s_addr; + } + + /* + * Let IP/ATM know if address has become valid + */ + if ((uap->ua_flags & UAF_VALID) == 0) + (*inp->inf_arpnotify)(ivp, MAP_VALID); + uap->ua_flags |= UAF_VALID; + uap->ua_aging = UNIARP_CLIENT_AGE; + uap->ua_retry = UNIARP_CLIENT_RETRY; + + /* + * Save ATM addresses just for debugging + */ + ATM_ADDR_COPY(atm, &uap->ua_dstatm); + ATM_ADDR_COPY(atmsub, &uap->ua_dstatmsub); + + return; +} + + +/* + * Validate IP address + * + * Arguments: + * uip pointer to UNI IP interface + * ip pointer to IP address structure + * origin source of arp information + * + * Returns: + * 0 IP address is acceptable + * else invalid IP address + * + */ +int +uniarp_validate_ip(uip, ip, origin) + struct uniip *uip; + struct in_addr *ip; + u_int origin; +{ + struct uniarp_prf *upp; + int i; + + + /* + * Can't be multicast or broadcast address + */ + if (IN_MULTICAST(ntohl(ip->s_addr)) || +#if (defined(BSD) && (BSD >= 199306)) + in_broadcast(*ip, &uip->uip_ipnif->inf_nif->nif_if)) +#else + in_broadcast(*ip)) +#endif + return (1); + + /* + * For ATMARP registration information (including SCSP data), + * the address must be allowed by the interface's prefix list. + */ + if ((origin == UAO_REGISTER) || (origin == UAO_SCSP)) { + for (i = uip->uip_nprefix, upp = uip->uip_prefix; + i; i--, upp++) { + if ((ip->s_addr & upp->upf_mask.s_addr) == + upp->upf_addr.s_addr) + break; + } + if (i == 0) + return (1); + } + + return (0); +} + |