Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / atm / spans / spans_arp.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
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.
12  *
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.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/netatm/spans/spans_arp.c,v 1.7 2000/01/15 20:34:55 mks Exp $
27  *
28  */
29
30 /*
31  * SPANS Signalling Manager
32  * ---------------------------
33  *
34  * SPANS CLS - ARP support
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
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>
45
46 #ifndef lint
47 __RCSID("@(#) $FreeBSD: src/sys/netatm/spans/spans_arp.c,v 1.7 2000/01/15 20:34:55 mks Exp $");
48 #endif
49
50
51 /*
52  * Global variables
53  */
54 struct spansarp         *spansarp_arptab[SPANSARP_HASHSIZ] = {NULL};
55
56
57 /*
58  * Local functions
59  */
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 *));
63
64 /*
65  * Local variables
66  */
67 static struct atm_time  spansarp_timer = {0, 0};        /* Aging timer */
68 static struct atm_time  spansarp_rtimer = {0, 0};       /* Retry timer */
69
70 static struct spansarp  *spansarp_retry_head = NULL;    /* Retry chain */
71
72 static struct sp_info   spansarp_pool = {
73         "spans arp pool",               /* si_name */
74         sizeof(struct spansarp),        /* si_blksiz */
75         10,                             /* si_blkcnt */
76         100                             /* si_maxallow */
77 };
78
79
80 /*
81  * Process a new outgoing SVC requiring SPANS ARP support
82  * 
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.
88  *
89  * Arguments:
90  *      ivp     pointer to SVC's IPVCC control block
91  *      dst     pointer to destination IP address
92  *
93  * Returns:
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
97  *
98  */
99 int
100 spansarp_svcout(ivp, dst)
101         struct ipvcc    *ivp;
102         struct in_addr  *dst;
103 {
104         struct spanscls *clp;
105         struct spansarp *sap;
106         int     s;
107
108         ivp->iv_arpent = NULL;
109
110         /*
111          * Lookup destination address
112          */
113         s = splnet();
114         SPANSARP_LOOKUP(dst->s_addr, sap);
115
116         if (sap) {
117                 /*
118                  * Link this vcc to entry queue
119                  */
120                 LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
121
122                 /*
123                  * If entry is valid, we're done
124                  */
125                 if (sap->sa_flags & SAF_VALID) {
126                         ivp->iv_arpent = (struct arpmap *)sap;
127                         (void) splx(s);
128                         return (MAP_VALID);
129                 }
130
131                 /*
132                  * We're already looking for this address
133                  */
134                 (void) splx(s);
135                 return (MAP_PROCEEDING);
136         }
137
138         /*
139          * Need a new arp entry - first, find the cls instance
140          * corresponding to the requestor's IP interface.
141          */
142         for (clp = spanscls_head; clp; clp = clp->cls_next) {
143                 if (clp->cls_ipnif == ivp->iv_ipnif)
144                         break;
145         }
146         if (clp == NULL) {
147                 (void) splx(s);
148                 return (MAP_FAILED);
149         }
150
151         /*
152          * Now get the new arp entry
153          */
154         sap = (struct spansarp *)atm_allocate(&spansarp_pool);
155         if (sap == NULL) {
156                 (void) splx(s);
157                 return (MAP_FAILED);
158         }
159
160         /*
161          * Get entry set up
162          */
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;
168         sap->sa_cls = clp;
169         sap->sa_origin = SAO_LOOKUP;
170
171         /*
172          * Link ipvcc to arp entry for later notification
173          */
174         LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
175
176         /*
177          * Add arp entry to table
178          */
179         SPANSARP_ADD(sap);
180
181         /*
182          * Add arp entry to retry list and start retry timer if needed
183          */
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);
187
188         /*
189          * Issue arp request for this address
190          */
191         (void) spansarp_request(sap);
192
193         (void) splx(s);
194         return (MAP_PROCEEDING);
195 }
196
197
198 /*
199  * Process a new incoming SVC requiring SPANS ARP support
200  * 
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.
204  *
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.
209  *
210  * Arguments:
211  *      ivp     pointer to SVC's IPVCC control block
212  *      dst     pointer to destination ATM address
213  *      dstsub  pointer to destination ATM subaddress
214  *
215  * Returns:
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
219  *
220  */
221 int
222 spansarp_svcin(ivp, dst, dstsub)
223         struct ipvcc    *ivp;
224         Atm_addr        *dst;
225         Atm_addr        *dstsub;
226 {
227         /*
228          * Clear ARP entry field
229          */
230         ivp->iv_arpent = NULL;
231
232         return (MAP_PROCEEDING);
233 }
234
235
236 /*
237  * SPANS ARP SVC activation notification
238  * 
239  * This function is called when a previously opened SVC has successfully
240  * been connected.
241  *
242  * Arguments:
243  *      ivp     pointer to SVC's IPVCC control block
244  *
245  * Returns:
246  *      0       activation processing successful
247  *      errno   activation failed - reason indicated
248  *
249  */
250 int
251 spansarp_svcactive(ivp)
252         struct ipvcc    *ivp;
253 {
254         struct spansarp *sap;
255         int     s = splnet();
256
257         /* 
258          * Find an entry for the destination address
259          */
260         SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
261         if (sap) {
262                 /*
263                  * IP is finished with entry, so remove IP VCC from chain
264                  */
265                 UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
266                 ivp->iv_arpent = NULL;
267
268                 /*
269                  * This seems like a reasonable reason to refresh the entry
270                  */
271                 sap->sa_reftime = 0;
272         }
273
274         (void) splx(s);
275         return (0);
276 }
277
278
279 /*
280  * SPANS ARP supported VCC is closing
281  * 
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.
285  *
286  * Arguments:
287  *      ivp     pointer to VCC's IPVCC control block
288  *
289  * Returns:
290  *      none
291  *
292  */
293 void
294 spansarp_vcclose(ivp)
295         struct ipvcc    *ivp;
296 {
297         struct spansarp *sap;
298         int     s = splnet();
299
300         /*
301          * Get spansarp entry
302          */
303         SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
304         if (sap == NULL) {
305                 (void) splx(s);
306                 return;
307         }
308
309         /*
310          * Remove IP VCC from chain
311          */
312         UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
313         ivp->iv_arpent = NULL;
314
315         /*
316          * If entry is currently valid or in use, not much else for us to do
317          */
318         if ((sap->sa_flags & (SAF_VALID | SAF_LOCKED)) ||
319             (sap->sa_origin >= SAO_PERM)) {
320                 (void) splx(s);
321                 return;
322         }
323
324         /*
325          * If there are still other VCCs waiting, exit
326          */
327         if (sap->sa_ivp) {
328                 (void) splx(s);
329                 return;
330         }
331
332         /*
333          * Noone else waiting, so remove entry from the retry chain
334          */
335         UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
336
337         /*
338          * Free entry
339          */
340         SPANSARP_DELETE(sap);
341         atm_free((caddr_t)sap);
342         (void) splx(s);
343 }
344
345
346 /*
347  * Process module unloading notification
348  * 
349  * Called whenever the spans module is about to be unloaded.  All signalling
350  * instances will have been previously detached.  All spansarp resources 
351  * must be freed now.
352  *
353  * Arguments:
354  *      none
355  *
356  * Returns:
357  *      none
358  *
359  */
360 void
361 spansarp_stop()
362 {
363         int     i;
364
365         /* 
366          * Make sure the arp table is empty
367          */
368         for (i = 0; i < SPANSARP_HASHSIZ; i++) {
369                 if (spansarp_arptab[i] != NULL)
370                         panic("spansarp_stop: arp table not empty");
371         }
372
373         /*
374          * Cancel timers
375          */
376         (void) atm_untimeout(&spansarp_timer);
377         (void) atm_untimeout(&spansarp_rtimer);
378
379         /*
380          * Free our storage pools
381          */
382         atm_release_pool(&spansarp_pool);
383 }
384
385
386 /*
387  * Process IP Network Interface Activation
388  * 
389  * Called whenever an IP network interface becomes active.
390  *
391  * Called at splnet.
392  *
393  * Arguments:
394  *      clp     pointer to CLS interface
395  *
396  * Returns:
397  *      none
398  *
399  */
400 void
401 spansarp_ipact(clp)
402         struct spanscls         *clp;
403 {
404         /*
405          * Make sure aging timer is running
406          */
407         if ((spansarp_timer.ti_flag & TIF_QUEUED) == 0)
408                 atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
409 }
410
411
412 /*
413  * Process IP Network Interface Deactivation
414  * 
415  * Called whenever an IP network interface becomes inactive.
416  *
417  * Called at splnet.
418  *
419  * Arguments:
420  *      clp     pointer to CLS interface
421  *
422  * Returns:
423  *      none
424  *
425  */
426 void
427 spansarp_ipdact(clp)
428         struct spanscls         *clp;
429 {
430         struct spanscls         *clp2;
431         struct spansarp         *sap, *snext;
432         int             i;
433
434         /* 
435          * Delete all interface entries
436          */
437         for (i = 0; i < SPANSARP_HASHSIZ; i++) {
438                 for (sap = spansarp_arptab[i]; sap; sap = snext) {
439                         snext = sap->sa_next;
440
441                         /*
442                          * Clean up entries for this interface
443                          */
444                         if (sap->sa_cls != clp)
445                                 continue;
446
447                         /*
448                          * All VCCs better be gone by now
449                          */
450                         if (sap->sa_ivp)
451                                 panic("spansarp_ipdact: entry not empty");
452
453                         /*
454                          * Remove entry from the retry chain
455                          */
456                         UNLINK(sap, struct spansarp, 
457                                 spansarp_retry_head, sa_rnext);
458
459                         /*
460                          * Delete entry from arp table
461                          */
462                         SPANSARP_DELETE(sap);
463                         atm_free((caddr_t)sap);
464                 }
465         }
466
467         /*
468          * Stop aging timer if this is the last active interface
469          */
470         for (clp2 = spanscls_head; clp2; clp2 = clp2->cls_next) {
471                 if ((clp != clp2) && (clp2->cls_ipnif))
472                         break;
473         }
474         if (clp2 == NULL)
475                 (void) atm_untimeout(&spansarp_timer);
476 }
477
478
479 /*
480  * Issue a SPANS ARP request packet
481  * 
482  * Arguments:
483  *      sap     pointer to arp table entry
484  *
485  * Returns:
486  *      0       packet was successfully sent
487  *      else    unable to send packet
488  *
489  */
490 static int
491 spansarp_request(sap)
492         struct spansarp *sap;
493 {
494         struct spanscls         *clp;
495         struct spans            *spp;
496         struct spanscls_hdr     *chp;
497         struct spansarp_hdr     *ahp;
498         KBuffer                 *m;
499         struct ip_nif           *inp;
500         int                     err;
501
502         clp = sap->sa_cls;
503         spp = clp->cls_spans;
504         inp = clp->cls_ipnif;
505
506         /*
507          * Make sure CLS VCC is open and that we know our addresses
508          */
509         if (clp->cls_state != CLS_OPEN)
510                 return (1);
511         if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR)
512                 return (1);
513         if (inp == NULL)
514                 return (1);
515
516         /*
517          * Get a buffer for pdu
518          */
519         KB_ALLOCPKT(m, ARP_PACKET_LEN, KB_F_NOWAIT, KB_T_DATA);
520         if (m == NULL)
521                 return (1);
522
523         /*
524          * Place pdu at end of buffer
525          */
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);
530
531         /*
532          * Build headers
533          */
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);
540
541
542         /*
543          * Build ARP packet
544          */
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));
554
555         /*
556          * Now, send the pdu via the CLS service
557          */
558         err = atm_cm_cpcs_data(clp->cls_conn, m);
559         if (err) {
560                 KB_FREEALL(m);
561                 return (1);
562         }
563
564         return (0);
565 }
566
567
568 /*
569  * Process a SPANS ARP input packet
570  * 
571  * Arguments:
572  *      clp     pointer to interface CLS control block
573  *      m       pointer to input packet buffer chain
574  *
575  * Returns:
576  *      none
577  *
578  */
579 void
580 spansarp_input(clp, m)
581         struct spanscls *clp;
582         KBuffer         *m;
583 {
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;
590         int             s, err;
591
592         /*
593          * Make sure IP interface has been activated
594          */
595         if (inp == NULL)
596                 goto free;
597
598         /*
599          * Get the packet together
600          */
601         if (KB_LEN(m) < ARP_PACKET_LEN) {
602                 KB_PULLUP(m, ARP_PACKET_LEN, m);
603                 if (m == 0)
604                         return;
605         }
606         KB_DATASTART(m, chp, struct spanscls_hdr *);
607         ahp = (struct spansarp_hdr *)(chp + 1);
608
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));
613
614         /*
615          * Initial packet verification
616          */
617         if ((ahp->ah_hrd != htons(ARP_SPANS)) ||
618             (ahp->ah_pro != htons(ETHERTYPE_IP)))
619                 goto free;
620
621         /*
622          * Validate source addresses
623          *      can't be from hardware broadcast
624          *      can't be from me
625          */
626         if (!spans_addr_cmp(&ahp->ah_sha, &spans_bcastaddr))
627                 goto free;
628         if (!spans_addr_cmp(&ahp->ah_sha, spp->sp_addr.address))
629                 goto free;
630         if (in_src.s_addr == in_me.s_addr) {
631                 log(LOG_ERR, 
632                         "duplicate IP address sent from spans address %s\n",
633                         spans_addr_print(&ahp->ah_sha));
634                 in_targ = in_me;
635                 goto chkop;
636         }
637
638         /*
639          * If source IP address is from unspecified or broadcast addresses,
640          * don't bother updating arp table, but answer possible requests
641          */
642 #if (defined(BSD) && (BSD >= 199306))
643         if (in_broadcast(in_src, &inp->inf_nif->nif_if))
644 #else
645         if (in_broadcast(in_src))
646 #endif
647                 goto chkop;
648
649         /*
650          * Update arp table with source address info
651          */
652         s = splnet();
653         SPANSARP_LOOKUP(in_src.s_addr, sap);
654         if (sap) {
655                 /*
656                  * Found an entry for the source, but don't
657                  * update permanent entries
658                  */
659                 if (sap->sa_origin != SAO_PERM) {
660
661                         /*
662                          * Update the entry
663                          */
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);
667                         sap->sa_cls = clp;
668                         sap->sa_reftime = 0;
669                         if ((sap->sa_flags & SAF_VALID) == 0) {
670                                 /*
671                                  * Newly valid entry, notify waiting users
672                                  */
673                                 struct ipvcc    *ivp, *inext;
674
675                                 sap->sa_flags |= SAF_VALID;
676                                 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
677                                         inext = ivp->iv_arpnext;
678
679                                         ivp->iv_arpent = (struct arpmap *)sap;
680                                         (*inp->inf_arpnotify)(ivp, MAP_VALID);
681                                 }
682
683                                 /*
684                                  * Remove ourselves from the retry chain
685                                  */
686                                 UNLINK(sap, struct spansarp,
687                                         spansarp_retry_head, sa_rnext);
688                         }
689                 }
690
691         } else if (in_targ.s_addr == in_me.s_addr) {
692                 /*
693                  * Source unknown and we're the target - add new entry
694                  */
695                 sap = (struct spansarp *)atm_allocate(&spansarp_pool);
696                 if (sap) {
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;
703                         sap->sa_cls = clp;
704                         sap->sa_flags = SAF_VALID;
705                         sap->sa_origin = SAO_LOOKUP;
706                         SPANSARP_ADD(sap);
707                 }
708         }
709         (void) splx(s);
710
711 chkop:
712         /*
713          * If this is a request for our address, send a reply 
714          */
715         if (ntohs(ahp->ah_op) != ARP_REQUEST)
716                 goto free;
717         if (in_targ.s_addr != in_me.s_addr)
718                 goto free;
719
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));
727
728         err = atm_cm_cpcs_data(clp->cls_conn, m);
729         if (err)
730                 goto free;
731         return;
732
733 free:
734         KB_FREEALL(m);
735 }
736
737
738 /*
739  * Process a SPANS ARP aging timer tick
740  * 
741  * This function is called every SPANSARP_AGING seconds, in order to age
742  * all the arp table entries.
743  *
744  * Called at splnet.
745  *
746  * Arguments:
747  *      tip     pointer to spansarp aging timer control block
748  *
749  * Returns:
750  *      none
751  *
752  */
753 static void
754 spansarp_aging(tip)
755         struct atm_time *tip;
756 {
757         struct spansarp *sap, *snext;
758         struct ipvcc    *ivp, *inext;
759         int             i;
760
761
762         /*
763          * Schedule next timeout
764          */
765         atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
766
767         /*
768          * Run through arp table bumping each entry's aging timer.
769          */
770         for (i = 0; i < SPANSARP_HASHSIZ; i++) {
771                 for (sap = spansarp_arptab[i]; sap; sap = snext) {
772                         snext = sap->sa_next;
773
774                         /*
775                          * Permanent (manually installed) entries aren't aged
776                          */
777                         if (sap->sa_origin == SAO_PERM)
778                                 continue;
779
780                         /*
781                          * See if entry is valid and over-aged
782                          */
783                         if ((sap->sa_flags & SAF_VALID) == 0)
784                                 continue;
785                         if (++sap->sa_reftime < SPANSARP_MAXAGE)
786                                 continue;
787
788                         /*
789                          * Entry is now invalid, tell IP/ATM about it
790                          */
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)
795                                                 (ivp, MAP_INVALID);
796                         }
797                         sap->sa_flags &= ~(SAF_LOCKED | SAF_VALID);
798
799                         if (sap->sa_ivp != NULL) {
800                                 /*
801                                  * Somebody still cares, so add the arp
802                                  * entry to the retry list.
803                                  */
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);
809
810                                 /*
811                                  * Issue arp request for this address
812                                  */
813                                 (void) spansarp_request(sap);
814
815                         } else {
816                                 /*
817                                  * Delete unused entry
818                                  */
819                                 SPANSARP_DELETE(sap);
820                                 atm_free((caddr_t)sap);
821                         }
822                 }
823         }
824 }
825
826
827 /*
828  * Process a SPANS ARP retry timer tick
829  * 
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.
834  *
835  * Called at splnet.
836  *
837  * Arguments:
838  *      tip     pointer to spansarp retry timer control block
839  *
840  * Returns:
841  *      none
842  *
843  */
844 static void
845 spansarp_retry(tip)
846         struct atm_time *tip;
847 {
848         struct spansarp *sap;
849
850
851         /*
852          * See if there's work to do
853          */
854         if (spansarp_retry_head == NULL) {
855                 return;
856         }
857
858         /*
859          * Schedule next timeout
860          */
861         atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
862
863         /*
864          * Run through retry chain, (re)issuing arp requests.
865          */
866         for (sap = spansarp_retry_head; sap; sap = sap->sa_next) {
867
868                 /*
869                  * Send another arp request
870                  */
871                 (void) spansarp_request(sap);
872         }
873 }
874
875
876 /*
877  * SPANS ARP IOCTL support
878  *
879  * Function will be called at splnet.
880  *
881  * Arguments:
882  *      code    PF_ATM sub-operation code
883  *      data    pointer to code specific parameter data area
884  *      arg1    pointer to code specific argument
885  *
886  * Returns:
887  *      0       request procesed
888  *      errno   error processing request - reason indicated
889  *
890  */
891 int
892 spansarp_ioctl(code, data, arg1)
893         int             code;
894         caddr_t         data;
895         caddr_t         arg1;
896 {
897         struct atmaddreq        *aap;
898         struct atmdelreq        *adp;
899         struct atminfreq        *aip;
900         struct spans            *spp;
901         struct spanscls         *clp;
902         struct spansarp         *sap;
903         struct air_arp_rsp      aar;
904         struct ip_nif           *inp;
905         struct ipvcc            *ivp, *inext;
906         struct in_addr          ip;
907         u_long                  dst;
908         int                     err = 0, i, buf_len;
909         caddr_t                 buf_addr;
910
911
912         switch (code) {
913
914         case AIOCS_ADD_ARP:
915                 /*
916                  * Add a permanent ARP mapping
917                  */
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)) {
923                         err = EINVAL;
924                         break;
925                 }
926                 ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
927
928                 /*
929                  * See if we already have an entry for this IP address
930                  */
931                 SPANSARP_LOOKUP(ip.s_addr, sap);
932                 if (sap == NULL) {
933                         /*
934                          * No, get a new arp entry
935                          */
936                         sap = (struct spansarp *)atm_allocate(&spansarp_pool);
937                         if (sap == NULL) {
938                                 err = ENOMEM;
939                                 break;
940                         }
941
942                         /*
943                          * Get entry set up
944                          */
945                         sap->sa_dstip = ip;
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;
949                         sap->sa_cls = clp;
950                         sap->sa_flags |= SAF_VALID;
951                         sap->sa_origin = SAO_PERM;
952
953                         /*
954                          * Add entry to table
955                          */
956                         SPANSARP_ADD(sap);
957                         break;
958
959                 }
960
961                 /*
962                  * See if we're attempting to change the ATM address for
963                  * this cached entry
964                  */
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))) {
968
969                         /*
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.
973                          */
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);
978                         }
979                         sap->sa_flags &= ~SAF_LOCKED;
980                 }
981
982                 /*
983                  * Update the cached entry with the new data
984                  */
985                 ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
986                 sap->sa_cls = clp;
987
988                 /*
989                  * If this entry isn't valid, notify anyone who might
990                  * be interested
991                  */
992                 if ((sap->sa_flags & SAF_VALID) == 0) {
993
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);
998                         }
999                         sap->sa_flags &= ~SAF_LOCKED;
1000                 }
1001
1002                 /*
1003                  * Remove this entry from the retry chain
1004                  */
1005                 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
1006
1007                 /*
1008                  * Mark the entry as permanent
1009                  */
1010                 sap->sa_flags |= SAF_VALID;
1011                 sap->sa_origin = SAO_PERM;
1012                 break;
1013
1014         case AIOCS_DEL_ARP:
1015                 /*
1016                  * Delete an ARP mapping
1017                  */
1018                 adp = (struct atmdelreq *)data;
1019                 clp = (struct spanscls *)arg1;
1020                 ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
1021
1022                 /*
1023                  * Now find the entry to be deleted
1024                  */
1025                 SPANSARP_LOOKUP(ip.s_addr, sap);
1026                 if (sap == NULL) {
1027                         err = ENOENT;
1028                         break;
1029                 }
1030
1031                 /*
1032                  * Notify all VCCs using this entry that they must finish
1033                  * up now.  
1034                  */
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);
1039                 }
1040
1041                 /*
1042                  * Now free up the entry
1043                  */
1044                 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
1045                 SPANSARP_DELETE(sap);
1046                 atm_free((caddr_t)sap);
1047                 break;
1048
1049         case AIOCS_INF_ARP:
1050                 /*
1051                  * Get ARP table information
1052                  */
1053                 aip = (struct atminfreq *)data;
1054                 spp = (struct spans *)arg1;
1055
1056                 if (aip->air_arp_addr.sa_family != AF_INET)
1057                         break;
1058                 dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr;
1059
1060                 buf_addr = aip->air_buf_addr;
1061                 buf_len = aip->air_buf_len;
1062
1063                 if ((clp = spp->sp_cls) == NULL)
1064                         break;
1065
1066                 /*
1067                  * Run through entire arp table
1068                  */
1069                 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
1070                         for (sap = spansarp_arptab[i]; sap;
1071                                                 sap = sap->sa_next) {
1072                                 /*
1073                                  * We only want entries learned
1074                                  * from the supplied interface.
1075                                  */
1076                                 if (sap->sa_cls != clp)
1077                                         continue;
1078                                 if ((dst != INADDR_ANY) &&
1079                                     (dst != sap->sa_dstip.s_addr))
1080                                         continue;
1081
1082                                 /*
1083                                  * Make sure there's room in the user's buffer
1084                                  */
1085                                 if (buf_len < sizeof(aar)) {
1086                                         err = ENOSPC;
1087                                         break;
1088                                 }
1089
1090                                 /*
1091                                  * Fill in info to be returned
1092                                  */
1093                                 SATOSIN(&aar.aap_arp_addr)->sin_family =
1094                                         AF_INET;
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
1101                                         );
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 - 
1106                                                         sap->sa_reftime;
1107                                 else
1108                                         aar.aap_age = 0;
1109                                 ATM_ADDR_COPY(&sap->sa_dstatm, &aar.aap_addr);
1110                                 ATM_ADDR_COPY(&sap->sa_dstatmsub,
1111                                         &aar.aap_subaddr);
1112
1113                                 /*
1114                                  * Copy the response into the user's buffer
1115                                  */
1116                                 if ((err = copyout((caddr_t)&aar, buf_addr, 
1117                                                         sizeof(aar))) != 0)
1118                                         break;
1119                                 buf_addr += sizeof(aar);
1120                                 buf_len -= sizeof(aar);
1121                         }
1122                         if (err)
1123                                 break;
1124                 }
1125
1126                 /*
1127                  * Update the buffer pointer and length
1128                  */
1129                 aip->air_buf_addr = buf_addr;
1130                 aip->air_buf_len = buf_len;
1131                 break;
1132
1133         case AIOCS_INF_ASV:
1134                 /*
1135                  * Get ARP server information
1136                  */
1137                 /* SPANS doesn't have an ARP server */
1138                 break;
1139
1140         default:
1141                 err = EOPNOTSUPP;
1142         }
1143
1144         return (err);
1145 }
1146