Merge branch 'master' of /home/aggelos/devel/dfly/dfly.git/
[dragonfly.git] / usr.bin / netstat / atalk.c
1 /*
2  * Copyright (c) 1983, 1988, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)atalk.c  1.1 (Whistle) 6/6/96
34  * $FreeBSD: src/usr.bin/netstat/atalk.c,v 1.13.2.2 2001/09/17 14:53:17 ru Exp $
35  * $DragonFly: src/usr.bin/netstat/atalk.c,v 1.4 2007/04/22 01:25:04 dillon Exp $
36  */
37
38 #define _KERNEL_STRUCTURES
39 #include <sys/param.h>
40 #include <sys/queue.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/protosw.h>
44
45 #include <net/route.h>
46
47 #include <netatalk/at.h>
48 #include <netatalk/ddp_var.h>
49
50 #include <errno.h>
51 #include <nlist.h>
52 #include <netdb.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include "netstat.h"
56
57 struct  ddpcb ddpcb;
58 struct  socket sockb;
59
60 static  int first = 1;
61
62 /*
63  * Print a summary of connections related to a Network Systems
64  * protocol.  For XXX, also give state of connection.
65  * Listening processes (aflag) are suppressed unless the
66  * -a (all) flag is specified.
67  */
68
69 static const char *
70 at_pr_net(struct sockaddr_at *sat, int numeric)
71 {
72 static  char mybuf[50];
73
74         if (!numeric) {
75                 switch(sat->sat_addr.s_net) {
76                 case 0xffff:
77                         return "????";
78                 case ATADDR_ANYNET:
79                         return("*");
80                 }
81         }
82         sprintf(mybuf,"%hu",ntohs(sat->sat_addr.s_net));
83         return mybuf;
84 }
85
86 static const char *
87 at_pr_host(struct sockaddr_at *sat, int numeric)
88 {
89 static  char mybuf[50];
90
91         if (!numeric) {
92                 switch(sat->sat_addr.s_node) {
93                 case ATADDR_BCAST:
94                         return "bcast";
95                 case ATADDR_ANYNODE:
96                         return("*");
97                 }
98         }
99         sprintf(mybuf,"%d",(unsigned int)sat->sat_addr.s_node);
100         return mybuf;
101 }
102
103 static const char *
104 at_pr_port(struct sockaddr_at *sat)
105 {
106 static  char mybuf[50];
107         struct servent *serv;
108
109         switch(sat->sat_port) {
110         case ATADDR_ANYPORT:
111                 return("*");
112         case 0xff:
113                 return "????";
114         default:
115                 if (numeric_port) {
116                         (void)snprintf(mybuf, sizeof(mybuf), "%d",
117                             (unsigned int)sat->sat_port);
118                 } else {
119                         serv = getservbyport(sat->sat_port, "ddp");
120                         if (serv == NULL)
121                                 (void)snprintf(mybuf, sizeof(mybuf), "%d",
122                                     (unsigned int) sat->sat_port);
123                         else
124                                 (void) snprintf(mybuf, sizeof(mybuf), "%s",
125                                     serv->s_name);
126                 }
127         }
128         return mybuf;
129 }
130
131 static char *
132 at_pr_range(struct sockaddr_at *sat)
133 {
134 static  char mybuf[50];
135
136         if(sat->sat_range.r_netrange.nr_firstnet
137            != sat->sat_range.r_netrange.nr_lastnet) {
138                 sprintf(mybuf,"%d-%d",
139                         ntohs(sat->sat_range.r_netrange.nr_firstnet),
140                         ntohs(sat->sat_range.r_netrange.nr_lastnet));
141         } else {
142                 sprintf(mybuf,"%d",
143                         ntohs(sat->sat_range.r_netrange.nr_firstnet));
144         }
145         return mybuf;
146 }
147
148
149 /* what == 0 for addr only == 3 */
150 /*         1 for net */
151 /*         2 for host */
152 /*         4 for port */
153 /*         8 for numeric only */
154 char *
155 atalk_print(struct sockaddr *sa, int what)
156 {
157         struct sockaddr_at *sat = (struct sockaddr_at *)sa;
158         static  char mybuf[50];
159         int numeric = (what & 0x08);
160
161         mybuf[0] = 0;
162         switch (what & 0x13) {
163         case 0:
164                 mybuf[0] = 0;
165                 break;
166         case 1:
167                 sprintf(mybuf,"%s",at_pr_net(sat, numeric));
168                 break;
169         case 2:
170                 sprintf(mybuf,"%s",at_pr_host(sat, numeric));
171                 break;
172         case 3:
173                 sprintf(mybuf,"%s.%s",
174                                 at_pr_net(sat, numeric),
175                                 at_pr_host(sat, numeric));
176                 break;
177         case 0x10:
178                 sprintf(mybuf,"%s", at_pr_range(sat));
179         }
180         if (what & 4) {
181                 sprintf(mybuf+strlen(mybuf),".%s",at_pr_port(sat));
182         }
183         return mybuf;
184 }
185
186 char *
187 atalk_print2(struct sockaddr *sa, struct sockaddr *mask, int what)
188 {
189   int n;
190   static char buf[100];
191   struct sockaddr_at *sat1, *sat2;
192   struct sockaddr_at thesockaddr;
193   struct sockaddr *sa2;
194
195   sat1 = (struct sockaddr_at *)sa;
196   sat2 = (struct sockaddr_at *)mask;
197   sa2 = (struct sockaddr *)&thesockaddr;
198
199   thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net & sat2->sat_addr.s_net;
200   n = snprintf(buf, sizeof(buf), "%s", atalk_print(sa2, 1 |(what & 8)));
201   if(sat2->sat_addr.s_net != 0xFFFF) {
202     thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net | ~sat2->sat_addr.s_net;
203     n += snprintf(buf + n, sizeof(buf) - n,
204                 "-%s", atalk_print(sa2, 1 |(what & 8)));
205   }
206   if(what & 2)
207   n += snprintf(buf + n, sizeof(buf) - n, ".%s", atalk_print(sa, what&(~1)));
208   return(buf);
209 }
210
211 void
212 atalkprotopr(u_long off __unused, const char *name, int af1 __unused)
213 {
214         struct ddpcb *this, *next;
215
216         if (off == 0)
217                 return;
218         kread(off, (char *)&this, sizeof (struct ddpcb *));
219         for ( ; this != NULL; this = next) {
220                 kread((u_long)this, (char *)&ddpcb, sizeof (ddpcb));
221                 next = ddpcb.ddp_next;
222 #if 0
223                 if (!aflag && atalk_nullhost(ddpcb.ddp_lsat) ) {
224                         continue;
225                 }
226 #endif
227                 kread((u_long)ddpcb.ddp_socket, (char *)&sockb, sizeof (sockb));
228                 if (first) {
229                         printf("Active ATALK connections");
230                         if (aflag)
231                                 printf(" (including servers)");
232                         putchar('\n');
233                         if (Aflag)
234                                 printf("%-8.8s ", "PCB");
235                         printf(Aflag ?
236                                 "%-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n" :
237                                 "%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
238                                 "Proto", "Recv-Q", "Send-Q",
239                                 "Local Address", "Foreign Address", "(state)");
240                         first = 0;
241                 }
242                 if (Aflag)
243                         printf("%8lx ", (u_long) this);
244                 printf("%-5.5s %6lu %6lu ", name, sockb.so_rcv.ssb_cc,
245                         sockb.so_snd.ssb_cc);
246                 printf(Aflag?" %-18.18s":" %-22.22s", atalk_print(
247                                         (struct sockaddr *)&ddpcb.ddp_lsat,7));
248                 printf(Aflag?" %-18.18s":" %-22.22s", atalk_print(
249                                         (struct sockaddr *)&ddpcb.ddp_fsat,7));
250                 putchar('\n');
251         }
252 }
253
254 #define ANY(x,y,z) if (x || sflag <= 1) \
255         printf("\t%lu %s%s%s\n",x,y,plural(x),z)
256
257 /*
258  * Dump DDP statistics structure.
259  */
260 void
261 ddp_stats(u_long off __unused, const char *name, int af1 __unused)
262 {
263         struct ddpstat ddpstat;
264
265         if (off == 0)
266                 return;
267         kread(off, (char *)&ddpstat, sizeof (ddpstat));
268         printf("%s:\n", name);
269         ANY(ddpstat.ddps_short, "packet", " with short headers ");
270         ANY(ddpstat.ddps_long, "packet", " with long headers ");
271         ANY(ddpstat.ddps_nosum, "packet", " with no checksum ");
272         ANY(ddpstat.ddps_tooshort, "packet", " too short ");
273         ANY(ddpstat.ddps_badsum, "packet", " with bad checksum ");
274         ANY(ddpstat.ddps_toosmall, "packet", " with not enough data ");
275         ANY(ddpstat.ddps_forward, "packet", " forwarded ");
276         ANY(ddpstat.ddps_encap, "packet", " encapsulated ");
277         ANY(ddpstat.ddps_cantforward, "packet", " rcvd for unreachable dest ");
278         ANY(ddpstat.ddps_nosockspace, "packet", " dropped due to no socket space ");
279 }