Clean (void) casts from usr.sbin
[dragonfly.git] / usr.sbin / atm / atmarpd / atmarp_subr.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/usr.sbin/atm/atmarpd/atmarp_subr.c,v 1.3 1999/08/28 01:15:30 peter Exp $
27  *      @(#) $DragonFly: src/usr.sbin/atm/atmarpd/atmarp_subr.c,v 1.4 2004/12/18 22:48:02 swildner Exp $
28  */
29
30
31 /*
32  * Server Cache Synchronization Protocol (SCSP) Support
33  * ----------------------------------------------------
34  *
35  * SCSP-ATMARP server interface: misc. subroutines
36  *
37  */
38
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <net/if.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <netatm/port.h>
47 #include <netatm/queue.h>
48 #include <netatm/atm.h>
49 #include <netatm/atm_if.h>
50 #include <netatm/atm_sap.h>
51 #include <netatm/atm_sigmgr.h>
52 #include <netatm/atm_sys.h>
53 #include <netatm/atm_ioctl.h>
54 #include <netatm/uni/unisig_var.h>
55 #include <netatm/uni/uniip_var.h>
56  
57 #include <errno.h>
58 #include <libatm.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <syslog.h>
63 #include <unistd.h>
64
65 #include "../scspd/scsp_msg.h"
66 #include "../scspd/scsp_if.h"
67 #include "../scspd/scsp_var.h"
68 #include "atmarp_var.h"
69
70 /*
71  * Find an ATMARP interface, given its socket number
72  *
73  * Arguments:
74  *      sd      socket descriptor
75  *
76  * Returns:
77  *      0       failure
78  *      else    pointer to interface associated with socket
79  *
80  */
81 Atmarp_intf *
82 atmarp_find_intf_sock(int sd)
83 {
84         Atmarp_intf     *aip;
85
86         /*
87          * Loop through the list of interfaces
88          */
89         for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
90                 if (aip->ai_scsp_sock == sd)
91                         break;
92         }
93
94         return(aip);
95 }
96
97
98 /*
99  * Find an ATMARP interface, given its name
100  *
101  * Arguments:
102  *      name    pointer to network interface name
103  *
104  * Returns:
105  *      0       failure
106  *      else    pointer to interface associated with name
107  *
108  */
109 Atmarp_intf *
110 atmarp_find_intf_name(char *name)
111 {
112         Atmarp_intf     *aip;
113
114         /*
115          * Loop through the list of interfaces
116          */
117         for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
118                 if (strcmp(name, aip->ai_intf) == 0)
119                         break;
120         }
121
122         return(aip);
123 }
124
125
126 /*
127  * Clear the mark field on all ATMARP cache entries
128  *
129  * Arguments:
130  *      none
131  *
132  * Returns:
133  *      none
134  *
135  */
136 void
137 atmarp_clear_marks(void)
138 {
139         int             i;
140         Atmarp_intf     *aip;
141         Atmarp          *aap;
142
143         /*
144          * Loop through list of interfaces
145          */
146         for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
147                 /*
148                  * Clear mark on every entry in the interface's cache
149                  */
150                 for (i = 0; i < ATMARP_HASHSIZ; i++ ) {
151                         for (aap = aip->ai_arptbl[i]; aap;
152                                         aap = aap->aa_next) {
153                                 aap->aa_mark = 0;
154                         }
155                 }
156         }
157 }
158
159
160 /*
161  * Check whether the host system is an ATMARP server for
162  * the LIS associated with a given interface
163  *
164  * Arguments:
165  *      aip     pointer to an ATMARP interface control block
166  *
167  * Returns:
168  *      1       host is a server
169  *      0       host is not a server
170  *
171  */
172 int
173 atmarp_is_server(Atmarp_intf *aip)
174 {
175         int                     rc;
176         int                     buf_len = sizeof(struct air_asrv_rsp);
177         struct atminfreq        air;
178         struct air_asrv_rsp     *asrv_info;
179
180         /*
181          * Get interface information from the kernel
182          */
183         strcpy(air.air_int_intf, aip->ai_intf);
184         air.air_opcode = AIOCS_INF_ASV;
185         buf_len = do_info_ioctl(&air, buf_len);
186         if (buf_len < 0)
187                 return(0);
188
189         /*
190          * Check the interface's ATMARP server address
191          */
192         asrv_info = (struct air_asrv_rsp *) air.air_buf_addr;
193         rc = (asrv_info->asp_addr.address_format == T_ATM_ABSENT) &&
194                         (asrv_info->asp_subaddr.address_format ==
195                                 T_ATM_ABSENT);
196         UM_FREE(asrv_info);
197         return(rc);
198 }
199
200
201 /*
202  * Check whether an interface is up and ready for service
203  *
204  * Arguments:
205  *      aip     pointer to network interface block
206  *
207  * Returns:
208  *      0       interface not ready, errno has reason
209  *      1       interface is ready to go (interface block is updated)
210  *
211  */
212 int
213 atmarp_if_ready(Atmarp_intf *aip)
214 {
215         int                     i, len, mtu, rc, sel;
216         Atmarp                  *aap = (Atmarp *)0;
217         struct atminfreq        air;
218         struct air_netif_rsp    *netif_rsp = (struct air_netif_rsp *)0;
219         struct air_int_rsp      *intf_rsp = (struct air_int_rsp *)0;
220         struct sockaddr_in      *ip_addr;
221         struct sockaddr_in      subnet_mask;
222         Atm_addr_nsap           *anp;
223
224         /*
225          * Get the IP address and physical interface name
226          * associated with the network interface
227          */
228         UM_ZERO(&air, sizeof(struct atminfreq));
229         air.air_opcode = AIOCS_INF_NIF;
230         strcpy(air.air_netif_intf, aip->ai_intf);
231         len = do_info_ioctl(&air, sizeof(struct air_netif_rsp));
232         if (len <= 0) {
233                 goto if_ready_fail;
234         }
235         netif_rsp = (struct air_netif_rsp *)air.air_buf_addr;
236
237         ip_addr = (struct sockaddr_in *)&netif_rsp->anp_proto_addr;
238         if (ip_addr->sin_family != AF_INET ||
239                         ip_addr->sin_addr.s_addr == 0) {
240                 errno = EAFNOSUPPORT;
241                 goto if_ready_fail;
242         }
243
244         /*
245          * Get the MTU for the network interface
246          */
247         mtu = get_mtu(aip->ai_intf);
248         if (mtu < 0) {
249                 goto if_ready_fail;
250         }
251
252
253         /*
254          * Get the subnet mask associated with the
255          * network interface
256          */
257         rc = get_subnet_mask(aip->ai_intf, &subnet_mask);
258         if (rc || subnet_mask.sin_family != AF_INET) {
259                 goto if_ready_fail;
260         }
261
262         /*
263          * Get physical interface information
264          */
265         UM_ZERO(&air, sizeof(struct atminfreq));
266         air.air_opcode = AIOCS_INF_INT;
267         strcpy(air.air_int_intf, netif_rsp->anp_phy_intf);
268         len = do_info_ioctl(&air, sizeof(struct air_int_rsp));
269         if (len <= 0) {
270                 goto if_ready_fail;
271         }
272         intf_rsp = (struct air_int_rsp *)air.air_buf_addr;
273
274         /*
275          * Check the signalling manager
276          */
277         if (intf_rsp->anp_sig_proto != ATM_SIG_UNI30 &&
278                         intf_rsp->anp_sig_proto != ATM_SIG_UNI31 &&
279                         intf_rsp->anp_sig_proto != ATM_SIG_UNI40) {
280                 errno = EINVAL;
281                 goto if_ready_fail;
282         }
283
284         /*
285          * Check the interface state
286          */
287         if (intf_rsp->anp_sig_state != UNISIG_ACTIVE) {
288                 errno = EINVAL;
289                 goto if_ready_fail;
290         }
291
292         /*
293          * Check the address format
294          */
295         if (intf_rsp->anp_addr.address_format != T_ATM_ENDSYS_ADDR &&
296                         !(intf_rsp->anp_addr.address_format ==
297                                 T_ATM_E164_ADDR &&
298                         intf_rsp->anp_subaddr.address_format ==
299                                 T_ATM_ENDSYS_ADDR)) {
300                 errno = EINVAL;
301                 goto if_ready_fail;
302         }
303
304         /*
305          * Find the selector byte value for the interface
306          */
307         for (i=0; i<strlen(aip->ai_intf); i++) {
308                 if (aip->ai_intf[i] >= '0' &&
309                                 aip->ai_intf[i] <= '9')
310                         break;
311         }
312         sel = atoi(&aip->ai_intf[i]);
313
314         /*
315          * Make sure we're the server for this interface's LIS
316          */
317         if (!atmarp_is_server(aip)) {
318                 rc = EINVAL;
319                 goto if_ready_fail;
320         }
321
322         /*
323          * If we already have the interface active and the address
324          * hasn't changed, return
325          */
326         if (aip->ai_state != AI_STATE_NULL &&
327                         bcmp((caddr_t) &((struct sockaddr_in *)
328                                 &netif_rsp->anp_proto_addr)->sin_addr,
329                                 (caddr_t)&aip->ai_ip_addr,
330                                 sizeof(aip->ai_ip_addr)) == 0 &&
331                         ATM_ADDR_EQUAL(&intf_rsp->anp_addr,
332                                 &aip->ai_atm_addr) &&
333                         ATM_ADDR_EQUAL(&intf_rsp->anp_subaddr,
334                                 &aip->ai_atm_subaddr)) {
335                 return(1);
336         }
337
338         /*
339          * Delete any existing ATMARP cache entry for this interface
340          */
341         ATMARP_LOOKUP(aip, aip->ai_ip_addr.s_addr, aap);
342         if (aap) {
343                 ATMARP_DELETE(aip, aap);
344                 UM_FREE(aap);
345         }
346
347         /*
348          * Update the interface entry
349          */
350         aip->ai_ip_addr = ((struct sockaddr_in *)
351                         &netif_rsp->anp_proto_addr)->sin_addr;
352         aip->ai_subnet_mask = subnet_mask.sin_addr;
353         aip->ai_mtu = mtu + 8;
354         ATM_ADDR_COPY(&intf_rsp->anp_addr,
355                         &aip->ai_atm_addr);
356         ATM_ADDR_COPY(&intf_rsp->anp_subaddr,
357                         &aip->ai_atm_subaddr);
358         anp = (Atm_addr_nsap *)aip->ai_atm_addr.address;
359         if (aip->ai_atm_addr.address_format == T_ATM_ENDSYS_ADDR) {
360                 anp->aan_sel = sel;
361         } else if (aip->ai_atm_addr.address_format ==
362                                 T_ATM_E164_ADDR &&
363                         aip->ai_atm_subaddr.address_format ==
364                                 T_ATM_ENDSYS_ADDR) {
365                 anp->aan_sel = sel;
366         }
367
368         /*
369          * Get a new ATMARP cache for the interface
370          */
371         aap = (Atmarp *)UM_ALLOC(sizeof(Atmarp));
372         if (!aap) {
373                 atmarp_mem_err("atmarp_if_ready: sizeof(Atmarp)");
374         }
375         UM_ZERO(aap, sizeof(Atmarp));
376         
377         /*
378          * Fill out the entry
379          */
380         aap->aa_dstip = aip->ai_ip_addr;
381         ATM_ADDR_COPY(&intf_rsp->anp_addr, &aap->aa_dstatm);
382         ATM_ADDR_COPY(&intf_rsp->anp_subaddr,
383                         &aap->aa_dstatmsub);
384         aap->aa_key.key_len = SCSP_ATMARP_KEY_LEN;
385         scsp_cache_key(&aap->aa_dstatm, &aap->aa_dstip,
386                         SCSP_ATMARP_KEY_LEN, aap->aa_key.key);
387         aap->aa_oid.id_len = SCSP_ATMARP_ID_LEN;
388         aap->aa_seq = SCSP_CSA_SEQ_MIN;
389         UM_COPY(&aap->aa_dstip.s_addr, aap->aa_oid.id,
390                         SCSP_ATMARP_ID_LEN);
391         aap->aa_intf = aip;
392         aap->aa_flags = AAF_SERVER;
393         aap->aa_origin = UAO_LOCAL;
394
395         /*
396          * Add the entry to the cache
397          */
398         ATMARP_ADD(aip, aap);
399         
400         /*
401          * Free dynamic data
402          */
403         UM_FREE(netif_rsp);
404         UM_FREE(intf_rsp);
405
406         return(1);
407
408 if_ready_fail:
409         if (netif_rsp)
410                 UM_FREE(netif_rsp);
411         if (intf_rsp)
412                 UM_FREE(intf_rsp);
413
414         return(0);
415 }
416
417
418 /*
419  * Copy an ATMARP cache entry from kernel format into an entry
420  * suitable for our cache
421  *
422  * Arguments:
423  *      cp      pointer to kernel entry
424  *
425  * Returns:
426  *      pointer to a new cache entry
427  *      0       error
428  *
429  */
430 Atmarp *
431 atmarp_copy_cache_entry(struct air_arp_rsp *cp)
432 {
433         struct sockaddr_in      *ipp;
434         Atmarp_intf             *aip;
435         Atmarp                  *aap;
436
437         /*
438          * Sanity checks
439          */
440         if (!cp)
441                 return((Atmarp *)0);
442         aip = atmarp_find_intf_name(cp->aap_intf);
443         if (!aip)
444                 return((Atmarp *)0);
445
446         /*
447          * Get a new cache entry
448          */
449         aap = (Atmarp *)UM_ALLOC(sizeof(Atmarp));
450         if (!aap) {
451                 errno = ENOMEM;
452                 return((Atmarp *)0);
453         }
454         UM_ZERO(aap, sizeof(Atmarp));
455         aap->aa_intf = aip;
456
457         /*
458          * Copy fields from the kernel entry to the new entry
459          */
460         ipp = (struct sockaddr_in *)&cp->aap_arp_addr;
461         UM_COPY(&ipp->sin_addr.s_addr, &aap->aa_dstip.s_addr,
462                         sizeof(aap->aa_dstip.s_addr));
463         ATM_ADDR_COPY(&cp->aap_addr, &aap->aa_dstatm);
464         ATM_ADDR_COPY(&cp->aap_subaddr, &aap->aa_dstatmsub);
465         if (cp->aap_origin == UAO_PERM)
466                 aap->aa_flags |= AAF_PERM;
467         aap->aa_origin = cp->aap_origin;
468
469         /*
470          * Set up fields for SCSP
471          */
472         aap->aa_key.key_len = SCSP_ATMARP_KEY_LEN;
473         scsp_cache_key(&cp->aap_addr, &aap->aa_dstip,
474                         SCSP_ATMARP_KEY_LEN, (char *)aap->aa_key.key);
475         aap->aa_oid.id_len = SCSP_ATMARP_ID_LEN;
476         UM_COPY(&aip->ai_ip_addr.s_addr, aap->aa_oid.id,
477                         SCSP_ATMARP_ID_LEN);
478         aap->aa_seq = SCSP_CSA_SEQ_MIN;
479
480         return(aap);
481 }
482
483
484 /*
485  * Send an updated ATMARP cache entry to the kernel
486  *
487  * Arguments:
488  *      aap     pointer to updated entry
489  *
490  * Returns:
491  *      0       success
492  *      errno   reason for failure
493  *
494  */
495 int
496 atmarp_update_kernel(Atmarp *aap)
497 {
498         int                     rc = 0, sd;
499         struct atmaddreq        aar;
500         struct sockaddr_in      *ipp;
501
502         /*
503          * Build ioctl request
504          */
505         UM_ZERO(&aar, sizeof(aar));
506         aar.aar_opcode = AIOCS_ADD_ARP;
507         strncpy(aar.aar_arp_intf, aap->aa_intf->ai_intf,
508                         sizeof(aar.aar_arp_intf));
509         aar.aar_arp_origin = UAO_SCSP;
510         ATM_ADDR_COPY(&aap->aa_dstatm, &aar.aar_arp_addr);
511         ipp = (struct sockaddr_in *)&aar.aar_arp_dst;
512         ipp->sin_family = AF_INET;
513 #if (defined(BSD) && (BSD >= 199103))
514         ipp->sin_len = sizeof(struct sockaddr_in);
515 #endif
516         ipp->sin_addr = aap->aa_dstip;
517         
518         /*
519          * Pass the new mapping to the kernel
520          */
521         sd = socket(AF_ATM, SOCK_DGRAM, 0);
522         if (sd < 0) {
523                 return(errno);
524         }
525         if (ioctl(sd, AIOCADD, (caddr_t)&aar) < 0) {
526                 rc = errno;
527         }
528
529         close(sd);
530         return(rc);
531 }
532
533
534 /*
535  * Read the ATMARP cache from the kernel and scan it, processing
536  * all entries
537  *
538  * Arguments:
539  *      none
540  *
541  * Returns:
542  *      none
543  *
544  */
545 void
546 atmarp_get_updated_cache(void)
547 {
548         int                     i, len, rc;
549         struct atminfreq        air;
550         struct air_arp_rsp      *cp;
551         struct sockaddr_in      *ipp;
552         Atmarp_intf             *aip;
553         Atmarp                  *aap;
554
555         /*
556          * Set up the request
557          */
558         air.air_opcode = AIOCS_INF_ARP;
559         air.air_arp_flags = ARP_RESET_REF;
560         ipp = (struct sockaddr_in *)&air.air_arp_addr;
561 #if (defined(BSD) && (BSD >= 199103))
562         ipp->sin_len = sizeof(struct sockaddr_in);
563 #endif
564         ipp->sin_family = AF_INET;
565         ipp->sin_addr.s_addr = INADDR_ANY;
566
567         /*
568          * Issue an ATMARP information request IOCTL
569          */
570         len = do_info_ioctl(&air, sizeof(struct air_arp_rsp) * 200);
571         if (len < 0) {
572                 return;
573         }
574
575         /*
576          * Clear marks on all our cache entries
577          */
578         atmarp_clear_marks();
579
580         /*
581          * Loop through the cache, processing each entry
582          */
583         for (cp = (struct air_arp_rsp *) air.air_buf_addr;
584                         len > 0;
585                         cp++, len -= sizeof(struct air_arp_rsp)) {
586                 atmarp_process_cache_entry(cp);
587         }
588
589         /*
590          * Now delete any old entries that aren't in the kernel's
591          * cache any more
592          */
593         for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
594                 for (i = 0; i < ATMARP_HASHSIZ; i++) {
595                         for (aap = aip->ai_arptbl[i]; aap;
596                                         aap = aap->aa_next) {
597                                 /*
598                                  * Don't delete the entry for the server
599                                  */
600                                 if (aap->aa_flags & AAF_SERVER)
601                                         continue;
602                                 /*
603                                  * Delete any entry that isn't marked
604                                  */
605                                 if (!aap->aa_mark) {
606                                         rc = atmarp_scsp_update(aap,
607                                                 SCSP_ASTATE_DEL);
608                                         if (rc == 0)
609                                                 ATMARP_DELETE(aip, aap);
610                                 }
611                         }
612                 }
613         }
614
615         /*
616          * Free the ioctl response
617          */
618         UM_FREE(air.air_buf_addr);
619 }
620
621
622 /*
623  * Process an ATMARP cache entry from the kernel.  If we already
624  * have the entry in our local cache, update it, otherwise, add
625  * it.  In either case, mark our local copy so we know it's still
626  * in the kernel's cache.
627  *
628  * Arguments:
629  *      cp      pointer to kernel's cache entry
630  *
631  * Returns:
632  *      none
633  *
634  */
635 void
636 atmarp_process_cache_entry(struct air_arp_rsp *cp)
637 {
638         int                     rc;
639         struct sockaddr_in      *ipp = (struct sockaddr_in *)&cp->aap_arp_addr;
640         Atmarp_intf             *aip;
641         Atmarp                  *aap;
642
643         /*
644          * See whether the entry is for an interface that's
645          * both configured and up
646          */
647         aip = atmarp_find_intf_name(cp->aap_intf);
648         if (!aip || aip->ai_state != AI_STATE_UP)
649                 return;
650
651         /*
652          * Make sure the entry is valid
653          */
654         if (!(cp->aap_flags & ARPF_VALID))
655                 return;
656
657         /*
658          * See whether we have the entry in our cache already
659          */
660         ATMARP_LOOKUP(aip, ipp->sin_addr.s_addr, aap);
661         if (aap) {
662                 /*
663                  * We already have this in our cache--update it
664                  */
665                 aap->aa_mark = 1;
666                 if ((cp->aap_flags & ARPF_REFRESH) &&
667                                 cp->aap_origin != UAO_SCSP) {
668                         aap->aa_seq++;
669                         rc = atmarp_scsp_update(aap, SCSP_ASTATE_UPD);
670                 }
671         } else {
672                 /*
673                  * This is a new entry--add it to the cache
674                  */
675                 aap = atmarp_copy_cache_entry(cp);
676                 if (!aap)
677                         return;
678                 ATMARP_ADD(aip, aap);
679                 aap->aa_mark = 1;
680                 rc = atmarp_scsp_update(aap, SCSP_ASTATE_NEW);
681         }
682
683         return;
684 }
685
686
687 /*
688  * Print an SCSP ID
689  *
690  * Arguments:
691  *      df      pointer to a FILE for the dump
692  *      ip      pointer to the SCSP ID to print
693  *
694  * Returns:
695  *      None
696  *
697  */
698 static void
699 print_scsp_id(FILE *df, Scsp_id *ip)
700 {
701         int     i;
702
703         fprintf(df, "\t  next:            %p\n", ip->next);
704         fprintf(df, "\t  id_len:          %d\n", ip->id_len);
705         fprintf(df, "\t  id:              0x");
706         for (i = 0; i < ip->id_len; i++) {
707                 fprintf(df, "%0x ", ip->id[i]);
708         }
709         fprintf(df, "\n");
710 }
711
712
713 /*
714  * Print an SCSP cacke key
715  *
716  * Arguments:
717  *      df      pointer to a FILE for the dump
718  *      cp      pointer to the cacke key to print
719  *
720  * Returns:
721  *      None
722  *
723  */
724 static void
725 print_scsp_cache_key(FILE *df, Scsp_ckey *cp)
726 {
727         int     i;
728
729         fprintf(df, "\t  key_len:         %d\n", cp->key_len);
730         fprintf(df, "\t  key:             0x");
731         for (i = 0; i < cp->key_len; i++) {
732                 fprintf(df, "%0x ", cp->key[i]);
733         }
734         fprintf(df, "\n");
735 }
736
737
738 /*
739  * Print an ATMARP interface entry
740  *
741  * Arguments:
742  *      df      pointer to a FILE for the dump
743  *      aip     pointer to interface entry
744  *
745  * Returns:
746  *      None
747  *
748  */
749 void
750 print_atmarp_intf(FILE *df, Atmarp_intf *aip)
751 {
752         if (!aip) {
753                 fprintf(df, "print_atmarp_intf: NULL interface entry address\n");
754                 return;
755         }
756
757         fprintf(df, "ATMARP network interface entry at %p\n", aip);
758         fprintf(df, "\tai_next:           %p\n", aip->ai_next);
759         fprintf(df, "\tai_intf:           %s\n", aip->ai_intf);
760         fprintf(df, "\tai_ip_addr:        %s\n",
761                         format_ip_addr(&aip->ai_ip_addr));
762         fprintf(df, "\tai_subnet_mask:    %s\n",
763                         inet_ntoa(aip->ai_subnet_mask));
764         fprintf(df, "\tai_mtu:            %d\n", aip->ai_mtu);
765         fprintf(df, "\tai_atm_addr:       %s\n",
766                         format_atm_addr(&aip->ai_atm_addr));
767         fprintf(df, "\tai_atm_subaddr:    %s\n",
768                         format_atm_addr(&aip->ai_atm_subaddr));
769         fprintf(df, "\tai_scsp_sock:      %d\n", aip->ai_scsp_sock);
770         fprintf(df, "\tai_scsp_sockname:  %s\n", aip->ai_scsp_sockname);
771         fprintf(df, "\tai_state:          %d\n", aip->ai_state);
772         fprintf(df, "\tai_mark:           %d\n", aip->ai_mark);
773 }
774
775
776 /*
777  * Print an ATMARP cache entry
778  *
779  * Arguments:
780  *      df      pointer to a FILE for the dump
781  *      aap     pointer to cache entry
782  *
783  * Returns:
784  *      None
785  *
786  */
787 void
788 print_atmarp_cache(FILE *df, Atmarp *aap)
789 {
790         if (!aap) {
791                 fprintf(df, "print_atmarp_cache: NULL ATMARP entry address\n");
792                 return;
793         }
794
795         fprintf(df, "ATMARP entry at %p\n", aap);
796         fprintf(df, "\taa_next:      %p\n", aap->aa_next);
797         fprintf(df, "\taa_dstip:     %s\n", inet_ntoa(aap->aa_dstip));
798         fprintf(df, "\taa_dstatm:    %s\n",
799                         format_atm_addr(&aap->aa_dstatm));
800         fprintf(df, "\taa_dstatmsub: %s\n",
801                         format_atm_addr(&aap->aa_dstatmsub));
802         fprintf(df, "\taa_key:\n");
803         print_scsp_cache_key(df, &aap->aa_key);
804         fprintf(df, "\taa_oid:\n");
805         print_scsp_id(df, &aap->aa_oid);
806         fprintf(df, "\taa_seq:       %ld (0x%lx)\n", aap->aa_seq,
807                         aap->aa_seq);
808         fprintf(df, "\taa_intf:      %p\n", aap->aa_intf);
809         fprintf(df, "\taa_flags:     ");
810         if (aap->aa_flags & AAF_PERM)
811                 fprintf(df, "Permanent ");
812         if (aap->aa_flags & AAF_SERVER)
813                 fprintf(df, "Server ");
814         fprintf(df, "\n");
815         fprintf(df, "\taa_origin:    %d\n", aap->aa_origin);
816         fprintf(df, "\taa_mark:      %d\n", aap->aa_mark);
817 }
818
819
820 /*
821  * Print the entire ATMARP cache
822  *
823  * Arguments:
824  *      df      pointer to a FILE for the dump
825  *      aip     pointer to interface whose cache is to be printed
826  *
827  * Returns:
828  *      None
829  *
830  */
831 void
832 dump_atmarp_cache(FILE *df, Atmarp_intf *aip)
833 {
834         int     i;
835         Atmarp  *aap;
836
837         if (!aip) {
838                 fprintf(df, "dump_atmarp_cache: NULL interface address\n");
839                 return;
840         }
841
842         fprintf(df, "ATMARP cache for interface %s\n", aip->ai_intf);
843         for (i=0; i<ATMARP_HASHSIZ; i++) {
844                 for (aap=aip->ai_arptbl[i]; aap; aap=aap->aa_next) {
845                         print_atmarp_cache(df, aap);
846                 }
847         }
848 }
849
850
851 #ifdef NOTDEF
852 /*
853  * Print an ATMARP super-LIS entry
854  *
855  * Arguments:
856  *      df      pointer to a FILE for the dump
857  *      asp     pointer to super-LIS entry to be printed
858  *
859  * Returns:
860  *      None
861  *
862  */
863 void
864 print_atmarp_slis(FILE *df, Atmarp_slis *asp)
865 {
866         Atmarp_intf     **aipp;
867
868         if (!asp) {
869                 fprintf(df, "print_atmarp_slis: NULL SLIS address\n");
870                 return;
871         }
872
873         fprintf(df, "SLIS entry at 0x%0x\n", (u_long)asp);
874         fprintf(df, "\tas_next:      0x%0x\n", (u_long)asp->as_next);
875         fprintf(df, "\tas_name:      %s\n", asp->as_name);
876         fprintf(df, "\tas_cnt:       %d\n", asp->as_cnt);
877         for (aipp = &asp->as_intfs; *aipp; aipp++) {
878                 fprintf(df, "\t%s (%s)\n", (*aipp)->ai_name,
879                                 (*aipp)->ai_intf);
880         }
881 }
882 #endif
883
884
885 /*
886  * Dump ATMARPD information
887  *
888  * Called as the result of a SIGINT signal.
889  *
890  * Arguments:
891  *      sig     signal number
892  *
893  * Returns:
894  *      None
895  *
896  */
897 void
898 atmarp_sigint(int sig)
899 {
900         Atmarp_intf     *aip;
901         FILE            *df;
902         char            fname[64];
903         static int      dump_no = 0;
904
905         /*
906          * Build a file name
907          */
908         UM_ZERO(fname, sizeof(fname));
909         sprintf(fname, "/tmp/atmarpd.%d.%03d.out", getpid(), dump_no++);
910
911         /*
912          * Open the output file
913          */
914         df = fopen(fname, "w");
915         if (df == (FILE *)0)
916                 return;
917
918         /*
919          * Dump the interface control blocks and
920          * associated ATMARP caches
921          */
922         for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
923                 print_atmarp_intf(df, aip);
924                 fprintf(df, "\n");
925                 dump_atmarp_cache(df, aip);
926                 fprintf(df, "\n");
927         }
928
929         /*
930          * Close the output file
931          */
932         fclose(df);
933 }