freebsd-skq/sys/netatm/spans/spans_arp.c
phk c3dd1fa899 Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc.
This software was developed with the support of the Defense Advanced
Research Projects Agency (DARPA).
1998-09-15 08:23:17 +00:00

1134 lines
24 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: spans_arp.c,v 1.9 1998/06/29 22:03:12 mks Exp $
*
*/
/*
* SPANS Signalling Manager
* ---------------------------
*
* SPANS CLS - ARP support
*
*/
#ifndef lint
static char *RCSid = "@(#) $Id: spans_arp.c,v 1.9 1998/06/29 22:03:12 mks Exp $";
#endif
#include <netatm/kern_include.h>
#include <netatm/ipatm/ipatm_var.h>
#include <netatm/ipatm/ipatm_serv.h>
#include "spans_xdr.h"
#include <netatm/spans/spans_var.h>
#include <netatm/spans/spans_cls.h>
/*
* Global variables
*/
struct spansarp *spansarp_arptab[SPANSARP_HASHSIZ] = {NULL};
/*
* Local functions
*/
static int spansarp_request __P((struct spansarp *));
static void spansarp_aging __P((struct atm_time *));
static void spansarp_retry __P((struct atm_time *));
/*
* Local variables
*/
static struct atm_time spansarp_timer = {0, 0}; /* Aging timer */
static struct atm_time spansarp_rtimer = {0, 0}; /* Retry timer */
static struct spansarp *spansarp_retry_head = NULL; /* Retry chain */
static struct sp_info spansarp_pool = {
"spans arp pool", /* si_name */
sizeof(struct spansarp), /* si_blksiz */
10, /* si_blkcnt */
100 /* si_maxallow */
};
/*
* Process a new outgoing SVC requiring SPANS ARP support
*
* This function is called by an endpoint wishing to resolve a destination
* IP address to an ATM address in order to open an SVC to that destination.
* If a valid mapping is already in our cache, then we just tell the caller
* about it and that's that. Otherwise, we have to allocate a new arp entry
* and issue a query for the mapping.
*
* Arguments:
* ivp pointer to SVC's IPVCC control block
* dst pointer to destination IP address
*
* Returns:
* MAP_VALID - Got the answer, returned via iv_arpent field.
* MAP_PROCEEDING - OK so far, querying for peer's mapping
* MAP_FAILED - error, unable to allocate resources
*
*/
int
spansarp_svcout(ivp, dst)
struct ipvcc *ivp;
struct in_addr *dst;
{
struct spanscls *clp;
struct spansarp *sap;
int s;
ivp->iv_arpent = NULL;
/*
* Lookup destination address
*/
s = splnet();
SPANSARP_LOOKUP(dst->s_addr, sap);
if (sap) {
/*
* Link this vcc to entry queue
*/
LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
/*
* If entry is valid, we're done
*/
if (sap->sa_flags & SAF_VALID) {
ivp->iv_arpent = (struct arpmap *)sap;
(void) splx(s);
return (MAP_VALID);
}
/*
* We're already looking for this address
*/
(void) splx(s);
return (MAP_PROCEEDING);
}
/*
* Need a new arp entry - first, find the cls instance
* corresponding to the requestor's IP interface.
*/
for (clp = spanscls_head; clp; clp = clp->cls_next) {
if (clp->cls_ipnif == ivp->iv_ipnif)
break;
}
if (clp == NULL) {
(void) splx(s);
return (MAP_FAILED);
}
/*
* Now get the new arp entry
*/
sap = (struct spansarp *)atm_allocate(&spansarp_pool);
if (sap == NULL) {
(void) splx(s);
return (MAP_FAILED);
}
/*
* Get entry set up
*/
sap->sa_dstip.s_addr = dst->s_addr;
sap->sa_dstatm.address_format = T_ATM_ABSENT;
sap->sa_dstatm.address_length = 0;
sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
sap->sa_dstatmsub.address_length = 0;
sap->sa_cls = clp;
sap->sa_origin = SAO_LOOKUP;
/*
* Link ipvcc to arp entry for later notification
*/
LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
/*
* Add arp entry to table
*/
SPANSARP_ADD(sap);
/*
* Add arp entry to retry list and start retry timer if needed
*/
LINK2TAIL(sap, struct spansarp, spansarp_retry_head, sa_rnext);
if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
/*
* Issue arp request for this address
*/
(void) spansarp_request(sap);
(void) splx(s);
return (MAP_PROCEEDING);
}
/*
* Process a new incoming SVC requiring SPANS ARP support
*
* This function is called by an endpoint wishing to resolve a destination
* ATM address to its IP address for an incoming call in order to allow a
* bi-directional flow of IP packets on the SVC.
*
* SPANS ARP does not provide reverse mapping facilities and only supports
* uni-directional SVCs. Thus, we lie a little to IP and always return a
* MAP_PROCEEDING indication, but we will never later notify IP of a
* MAP_VALID condition.
*
* Arguments:
* ivp pointer to SVC's IPVCC control block
* dst pointer to destination ATM address
* dstsub pointer to destination ATM subaddress
*
* Returns:
* MAP_VALID - Got the answer, returned via iv_arpent field.
* MAP_PROCEEDING - OK so far, querying for peer's mapping
* MAP_FAILED - error, unable to allocate resources
*
*/
int
spansarp_svcin(ivp, dst, dstsub)
struct ipvcc *ivp;
Atm_addr *dst;
Atm_addr *dstsub;
{
/*
* Clear ARP entry field
*/
ivp->iv_arpent = NULL;
return (MAP_PROCEEDING);
}
/*
* SPANS ARP SVC activation notification
*
* This function is called when a previously opened SVC has successfully
* been connected.
*
* Arguments:
* ivp pointer to SVC's IPVCC control block
*
* Returns:
* 0 activation processing successful
* errno activation failed - reason indicated
*
*/
int
spansarp_svcactive(ivp)
struct ipvcc *ivp;
{
struct spansarp *sap;
int s = splnet();
/*
* Find an entry for the destination address
*/
SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
if (sap) {
/*
* IP is finished with entry, so remove IP VCC from chain
*/
UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
ivp->iv_arpent = NULL;
/*
* This seems like a reasonable reason to refresh the entry
*/
sap->sa_reftime = 0;
}
(void) splx(s);
return (0);
}
/*
* SPANS ARP supported VCC is closing
*
* This function is called just prior to a user closing a VCC which
* supports SPANS ARP. We'll sever our links to the VCC and then
* figure out how much more cleanup we need to do for now.
*
* Arguments:
* ivp pointer to VCC's IPVCC control block
*
* Returns:
* none
*
*/
void
spansarp_vcclose(ivp)
struct ipvcc *ivp;
{
struct spansarp *sap;
int s = splnet();
/*
* Get spansarp entry
*/
SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
if (sap == NULL) {
(void) splx(s);
return;
}
/*
* Remove IP VCC from chain
*/
UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
ivp->iv_arpent = NULL;
/*
* If entry is currently valid or in use, not much else for us to do
*/
if ((sap->sa_flags & (SAF_VALID | SAF_LOCKED)) ||
(sap->sa_origin >= SAO_PERM)) {
(void) splx(s);
return;
}
/*
* If there are still other VCCs waiting, exit
*/
if (sap->sa_ivp) {
(void) splx(s);
return;
}
/*
* Noone else waiting, so remove entry from the retry chain
*/
UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
/*
* Free entry
*/
SPANSARP_DELETE(sap);
atm_free((caddr_t)sap);
(void) splx(s);
}
/*
* Process module unloading notification
*
* Called whenever the spans module is about to be unloaded. All signalling
* instances will have been previously detached. All spansarp resources
* must be freed now.
*
* Arguments:
* none
*
* Returns:
* none
*
*/
void
spansarp_stop()
{
int i;
/*
* Make sure the arp table is empty
*/
for (i = 0; i < SPANSARP_HASHSIZ; i++) {
if (spansarp_arptab[i] != NULL)
panic("spansarp_stop: arp table not empty");
}
/*
* Cancel timers
*/
(void) atm_untimeout(&spansarp_timer);
(void) atm_untimeout(&spansarp_rtimer);
/*
* Free our storage pools
*/
atm_release_pool(&spansarp_pool);
}
/*
* Process IP Network Interface Activation
*
* Called whenever an IP network interface becomes active.
*
* Called at splnet.
*
* Arguments:
* clp pointer to CLS interface
*
* Returns:
* none
*
*/
void
spansarp_ipact(clp)
struct spanscls *clp;
{
/*
* Make sure aging timer is running
*/
if ((spansarp_timer.ti_flag & TIF_QUEUED) == 0)
atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
}
/*
* Process IP Network Interface Deactivation
*
* Called whenever an IP network interface becomes inactive.
*
* Called at splnet.
*
* Arguments:
* clp pointer to CLS interface
*
* Returns:
* none
*
*/
void
spansarp_ipdact(clp)
struct spanscls *clp;
{
struct spanscls *clp2;
struct spansarp *sap, *snext;
int i;
/*
* Delete all interface entries
*/
for (i = 0; i < SPANSARP_HASHSIZ; i++) {
for (sap = spansarp_arptab[i]; sap; sap = snext) {
snext = sap->sa_next;
/*
* Clean up entries for this interface
*/
if (sap->sa_cls != clp)
continue;
/*
* All VCCs better be gone by now
*/
if (sap->sa_ivp)
panic("spansarp_ipdact: entry not empty");
/*
* Remove entry from the retry chain
*/
UNLINK(sap, struct spansarp,
spansarp_retry_head, sa_rnext);
/*
* Delete entry from arp table
*/
SPANSARP_DELETE(sap);
atm_free((caddr_t)sap);
}
}
/*
* Stop aging timer if this is the last active interface
*/
for (clp2 = spanscls_head; clp2; clp2 = clp2->cls_next) {
if ((clp != clp2) && (clp2->cls_ipnif))
break;
}
if (clp2 == NULL)
(void) atm_untimeout(&spansarp_timer);
}
/*
* Issue a SPANS ARP request packet
*
* Arguments:
* sap pointer to arp table entry
*
* Returns:
* 0 packet was successfully sent
* else unable to send packet
*
*/
static int
spansarp_request(sap)
struct spansarp *sap;
{
struct spanscls *clp;
struct spans *spp;
struct spanscls_hdr *chp;
struct spansarp_hdr *ahp;
KBuffer *m;
struct ip_nif *inp;
int err;
clp = sap->sa_cls;
spp = clp->cls_spans;
inp = clp->cls_ipnif;
/*
* Make sure CLS VCC is open and that we know our addresses
*/
if (clp->cls_state != CLS_OPEN)
return (1);
if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR)
return (1);
if (inp == NULL)
return (1);
/*
* Get a buffer for pdu
*/
KB_ALLOCPKT(m, ARP_PACKET_LEN, KB_F_NOWAIT, KB_T_DATA);
if (m == NULL)
return (1);
/*
* Place pdu at end of buffer
*/
KB_PLENSET(m, ARP_PACKET_LEN);
KB_TAILALIGN(m, ARP_PACKET_LEN);
KB_DATASTART(m, chp, struct spanscls_hdr *);
ahp = (struct spansarp_hdr *)(chp + 1);
/*
* Build headers
*/
spans_addr_copy(&spans_bcastaddr, &chp->ch_dst);
spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
*(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto;
*(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap;
*(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1];
chp->ch_pid = htons(ETHERTYPE_ARP);
/*
* Build ARP packet
*/
ahp->ah_hrd = htons(ARP_SPANS);
ahp->ah_pro = htons(ETHERTYPE_IP);
ahp->ah_hln = sizeof(spans_addr);
ahp->ah_pln = sizeof(struct in_addr);
ahp->ah_op = htons(ARP_REQUEST);
spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), ahp->ah_spa,
sizeof(struct in_addr));
KM_COPY(&sap->sa_dstip, ahp->ah_tpa, sizeof(struct in_addr));
/*
* Now, send the pdu via the CLS service
*/
err = atm_cm_cpcs_data(clp->cls_conn, m);
if (err) {
KB_FREEALL(m);
return (1);
}
return (0);
}
/*
* Process a SPANS ARP input packet
*
* Arguments:
* clp pointer to interface CLS control block
* m pointer to input packet buffer chain
*
* Returns:
* none
*
*/
void
spansarp_input(clp, m)
struct spanscls *clp;
KBuffer *m;
{
struct spans *spp = clp->cls_spans;
struct spanscls_hdr *chp;
struct spansarp_hdr *ahp;
struct spansarp *sap;
struct ip_nif *inp = clp->cls_ipnif;
struct in_addr in_me, in_src, in_targ;
int s, err;
/*
* Make sure IP interface has been activated
*/
if (inp == NULL)
goto free;
/*
* Get the packet together
*/
if (KB_LEN(m) < ARP_PACKET_LEN) {
KB_PULLUP(m, ARP_PACKET_LEN, m);
if (m == 0)
return;
}
KB_DATASTART(m, chp, struct spanscls_hdr *);
ahp = (struct spansarp_hdr *)(chp + 1);
KM_COPY(ahp->ah_spa, &in_src, sizeof(struct in_addr));
KM_COPY(ahp->ah_tpa, &in_targ, sizeof(struct in_addr));
KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), &in_me,
sizeof(struct in_addr));
/*
* Initial packet verification
*/
if ((ahp->ah_hrd != htons(ARP_SPANS)) ||
(ahp->ah_pro != htons(ETHERTYPE_IP)))
goto free;
/*
* Validate source addresses
* can't be from broadcast
* can't be from me
*/
if (!spans_addr_cmp(&ahp->ah_sha, &spans_bcastaddr))
goto free;
#if (defined(BSD) && (BSD >= 199306))
if (in_broadcast(in_src, &inp->inf_nif->nif_if))
#else
if (in_broadcast(in_src))
#endif
goto free;
if (!spans_addr_cmp(&ahp->ah_sha, spp->sp_addr.address))
goto free;
if (in_src.s_addr == in_me.s_addr) {
log(LOG_ERR,
"duplicate IP address sent from spans address %s\n",
spans_addr_print(&ahp->ah_sha));
in_targ = in_me;
goto chkop;
}
/*
* Update arp table with source address info
*/
s = splnet();
SPANSARP_LOOKUP(in_src.s_addr, sap);
if (sap) {
/*
* Found an entry for the source, but don't
* update permanent entries
*/
if (sap->sa_origin != SAO_PERM) {
/*
* Update the entry
*/
sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
sap->sa_dstatm.address_length = sizeof(spans_addr);
spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
sap->sa_cls = clp;
sap->sa_reftime = 0;
if ((sap->sa_flags & SAF_VALID) == 0) {
/*
* Newly valid entry, notify waiting users
*/
struct ipvcc *ivp, *inext;
sap->sa_flags |= SAF_VALID;
for (ivp = sap->sa_ivp; ivp; ivp = inext) {
inext = ivp->iv_arpnext;
ivp->iv_arpent = (struct arpmap *)sap;
(*inp->inf_arpnotify)(ivp, MAP_VALID);
}
/*
* Remove ourselves from the retry chain
*/
UNLINK(sap, struct spansarp,
spansarp_retry_head, sa_rnext);
}
}
} else if (in_targ.s_addr == in_me.s_addr) {
/*
* Source unknown and we're the target - add new entry
*/
sap = (struct spansarp *)atm_allocate(&spansarp_pool);
if (sap) {
sap->sa_dstip.s_addr = in_src.s_addr;
sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
sap->sa_dstatm.address_length = sizeof(spans_addr);
spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
sap->sa_dstatmsub.address_length = 0;
sap->sa_cls = clp;
sap->sa_flags = SAF_VALID;
sap->sa_origin = SAO_LOOKUP;
SPANSARP_ADD(sap);
}
}
(void) splx(s);
chkop:
/*
* If this is a request for our address, send a reply
*/
if (ntohs(ahp->ah_op) != ARP_REQUEST)
goto free;
if (in_targ.s_addr != in_me.s_addr)
goto free;
spans_addr_copy(&chp->ch_src, &chp->ch_dst);
spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
ahp->ah_op = htons(ARP_REPLY);
spans_addr_copy(&ahp->ah_sha, &ahp->ah_tha);
spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
KM_COPY(ahp->ah_spa, ahp->ah_tpa, sizeof(struct in_addr));
KM_COPY(&in_me, ahp->ah_spa, sizeof(struct in_addr));
err = atm_cm_cpcs_data(clp->cls_conn, m);
if (err)
goto free;
return;
free:
KB_FREEALL(m);
}
/*
* Process a SPANS ARP aging timer tick
*
* This function is called every SPANSARP_AGING seconds, in order to age
* all the arp table entries.
*
* Called at splnet.
*
* Arguments:
* tip pointer to spansarp aging timer control block
*
* Returns:
* none
*
*/
static void
spansarp_aging(tip)
struct atm_time *tip;
{
struct spansarp *sap, *snext;
struct ipvcc *ivp, *inext;
int i;
/*
* Schedule next timeout
*/
atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
/*
* Run through arp table bumping each entry's aging timer.
*/
for (i = 0; i < SPANSARP_HASHSIZ; i++) {
for (sap = spansarp_arptab[i]; sap; sap = snext) {
snext = sap->sa_next;
/*
* Permanent (manually installed) entries aren't aged
*/
if (sap->sa_origin == SAO_PERM)
continue;
/*
* See if entry is valid and over-aged
*/
if ((sap->sa_flags & SAF_VALID) == 0)
continue;
if (++sap->sa_reftime < SPANSARP_MAXAGE)
continue;
/*
* Entry is now invalid, tell IP/ATM about it
*/
sap->sa_flags |= SAF_LOCKED;
for (ivp = sap->sa_ivp; ivp; ivp = inext) {
inext = ivp->iv_arpnext;
(*ivp->iv_ipnif->inf_arpnotify)
(ivp, MAP_INVALID);
}
sap->sa_flags &= ~(SAF_LOCKED | SAF_VALID);
if (sap->sa_ivp != NULL) {
/*
* Somebody still cares, so add the arp
* entry to the retry list.
*/
LINK2TAIL(sap, struct spansarp,
spansarp_retry_head, sa_rnext);
if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
atm_timeout(&spansarp_rtimer,
SPANSARP_RETRY, spansarp_retry);
/*
* Issue arp request for this address
*/
(void) spansarp_request(sap);
} else {
/*
* Delete unused entry
*/
SPANSARP_DELETE(sap);
atm_free((caddr_t)sap);
}
}
}
}
/*
* Process a SPANS ARP retry timer tick
*
* This function is called every SPANSARP_RETRY seconds, in order to retry
* awaiting arp resolution requests. We will retry requests indefinitely,
* assuming that IP will set a timeout to close the VCC(s) requesting the
* failing address resolution.
*
* Called at splnet.
*
* Arguments:
* tip pointer to spansarp retry timer control block
*
* Returns:
* none
*
*/
static void
spansarp_retry(tip)
struct atm_time *tip;
{
struct spansarp *sap;
/*
* See if there's work to do
*/
if (spansarp_retry_head == NULL) {
return;
}
/*
* Schedule next timeout
*/
atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
/*
* Run through retry chain, (re)issuing arp requests.
*/
for (sap = spansarp_retry_head; sap; sap = sap->sa_next) {
/*
* Send another arp request
*/
(void) spansarp_request(sap);
}
}
/*
* SPANS ARP IOCTL support
*
* Function will be called at splnet.
*
* Arguments:
* code PF_ATM sub-operation code
* data pointer to code specific parameter data area
* arg1 pointer to code specific argument
*
* Returns:
* 0 request procesed
* errno error processing request - reason indicated
*
*/
int
spansarp_ioctl(code, data, arg1)
int code;
caddr_t data;
caddr_t arg1;
{
struct atmaddreq *aap;
struct atmdelreq *adp;
struct atminfreq *aip;
struct spans *spp;
struct spanscls *clp;
struct spansarp *sap;
struct air_arp_rsp aar;
struct ip_nif *inp;
struct ipvcc *ivp, *inext;
struct in_addr ip;
u_long dst;
int err = 0, i, buf_len;
caddr_t buf_addr;
switch (code) {
case AIOCS_ADD_ARP:
/*
* Add a permanent ARP mapping
*/
aap = (struct atmaddreq *)data;
clp = (struct spanscls *)arg1;
inp = clp->cls_ipnif;
if ((aap->aar_arp_addr.address_format != T_ATM_SPANS_ADDR) ||
(aap->aar_arp_origin != ARP_ORIG_PERM)) {
err = EINVAL;
break;
}
ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
/*
* See if we already have an entry for this IP address
*/
SPANSARP_LOOKUP(ip.s_addr, sap);
if (sap == NULL) {
/*
* No, get a new arp entry
*/
sap = (struct spansarp *)atm_allocate(&spansarp_pool);
if (sap == NULL) {
err = ENOMEM;
break;
}
/*
* Get entry set up
*/
sap->sa_dstip = ip;
ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
sap->sa_dstatmsub.address_length = 0;
sap->sa_cls = clp;
sap->sa_flags |= SAF_VALID;
sap->sa_origin = SAO_PERM;
/*
* Add entry to table
*/
SPANSARP_ADD(sap);
break;
}
/*
* See if we're attempting to change the ATM address for
* this cached entry
*/
if ((sap->sa_dstatm.address_format != T_ATM_ABSENT) &&
(!ATM_ADDR_EQUAL(&aap->aar_arp_addr, &sap->sa_dstatm) ||
(clp != sap->sa_cls))) {
/*
* Yes, notify IP/ATM that a mapping change has
* occurred. IP/ATM will close any VCC's which
* aren't waiting for this map.
*/
sap->sa_flags |= SAF_LOCKED;
for (ivp = sap->sa_ivp; ivp; ivp = inext) {
inext = ivp->iv_arpnext;
(*inp->inf_arpnotify)(ivp, MAP_CHANGED);
}
sap->sa_flags &= ~SAF_LOCKED;
}
/*
* Update the cached entry with the new data
*/
ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
sap->sa_cls = clp;
/*
* If this entry isn't valid, notify anyone who might
* be interested
*/
if ((sap->sa_flags & SAF_VALID) == 0) {
sap->sa_flags |= SAF_LOCKED;
for (ivp = sap->sa_ivp; ivp; ivp = inext) {
inext = ivp->iv_arpnext;
(*inp->inf_arpnotify)(ivp, MAP_VALID);
}
sap->sa_flags &= ~SAF_LOCKED;
}
/*
* Remove this entry from the retry chain
*/
UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
/*
* Mark the entry as permanent
*/
sap->sa_flags |= SAF_VALID;
sap->sa_origin = SAO_PERM;
break;
case AIOCS_DEL_ARP:
/*
* Delete an ARP mapping
*/
adp = (struct atmdelreq *)data;
clp = (struct spanscls *)arg1;
ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
/*
* Now find the entry to be deleted
*/
SPANSARP_LOOKUP(ip.s_addr, sap);
if (sap == NULL) {
err = ENOENT;
break;
}
/*
* Notify all VCCs using this entry that they must finish
* up now.
*/
sap->sa_flags |= SAF_LOCKED;
for (ivp = sap->sa_ivp; ivp; ivp = inext) {
inext = ivp->iv_arpnext;
(*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
}
/*
* Now free up the entry
*/
UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
SPANSARP_DELETE(sap);
atm_free((caddr_t)sap);
break;
case AIOCS_INF_ARP:
/*
* Get ARP table information
*/
aip = (struct atminfreq *)data;
spp = (struct spans *)arg1;
if (aip->air_arp_addr.sa_family != AF_INET)
break;
dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr;
buf_addr = aip->air_buf_addr;
buf_len = aip->air_buf_len;
if ((clp = spp->sp_cls) == NULL)
break;
/*
* Run through entire arp table
*/
for (i = 0; i < SPANSARP_HASHSIZ; i++) {
for (sap = spansarp_arptab[i]; sap;
sap = sap->sa_next) {
/*
* We only want entries learned
* from the supplied interface.
*/
if (sap->sa_cls != clp)
continue;
if ((dst != INADDR_ANY) &&
(dst != sap->sa_dstip.s_addr))
continue;
/*
* Make sure there's room in the user's buffer
*/
if (buf_len < sizeof(aar)) {
err = ENOSPC;
break;
}
/*
* Fill in info to be returned
*/
SATOSIN(&aar.aap_arp_addr)->sin_family =
AF_INET;
SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr =
sap->sa_dstip.s_addr;
(void) sprintf(aar.aap_intf, "%s%d",
clp->cls_ipnif->inf_nif->nif_if.if_name,
clp->cls_ipnif->inf_nif->nif_if.if_unit
);
aar.aap_flags = sap->sa_flags;
aar.aap_origin = sap->sa_origin;
if (sap->sa_flags & SAF_VALID)
aar.aap_age = SPANSARP_MAXAGE -
sap->sa_reftime;
else
aar.aap_age = 0;
ATM_ADDR_COPY(&sap->sa_dstatm, &aar.aap_addr);
ATM_ADDR_COPY(&sap->sa_dstatmsub,
&aar.aap_subaddr);
/*
* Copy the response into the user's buffer
*/
if (err = copyout((caddr_t)&aar, buf_addr,
sizeof(aar)))
break;
buf_addr += sizeof(aar);
buf_len -= sizeof(aar);
}
if (err)
break;
}
/*
* Update the buffer pointer and length
*/
aip->air_buf_addr = buf_addr;
aip->air_buf_len = buf_len;
break;
default:
err = EOPNOTSUPP;
}
return (err);
}