3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
8 * This Host ATM Research Platform ("HARP") file (the "Software") is
9 * made available by Network Computing Services, Inc. ("NetworkCS")
10 * "AS IS". NetworkCS does not provide maintenance, improvements or
11 * support of any kind.
13 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17 * In no event shall NetworkCS be responsible for any damages, including
18 * but not limited to consequential damages, arising from or relating to
19 * any use of the Software or related support.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/sys/netatm/spans/spans_arp.c,v 1.7 2000/01/15 20:34:55 mks Exp $
27 * @(#) $DragonFly: src/sys/netproto/atm/spans/spans_arp.c,v 1.7 2005/02/01 00:51:50 joerg Exp $
31 * SPANS Signalling Manager
32 * ---------------------------
34 * SPANS CLS - ARP support
38 #include <netproto/atm/kern_include.h>
40 #include <netproto/atm/ipatm/ipatm_var.h>
41 #include <netproto/atm/ipatm/ipatm_serv.h>
42 #include "spans_xdr.h"
43 #include "spans_var.h"
44 #include "spans_cls.h"
49 struct spansarp *spansarp_arptab[SPANSARP_HASHSIZ] = {NULL};
55 static int spansarp_request (struct spansarp *);
56 static void spansarp_aging (struct atm_time *);
57 static void spansarp_retry (struct atm_time *);
62 static struct atm_time spansarp_timer = {0, 0}; /* Aging timer */
63 static struct atm_time spansarp_rtimer = {0, 0}; /* Retry timer */
65 static struct spansarp *spansarp_retry_head = NULL; /* Retry chain */
67 static struct sp_info spansarp_pool = {
68 "spans arp pool", /* si_name */
69 sizeof(struct spansarp), /* si_blksiz */
76 * Process a new outgoing SVC requiring SPANS ARP support
78 * This function is called by an endpoint wishing to resolve a destination
79 * IP address to an ATM address in order to open an SVC to that destination.
80 * If a valid mapping is already in our cache, then we just tell the caller
81 * about it and that's that. Otherwise, we have to allocate a new arp entry
82 * and issue a query for the mapping.
85 * ivp pointer to SVC's IPVCC control block
86 * dst pointer to destination IP address
89 * MAP_VALID - Got the answer, returned via iv_arpent field.
90 * MAP_PROCEEDING - OK so far, querying for peer's mapping
91 * MAP_FAILED - error, unable to allocate resources
95 spansarp_svcout(ivp, dst)
100 struct spansarp *sap;
103 ivp->iv_arpent = NULL;
106 * Lookup destination address
109 SPANSARP_LOOKUP(dst->s_addr, sap);
113 * Link this vcc to entry queue
115 LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
118 * If entry is valid, we're done
120 if (sap->sa_flags & SAF_VALID) {
121 ivp->iv_arpent = (struct arpmap *)sap;
127 * We're already looking for this address
130 return (MAP_PROCEEDING);
134 * Need a new arp entry - first, find the cls instance
135 * corresponding to the requestor's IP interface.
137 for (clp = spanscls_head; clp; clp = clp->cls_next) {
138 if (clp->cls_ipnif == ivp->iv_ipnif)
147 * Now get the new arp entry
149 sap = (struct spansarp *)atm_allocate(&spansarp_pool);
158 sap->sa_dstip.s_addr = dst->s_addr;
159 sap->sa_dstatm.address_format = T_ATM_ABSENT;
160 sap->sa_dstatm.address_length = 0;
161 sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
162 sap->sa_dstatmsub.address_length = 0;
164 sap->sa_origin = SAO_LOOKUP;
167 * Link ipvcc to arp entry for later notification
169 LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
172 * Add arp entry to table
177 * Add arp entry to retry list and start retry timer if needed
179 LINK2TAIL(sap, struct spansarp, spansarp_retry_head, sa_rnext);
180 if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
181 atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
184 * Issue arp request for this address
186 (void) spansarp_request(sap);
189 return (MAP_PROCEEDING);
194 * Process a new incoming SVC requiring SPANS ARP support
196 * This function is called by an endpoint wishing to resolve a destination
197 * ATM address to its IP address for an incoming call in order to allow a
198 * bi-directional flow of IP packets on the SVC.
200 * SPANS ARP does not provide reverse mapping facilities and only supports
201 * uni-directional SVCs. Thus, we lie a little to IP and always return a
202 * MAP_PROCEEDING indication, but we will never later notify IP of a
203 * MAP_VALID condition.
206 * ivp pointer to SVC's IPVCC control block
207 * dst pointer to destination ATM address
208 * dstsub pointer to destination ATM subaddress
211 * MAP_VALID - Got the answer, returned via iv_arpent field.
212 * MAP_PROCEEDING - OK so far, querying for peer's mapping
213 * MAP_FAILED - error, unable to allocate resources
217 spansarp_svcin(ivp, dst, dstsub)
223 * Clear ARP entry field
225 ivp->iv_arpent = NULL;
227 return (MAP_PROCEEDING);
232 * SPANS ARP SVC activation notification
234 * This function is called when a previously opened SVC has successfully
238 * ivp pointer to SVC's IPVCC control block
241 * 0 activation processing successful
242 * errno activation failed - reason indicated
246 spansarp_svcactive(ivp)
249 struct spansarp *sap;
253 * Find an entry for the destination address
255 SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
258 * IP is finished with entry, so remove IP VCC from chain
260 UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
261 ivp->iv_arpent = NULL;
264 * This seems like a reasonable reason to refresh the entry
275 * SPANS ARP supported VCC is closing
277 * This function is called just prior to a user closing a VCC which
278 * supports SPANS ARP. We'll sever our links to the VCC and then
279 * figure out how much more cleanup we need to do for now.
282 * ivp pointer to VCC's IPVCC control block
289 spansarp_vcclose(ivp)
292 struct spansarp *sap;
298 SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
305 * Remove IP VCC from chain
307 UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
308 ivp->iv_arpent = NULL;
311 * If entry is currently valid or in use, not much else for us to do
313 if ((sap->sa_flags & (SAF_VALID | SAF_LOCKED)) ||
314 (sap->sa_origin >= SAO_PERM)) {
320 * If there are still other VCCs waiting, exit
328 * Noone else waiting, so remove entry from the retry chain
330 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
335 SPANSARP_DELETE(sap);
336 atm_free((caddr_t)sap);
342 * Process module unloading notification
344 * Called whenever the spans module is about to be unloaded. All signalling
345 * instances will have been previously detached. All spansarp resources
361 * Make sure the arp table is empty
363 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
364 if (spansarp_arptab[i] != NULL)
365 panic("spansarp_stop: arp table not empty");
371 (void) atm_untimeout(&spansarp_timer);
372 (void) atm_untimeout(&spansarp_rtimer);
375 * Free our storage pools
377 atm_release_pool(&spansarp_pool);
382 * Process IP Network Interface Activation
384 * Called whenever an IP network interface becomes active.
389 * clp pointer to CLS interface
397 struct spanscls *clp;
400 * Make sure aging timer is running
402 if ((spansarp_timer.ti_flag & TIF_QUEUED) == 0)
403 atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
408 * Process IP Network Interface Deactivation
410 * Called whenever an IP network interface becomes inactive.
415 * clp pointer to CLS interface
423 struct spanscls *clp;
425 struct spanscls *clp2;
426 struct spansarp *sap, *snext;
430 * Delete all interface entries
432 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
433 for (sap = spansarp_arptab[i]; sap; sap = snext) {
434 snext = sap->sa_next;
437 * Clean up entries for this interface
439 if (sap->sa_cls != clp)
443 * All VCCs better be gone by now
446 panic("spansarp_ipdact: entry not empty");
449 * Remove entry from the retry chain
451 UNLINK(sap, struct spansarp,
452 spansarp_retry_head, sa_rnext);
455 * Delete entry from arp table
457 SPANSARP_DELETE(sap);
458 atm_free((caddr_t)sap);
463 * Stop aging timer if this is the last active interface
465 for (clp2 = spanscls_head; clp2; clp2 = clp2->cls_next) {
466 if ((clp != clp2) && (clp2->cls_ipnif))
470 (void) atm_untimeout(&spansarp_timer);
475 * Issue a SPANS ARP request packet
478 * sap pointer to arp table entry
481 * 0 packet was successfully sent
482 * else unable to send packet
486 spansarp_request(sap)
487 struct spansarp *sap;
489 struct spanscls *clp;
491 struct spanscls_hdr *chp;
492 struct spansarp_hdr *ahp;
498 spp = clp->cls_spans;
499 inp = clp->cls_ipnif;
502 * Make sure CLS VCC is open and that we know our addresses
504 if (clp->cls_state != CLS_OPEN)
506 if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR)
512 * Get a buffer for pdu
514 KB_ALLOCPKT(m, ARP_PACKET_LEN, KB_F_NOWAIT, KB_T_DATA);
519 * Place pdu at end of buffer
521 KB_PLENSET(m, ARP_PACKET_LEN);
522 KB_TAILALIGN(m, ARP_PACKET_LEN);
523 KB_DATASTART(m, chp, struct spanscls_hdr *);
524 ahp = (struct spansarp_hdr *)(chp + 1);
529 spans_addr_copy(&spans_bcastaddr, &chp->ch_dst);
530 spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
531 *(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto;
532 *(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap;
533 *(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1];
534 chp->ch_pid = htons(ETHERTYPE_ARP);
540 ahp->ah_hrd = htons(ARP_SPANS);
541 ahp->ah_pro = htons(ETHERTYPE_IP);
542 ahp->ah_hln = sizeof(spans_addr);
543 ahp->ah_pln = sizeof(struct in_addr);
544 ahp->ah_op = htons(ARP_REQUEST);
545 spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
546 KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), ahp->ah_spa,
547 sizeof(struct in_addr));
548 KM_COPY(&sap->sa_dstip, ahp->ah_tpa, sizeof(struct in_addr));
551 * Now, send the pdu via the CLS service
553 err = atm_cm_cpcs_data(clp->cls_conn, m);
564 * Process a SPANS ARP input packet
567 * clp pointer to interface CLS control block
568 * m pointer to input packet buffer chain
575 spansarp_input(clp, m)
576 struct spanscls *clp;
579 struct spans *spp = clp->cls_spans;
580 struct spanscls_hdr *chp;
581 struct spansarp_hdr *ahp;
582 struct spansarp *sap;
583 struct ip_nif *inp = clp->cls_ipnif;
584 struct in_addr in_me, in_src, in_targ;
588 * Make sure IP interface has been activated
594 * Get the packet together
596 if (KB_LEN(m) < ARP_PACKET_LEN) {
597 KB_PULLUP(m, ARP_PACKET_LEN, m);
601 KB_DATASTART(m, chp, struct spanscls_hdr *);
602 ahp = (struct spansarp_hdr *)(chp + 1);
604 KM_COPY(ahp->ah_spa, &in_src, sizeof(struct in_addr));
605 KM_COPY(ahp->ah_tpa, &in_targ, sizeof(struct in_addr));
606 KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), &in_me,
607 sizeof(struct in_addr));
610 * Initial packet verification
612 if ((ahp->ah_hrd != htons(ARP_SPANS)) ||
613 (ahp->ah_pro != htons(ETHERTYPE_IP)))
617 * Validate source addresses
618 * can't be from hardware broadcast
621 if (!spans_addr_cmp(&ahp->ah_sha, &spans_bcastaddr))
623 if (!spans_addr_cmp(&ahp->ah_sha, spp->sp_addr.address))
625 if (in_src.s_addr == in_me.s_addr) {
627 "duplicate IP address sent from spans address %s\n",
628 spans_addr_print(&ahp->ah_sha));
634 * If source IP address is from unspecified or broadcast addresses,
635 * don't bother updating arp table, but answer possible requests
637 if (in_broadcast(in_src, &inp->inf_nif->nif_if))
641 * Update arp table with source address info
644 SPANSARP_LOOKUP(in_src.s_addr, sap);
647 * Found an entry for the source, but don't
648 * update permanent entries
650 if (sap->sa_origin != SAO_PERM) {
655 sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
656 sap->sa_dstatm.address_length = sizeof(spans_addr);
657 spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
660 if ((sap->sa_flags & SAF_VALID) == 0) {
662 * Newly valid entry, notify waiting users
664 struct ipvcc *ivp, *inext;
666 sap->sa_flags |= SAF_VALID;
667 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
668 inext = ivp->iv_arpnext;
670 ivp->iv_arpent = (struct arpmap *)sap;
671 (*inp->inf_arpnotify)(ivp, MAP_VALID);
675 * Remove ourselves from the retry chain
677 UNLINK(sap, struct spansarp,
678 spansarp_retry_head, sa_rnext);
682 } else if (in_targ.s_addr == in_me.s_addr) {
684 * Source unknown and we're the target - add new entry
686 sap = (struct spansarp *)atm_allocate(&spansarp_pool);
688 sap->sa_dstip.s_addr = in_src.s_addr;
689 sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
690 sap->sa_dstatm.address_length = sizeof(spans_addr);
691 spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
692 sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
693 sap->sa_dstatmsub.address_length = 0;
695 sap->sa_flags = SAF_VALID;
696 sap->sa_origin = SAO_LOOKUP;
704 * If this is a request for our address, send a reply
706 if (ntohs(ahp->ah_op) != ARP_REQUEST)
708 if (in_targ.s_addr != in_me.s_addr)
711 spans_addr_copy(&chp->ch_src, &chp->ch_dst);
712 spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
713 ahp->ah_op = htons(ARP_REPLY);
714 spans_addr_copy(&ahp->ah_sha, &ahp->ah_tha);
715 spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
716 KM_COPY(ahp->ah_spa, ahp->ah_tpa, sizeof(struct in_addr));
717 KM_COPY(&in_me, ahp->ah_spa, sizeof(struct in_addr));
719 err = atm_cm_cpcs_data(clp->cls_conn, m);
730 * Process a SPANS ARP aging timer tick
732 * This function is called every SPANSARP_AGING seconds, in order to age
733 * all the arp table entries.
738 * tip pointer to spansarp aging timer control block
746 struct atm_time *tip;
748 struct spansarp *sap, *snext;
749 struct ipvcc *ivp, *inext;
754 * Schedule next timeout
756 atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
759 * Run through arp table bumping each entry's aging timer.
761 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
762 for (sap = spansarp_arptab[i]; sap; sap = snext) {
763 snext = sap->sa_next;
766 * Permanent (manually installed) entries aren't aged
768 if (sap->sa_origin == SAO_PERM)
772 * See if entry is valid and over-aged
774 if ((sap->sa_flags & SAF_VALID) == 0)
776 if (++sap->sa_reftime < SPANSARP_MAXAGE)
780 * Entry is now invalid, tell IP/ATM about it
782 sap->sa_flags |= SAF_LOCKED;
783 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
784 inext = ivp->iv_arpnext;
785 (*ivp->iv_ipnif->inf_arpnotify)
788 sap->sa_flags &= ~(SAF_LOCKED | SAF_VALID);
790 if (sap->sa_ivp != NULL) {
792 * Somebody still cares, so add the arp
793 * entry to the retry list.
795 LINK2TAIL(sap, struct spansarp,
796 spansarp_retry_head, sa_rnext);
797 if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
798 atm_timeout(&spansarp_rtimer,
799 SPANSARP_RETRY, spansarp_retry);
802 * Issue arp request for this address
804 (void) spansarp_request(sap);
808 * Delete unused entry
810 SPANSARP_DELETE(sap);
811 atm_free((caddr_t)sap);
819 * Process a SPANS ARP retry timer tick
821 * This function is called every SPANSARP_RETRY seconds, in order to retry
822 * awaiting arp resolution requests. We will retry requests indefinitely,
823 * assuming that IP will set a timeout to close the VCC(s) requesting the
824 * failing address resolution.
829 * tip pointer to spansarp retry timer control block
837 struct atm_time *tip;
839 struct spansarp *sap;
843 * See if there's work to do
845 if (spansarp_retry_head == NULL) {
850 * Schedule next timeout
852 atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
855 * Run through retry chain, (re)issuing arp requests.
857 for (sap = spansarp_retry_head; sap; sap = sap->sa_next) {
860 * Send another arp request
862 (void) spansarp_request(sap);
868 * SPANS ARP IOCTL support
870 * Function will be called at splnet.
873 * code PF_ATM sub-operation code
874 * data pointer to code specific parameter data area
875 * arg1 pointer to code specific argument
879 * errno error processing request - reason indicated
883 spansarp_ioctl(code, data, arg1)
888 struct atmaddreq *aap;
889 struct atmdelreq *adp;
890 struct atminfreq *aip;
892 struct spanscls *clp;
893 struct spansarp *sap;
894 struct air_arp_rsp aar;
896 struct ipvcc *ivp, *inext;
899 int err = 0, i, buf_len;
907 * Add a permanent ARP mapping
909 aap = (struct atmaddreq *)data;
910 clp = (struct spanscls *)arg1;
911 inp = clp->cls_ipnif;
912 if ((aap->aar_arp_addr.address_format != T_ATM_SPANS_ADDR) ||
913 (aap->aar_arp_origin != ARP_ORIG_PERM)) {
917 ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
920 * See if we already have an entry for this IP address
922 SPANSARP_LOOKUP(ip.s_addr, sap);
925 * No, get a new arp entry
927 sap = (struct spansarp *)atm_allocate(&spansarp_pool);
937 ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
938 sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
939 sap->sa_dstatmsub.address_length = 0;
941 sap->sa_flags |= SAF_VALID;
942 sap->sa_origin = SAO_PERM;
953 * See if we're attempting to change the ATM address for
956 if ((sap->sa_dstatm.address_format != T_ATM_ABSENT) &&
957 (!ATM_ADDR_EQUAL(&aap->aar_arp_addr, &sap->sa_dstatm) ||
958 (clp != sap->sa_cls))) {
961 * Yes, notify IP/ATM that a mapping change has
962 * occurred. IP/ATM will close any VCC's which
963 * aren't waiting for this map.
965 sap->sa_flags |= SAF_LOCKED;
966 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
967 inext = ivp->iv_arpnext;
968 (*inp->inf_arpnotify)(ivp, MAP_CHANGED);
970 sap->sa_flags &= ~SAF_LOCKED;
974 * Update the cached entry with the new data
976 ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
980 * If this entry isn't valid, notify anyone who might
983 if ((sap->sa_flags & SAF_VALID) == 0) {
985 sap->sa_flags |= SAF_LOCKED;
986 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
987 inext = ivp->iv_arpnext;
988 (*inp->inf_arpnotify)(ivp, MAP_VALID);
990 sap->sa_flags &= ~SAF_LOCKED;
994 * Remove this entry from the retry chain
996 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
999 * Mark the entry as permanent
1001 sap->sa_flags |= SAF_VALID;
1002 sap->sa_origin = SAO_PERM;
1007 * Delete an ARP mapping
1009 adp = (struct atmdelreq *)data;
1010 clp = (struct spanscls *)arg1;
1011 ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
1014 * Now find the entry to be deleted
1016 SPANSARP_LOOKUP(ip.s_addr, sap);
1023 * Notify all VCCs using this entry that they must finish
1026 sap->sa_flags |= SAF_LOCKED;
1027 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
1028 inext = ivp->iv_arpnext;
1029 (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
1033 * Now free up the entry
1035 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
1036 SPANSARP_DELETE(sap);
1037 atm_free((caddr_t)sap);
1042 * Get ARP table information
1044 aip = (struct atminfreq *)data;
1045 spp = (struct spans *)arg1;
1047 if (aip->air_arp_addr.sa_family != AF_INET)
1049 dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr;
1051 buf_addr = aip->air_buf_addr;
1052 buf_len = aip->air_buf_len;
1054 if ((clp = spp->sp_cls) == NULL)
1058 * Run through entire arp table
1060 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
1061 for (sap = spansarp_arptab[i]; sap;
1062 sap = sap->sa_next) {
1064 * We only want entries learned
1065 * from the supplied interface.
1067 if (sap->sa_cls != clp)
1069 if ((dst != INADDR_ANY) &&
1070 (dst != sap->sa_dstip.s_addr))
1074 * Make sure there's room in the user's buffer
1076 if (buf_len < sizeof(aar)) {
1082 * Fill in info to be returned
1084 SATOSIN(&aar.aap_arp_addr)->sin_family =
1086 SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr =
1087 sap->sa_dstip.s_addr;
1088 (void) strlcpy(aar.aap_intf,
1089 clp->cls_ipnif->inf_nif->nif_if.if_xname,
1090 sizeof(aar.aap_intf));
1091 aar.aap_flags = sap->sa_flags;
1092 aar.aap_origin = sap->sa_origin;
1093 if (sap->sa_flags & SAF_VALID)
1094 aar.aap_age = SPANSARP_MAXAGE -
1098 ATM_ADDR_COPY(&sap->sa_dstatm, &aar.aap_addr);
1099 ATM_ADDR_COPY(&sap->sa_dstatmsub,
1103 * Copy the response into the user's buffer
1105 if ((err = copyout((caddr_t)&aar, buf_addr,
1108 buf_addr += sizeof(aar);
1109 buf_len -= sizeof(aar);
1116 * Update the buffer pointer and length
1118 aip->air_buf_addr = buf_addr;
1119 aip->air_buf_len = buf_len;
1124 * Get ARP server information
1126 /* SPANS doesn't have an ARP server */