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