aboutsummaryrefslogtreecommitdiff
path: root/slirp/debug.c
blob: ac856ca19b42a022abb0f7bf211f96c8206f1642 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/*
 * Copyright (c) 1995 Danny Gasparovski.
 * Portions copyright (c) 2000 Kelly Price.
 *
 * Please read the file COPYRIGHT for the
 * terms and conditions of the copyright.
 */

#include <slirp.h>

FILE *dfd = NULL;
#ifdef DEBUG
int dostats = 1;
#else
int dostats = 0;
#endif
int slirp_debug = 0;

/* Carry over one item from main.c so that the tty's restored.
 * Only done when the tty being used is /dev/tty --RedWolf */
#ifndef CONFIG_QEMU
extern struct termios slirp_tty_settings;
extern int slirp_tty_restore;


void
debug_init(file, dbg)
	char *file;
	int dbg;
{
	/* Close the old debugging file */
	if (dfd)
	   fclose(dfd);

	dfd = fopen(file,"w");
	if (dfd != NULL) {
#if 0
		fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION);
#endif
		fprintf(dfd,"Debugging Started level %i.\r\n",dbg);
		fflush(dfd);
		slirp_debug = dbg;
	} else {
		lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n",
			file, strerror(errno));
	}
}

/*
 * Dump a packet in the same format as tcpdump -x
 */
#ifdef DEBUG
void
dump_packet(dat, n)
	void *dat;
	int n;
{
	u_char *pptr = (u_char *)dat;
	int j,k;

	n /= 16;
	n++;
	DEBUG_MISC((dfd, "PACKET DUMPED: \n"));
	for(j = 0; j < n; j++) {
		for(k = 0; k < 6; k++)
			DEBUG_MISC((dfd, "%02x ", *pptr++));
		DEBUG_MISC((dfd, "\n"));
		fflush(dfd);
	}
}
#endif
#endif

#ifdef LOG_ENABLED
#if 0
/*
 * Statistic routines
 *
 * These will print statistics to the screen, the debug file (dfd), or
 * a buffer, depending on "type", so that the stats can be sent over
 * the link as well.
 */

static void
ttystats(ttyp)
	struct ttys *ttyp;
{
	struct slirp_ifstats *is = &ttyp->ifstats;
	char buff[512];

	lprint(" \r\n");

