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 $
31 * SPANS Signalling Manager
32 * ---------------------------
34 * SPANS CLS - ARP support
38 #include <netatm/kern_include.h>
40 #include <netatm/ipatm/ipatm_var.h>
41 #include <netatm/ipatm/ipatm_serv.h>
42 #include "spans_xdr.h"
43 #include <netatm/spans/spans_var.h>
44 #include <netatm/spans/spans_cls.h>
47 __RCSID("@(#) $FreeBSD: src/sys/netatm/spans/spans_arp.c,v 1.7 2000/01/15 20:34:55 mks Exp $");
54 struct spansarp *spansarp_arptab[SPANSARP_HASHSIZ] = {NULL};
60 static int spansarp_request __P((struct spansarp *));
61 static void spansarp_aging __P((struct atm_time *));
62 static void spansarp_retry __P((struct atm_time *));
67 static struct atm_time spansarp_timer = {0, 0}; /* Aging timer */
68 static struct atm_time spansarp_rtimer = {0, 0}; /* Retry timer */
70 static struct spansarp *spansarp_retry_head = NULL; /* Retry chain */
72 static struct sp_info spansarp_pool = {
73 "spans arp pool", /* si_name */
74 sizeof(struct spansarp), /* si_blksiz */
81 * Process a new outgoing SVC requiring SPANS ARP support
83 * This function is called by an endpoint wishing to resolve a destination
84 * IP address to an ATM address in order to open an SVC to that destination.
85 * If a valid mapping is already in our cache, then we just tell the caller
86 * about it and that's that. Otherwise, we have to allocate a new arp entry
87 * and issue a query for the mapping.
90 * ivp pointer to SVC's IPVCC control block
91 * dst pointer to destination IP address
94 * MAP_VALID - Got the answer, returned via iv_arpent field.
95 * MAP_PROCEEDING - OK so far, querying for peer's mapping
96 * MAP_FAILED - error, unable to allocate resources
100 spansarp_svcout(ivp, dst)
104 struct spanscls *clp;
105 struct spansarp *sap;
108 ivp->iv_arpent = NULL;
111 * Lookup destination address
114 SPANSARP_LOOKUP(dst->s_addr, sap);
118 * Link this vcc to entry queue
120 LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
123 * If entry is valid, we're done
125 if (sap->sa_flags & SAF_VALID) {
126 ivp->iv_arpent = (struct arpmap *)sap;
132 * We're already looking for this address
135 return (MAP_PROCEEDING);
139 * Need a new arp entry - first, find the cls instance
140 * corresponding to the requestor's IP interface.
142 for (clp = spanscls_head; clp; clp = clp->cls_next) {
143 if (clp->cls_ipnif == ivp->iv_ipnif)
152 * Now get the new arp entry
154 sap = (struct spansarp *)atm_allocate(&spansarp_pool);
163 sap->sa_dstip.s_addr = dst->s_addr;
164 sap->sa_dstatm.address_format = T_ATM_ABSENT;
165 sap->sa_dstatm.address_length = 0;
166 sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
167 sap->sa_dstatmsub.address_length = 0;
169 sap->sa_origin = SAO_LOOKUP;
172 * Link ipvcc to arp entry for later notification
174 LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
177 * Add arp entry to table
182 * Add arp entry to retry list and start retry timer if needed
184 LINK2TAIL(sap, struct spansarp, spansarp_retry_head, sa_rnext);
185 if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
186 atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
189 * Issue arp request for this address
191 (void) spansarp_request(sap);
194 return (MAP_PROCEEDING);
199 * Process a new incoming SVC requiring SPANS ARP support
201 * This function is called by an endpoint wishing to resolve a destination
202 * ATM address to its IP address for an incoming call in order to allow a
203 * bi-directional flow of IP packets on the SVC.
205 * SPANS ARP does not provide reverse mapping facilities and only supports
206 * uni-directional SVCs. Thus, we lie a little to IP and always return a
207 * MAP_PROCEEDING indication, but we will never later notify IP of a
208 * MAP_VALID condition.
211 * ivp pointer to SVC's IPVCC control block
212 * dst pointer to destination ATM address
213 * dstsub pointer to destination ATM subaddress
216 * MAP_VALID - Got the answer, returned via iv_arpent field.
217 * MAP_PROCEEDING - OK so far, querying for peer's mapping
218 * MAP_FAILED - error, unable to allocate resources
222 spansarp_svcin(ivp, dst, dstsub)
228 * Clear ARP entry field
230 ivp->iv_arpent = NULL;
232 return (MAP_PROCEEDING);
237 * SPANS ARP SVC activation notification
239 * This function is called when a previously opened SVC has successfully
243 * ivp pointer to SVC's IPVCC control block
246 * 0 activation processing successful
247 * errno activation failed - reason indicated
251 spansarp_svcactive(ivp)
254 struct spansarp *sap;
258 * Find an entry for the destination address
260 SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
263 * IP is finished with entry, so remove IP VCC from chain
265 UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
266 ivp->iv_arpent = NULL;
269 * This seems like a reasonable reason to refresh the entry
280 * SPANS ARP supported VCC is closing
282 * This function is called just prior to a user closing a VCC which
283 * supports SPANS ARP. We'll sever our links to the VCC and then
284 * figure out how much more cleanup we need to do for now.
287 * ivp pointer to VCC's IPVCC control block
294 spansarp_vcclose(ivp)
297 struct spansarp *sap;
303 SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
310 * Remove IP VCC from chain
312 UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
313 ivp->iv_arpent = NULL;
316 * If entry is currently valid or in use, not much else for us to do
318 if ((sap->sa_flags & (SAF_VALID | SAF_LOCKED)) ||
319 (sap->sa_origin >= SAO_PERM)) {
325 * If there are still other VCCs waiting, exit
333 * Noone else waiting, so remove entry from the retry chain
335 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
340 SPANSARP_DELETE(sap);
341 atm_free((caddr_t)sap);
347 * Process module unloading notification
349 * Called whenever the spans module is about to be unloaded. All signalling
350 * instances will have been previously detached. All spansarp resources
366 * Make sure the arp table is empty
368 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
369 if (spansarp_arptab[i] != NULL)
370 panic("spansarp_stop: arp table not empty");
376 (void) atm_untimeout(&spansarp_timer);
377 (void) atm_untimeout(&spansarp_rtimer);
380 * Free our storage pools
382 atm_release_pool(&spansarp_pool);
387 * Process IP Network Interface Activation
389 * Called whenever an IP network interface becomes active.
394 * clp pointer to CLS interface
402 struct spanscls *clp;
405 * Make sure aging timer is running
407 if ((spansarp_timer.ti_flag & TIF_QUEUED) == 0)
408 atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
413 * Process IP Network Interface Deactivation
415 * Called whenever an IP network interface becomes inactive.
420 * clp pointer to CLS interface
428 struct spanscls *clp;
430 struct spanscls *clp2;
431 struct spansarp *sap, *snext;
435 * Delete all interface entries
437 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
438 for (sap = spansarp_arptab[i]; sap; sap = snext) {
439 snext = sap->sa_next;
442 * Clean up entries for this interface
444 if (sap->sa_cls != clp)
448 * All VCCs better be gone by now
451 panic("spansarp_ipdact: entry not empty");
454 * Remove entry from the retry chain
456 UNLINK(sap, struct spansarp,
457 spansarp_retry_head, sa_rnext);
460 * Delete entry from arp table
462 SPANSARP_DELETE(sap);
463 atm_free((caddr_t)sap);
468 * Stop aging timer if this is the last active interface
470 for (clp2 = spanscls_head; clp2; clp2 = clp2->cls_next) {
471 if ((clp != clp2) && (clp2->cls_ipnif))
475 (void) atm_untimeout(&spansarp_timer);
480 * Issue a SPANS ARP request packet
483 * sap pointer to arp table entry
486 * 0 packet was successfully sent
487 * else unable to send packet
491 spansarp_request(sap)
492 struct spansarp *sap;
494 struct spanscls *clp;
496 struct spanscls_hdr *chp;
497 struct spansarp_hdr *ahp;
503 spp = clp->cls_spans;
504 inp = clp->cls_ipnif;
507 * Make sure CLS VCC is open and that we know our addresses
509 if (clp->cls_state != CLS_OPEN)
511 if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR)
517 * Get a buffer for pdu
519 KB_ALLOCPKT(m, ARP_PACKET_LEN, KB_F_NOWAIT, KB_T_DATA);
524 * Place pdu at end of buffer
526 KB_PLENSET(m, ARP_PACKET_LEN);
527 KB_TAILALIGN(m, ARP_PACKET_LEN);
528 KB_DATASTART(m, chp, struct spanscls_hdr *);
529 ahp = (struct spansarp_hdr *)(chp + 1);
534 spans_addr_copy(&spans_bcastaddr, &chp->ch_dst);
535 spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
536 *(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto;
537 *(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap;
538 *(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1];
539 chp->ch_pid = htons(ETHERTYPE_ARP);
545 ahp->ah_hrd = htons(ARP_SPANS);
546 ahp->ah_pro = htons(ETHERTYPE_IP);
547 ahp->ah_hln = sizeof(spans_addr);
548 ahp->ah_pln = sizeof(struct in_addr);
549 ahp->ah_op = htons(ARP_REQUEST);
550 spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
551 KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), ahp->ah_spa,
552 sizeof(struct in_addr));
553 KM_COPY(&sap->sa_dstip, ahp->ah_tpa, sizeof(struct in_addr));
556 * Now, send the pdu via the CLS service
558 err = atm_cm_cpcs_data(clp->cls_conn, m);
569 * Process a SPANS ARP input packet
572 * clp pointer to interface CLS control block
573 * m pointer to input packet buffer chain
580 spansarp_input(clp, m)
581 struct spanscls *clp;
584 struct spans *spp = clp->cls_spans;
585 struct spanscls_hdr *chp;
586 struct spansarp_hdr *ahp;
587 struct spansarp *sap;
588 struct ip_nif *inp = clp->cls_ipnif;
589 struct in_addr in_me, in_src, in_targ;
593 * Make sure IP interface has been activated
599 * Get the packet together
601 if (KB_LEN(m) < ARP_PACKET_LEN) {
602 KB_PULLUP(m, ARP_PACKET_LEN, m);
606 KB_DATASTART(m, chp, struct spanscls_hdr *);
607 ahp = (struct spansarp_hdr *)(chp + 1);
609 KM_COPY(ahp->ah_spa, &in_src, sizeof(struct in_addr));
610 KM_COPY(ahp->ah_tpa, &in_targ, sizeof(struct in_addr));
611 KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), &in_me,
612 sizeof(struct in_addr));
615 * Initial packet verification
617 if ((ahp->ah_hrd != htons(ARP_SPANS)) ||
618 (ahp->ah_pro != htons(ETHERTYPE_IP)))
622 * Validate source addresses
623 * can't be from hardware broadcast
626 if (!spans_addr_cmp(&ahp->ah_sha, &spans_bcastaddr))
628 if (!spans_addr_cmp(&ahp->ah_sha, spp->sp_addr.address))
630 if (in_src.s_addr == in_me.s_addr) {
632 "duplicate IP address sent from spans address %s\n",
633 spans_addr_print(&ahp->ah_sha));
639 * If source IP address is from unspecified or broadcast addresses,
640 * don't bother updating arp table, but answer possible requests
642 #if (defined(BSD) && (BSD >= 199306))
643 if (in_broadcast(in_src, &inp->inf_nif->nif_if))
645 if (in_broadcast(in_src))
650 * Update arp table with source address info
653 SPANSARP_LOOKUP(in_src.s_addr, sap);
656 * Found an entry for the source, but don't
657 * update permanent entries
659 if (sap->sa_origin != SAO_PERM) {
664 sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
665 sap->sa_dstatm.address_length = sizeof(spans_addr);
666 spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
669 if ((sap->sa_flags & SAF_VALID) == 0) {
671 * Newly valid entry, notify waiting users
673 struct ipvcc *ivp, *inext;
675 sap->sa_flags |= SAF_VALID;
676 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
677 inext = ivp->iv_arpnext;
679 ivp->iv_arpent = (struct arpmap *)sap;
680 (*inp->inf_arpnotify)(ivp, MAP_VALID);
684 * Remove ourselves from the retry chain
686 UNLINK(sap, struct spansarp,
687 spansarp_retry_head, sa_rnext);
691 } else if (in_targ.s_addr == in_me.s_addr) {
693 * Source unknown and we're the target - add new entry
695 sap = (struct spansarp *)atm_allocate(&spansarp_pool);
697 sap->sa_dstip.s_addr = in_src.s_addr;
698 sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
699 sap->sa_dstatm.address_length = sizeof(spans_addr);
700 spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
701 sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
702 sap->sa_dstatmsub.address_length = 0;
704 sap->sa_flags = SAF_VALID;
705 sap->sa_origin = SAO_LOOKUP;
713 * If this is a request for our address, send a reply
715 if (ntohs(ahp->ah_op) != ARP_REQUEST)
717 if (in_targ.s_addr != in_me.s_addr)
720 spans_addr_copy(&chp->ch_src, &chp->ch_dst);
721 spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
722 ahp->ah_op = htons(ARP_REPLY);
723 spans_addr_copy(&ahp->ah_sha, &ahp->ah_tha);
724 spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
725 KM_COPY(ahp->ah_spa, ahp->ah_tpa, sizeof(struct in_addr));
726 KM_COPY(&in_me, ahp->ah_spa, sizeof(struct in_addr));
728 err = atm_cm_cpcs_data(clp->cls_conn, m);
739 * Process a SPANS ARP aging timer tick
741 * This function is called every SPANSARP_AGING seconds, in order to age
742 * all the arp table entries.
747 * tip pointer to spansarp aging timer control block
755 struct atm_time *tip;
757 struct spansarp *sap, *snext;
758 struct ipvcc *ivp, *inext;
763 * Schedule next timeout
765 atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
768 * Run through arp table bumping each entry's aging timer.
770 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
771 for (sap = spansarp_arptab[i]; sap; sap = snext) {
772 snext = sap->sa_next;
775 * Permanent (manually installed) entries aren't aged
777 if (sap->sa_origin == SAO_PERM)
781 * See if entry is valid and over-aged
783 if ((sap->sa_flags & SAF_VALID) == 0)
785 if (++sap->sa_reftime < SPANSARP_MAXAGE)
789 * Entry is now invalid, tell IP/ATM about it
791 sap->sa_flags |= SAF_LOCKED;
792 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
793 inext = ivp->iv_arpnext;
794 (*ivp->iv_ipnif->inf_arpnotify)
797 sap->sa_flags &= ~(SAF_LOCKED | SAF_VALID);
799 if (sap->sa_ivp != NULL) {
801 * Somebody still cares, so add the arp
802 * entry to the retry list.
804 LINK2TAIL(sap, struct spansarp,
805 spansarp_retry_head, sa_rnext);
806 if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
807 atm_timeout(&spansarp_rtimer,
808 SPANSARP_RETRY, spansarp_retry);
811 * Issue arp request for this address
813 (void) spansarp_request(sap);
817 * Delete unused entry
819 SPANSARP_DELETE(sap);
820 atm_free((caddr_t)sap);
828 * Process a SPANS ARP retry timer tick
830 * This function is called every SPANSARP_RETRY seconds, in order to retry
831 * awaiting arp resolution requests. We will retry requests indefinitely,
832 * assuming that IP will set a timeout to close the VCC(s) requesting the
833 * failing address resolution.
838 * tip pointer to spansarp retry timer control block
846 struct atm_time *tip;
848 struct spansarp *sap;
852 * See if there's work to do
854 if (spansarp_retry_head == NULL) {
859 * Schedule next timeout
861 atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
864 * Run through retry chain, (re)issuing arp requests.
866 for (sap = spansarp_retry_head; sap; sap = sap->sa_next) {
869 * Send another arp request
871 (void) spansarp_request(sap);
877 * SPANS ARP IOCTL support
879 * Function will be called at splnet.
882 * code PF_ATM sub-operation code
883 * data pointer to code specific parameter data area
884 * arg1 pointer to code specific argument
888 * errno error processing request - reason indicated
892 spansarp_ioctl(code, data, arg1)
897 struct atmaddreq *aap;
898 struct atmdelreq *adp;
899 struct atminfreq *aip;
901 struct spanscls *clp;
902 struct spansarp *sap;
903 struct air_arp_rsp aar;
905 struct ipvcc *ivp, *inext;
908 int err = 0, i, buf_len;
916 * Add a permanent ARP mapping
918 aap = (struct atmaddreq *)data;
919 clp = (struct spanscls *)arg1;
920 inp = clp->cls_ipnif;
921 if ((aap->aar_arp_addr.address_format != T_ATM_SPANS_ADDR) ||
922 (aap->aar_arp_origin != ARP_ORIG_PERM)) {
926 ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
929 * See if we already have an entry for this IP address
931 SPANSARP_LOOKUP(ip.s_addr, sap);
934 * No, get a new arp entry
936 sap = (struct spansarp *)atm_allocate(&spansarp_pool);
946 ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
947 sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
948 sap->sa_dstatmsub.address_length = 0;
950 sap->sa_flags |= SAF_VALID;
951 sap->sa_origin = SAO_PERM;
962 * See if we're attempting to change the ATM address for
965 if ((sap->sa_dstatm.address_format != T_ATM_ABSENT) &&
966 (!ATM_ADDR_EQUAL(&aap->aar_arp_addr, &sap->sa_dstatm) ||
967 (clp != sap->sa_cls))) {
970 * Yes, notify IP/ATM that a mapping change has
971 * occurred. IP/ATM will close any VCC's which
972 * aren't waiting for this map.
974 sap->sa_flags |= SAF_LOCKED;
975 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
976 inext = ivp->iv_arpnext;
977 (*inp->inf_arpnotify)(ivp, MAP_CHANGED);
979 sap->sa_flags &= ~SAF_LOCKED;
983 * Update the cached entry with the new data
985 ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
989 * If this entry isn't valid, notify anyone who might
992 if ((sap->sa_flags & SAF_VALID) == 0) {
994 sap->sa_flags |= SAF_LOCKED;
995 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
996 inext = ivp->iv_arpnext;
997 (*inp->inf_arpnotify)(ivp, MAP_VALID);
999 sap->sa_flags &= ~SAF_LOCKED;
1003 * Remove this entry from the retry chain
1005 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
1008 * Mark the entry as permanent
1010 sap->sa_flags |= SAF_VALID;
1011 sap->sa_origin = SAO_PERM;
1016 * Delete an ARP mapping
1018 adp = (struct atmdelreq *)data;
1019 clp = (struct spanscls *)arg1;
1020 ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
1023 * Now find the entry to be deleted
1025 SPANSARP_LOOKUP(ip.s_addr, sap);
1032 * Notify all VCCs using this entry that they must finish
1035 sap->sa_flags |= SAF_LOCKED;
1036 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
1037 inext = ivp->iv_arpnext;
1038 (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
1042 * Now free up the entry
1044 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
1045 SPANSARP_DELETE(sap);
1046 atm_free((caddr_t)sap);
1051 * Get ARP table information
1053 aip = (struct atminfreq *)data;
1054 spp = (struct spans *)arg1;
1056 if (aip->air_arp_addr.sa_family != AF_INET)
1058 dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr;
1060 buf_addr = aip->air_buf_addr;
1061 buf_len = aip->air_buf_len;
1063 if ((clp = spp->sp_cls) == NULL)
1067 * Run through entire arp table
1069 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
1070 for (sap = spansarp_arptab[i]; sap;
1071 sap = sap->sa_next) {
1073 * We only want entries learned
1074 * from the supplied interface.
1076 if (sap->sa_cls != clp)
1078 if ((dst != INADDR_ANY) &&
1079 (dst != sap->sa_dstip.s_addr))
1083 * Make sure there's room in the user's buffer
1085 if (buf_len < sizeof(aar)) {
1091 * Fill in info to be returned
1093 SATOSIN(&aar.aap_arp_addr)->sin_family =
1095 SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr =
1096 sap->sa_dstip.s_addr;
1097 (void) snprintf(aar.aap_intf,
1098 sizeof(aar.aap_intf), "%s%d",
1099 clp->cls_ipnif->inf_nif->nif_if.if_name,
1100 clp->cls_ipnif->inf_nif->nif_if.if_unit
1102 aar.aap_flags = sap->sa_flags;
1103 aar.aap_origin = sap->sa_origin;
1104 if (sap->sa_flags & SAF_VALID)
1105 aar.aap_age = SPANSARP_MAXAGE -
1109 ATM_ADDR_COPY(&sap->sa_dstatm, &aar.aap_addr);
1110 ATM_ADDR_COPY(&sap->sa_dstatmsub,
1114 * Copy the response into the user's buffer
1116 if ((err = copyout((caddr_t)&aar, buf_addr,
1119 buf_addr += sizeof(aar);
1120 buf_len -= sizeof(aar);
1127 * Update the buffer pointer and length
1129 aip->air_buf_addr = buf_addr;
1130 aip->air_buf_len = buf_len;
1135 * Get ARP server information
1137 /* SPANS doesn't have an ARP server */