2 * ===================================
3 * HARP | Host ATM Research Platform
4 * ===================================
7 * This Host ATM Research Platform ("HARP") file (the "Software") is
8 * made available by Network Computing Services, Inc. ("NetworkCS")
9 * "AS IS". NetworkCS does not provide maintenance, improvements or
10 * support of any kind.
12 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
13 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
14 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
15 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
16 * In no event shall NetworkCS be responsible for any damages, including
17 * but not limited to consequential damages, arising from or relating to
18 * any use of the Software or related support.
20 * Copyright 1994-1998 Network Computing Services, Inc.
22 * Copies of this Software may be made, however, the above copyright
23 * notice must be reproduced on all copies.
27 * SPANS Signalling Manager
28 * ---------------------------
30 * SPANS CLS - ARP support
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/types.h>
39 #include <sys/errno.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/syslog.h>
45 #include <netinet/in.h>
46 #include <netinet/in_var.h>
47 #include <netinet/if_ether.h>
48 #include <netatm/port.h>
49 #include <netatm/queue.h>
50 #include <netatm/atm.h>
51 #include <netatm/atm_sys.h>
52 #include <netatm/atm_sap.h>
53 #include <netatm/atm_cm.h>
54 #include <netatm/atm_if.h>
55 #include <netatm/atm_vc.h>
56 #include <netatm/atm_ioctl.h>
57 #include <netatm/atm_sigmgr.h>
58 #include <netatm/atm_stack.h>
59 #include <netatm/atm_pcb.h>
60 #include <netatm/atm_var.h>
62 #include <netatm/ipatm/ipatm_var.h>
63 #include <netatm/ipatm/ipatm_serv.h>
64 #include "spans_xdr.h"
65 #include <netatm/spans/spans_var.h>
66 #include <netatm/spans/spans_cls.h>
73 struct spansarp *spansarp_arptab[SPANSARP_HASHSIZ] = {NULL};
79 static int spansarp_request(struct spansarp *);
80 static void spansarp_aging(struct atm_time *);
81 static void spansarp_retry(struct atm_time *);
86 static struct atm_time spansarp_timer = {0, 0}; /* Aging timer */
87 static struct atm_time spansarp_rtimer = {0, 0}; /* Retry timer */
89 static struct spansarp *spansarp_retry_head = NULL; /* Retry chain */
91 static uma_zone_t spansarp_zone;
95 * Process a new outgoing SVC requiring SPANS ARP support
97 * This function is called by an endpoint wishing to resolve a destination
98 * IP address to an ATM address in order to open an SVC to that destination.
99 * If a valid mapping is already in our cache, then we just tell the caller
100 * about it and that's that. Otherwise, we have to allocate a new arp entry
101 * and issue a query for the mapping.
104 * ivp pointer to SVC's IPVCC control block
105 * dst pointer to destination IP address
108 * MAP_VALID - Got the answer, returned via iv_arpent field.
109 * MAP_PROCEEDING - OK so far, querying for peer's mapping
110 * MAP_FAILED - error, unable to allocate resources
114 spansarp_svcout(ivp, dst)
118 struct spanscls *clp;
119 struct spansarp *sap;
122 ivp->iv_arpent = NULL;
125 * Lookup destination address
128 SPANSARP_LOOKUP(dst->s_addr, sap);
132 * Link this vcc to entry queue
134 LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
137 * If entry is valid, we're done
139 if (sap->sa_flags & SAF_VALID) {
140 ivp->iv_arpent = (struct arpmap *)sap;
146 * We're already looking for this address
149 return (MAP_PROCEEDING);
153 * Need a new arp entry - first, find the cls instance
154 * corresponding to the requestor's IP interface.
156 for (clp = spanscls_head; clp; clp = clp->cls_next) {
157 if (clp->cls_ipnif == ivp->iv_ipnif)
166 * Now get the new arp entry
168 sap = uma_zalloc(spansarp_zone, M_WAITOK);
177 sap->sa_dstip.s_addr = dst->s_addr;
178 sap->sa_dstatm.address_format = T_ATM_ABSENT;
179 sap->sa_dstatm.address_length = 0;
180 sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
181 sap->sa_dstatmsub.address_length = 0;
183 sap->sa_origin = SAO_LOOKUP;
186 * Link ipvcc to arp entry for later notification
188 LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
191 * Add arp entry to table
196 * Add arp entry to retry list and start retry timer if needed
198 LINK2TAIL(sap, struct spansarp, spansarp_retry_head, sa_rnext);
199 if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
200 atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
203 * Issue arp request for this address
205 (void) spansarp_request(sap);
208 return (MAP_PROCEEDING);
213 * Process a new incoming SVC requiring SPANS ARP support
215 * This function is called by an endpoint wishing to resolve a destination
216 * ATM address to its IP address for an incoming call in order to allow a
217 * bi-directional flow of IP packets on the SVC.
219 * SPANS ARP does not provide reverse mapping facilities and only supports
220 * uni-directional SVCs. Thus, we lie a little to IP and always return a
221 * MAP_PROCEEDING indication, but we will never later notify IP of a
222 * MAP_VALID condition.
225 * ivp pointer to SVC's IPVCC control block
226 * dst pointer to destination ATM address
227 * dstsub pointer to destination ATM subaddress
230 * MAP_VALID - Got the answer, returned via iv_arpent field.
231 * MAP_PROCEEDING - OK so far, querying for peer's mapping
232 * MAP_FAILED - error, unable to allocate resources
236 spansarp_svcin(ivp, dst, dstsub)
242 * Clear ARP entry field
244 ivp->iv_arpent = NULL;
246 return (MAP_PROCEEDING);
251 * SPANS ARP SVC activation notification
253 * This function is called when a previously opened SVC has successfully
257 * ivp pointer to SVC's IPVCC control block
260 * 0 activation processing successful
261 * errno activation failed - reason indicated
265 spansarp_svcactive(ivp)
268 struct spansarp *sap;
272 * Find an entry for the destination address
274 SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
277 * IP is finished with entry, so remove IP VCC from chain
279 UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
280 ivp->iv_arpent = NULL;
283 * This seems like a reasonable reason to refresh the entry
294 * SPANS ARP supported VCC is closing
296 * This function is called just prior to a user closing a VCC which
297 * supports SPANS ARP. We'll sever our links to the VCC and then
298 * figure out how much more cleanup we need to do for now.
301 * ivp pointer to VCC's IPVCC control block
308 spansarp_vcclose(ivp)
311 struct spansarp *sap;
317 SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
324 * Remove IP VCC from chain
326 UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
327 ivp->iv_arpent = NULL;
330 * If entry is currently valid or in use, not much else for us to do
332 if ((sap->sa_flags & (SAF_VALID | SAF_LOCKED)) ||
333 (sap->sa_origin >= SAO_PERM)) {
339 * If there are still other VCCs waiting, exit
347 * Noone else waiting, so remove entry from the retry chain
349 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
354 SPANSARP_DELETE(sap);
355 uma_zfree(spansarp_zone, sap);
360 * Called when the spans module is loaded.
366 spansarp_zone = uma_zcreate("spansarp", sizeof(struct spansarp),
367 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
368 if (spansarp_zone == NULL)
369 panic("spansarp_zone");
373 * Process module unloading notification
375 * Called whenever the spans module is about to be unloaded. All signalling
376 * instances will have been previously detached. All spansarp resources
392 * Make sure the arp table is empty
394 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
395 if (spansarp_arptab[i] != NULL)
396 panic("spansarp_stop: arp table not empty");
402 (void) atm_untimeout(&spansarp_timer);
403 (void) atm_untimeout(&spansarp_rtimer);
406 * Free our storage pools
408 uma_zdestroy(spansarp_zone);
413 * Process IP Network Interface Activation
415 * Called whenever an IP network interface becomes active.
420 * clp pointer to CLS interface
428 struct spanscls *clp;
431 * Make sure aging timer is running
433 if ((spansarp_timer.ti_flag & TIF_QUEUED) == 0)
434 atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
439 * Process IP Network Interface Deactivation
441 * Called whenever an IP network interface becomes inactive.
446 * clp pointer to CLS interface
454 struct spanscls *clp;
456 struct spanscls *clp2;
457 struct spansarp *sap, *snext;
461 * Delete all interface entries
463 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
464 for (sap = spansarp_arptab[i]; sap; sap = snext) {
465 snext = sap->sa_next;
468 * Clean up entries for this interface
470 if (sap->sa_cls != clp)
474 * All VCCs better be gone by now
477 panic("spansarp_ipdact: entry not empty");
480 * Remove entry from the retry chain
482 UNLINK(sap, struct spansarp,
483 spansarp_retry_head, sa_rnext);
486 * Delete entry from arp table
488 SPANSARP_DELETE(sap);
489 uma_zfree(spansarp_zone, sap);
494 * Stop aging timer if this is the last active interface
496 for (clp2 = spanscls_head; clp2; clp2 = clp2->cls_next) {
497 if ((clp != clp2) && (clp2->cls_ipnif))
501 (void) atm_untimeout(&spansarp_timer);
506 * Issue a SPANS ARP request packet
509 * sap pointer to arp table entry
512 * 0 packet was successfully sent
513 * else unable to send packet
517 spansarp_request(sap)
518 struct spansarp *sap;
520 struct spanscls *clp;
522 struct spanscls_hdr *chp;
523 struct spansarp_hdr *ahp;
529 spp = clp->cls_spans;
530 inp = clp->cls_ipnif;
533 * Make sure CLS VCC is open and that we know our addresses
535 if (clp->cls_state != CLS_OPEN)
537 if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR)
543 * Get a buffer for pdu
545 KB_ALLOCPKT(m, ARP_PACKET_LEN, KB_F_NOWAIT, KB_T_DATA);
550 * Place pdu at end of buffer
552 KB_PLENSET(m, ARP_PACKET_LEN);
553 KB_TAILALIGN(m, ARP_PACKET_LEN);
554 KB_DATASTART(m, chp, struct spanscls_hdr *);
555 ahp = (struct spansarp_hdr *)(chp + 1);
560 spans_addr_copy(&spans_bcastaddr, &chp->ch_dst);
561 spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
562 *(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto;
563 *(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap;
564 *(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1];
565 chp->ch_pid = htons(ETHERTYPE_ARP);
571 ahp->ah_hrd = htons(ARP_SPANS);
572 ahp->ah_pro = htons(ETHERTYPE_IP);
573 ahp->ah_hln = sizeof(spans_addr);
574 ahp->ah_pln = sizeof(struct in_addr);
575 ahp->ah_op = htons(ARP_REQUEST);
576 spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
577 bcopy(&(IA_SIN(inp->inf_addr)->sin_addr), ahp->ah_spa,
578 sizeof(struct in_addr));
579 bcopy(&sap->sa_dstip, ahp->ah_tpa, sizeof(struct in_addr));
582 * Now, send the pdu via the CLS service
584 err = atm_cm_cpcs_data(clp->cls_conn, m);
595 * Process a SPANS ARP input packet
598 * clp pointer to interface CLS control block
599 * m pointer to input packet buffer chain
606 spansarp_input(clp, m)
607 struct spanscls *clp;
610 struct spans *spp = clp->cls_spans;
611 struct spanscls_hdr *chp;
612 struct spansarp_hdr *ahp;
613 struct spansarp *sap;
614 struct ip_nif *inp = clp->cls_ipnif;
615 struct in_addr in_me, in_src, in_targ;
619 * Make sure IP interface has been activated
625 * Get the packet together
627 if (KB_LEN(m) < ARP_PACKET_LEN) {
628 KB_PULLUP(m, ARP_PACKET_LEN, m);
632 KB_DATASTART(m, chp, struct spanscls_hdr *);
633 ahp = (struct spansarp_hdr *)(chp + 1);
635 bcopy(ahp->ah_spa, &in_src, sizeof(struct in_addr));
636 bcopy(ahp->ah_tpa, &in_targ, sizeof(struct in_addr));
637 bcopy(&(IA_SIN(inp->inf_addr)->sin_addr), &in_me,
638 sizeof(struct in_addr));
641 * Initial packet verification
643 if ((ahp->ah_hrd != htons(ARP_SPANS)) ||
644 (ahp->ah_pro != htons(ETHERTYPE_IP)))
648 * Validate source addresses
649 * can't be from hardware broadcast
652 if (!spans_addr_cmp(&ahp->ah_sha, &spans_bcastaddr))
654 if (!spans_addr_cmp(&ahp->ah_sha, spp->sp_addr.address))
656 if (in_src.s_addr == in_me.s_addr) {
658 "duplicate IP address sent from spans address %s\n",
659 spans_addr_print(&ahp->ah_sha));
665 * If source IP address is from unspecified or broadcast addresses,
666 * don't bother updating arp table, but answer possible requests
668 if (in_broadcast(in_src, ANIF2IFP(inp->inf_nif)))
672 * Update arp table with source address info
675 SPANSARP_LOOKUP(in_src.s_addr, sap);
678 * Found an entry for the source, but don't
679 * update permanent entries
681 if (sap->sa_origin != SAO_PERM) {
686 sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
687 sap->sa_dstatm.address_length = sizeof(spans_addr);
688 spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
691 if ((sap->sa_flags & SAF_VALID) == 0) {
693 * Newly valid entry, notify waiting users
695 struct ipvcc *ivp, *inext;
697 sap->sa_flags |= SAF_VALID;
698 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
699 inext = ivp->iv_arpnext;
701 ivp->iv_arpent = (struct arpmap *)sap;
702 (*inp->inf_arpnotify)(ivp, MAP_VALID);
706 * Remove ourselves from the retry chain
708 UNLINK(sap, struct spansarp,
709 spansarp_retry_head, sa_rnext);
713 } else if (in_targ.s_addr == in_me.s_addr) {
715 * Source unknown and we're the target - add new entry
717 sap = uma_zalloc(spansarp_zone, M_WAITOK);
719 sap->sa_dstip.s_addr = in_src.s_addr;
720 sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
721 sap->sa_dstatm.address_length = sizeof(spans_addr);
722 spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
723 sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
724 sap->sa_dstatmsub.address_length = 0;
726 sap->sa_flags = SAF_VALID;
727 sap->sa_origin = SAO_LOOKUP;
735 * If this is a request for our address, send a reply
737 if (ntohs(ahp->ah_op) != ARP_REQUEST)
739 if (in_targ.s_addr != in_me.s_addr)
742 spans_addr_copy(&chp->ch_src, &chp->ch_dst);
743 spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
744 ahp->ah_op = htons(ARP_REPLY);
745 spans_addr_copy(&ahp->ah_sha, &ahp->ah_tha);
746 spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
747 bcopy(ahp->ah_spa, ahp->ah_tpa, sizeof(struct in_addr));
748 bcopy(&in_me, ahp->ah_spa, sizeof(struct in_addr));
750 err = atm_cm_cpcs_data(clp->cls_conn, m);
761 * Process a SPANS ARP aging timer tick
763 * This function is called every SPANSARP_AGING seconds, in order to age
764 * all the arp table entries.
769 * tip pointer to spansarp aging timer control block
777 struct atm_time *tip;
779 struct spansarp *sap, *snext;
780 struct ipvcc *ivp, *inext;
785 * Schedule next timeout
787 atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
790 * Run through arp table bumping each entry's aging timer.
792 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
793 for (sap = spansarp_arptab[i]; sap; sap = snext) {
794 snext = sap->sa_next;
797 * Permanent (manually installed) entries aren't aged
799 if (sap->sa_origin == SAO_PERM)
803 * See if entry is valid and over-aged
805 if ((sap->sa_flags & SAF_VALID) == 0)
807 if (++sap->sa_reftime < SPANSARP_MAXAGE)
811 * Entry is now invalid, tell IP/ATM about it
813 sap->sa_flags |= SAF_LOCKED;
814 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
815 inext = ivp->iv_arpnext;
816 (*ivp->iv_ipnif->inf_arpnotify)
819 sap->sa_flags &= ~(SAF_LOCKED | SAF_VALID);
821 if (sap->sa_ivp != NULL) {
823 * Somebody still cares, so add the arp
824 * entry to the retry list.
826 LINK2TAIL(sap, struct spansarp,
827 spansarp_retry_head, sa_rnext);
828 if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
829 atm_timeout(&spansarp_rtimer,
830 SPANSARP_RETRY, spansarp_retry);
833 * Issue arp request for this address
835 (void) spansarp_request(sap);
839 * Delete unused entry
841 SPANSARP_DELETE(sap);
842 uma_zfree(spansarp_zone, sap);
850 * Process a SPANS ARP retry timer tick
852 * This function is called every SPANSARP_RETRY seconds, in order to retry
853 * awaiting arp resolution requests. We will retry requests indefinitely,
854 * assuming that IP will set a timeout to close the VCC(s) requesting the
855 * failing address resolution.
860 * tip pointer to spansarp retry timer control block
868 struct atm_time *tip;
870 struct spansarp *sap;
874 * See if there's work to do
876 if (spansarp_retry_head == NULL) {
881 * Schedule next timeout
883 atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
886 * Run through retry chain, (re)issuing arp requests.
888 for (sap = spansarp_retry_head; sap; sap = sap->sa_next) {
891 * Send another arp request
893 (void) spansarp_request(sap);
899 * SPANS ARP IOCTL support
901 * Function will be called at splnet.
904 * code PF_ATM sub-operation code
905 * data pointer to code specific parameter data area
906 * arg1 pointer to code specific argument
910 * errno error processing request - reason indicated
914 spansarp_ioctl(code, data, arg1)
919 struct atmaddreq *aap;
920 struct atmdelreq *adp;
921 struct atminfreq *aip;
923 struct spanscls *clp;
924 struct spansarp *sap;
925 struct air_arp_rsp aar;
927 struct ipvcc *ivp, *inext;
939 * Add a permanent ARP mapping
941 aap = (struct atmaddreq *)data;
942 clp = (struct spanscls *)arg1;
943 inp = clp->cls_ipnif;
944 if ((aap->aar_arp_addr.address_format != T_ATM_SPANS_ADDR) ||
945 (aap->aar_arp_origin != ARP_ORIG_PERM)) {
949 ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
952 * See if we already have an entry for this IP address
954 SPANSARP_LOOKUP(ip.s_addr, sap);
957 * No, get a new arp entry
959 sap = uma_zalloc(spansarp_zone, M_WAITOK);
969 ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
970 sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
971 sap->sa_dstatmsub.address_length = 0;
973 sap->sa_flags |= SAF_VALID;
974 sap->sa_origin = SAO_PERM;
985 * See if we're attempting to change the ATM address for
988 if ((sap->sa_dstatm.address_format != T_ATM_ABSENT) &&
989 (!ATM_ADDR_EQUAL(&aap->aar_arp_addr, &sap->sa_dstatm) ||
990 (clp != sap->sa_cls))) {
993 * Yes, notify IP/ATM that a mapping change has
994 * occurred. IP/ATM will close any VCC's which
995 * aren't waiting for this map.
997 sap->sa_flags |= SAF_LOCKED;
998 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
999 inext = ivp->iv_arpnext;
1000 (*inp->inf_arpnotify)(ivp, MAP_CHANGED);
1002 sap->sa_flags &= ~SAF_LOCKED;
1006 * Update the cached entry with the new data
1008 ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
1012 * If this entry isn't valid, notify anyone who might
1015 if ((sap->sa_flags & SAF_VALID) == 0) {
1017 sap->sa_flags |= SAF_LOCKED;
1018 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
1019 inext = ivp->iv_arpnext;
1020 (*inp->inf_arpnotify)(ivp, MAP_VALID);
1022 sap->sa_flags &= ~SAF_LOCKED;
1026 * Remove this entry from the retry chain
1028 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
1031 * Mark the entry as permanent
1033 sap->sa_flags |= SAF_VALID;
1034 sap->sa_origin = SAO_PERM;
1039 * Delete an ARP mapping
1041 adp = (struct atmdelreq *)data;
1042 clp = (struct spanscls *)arg1;
1043 ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
1046 * Now find the entry to be deleted
1048 SPANSARP_LOOKUP(ip.s_addr, sap);
1055 * Notify all VCCs using this entry that they must finish
1058 sap->sa_flags |= SAF_LOCKED;
1059 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
1060 inext = ivp->iv_arpnext;
1061 (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
1065 * Now free up the entry
1067 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
1068 SPANSARP_DELETE(sap);
1069 uma_zfree(spansarp_zone, sap);
1074 * Get ARP table information
1076 aip = (struct atminfreq *)data;
1077 spp = (struct spans *)arg1;
1079 if (aip->air_arp_addr.sa_family != AF_INET)
1081 dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr;
1083 buf_addr = aip->air_buf_addr;
1084 buf_len = aip->air_buf_len;
1086 if ((clp = spp->sp_cls) == NULL)
1090 * Run through entire arp table
1092 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
1093 for (sap = spansarp_arptab[i]; sap;
1094 sap = sap->sa_next) {
1096 * We only want entries learned
1097 * from the supplied interface.
1099 if (sap->sa_cls != clp)
1101 if ((dst != INADDR_ANY) &&
1102 (dst != sap->sa_dstip.s_addr))
1106 * Make sure there's room in the user's buffer
1108 if (buf_len < sizeof(aar)) {
1114 * Fill in info to be returned
1116 SATOSIN(&aar.aap_arp_addr)->sin_family =
1118 SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr =
1119 sap->sa_dstip.s_addr;
1120 strlcpy(aar.aap_intf,
1121 ANIF2IFP(clp->cls_ipnif->inf_nif)->if_xname,
1122 sizeof(aar.aap_intf));
1123 aar.aap_flags = sap->sa_flags;
1124 aar.aap_origin = sap->sa_origin;
1125 if (sap->sa_flags & SAF_VALID)
1126 aar.aap_age = SPANSARP_MAXAGE -
1130 ATM_ADDR_COPY(&sap->sa_dstatm, &aar.aap_addr);
1131 ATM_ADDR_COPY(&sap->sa_dstatmsub,
1135 * Copy the response into the user's buffer
1137 if ((err = copyout((caddr_t)&aar, buf_addr,
1140 buf_addr += sizeof(aar);
1141 buf_len -= sizeof(aar);
1148 * Update the buffer pointer and length
1150 aip->air_buf_addr = buf_addr;
1151 aip->air_buf_len = buf_len;
1156 * Get ARP server information
1158 /* SPANS doesn't have an ARP server */