freebsd-skq/sys/netatm/uni/uniarp_cache.c
archie 982e80577d Examine all occurrences of sprintf(), strcat(), and str[n]cpy()
for possible buffer overflow problems. Replaced most sprintf()'s
with snprintf(); for others cases, added terminating NUL bytes where
appropriate, replaced constants like "16" with sizeof(), etc.

These changes include several bug fixes, but most changes are for
maintainability's sake. Any instance where it wasn't "immediately
obvious" that a buffer overflow could not occur was made safer.

Reviewed by:	Bruce Evans <bde@zeta.org.au>
Reviewed by:	Matthew Dillon <dillon@apollo.backplane.com>
Reviewed by:	Mike Spengler <mks@networkcs.com>
1998-12-04 22:54:57 +00:00

425 lines
10 KiB
C

/*
*
* ===================================
* 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.2 1998/10/31 20:07:00 phk Exp $
*
*/
/*
* ATM Forum UNI Support
* ---------------------
*
* UNI ATMARP support (RFC1577) - ARP cache processing
*
*/
#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>
#ifndef lint
__RCSID("@(#) $Id: uniarp_cache.c,v 1.2 1998/10/31 20:07:00 phk Exp $");
#endif
/*
* 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));
abuf[sizeof(abuf) - 1] = 0;
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));
abuf[sizeof(abuf) - 1] = 0;
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));
abuf[sizeof(abuf) - 1] = 0;
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));
buf[sizeof(buf) - 1] = 0;
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);
}