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