diff options
author | Poul-Henning Kamp <phk@FreeBSD.org> | 1998-09-15 08:23:17 +0000 |
---|---|---|
committer | Poul-Henning Kamp <phk@FreeBSD.org> | 1998-09-15 08:23:17 +0000 |
commit | 1820df7a2d615975e02b646f749fb05757e92f79 (patch) | |
tree | a7cd0079858aee749b0cbaadb313a655dee7765b /sys/netatm/spans/spans_arp.c | |
parent | 06915ea69a48dd223d1612cefc20795c2d38d359 (diff) | |
download | src-1820df7a2d615975e02b646f749fb05757e92f79.tar.gz src-1820df7a2d615975e02b646f749fb05757e92f79.zip |
Notes
Diffstat (limited to 'sys/netatm/spans/spans_arp.c')
-rw-r--r-- | sys/netatm/spans/spans_arp.c | 1133 |
1 files changed, 1133 insertions, 0 deletions
diff --git a/sys/netatm/spans/spans_arp.c b/sys/netatm/spans/spans_arp.c new file mode 100644 index 000000000000..5a2443af9de3 --- /dev/null +++ b/sys/netatm/spans/spans_arp.c @@ -0,0 +1,1133 @@ +/* + * + * =================================== + * 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); +} + |