	if (IF_COMP & IF_COMPRESS)
	   strcpy(buff, "on");
	else if (IF_COMP & IF_NOCOMPRESS)
	   strcpy(buff, "off");
	else
	   strcpy(buff, "off (for now)");
	lprint("Unit %d:\r\n", ttyp->unit);
	lprint("  using %s encapsulation (VJ compression is %s)\r\n", (
#ifdef USE_PPP
	       ttyp->proto==PROTO_PPP?"PPP":
#endif
	       "SLIP"), buff);
	lprint("  %d baudrate\r\n", ttyp->baud);
	lprint("  interface is %s\r\n", ttyp->up?"up":"down");
	lprint("  using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid);
#ifndef FULL_BOLT
	lprint("  towrite is %d bytes\r\n", ttyp->towrite);
#endif
	if (ttyp->zeros)
	   lprint("  %d zeros have been typed\r\n", ttyp->zeros);
	else if (ttyp->ones)
	   lprint("  %d ones have been typed\r\n", ttyp->ones);
	lprint("Interface stats:\r\n");
	lprint("  %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes);
	lprint("  %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes);
	lprint("  %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes);
	lprint("  %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes);
	lprint("  %6d bad input packets\r\n", is->in_mbad);
}

static void
allttystats(void)
{
	struct ttys *ttyp;

	for (ttyp = ttys; ttyp; ttyp = ttyp->next)
	   ttystats(ttyp);
}
#endif

static void
ipstats(void)
{
	lprint(" \r\n");

	lprint("IP stats:\r\n");
	lprint("  %6d total packets received (%d were unaligned)\r\n",
			ipstat.ips_total, ipstat.ips_unaligned);
	lprint("  %6d with incorrect version\r\n", ipstat.ips_badvers);
	lprint("  %6d with bad header checksum\r\n", ipstat.ips_badsum);
	lprint("  %6d with length too short (len < sizeof(iphdr))\r\n", ipstat.ips_tooshort);
	lprint("  %6d with length too small (len < ip->len)\r\n", ipstat.ips_toosmall);
	lprint("  %6d with bad header length\r\n", ipstat.ips_badhlen);
	lprint("  %6d with bad packet length\r\n", ipstat.ips_badlen);
	lprint("  %6d fragments received\r\n", ipstat.ips_fragments);
	lprint("  %6d fragments dropped\r\n", ipstat.ips_fragdropped);
	lprint("  %6d fragments timed out\r\n", ipstat.ips_fragtimeout);
	lprint("  %6d packets reassembled ok\r\n", ipstat.ips_reassembled);
	lprint("  %6d outgoing packets fragmented\r\n", ipstat.ips_fragmented);
	lprint("  %6d total outgoing fragments\r\n", ipstat.ips_ofragments);
	lprint("  %6d with bad protocol field\r\n", ipstat.ips_noproto);
	lprint("  %6d total packets delivered\r\n", ipstat.ips_delivered);
}

#ifndef CONFIG_QEMU
static void
vjstats(void)
{
	lprint(" \r\n");

	lprint("VJ compression stats:\r\n");

	lprint("  %6d outbound packets (%d compressed)\r\n",
	       comp_s.sls_packets, comp_s.sls_compressed);
	lprint("  %6d searches for connection stats (%d misses)\r\n",
	       comp_s.sls_searches, comp_s.sls_misses);
	lprint("  %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin);
	lprint("  %6d inbound compressed packets\r\n", comp_s.sls_compressedin);
	lprint("  %6d inbound unknown type packets\r\n", comp_s.sls_errorin);
	lprint("  %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed);
}
#endif

static void
tcpstats(void)
{
	lprint(" \r\n");

	lprint("TCP stats:\r\n");

	lprint("  %6d packets sent\r\n", tcpstat.tcps_sndtotal);
	lprint("          %6d data packets (%d bytes)\r\n",
			tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte);
	lprint("          %6d data packets retransmitted (%d bytes)\r\n",
			tcpstat.tcps_sndrexmitpack, tcpstat.tcps_sndrexmitbyte);
	lprint("          %6d ack-only packets (%d delayed)\r\n",
			tcpstat.tcps_sndacks, tcpstat.tcps_delack);
	lprint("          %6d URG only packets\r\n", tcpstat.tcps_sndurg);
	lprint("          %6d window probe packets\r\n", tcpstat.tcps_sndprobe);
	lprint("          %6d window update packets\r\n", tcpstat.tcps_sndwinup);
	lprint("          %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl);
	lprint("          %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin);

	lprint("  %6d packets received\r\n", tcpstat.tcps_rcvtotal);
	lprint("          %6d acks (for %d bytes)\r\n",
			tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte);
	lprint("          %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack);
	lprint("          %6d acks for unsent data\r\n", tcpstat.tcps_rcvacktoomuch);
	lprint("          %6d packets received in sequence (%d bytes)\r\n",
			tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte);
        lprint("          %6d completely duplicate packets (%d bytes)\r\n",
			tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte);

	lprint("          %6d packets with some duplicate data (%d bytes duped)\r\n",
			tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte);
	lprint("          %6d out-of-order packets (%d bytes)\r\n",
			tcpstat.tcps_rcvoopack, tcpstat.tcps_rcvoobyte);
	lprint("          %6d packets of data after window (%d bytes)\r\n",
			tcpstat.tcps_rcvpackafterwin, tcpstat.tcps_rcvbyteafterwin);
	lprint("          %6d window probes\r\n", tcpstat.tcps_rcvwinprobe);
	lprint("          %6d window update packets\r\n", tcpstat.tcps_rcvwinupd);
	lprint("          %6d packets received after close\r\n", tcpstat.tcps_rcvafterclose);
	lprint("          %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum);
	lprint("          %6d discarded for bad header offset fields\r\n",
			tcpstat.tcps_rcvbadoff);

	lprint("  %6d connection requests\r\n", tcpstat.tcps_connattempt);
	lprint("  %6d connection accepts\r\n", tcpstat.tcps_accepts);
	lprint("  %6d connections established (including accepts)\r\n", tcpstat.tcps_connects);
	lprint("  %6d connections closed (including %d drop)\r\n",
			tcpstat.tcps_closed, tcpstat.tcps_drops);
	lprint("  %6d embryonic connections dropped\r\n", tcpstat.tcps_conndrops);
	lprint("  %6d segments we tried to get rtt (%d succeeded)\r\n",
			tcpstat.tcps_segstimed, tcpstat.tcps_rttupdated);
	lprint("  %6d retransmit timeouts\r\n", tcpstat.tcps_rexmttimeo);
	lprint("          %6d connections dropped by rxmt timeout\r\n",
			tcpstat.tcps_timeoutdrop);
	lprint("  %6d persist timeouts\r\n", tcpstat.tcps_persisttimeo);
	lprint("  %6d keepalive timeouts\r\n", tcpstat.tcps_keeptimeo);
	lprint("          %6d keepalive probes sent\r\n", tcpstat.tcps_keepprobe);
	lprint("          %6d connections dropped by keepalive\r\n", tcpstat.tcps_keepdrops);
	lprint("  %6d correct ACK header predictions\r\n", tcpstat.tcps_predack);
	lprint("  %6d correct data packet header predictions\n", tcpstat.tcps_preddat);
	lprint("  %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss);


/*	lprint("    Packets received too short:		%d\r\n", tcpstat.tcps_rcvshort); */
/*	lprint("    Segments dropped due to PAWS:	%d\r\n", tcpstat.tcps_pawsdrop); */

}

static void
udpstats(void)
{
        lprint(" \r\n");

	lprint("UDP stats:\r\n");
	lprint("  %6d datagrams received\r\n", udpstat.udps_ipackets);
	lprint("  %6d with packets shorter than header\r\n", udpstat.udps_hdrops);
	lprint("  %6d with bad checksums\r\n", udpstat.udps_badsum);
	lprint("  %6d with data length larger than packet\r\n", udpstat.udps_badlen);
	lprint("  %6d UDP socket cache misses\r\n", udpstat.udpps_pcbcachemiss);
	lprint("  %6d datagrams sent\r\n", udpstat.udps_opackets);
}

static void
icmpstats(void)
{
	lprint(" \r\n");
	lprint("ICMP stats:\r\n");
	lprint("  %6d ICMP packets received\r\n", icmpstat.icps_received);
	lprint("  %6d were too short\r\n", icmpstat.icps_tooshort);
	lprint("  %6d with bad checksums\r\n", icmpstat.icps_checksum);
	lprint("  %6d with type not supported\r\n", icmpstat.icps_notsupp);
	lprint("  %6d with bad type feilds\r\n", icmpstat.icps_badtype);
	lprint("  %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect);
}

static void
mbufstats(void)
{
	struct mbuf *m;
	int i;

        lprint(" \r\n");

	lprint("Mbuf stats:\r\n");

	lprint("  %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max);

	i = 0;
	for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next)
		i++;
	lprint("  %6d mbufs on free list\r\n",  i);

	i = 0;
	for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next)
		i++;
	lprint("  %6d mbufs on used list\r\n",  i);
        lprint("  %6d mbufs queued as packets\r\n\r\n", if_queued);
}
#endif

#ifndef CONFIG_QEMU
void
slirp_exit(exit_status)
	int exit_status;
{
	struct ttys *ttyp;

	DEBUG_CALL("slirp_exit");
	DEBUG_ARG("exit_status = %d", exit_status);

	if (dostats) {
		lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf;
		if (!dfd)
		   debug_init("slirp_stats", 0xf);
		lprint_arg = (char **)&dfd;

		ipstats();
		tcpstats();
		udpstats();
		icmpstats();
		mbufstats();
		sockstats();
		allttystats();
		vjstats();
	}

	for (ttyp = ttys; ttyp; ttyp = ttyp->next)
	   tty_detached(ttyp, 1);

	if (slirp_forked) {
		/* Menendez time */
		if (kill(getppid(), SIGQUIT) < 0)
			lprint("Couldn't kill parent process %ld!\n",
			    (long) getppid());
    	}

	/* Restore the terminal if we gotta */
	if(slirp_tty_restore)
	  tcsetattr(0,TCSANOW, &slirp_tty_settings);  /* NOW DAMMIT! */
	exit(exit_status);
}
#endif

void
slirp_stats(void)
{
#ifdef LOG_ENABLED
    ipstats();
    tcpstats();
    udpstats();
    icmpstats();
    mbufstats();
#else
    lprint("SLIRP statistics code not compiled.\n");
#endif
}