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