Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:28:49 dillon Exp $
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 /*
47  * Global variables
48  */
49 struct spansarp         *spansarp_arptab[SPANSARP_HASHSIZ] = {NULL};
50
51
52 /*
53  * Local functions
54  */
55 static int              spansarp_request __P((struct spansarp *));
56 static void             spansarp_aging __P((struct atm_time *));
57 static void             spansarp_retry __P((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 (defined(BSD) && (BSD >= 199306))
638         if (in_broadcast(in_src, &inp->inf_nif->nif_if))
639 #else
640         if (in_broadcast(in_src))
641 #endif
642                 goto chkop;
643
644         /*
645          * Update arp table with source address info
646          */
647         s = splnet();
648         SPANSARP_LOOKUP(in_src.s_addr, sap);
649         if (sap) {
650                 /*
651                  * Found an entry for the source, but don't
652                  * update permanent entries
653                  */
654                 if (sap->sa_origin != SAO_PERM) {
655
656                         /*
657                          * Update the entry
658                          */
659                         sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
660                         sap->sa_dstatm.address_length = sizeof(spans_addr);
661                         spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
662                         sap->sa_cls = clp;
663                         sap->sa_reftime = 0;
664                         if ((sap->sa_flags & SAF_VALID) == 0) {
665                                 /*
666                                  * Newly valid entry, notify waiting users
667                                  */
668                                 struct ipvcc    *ivp, *inext;
669
670                                 sap->sa_flags |= SAF_VALID;
671                                 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
672                                         inext = ivp->iv_arpnext;
673
674                                         ivp->iv_arpent = (struct arpmap *)sap;
675                                         (*inp->inf_arpnotify)(ivp, MAP_VALID);
676                                 }
677
678                                 /*
679                                  * Remove ourselves from the retry chain
680                                  */
681                                 UNLINK(sap, struct spansarp,
682                                         spansarp_retry_head, sa_rnext);
683                         }
684                 }
685
686         } else if (in_targ.s_addr == in_me.s_addr) {
687                 /*
688                  * Source unknown and we're the target - add new entry
689                  */
690                 sap = (struct spansarp *)atm_allocate(&spansarp_pool);
691                 if (sap) {
692                         sap->sa_dstip.s_addr = in_src.s_addr;
693                         sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
694                         sap->sa_dstatm.address_length = sizeof(spans_addr);
695                         spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
696                         sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
697                         sap->sa_dstatmsub.address_length = 0;
698                         sap->sa_cls = clp;
699                         sap->sa_flags = SAF_VALID;
700                         sap->sa_origin = SAO_LOOKUP;
701                         SPANSARP_ADD(sap);
702                 }
703         }
704         (void) splx(s);
705
706 chkop:
707         /*
708          * If this is a request for our address, send a reply 
709          */
710         if (ntohs(ahp->ah_op) != ARP_REQUEST)
711                 goto free;
712         if (in_targ.s_addr != in_me.s_addr)
713                 goto free;
714
715         spans_addr_copy(&chp->ch_src, &chp->ch_dst);
716         spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
717         ahp->ah_op = htons(ARP_REPLY);
718         spans_addr_copy(&ahp->ah_sha, &ahp->ah_tha);
719         spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
720         KM_COPY(ahp->ah_spa, ahp->ah_tpa, sizeof(struct in_addr));
721         KM_COPY(&in_me, ahp->ah_spa, sizeof(struct in_addr));
722
723         err = atm_cm_cpcs_data(clp->cls_conn, m);
724         if (err)
725                 goto free;
726         return;
727
728 free:
729         KB_FREEALL(m);
730 }
731
732
733 /*
734  * Process a SPANS ARP aging timer tick
735  * 
736  * This function is called every SPANSARP_AGING seconds, in order to age
737  * all the arp table entries.
738  *
739  * Called at splnet.
740  *
741  * Arguments:
742  *      tip     pointer to spansarp aging timer control block
743  *
744  * Returns:
745  *      none
746  *
747  */
748 static void
749 spansarp_aging(tip)
750         struct atm_time *tip;
751 {
752         struct spansarp *sap, *snext;
753         struct ipvcc    *ivp, *inext;
754         int             i;
755
756
757         /*
758          * Schedule next timeout
759          */
760         atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
761
762         /*
763          * Run through arp table bumping each entry's aging timer.
764          */
765         for (i = 0; i < SPANSARP_HASHSIZ; i++) {
766                 for (sap = spansarp_arptab[i]; sap; sap = snext) {
767                         snext = sap->sa_next;
768
769                         /*
770                          * Permanent (manually installed) entries aren't aged
771                          */
772                         if (sap->sa_origin == SAO_PERM)
773                                 continue;
774
775                         /*
776                          * See if entry is valid and over-aged
777                          */
778                         if ((sap->sa_flags & SAF_VALID) == 0)
779                                 continue;
780                         if (++sap->sa_reftime < SPANSARP_MAXAGE)
781                                 continue;
782
783                         /*
784                          * Entry is now invalid, tell IP/ATM about it
785                          */
786                         sap->sa_flags |= SAF_LOCKED;
787                         for (ivp = sap->sa_ivp; ivp; ivp = inext) {
788                                 inext = ivp->iv_arpnext;
789                                 (*ivp->iv_ipnif->inf_arpnotify)
790                                                 (ivp, MAP_INVALID);
791                         }
792                         sap->sa_flags &= ~(SAF_LOCKED | SAF_VALID);
793
794                         if (sap->sa_ivp != NULL) {
795                                 /*
796                                  * Somebody still cares, so add the arp
797                                  * entry to the retry list.
798                                  */
799                                 LINK2TAIL(sap, struct spansarp,
800                                                 spansarp_retry_head, sa_rnext);
801                                 if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
802                                         atm_timeout(&spansarp_rtimer,
803                                                 SPANSARP_RETRY, spansarp_retry);
804
805                                 /*
806                                  * Issue arp request for this address
807                                  */
808                                 (void) spansarp_request(sap);
809
810                         } else {
811                                 /*
812                                  * Delete unused entry
813                                  */
814                                 SPANSARP_DELETE(sap);
815                                 atm_free((caddr_t)sap);
816                         }
817                 }
818         }
819 }
820
821
822 /*
823  * Process a SPANS ARP retry timer tick
824  * 
825  * This function is called every SPANSARP_RETRY seconds, in order to retry
826  * awaiting arp resolution requests.  We will retry requests indefinitely,
827  * assuming that IP will set a timeout to close the VCC(s) requesting the
828  * failing address resolution.
829  *
830  * Called at splnet.
831  *
832  * Arguments:
833  *      tip     pointer to spansarp retry timer control block
834  *
835  * Returns:
836  *      none
837  *
838  */
839 static void
840 spansarp_retry(tip)
841         struct atm_time *tip;
842 {
843         struct spansarp *sap;
844
845
846         /*
847          * See if there's work to do
848          */
849         if (spansarp_retry_head == NULL) {
850                 return;
851         }
852
853         /*
854          * Schedule next timeout
855          */
856         atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
857
858         /*
859          * Run through retry chain, (re)issuing arp requests.
860          */
861         for (sap = spansarp_retry_head; sap; sap = sap->sa_next) {
862
863                 /*
864                  * Send another arp request
865                  */
866                 (void) spansarp_request(sap);
867         }
868 }
869
870
871 /*
872  * SPANS ARP IOCTL support
873  *
874  * Function will be called at splnet.
875  *
876  * Arguments:
877  *      code    PF_ATM sub-operation code
878  *      data    pointer to code specific parameter data area
879  *      arg1    pointer to code specific argument
880  *
881  * Returns:
882  *      0       request procesed
883  *      errno   error processing request - reason indicated
884  *
885  */
886 int
887 spansarp_ioctl(code, data, arg1)
888         int             code;
889         caddr_t         data;
890         caddr_t         arg1;
891 {
892         struct atmaddreq        *aap;
893         struct atmdelreq        *adp;
894         struct atminfreq        *aip;
895         struct spans            *spp;
896         struct spanscls         *clp;
897         struct spansarp         *sap;
898         struct air_arp_rsp      aar;
899         struct ip_nif           *inp;
900         struct ipvcc            *ivp, *inext;
901         struct in_addr          ip;
902         u_long                  dst;
903         int                     err = 0, i, buf_len;
904         caddr_t                 buf_addr;
905
906
907         switch (code) {
908
909         case AIOCS_ADD_ARP:
910                 /*
911                  * Add a permanent ARP mapping
912                  */
913                 aap = (struct atmaddreq *)data;
914                 clp = (struct spanscls *)arg1;
915                 inp = clp->cls_ipnif;
916                 if ((aap->aar_arp_addr.address_format != T_ATM_SPANS_ADDR) ||
917                     (aap->aar_arp_origin != ARP_ORIG_PERM)) {
918                         err = EINVAL;
919                         break;
920                 }
921                 ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
922
923                 /*
924                  * See if we already have an entry for this IP address
925                  */
926                 SPANSARP_LOOKUP(ip.s_addr, sap);
927                 if (sap == NULL) {
928                         /*
929                          * No, get a new arp entry
930                          */
931                         sap = (struct spansarp *)atm_allocate(&spansarp_pool);
932                         if (sap == NULL) {
933                                 err = ENOMEM;
934                                 break;
935                         }
936
937                         /*
938                          * Get entry set up
939                          */
940                         sap->sa_dstip = ip;
941                         ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
942                         sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
943                         sap->sa_dstatmsub.address_length = 0;
944                         sap->sa_cls = clp;
945                         sap->sa_flags |= SAF_VALID;
946                         sap->sa_origin = SAO_PERM;
947
948                         /*
949                          * Add entry to table
950                          */
951                         SPANSARP_ADD(sap);
952                         break;
953
954                 }
955
956                 /*
957                  * See if we're attempting to change the ATM address for
958                  * this cached entry
959                  */
960                 if ((sap->sa_dstatm.address_format != T_ATM_ABSENT) &&
961                     (!ATM_ADDR_EQUAL(&aap->aar_arp_addr, &sap->sa_dstatm) ||
962                      (clp != sap->sa_cls))) {
963
964                         /*
965                          * Yes, notify IP/ATM that a mapping change has
966                          * occurred.  IP/ATM will close any VCC's which
967                          * aren't waiting for this map.
968                          */
969                         sap->sa_flags |= SAF_LOCKED;
970                         for (ivp = sap->sa_ivp; ivp; ivp = inext) {
971                                 inext = ivp->iv_arpnext;
972                                 (*inp->inf_arpnotify)(ivp, MAP_CHANGED);
973                         }
974                         sap->sa_flags &= ~SAF_LOCKED;
975                 }
976
977                 /*
978                  * Update the cached entry with the new data
979                  */
980                 ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
981                 sap->sa_cls = clp;
982
983                 /*
984                  * If this entry isn't valid, notify anyone who might
985                  * be interested
986                  */
987                 if ((sap->sa_flags & SAF_VALID) == 0) {
988
989                         sap->sa_flags |= SAF_LOCKED;
990                         for (ivp = sap->sa_ivp; ivp; ivp = inext) {
991                                 inext = ivp->iv_arpnext;
992                                 (*inp->inf_arpnotify)(ivp, MAP_VALID);
993                         }
994                         sap->sa_flags &= ~SAF_LOCKED;
995                 }
996
997                 /*
998                  * Remove this entry from the retry chain
999                  */
1000                 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
1001
1002                 /*
1003                  * Mark the entry as permanent
1004                  */
1005                 sap->sa_flags |= SAF_VALID;
1006                 sap->sa_origin = SAO_PERM;
1007                 break;
1008
1009         case AIOCS_DEL_ARP:
1010                 /*
1011                  * Delete an ARP mapping
1012                  */
1013                 adp = (struct atmdelreq *)data;
1014                 clp = (struct spanscls *)arg1;
1015                 ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
1016
1017                 /*
1018                  * Now find the entry to be deleted
1019                  */
1020                 SPANSARP_LOOKUP(ip.s_addr, sap);
1021                 if (sap == NULL) {
1022                         err = ENOENT;
1023                         break;
1024                 }
1025
1026                 /*
1027                  * Notify all VCCs using this entry that they must finish
1028                  * up now.  
1029                  */
1030                 sap->sa_flags |= SAF_LOCKED;
1031                 for (ivp = sap->sa_ivp; ivp; ivp = inext) {
1032                         inext = ivp->iv_arpnext;
1033                         (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
1034                 }
1035
1036                 /*
1037                  * Now free up the entry
1038                  */
1039                 UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
1040                 SPANSARP_DELETE(sap);
1041                 atm_free((caddr_t)sap);
1042                 break;
1043
1044         case AIOCS_INF_ARP:
1045                 /*
1046                  * Get ARP table information
1047                  */
1048                 aip = (struct atminfreq *)data;
1049                 spp = (struct spans *)arg1;
1050
1051                 if (aip->air_arp_addr.sa_family != AF_INET)
1052                         break;
1053                 dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr;
1054
1055                 buf_addr = aip->air_buf_addr;
1056                 buf_len = aip->air_buf_len;
1057
1058                 if ((clp = spp->sp_cls) == NULL)
1059                         break;
1060
1061                 /*
1062                  * Run through entire arp table
1063                  */
1064                 for (i = 0; i < SPANSARP_HASHSIZ; i++) {
1065                         for (sap = spansarp_arptab[i]; sap;
1066                                                 sap = sap->sa_next) {
1067                                 /*
1068                                  * We only want entries learned
1069                                  * from the supplied interface.
1070                                  */
1071                                 if (sap->sa_cls != clp)
1072                                         continue;
1073                                 if ((dst != INADDR_ANY) &&
1074                                     (dst != sap->sa_dstip.s_addr))
1075                                         continue;
1076
1077                                 /*
1078                                  * Make sure there's room in the user's buffer
1079                                  */
1080                                 if (buf_len < sizeof(aar)) {
1081                                         err = ENOSPC;
1082                                         break;
1083                                 }
1084
1085                                 /*
1086                                  * Fill in info to be returned
1087                                  */
1088                                 SATOSIN(&aar.aap_arp_addr)->sin_family =
1089                                         AF_INET;
1090                                 SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr =
1091                                         sap->sa_dstip.s_addr;
1092                                 (void) snprintf(aar.aap_intf,
1093                                     sizeof(aar.aap_intf), "%s%d",
1094                                         clp->cls_ipnif->inf_nif->nif_if.if_name,
1095                                         clp->cls_ipnif->inf_nif->nif_if.if_unit
1096                                         );
1097                                 aar.aap_flags = sap->sa_flags;
1098                                 aar.aap_origin = sap->sa_origin;
1099                                 if (sap->sa_flags & SAF_VALID)
1100                                         aar.aap_age = SPANSARP_MAXAGE - 
1101                                                         sap->sa_reftime;
1102                                 else
1103                                         aar.aap_age = 0;
1104                                 ATM_ADDR_COPY(&sap->sa_dstatm, &aar.aap_addr);
1105                                 ATM_ADDR_COPY(&sap->sa_dstatmsub,
1106                                         &aar.aap_subaddr);
1107
1108                                 /*
1109                                  * Copy the response into the user's buffer
1110                                  */
1111                                 if ((err = copyout((caddr_t)&aar, buf_addr, 
1112                                                         sizeof(aar))) != 0)
1113                                         break;
1114                                 buf_addr += sizeof(aar);
1115                                 buf_len -= sizeof(aar);
1116                         }
1117                         if (err)
1118                                 break;
1119                 }
1120
1121                 /*
1122                  * Update the buffer pointer and length
1123                  */
1124                 aip->air_buf_addr = buf_addr;
1125                 aip->air_buf_len = buf_len;
1126                 break;
1127
1128         case AIOCS_INF_ASV:
1129                 /*
1130                  * Get ARP server information
1131                  */
1132                 /* SPANS doesn't have an ARP server */
1133                 break;
1134
1135         default:
1136                 err = EOPNOTSUPP;
1137         }
1138
1139         return (err);
1140 }
1141