xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.bin/pppdump/pppdump.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * pppdump - print out the contents of a record file generated by
3*0Sstevel@tonic-gate  * pppd in readable form.
4*0Sstevel@tonic-gate  *
5*0Sstevel@tonic-gate  * Copyright (C) 1999  Paul Mackerras.  All rights reserved.
6*0Sstevel@tonic-gate  *
7*0Sstevel@tonic-gate  *  This program is free software; you can redistribute it and/or
8*0Sstevel@tonic-gate  *  modify it under the terms of the GNU General Public License
9*0Sstevel@tonic-gate  *  as published by the Free Software Foundation; either version
10*0Sstevel@tonic-gate  *  2 of the License, or (at your option) any later version.
11*0Sstevel@tonic-gate  */
12*0Sstevel@tonic-gate 
13*0Sstevel@tonic-gate #include <stdio.h>
14*0Sstevel@tonic-gate #include <unistd.h>
15*0Sstevel@tonic-gate #include <time.h>
16*0Sstevel@tonic-gate #include <sys/types.h>
17*0Sstevel@tonic-gate #ifdef PPP_DEFS_IN_NET
18*0Sstevel@tonic-gate #include <net/ppp_defs.h>
19*0Sstevel@tonic-gate #else
20*0Sstevel@tonic-gate #include "ppp_defs.h"
21*0Sstevel@tonic-gate #endif
22*0Sstevel@tonic-gate #include "ppp-comp.h"
23*0Sstevel@tonic-gate 
24*0Sstevel@tonic-gate int hexmode;
25*0Sstevel@tonic-gate int pppmode;
26*0Sstevel@tonic-gate int reverse;
27*0Sstevel@tonic-gate int decompress;
28*0Sstevel@tonic-gate int mru = 1500;
29*0Sstevel@tonic-gate int abs_times;
30*0Sstevel@tonic-gate time_t start_time;
31*0Sstevel@tonic-gate int start_time_tenths;
32*0Sstevel@tonic-gate int tot_sent, tot_rcvd;
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate extern int optind;
35*0Sstevel@tonic-gate extern char *optarg;
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate main(ac, av)
38*0Sstevel@tonic-gate     int ac;
39*0Sstevel@tonic-gate     char **av;
40*0Sstevel@tonic-gate {
41*0Sstevel@tonic-gate     int i;
42*0Sstevel@tonic-gate     char *p;
43*0Sstevel@tonic-gate     FILE *f;
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate     while ((i = getopt(ac, av, "hprdm:a")) != -1) {
46*0Sstevel@tonic-gate 	switch (i) {
47*0Sstevel@tonic-gate 	case 'h':
48*0Sstevel@tonic-gate 	    hexmode = 1;
49*0Sstevel@tonic-gate 	    break;
50*0Sstevel@tonic-gate 	case 'p':
51*0Sstevel@tonic-gate 	    pppmode = 1;
52*0Sstevel@tonic-gate 	    break;
53*0Sstevel@tonic-gate 	case 'r':
54*0Sstevel@tonic-gate 	    reverse = 1;
55*0Sstevel@tonic-gate 	    break;
56*0Sstevel@tonic-gate 	case 'd':
57*0Sstevel@tonic-gate 	    decompress = 1;
58*0Sstevel@tonic-gate 	    break;
59*0Sstevel@tonic-gate 	case 'm':
60*0Sstevel@tonic-gate 	    mru = atoi(optarg);
61*0Sstevel@tonic-gate 	    break;
62*0Sstevel@tonic-gate 	case 'a':
63*0Sstevel@tonic-gate 	    abs_times = 1;
64*0Sstevel@tonic-gate 	    break;
65*0Sstevel@tonic-gate 	default:
66*0Sstevel@tonic-gate 	    fprintf(stderr, "Usage: %s [-h | -p[d]] [-r] [-m mru] [-a] [file ...]\n", av[0]);
67*0Sstevel@tonic-gate 	    exit(1);
68*0Sstevel@tonic-gate 	}
69*0Sstevel@tonic-gate     }
70*0Sstevel@tonic-gate     if (optind >= ac)
71*0Sstevel@tonic-gate 	dumplog(stdin);
72*0Sstevel@tonic-gate     else {
73*0Sstevel@tonic-gate 	for (i = optind; i < ac; ++i) {
74*0Sstevel@tonic-gate 	    p = av[i];
75*0Sstevel@tonic-gate 	    if ((f = fopen(p, "r")) == NULL) {
76*0Sstevel@tonic-gate 		perror(p);
77*0Sstevel@tonic-gate 		exit(1);
78*0Sstevel@tonic-gate 	    }
79*0Sstevel@tonic-gate 	    if (pppmode)
80*0Sstevel@tonic-gate 		dumpppp(f);
81*0Sstevel@tonic-gate 	    else
82*0Sstevel@tonic-gate 		dumplog(f);
83*0Sstevel@tonic-gate 	    fclose(f);
84*0Sstevel@tonic-gate 	}
85*0Sstevel@tonic-gate     }
86*0Sstevel@tonic-gate     exit(0);
87*0Sstevel@tonic-gate }
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate dumplog(f)
90*0Sstevel@tonic-gate     FILE *f;
91*0Sstevel@tonic-gate {
92*0Sstevel@tonic-gate     int c, n, k, col;
93*0Sstevel@tonic-gate     int nb, c2;
94*0Sstevel@tonic-gate     unsigned char buf[16];
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate     while ((c = getc(f)) != EOF) {
97*0Sstevel@tonic-gate 	switch (c) {
98*0Sstevel@tonic-gate 	case RECMARK_STARTSEND:
99*0Sstevel@tonic-gate 	case RECMARK_STARTRECV:
100*0Sstevel@tonic-gate 	    if (reverse)
101*0Sstevel@tonic-gate 		c = c==RECMARK_STARTSEND ? RECMARK_STARTRECV :
102*0Sstevel@tonic-gate 		    RECMARK_STARTSEND;
103*0Sstevel@tonic-gate 	    printf("%s %c", c==RECMARK_STARTSEND? "sent": "rcvd",
104*0Sstevel@tonic-gate 		hexmode? ' ': '"');
105*0Sstevel@tonic-gate 	    col = 6;
106*0Sstevel@tonic-gate 	    n = getc(f);
107*0Sstevel@tonic-gate 	    n = (n << 8) + getc(f);
108*0Sstevel@tonic-gate 	    *(c==1? &tot_sent: &tot_rcvd) += n;
109*0Sstevel@tonic-gate 	    nb = 0;
110*0Sstevel@tonic-gate 	    for (; n > 0; --n) {
111*0Sstevel@tonic-gate 		c = getc(f);
112*0Sstevel@tonic-gate 		if (c == EOF) {
113*0Sstevel@tonic-gate 		    printf("\nEOF\n");
114*0Sstevel@tonic-gate 		    exit(0);
115*0Sstevel@tonic-gate 		}
116*0Sstevel@tonic-gate 		if (hexmode) {
117*0Sstevel@tonic-gate 		    if (nb >= 16) {
118*0Sstevel@tonic-gate 			printf("  ");
119*0Sstevel@tonic-gate 			for (k = 0; k < nb; ++k) {
120*0Sstevel@tonic-gate 			    c2 = buf[k];
121*0Sstevel@tonic-gate 			    putchar((' ' <= c2 && c2 <= '~')? c2: '.');
122*0Sstevel@tonic-gate 			}
123*0Sstevel@tonic-gate 			printf("\n      ");
124*0Sstevel@tonic-gate 			nb = 0;
125*0Sstevel@tonic-gate 		    }
126*0Sstevel@tonic-gate 		    buf[nb++] = c;
127*0Sstevel@tonic-gate 		    printf(" %.2x", c);
128*0Sstevel@tonic-gate 		} else {
129*0Sstevel@tonic-gate 		    k = (' ' <= c && c <= '~')? (c != '\\' && c != '"')? 1: 2: 3;
130*0Sstevel@tonic-gate 		    if ((col += k) >= 78) {
131*0Sstevel@tonic-gate 			printf("\n      ");
132*0Sstevel@tonic-gate 			col = 6 + k;
133*0Sstevel@tonic-gate 		    }
134*0Sstevel@tonic-gate 		    switch (k) {
135*0Sstevel@tonic-gate 		    case 1:
136*0Sstevel@tonic-gate 			putchar(c);
137*0Sstevel@tonic-gate 			break;
138*0Sstevel@tonic-gate 		    case 2:
139*0Sstevel@tonic-gate 			printf("\\%c", c);
140*0Sstevel@tonic-gate 			break;
141*0Sstevel@tonic-gate 		    case 3:
142*0Sstevel@tonic-gate 			printf("\\%.2x", c);
143*0Sstevel@tonic-gate 			break;
144*0Sstevel@tonic-gate 		    }
145*0Sstevel@tonic-gate 		}
146*0Sstevel@tonic-gate 	    }
147*0Sstevel@tonic-gate 	    if (hexmode) {
148*0Sstevel@tonic-gate 		for (k = nb; k < 16; ++k)
149*0Sstevel@tonic-gate 		    printf("   ");
150*0Sstevel@tonic-gate 		printf("  ");
151*0Sstevel@tonic-gate 		for (k = 0; k < nb; ++k) {
152*0Sstevel@tonic-gate 		    c2 = buf[k];
153*0Sstevel@tonic-gate 		    putchar((' ' <= c2 && c2 <= '~')? c2: '.');
154*0Sstevel@tonic-gate 		}
155*0Sstevel@tonic-gate 	    } else
156*0Sstevel@tonic-gate 		putchar('"');
157*0Sstevel@tonic-gate 	    printf("\n");
158*0Sstevel@tonic-gate 	    break;
159*0Sstevel@tonic-gate 	case RECMARK_ENDSEND:
160*0Sstevel@tonic-gate 	case RECMARK_ENDRECV:
161*0Sstevel@tonic-gate 	    if (reverse)
162*0Sstevel@tonic-gate 		c = c==RECMARK_ENDSEND ? RECMARK_ENDRECV : RECMARK_ENDSEND;
163*0Sstevel@tonic-gate 	    printf("end %s\n", c==RECMARK_ENDSEND? "send": "recv");
164*0Sstevel@tonic-gate 	    break;
165*0Sstevel@tonic-gate 	case RECMARK_TIMEDELTA32:
166*0Sstevel@tonic-gate 	case RECMARK_TIMEDELTA8:
167*0Sstevel@tonic-gate 	case RECMARK_TIMESTART:
168*0Sstevel@tonic-gate 	    show_time(f, c);
169*0Sstevel@tonic-gate 	    break;
170*0Sstevel@tonic-gate 	default:
171*0Sstevel@tonic-gate 	    printf("?%.2x\n");
172*0Sstevel@tonic-gate 	}
173*0Sstevel@tonic-gate     }
174*0Sstevel@tonic-gate }
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate /*
177*0Sstevel@tonic-gate  * FCS lookup table as calculated by genfcstab.
178*0Sstevel@tonic-gate  */
179*0Sstevel@tonic-gate static u_short fcstab[256] = {
180*0Sstevel@tonic-gate 	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
181*0Sstevel@tonic-gate 	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
182*0Sstevel@tonic-gate 	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
183*0Sstevel@tonic-gate 	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
184*0Sstevel@tonic-gate 	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
185*0Sstevel@tonic-gate 	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
186*0Sstevel@tonic-gate 	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
187*0Sstevel@tonic-gate 	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
188*0Sstevel@tonic-gate 	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
189*0Sstevel@tonic-gate 	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
190*0Sstevel@tonic-gate 	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
191*0Sstevel@tonic-gate 	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
192*0Sstevel@tonic-gate 	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
193*0Sstevel@tonic-gate 	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
194*0Sstevel@tonic-gate 	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
195*0Sstevel@tonic-gate 	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
196*0Sstevel@tonic-gate 	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
197*0Sstevel@tonic-gate 	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
198*0Sstevel@tonic-gate 	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
199*0Sstevel@tonic-gate 	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
200*0Sstevel@tonic-gate 	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
201*0Sstevel@tonic-gate 	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
202*0Sstevel@tonic-gate 	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
203*0Sstevel@tonic-gate 	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
204*0Sstevel@tonic-gate 	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
205*0Sstevel@tonic-gate 	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
206*0Sstevel@tonic-gate 	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
207*0Sstevel@tonic-gate 	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
208*0Sstevel@tonic-gate 	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
209*0Sstevel@tonic-gate 	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
210*0Sstevel@tonic-gate 	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
211*0Sstevel@tonic-gate 	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
212*0Sstevel@tonic-gate };
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate struct pkt {
215*0Sstevel@tonic-gate     int	cnt;
216*0Sstevel@tonic-gate     int	esc;
217*0Sstevel@tonic-gate     int	flags;
218*0Sstevel@tonic-gate     struct compressor *comp;
219*0Sstevel@tonic-gate     void *state;
220*0Sstevel@tonic-gate     unsigned char buf[8192];
221*0Sstevel@tonic-gate } spkt, rpkt;
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate /* Values for flags */
224*0Sstevel@tonic-gate #define CCP_ISUP	1
225*0Sstevel@tonic-gate #define CCP_ERROR	2
226*0Sstevel@tonic-gate #define CCP_FATALERROR	4
227*0Sstevel@tonic-gate #define CCP_ERR		(CCP_ERROR | CCP_FATALERROR)
228*0Sstevel@tonic-gate #define CCP_DECOMP_RUN	8
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate unsigned char dbuf[8192];
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate dumpppp(f)
233*0Sstevel@tonic-gate     FILE *f;
234*0Sstevel@tonic-gate {
235*0Sstevel@tonic-gate     int c, n, k;
236*0Sstevel@tonic-gate     int nb, nl, dn, proto, rv;
237*0Sstevel@tonic-gate     char *dir, *q;
238*0Sstevel@tonic-gate     unsigned char *p, *r, *endp;
239*0Sstevel@tonic-gate     unsigned char *d;
240*0Sstevel@tonic-gate     unsigned short fcs;
241*0Sstevel@tonic-gate     struct pkt *pkt;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate     spkt.cnt = rpkt.cnt = 0;
244*0Sstevel@tonic-gate     spkt.esc = rpkt.esc = 0;
245*0Sstevel@tonic-gate     while ((c = getc(f)) != EOF) {
246*0Sstevel@tonic-gate 	switch (c) {
247*0Sstevel@tonic-gate 	case RECMARK_STARTSEND:
248*0Sstevel@tonic-gate 	case RECMARK_STARTRECV:
249*0Sstevel@tonic-gate 	    if (reverse)
250*0Sstevel@tonic-gate 		c = c==RECMARK_STARTSEND ? RECMARK_STARTRECV :
251*0Sstevel@tonic-gate 		    RECMARK_STARTSEND;
252*0Sstevel@tonic-gate 	    dir = c==RECMARK_STARTSEND? "sent": "rcvd";
253*0Sstevel@tonic-gate 	    pkt = c==RECMARK_STARTSEND? &spkt: &rpkt;
254*0Sstevel@tonic-gate 	    n = getc(f);
255*0Sstevel@tonic-gate 	    n = (n << 8) + getc(f);
256*0Sstevel@tonic-gate 	    *(c==1? &tot_sent: &tot_rcvd) += n;
257*0Sstevel@tonic-gate 	    for (; n > 0; --n) {
258*0Sstevel@tonic-gate 		c = getc(f);
259*0Sstevel@tonic-gate 		switch (c) {
260*0Sstevel@tonic-gate 		case EOF:
261*0Sstevel@tonic-gate 		    printf("\nEOF\n");
262*0Sstevel@tonic-gate 		    if (spkt.cnt > 0)
263*0Sstevel@tonic-gate 			printf("[%d bytes in incomplete send packet]\n",
264*0Sstevel@tonic-gate 			       spkt.cnt);
265*0Sstevel@tonic-gate 		    if (rpkt.cnt > 0)
266*0Sstevel@tonic-gate 			printf("[%d bytes in incomplete recv packet]\n",
267*0Sstevel@tonic-gate 			       rpkt.cnt);
268*0Sstevel@tonic-gate 		    exit(0);
269*0Sstevel@tonic-gate 		case '~':
270*0Sstevel@tonic-gate 		    if (pkt->cnt > 0) {
271*0Sstevel@tonic-gate 			q = dir;
272*0Sstevel@tonic-gate 			if (pkt->esc) {
273*0Sstevel@tonic-gate 			    printf("%s aborted packet:\n     ", dir);
274*0Sstevel@tonic-gate 			    q = "    ";
275*0Sstevel@tonic-gate 			}
276*0Sstevel@tonic-gate 			nb = pkt->cnt;
277*0Sstevel@tonic-gate 			p = pkt->buf;
278*0Sstevel@tonic-gate 			pkt->cnt = 0;
279*0Sstevel@tonic-gate 			pkt->esc = 0;
280*0Sstevel@tonic-gate 			if (nb <= 2) {
281*0Sstevel@tonic-gate 			    printf("%s short packet [%d bytes]:", q, nb);
282*0Sstevel@tonic-gate 			    for (k = 0; k < nb; ++k)
283*0Sstevel@tonic-gate 				printf(" %.2x", p[k]);
284*0Sstevel@tonic-gate 			    printf("\n");
285*0Sstevel@tonic-gate 			    break;
286*0Sstevel@tonic-gate 			}
287*0Sstevel@tonic-gate 			fcs = PPP_INITFCS;
288*0Sstevel@tonic-gate 			for (k = 0; k < nb; ++k)
289*0Sstevel@tonic-gate 			    fcs = PPP_FCS(fcs, p[k]);
290*0Sstevel@tonic-gate 			fcs &= 0xFFFF;
291*0Sstevel@tonic-gate 			nb -= 2;
292*0Sstevel@tonic-gate 			endp = p + nb;
293*0Sstevel@tonic-gate 			r = p;
294*0Sstevel@tonic-gate 			if (r[0] == 0xff && r[1] == 3)
295*0Sstevel@tonic-gate 			    r += 2;
296*0Sstevel@tonic-gate 			if ((r[0] & 1) == 0)
297*0Sstevel@tonic-gate 			    ++r;
298*0Sstevel@tonic-gate 			++r;
299*0Sstevel@tonic-gate 			if (endp - r > mru)
300*0Sstevel@tonic-gate 			    printf("     ERROR: length (%d) > MRU (%d)\n",
301*0Sstevel@tonic-gate 				   endp - r, mru);
302*0Sstevel@tonic-gate 			if (decompress && fcs == PPP_GOODFCS) {
303*0Sstevel@tonic-gate 			    /* See if this is a CCP or compressed packet */
304*0Sstevel@tonic-gate 			    d = dbuf;
305*0Sstevel@tonic-gate 			    r = p;
306*0Sstevel@tonic-gate 			    if (r[0] == 0xff && r[1] == 3) {
307*0Sstevel@tonic-gate 				*d++ = *r++;
308*0Sstevel@tonic-gate 				*d++ = *r++;
309*0Sstevel@tonic-gate 			    }
310*0Sstevel@tonic-gate 			    proto = r[0];
311*0Sstevel@tonic-gate 			    if ((proto & 1) == 0)
312*0Sstevel@tonic-gate 				proto = (proto << 8) + r[1];
313*0Sstevel@tonic-gate 			    if (proto == PPP_CCP) {
314*0Sstevel@tonic-gate 				handle_ccp(pkt, r + 2, endp - r - 2);
315*0Sstevel@tonic-gate 			    } else if (proto == PPP_COMP) {
316*0Sstevel@tonic-gate 				if ((pkt->flags & CCP_ISUP)
317*0Sstevel@tonic-gate 				    && (pkt->flags & CCP_DECOMP_RUN)
318*0Sstevel@tonic-gate 				    && pkt->state
319*0Sstevel@tonic-gate 				    && (pkt->flags & CCP_ERR) == 0) {
320*0Sstevel@tonic-gate 				    rv = pkt->comp->decompress(pkt->state, r,
321*0Sstevel@tonic-gate 							endp - r, d, &dn);
322*0Sstevel@tonic-gate 				    switch (rv) {
323*0Sstevel@tonic-gate 				    case DECOMP_OK:
324*0Sstevel@tonic-gate 					p = dbuf;
325*0Sstevel@tonic-gate 					nb = d + dn - p;
326*0Sstevel@tonic-gate 					if ((d[0] & 1) == 0)
327*0Sstevel@tonic-gate 					    --dn;
328*0Sstevel@tonic-gate 					--dn;
329*0Sstevel@tonic-gate 					if (dn > mru)
330*0Sstevel@tonic-gate 					    printf("     ERROR: decompressed length (%d) > MRU (%d)\n", dn, mru);
331*0Sstevel@tonic-gate 					break;
332*0Sstevel@tonic-gate 				    case DECOMP_ERROR:
333*0Sstevel@tonic-gate 					printf("     DECOMPRESSION ERROR\n");
334*0Sstevel@tonic-gate 					pkt->flags |= CCP_ERROR;
335*0Sstevel@tonic-gate 					break;
336*0Sstevel@tonic-gate 				    case DECOMP_FATALERROR:
337*0Sstevel@tonic-gate 					printf("     FATAL DECOMPRESSION ERROR\n");
338*0Sstevel@tonic-gate 					pkt->flags |= CCP_FATALERROR;
339*0Sstevel@tonic-gate 					break;
340*0Sstevel@tonic-gate 				    }
341*0Sstevel@tonic-gate 				}
342*0Sstevel@tonic-gate 			    } else if (pkt->state
343*0Sstevel@tonic-gate 				       && (pkt->flags & CCP_DECOMP_RUN)) {
344*0Sstevel@tonic-gate 				pkt->comp->incomp(pkt->state, r, endp - r);
345*0Sstevel@tonic-gate 			    }
346*0Sstevel@tonic-gate 			}
347*0Sstevel@tonic-gate 			do {
348*0Sstevel@tonic-gate 			    nl = nb < 16? nb: 16;
349*0Sstevel@tonic-gate 			    printf("%s ", q);
350*0Sstevel@tonic-gate 			    for (k = 0; k < nl; ++k)
351*0Sstevel@tonic-gate 				printf(" %.2x", p[k]);
352*0Sstevel@tonic-gate 			    for (; k < 16; ++k)
353*0Sstevel@tonic-gate 				printf("   ");
354*0Sstevel@tonic-gate 			    printf("  ");
355*0Sstevel@tonic-gate 			    for (k = 0; k < nl; ++k) {
356*0Sstevel@tonic-gate 				c = p[k];
357*0Sstevel@tonic-gate 				putchar((' ' <= c && c <= '~')? c: '.');
358*0Sstevel@tonic-gate 			    }
359*0Sstevel@tonic-gate 			    printf("\n");
360*0Sstevel@tonic-gate 			    q = "    ";
361*0Sstevel@tonic-gate 			    p += nl;
362*0Sstevel@tonic-gate 			    nb -= nl;
363*0Sstevel@tonic-gate 			} while (nb > 0);
364*0Sstevel@tonic-gate 			if (fcs != PPP_GOODFCS)
365*0Sstevel@tonic-gate 			    printf("     BAD FCS: (residue = %x)\n", fcs);
366*0Sstevel@tonic-gate 		    }
367*0Sstevel@tonic-gate 		    break;
368*0Sstevel@tonic-gate 		case '}':
369*0Sstevel@tonic-gate 		    if (!pkt->esc) {
370*0Sstevel@tonic-gate 			pkt->esc = 1;
371*0Sstevel@tonic-gate 			break;
372*0Sstevel@tonic-gate 		    }
373*0Sstevel@tonic-gate 		    /* else fall through */
374*0Sstevel@tonic-gate 		default:
375*0Sstevel@tonic-gate 		    if (pkt->esc) {
376*0Sstevel@tonic-gate 			c ^= 0x20;
377*0Sstevel@tonic-gate 			pkt->esc = 0;
378*0Sstevel@tonic-gate 		    }
379*0Sstevel@tonic-gate 		    pkt->buf[pkt->cnt++] = c;
380*0Sstevel@tonic-gate 		    break;
381*0Sstevel@tonic-gate 		}
382*0Sstevel@tonic-gate 	    }
383*0Sstevel@tonic-gate 	    break;
384*0Sstevel@tonic-gate 	case RECMARK_ENDSEND:
385*0Sstevel@tonic-gate 	case RECMARK_ENDRECV:
386*0Sstevel@tonic-gate 	    if (reverse)
387*0Sstevel@tonic-gate 		c = c==RECMARK_ENDSEND ? RECMARK_ENDRECV : RECMARK_ENDSEND;
388*0Sstevel@tonic-gate 	    dir = c==RECMARK_ENDSEND ? "send": "recv";
389*0Sstevel@tonic-gate 	    pkt = c==RECMARK_ENDSEND ? &spkt: &rpkt;
390*0Sstevel@tonic-gate 	    printf("end %s", dir);
391*0Sstevel@tonic-gate 	    if (pkt->cnt > 0)
392*0Sstevel@tonic-gate 		printf("  [%d bytes in incomplete packet]", pkt->cnt);
393*0Sstevel@tonic-gate 	    printf("\n");
394*0Sstevel@tonic-gate 	    break;
395*0Sstevel@tonic-gate 	case RECMARK_TIMEDELTA32:
396*0Sstevel@tonic-gate 	case RECMARK_TIMEDELTA8:
397*0Sstevel@tonic-gate 	case RECMARK_TIMESTART:
398*0Sstevel@tonic-gate 	    show_time(f, c);
399*0Sstevel@tonic-gate 	    break;
400*0Sstevel@tonic-gate 	default:
401*0Sstevel@tonic-gate 	    printf("?%.2x\n");
402*0Sstevel@tonic-gate 	}
403*0Sstevel@tonic-gate     }
404*0Sstevel@tonic-gate }
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate extern struct compressor ppp_bsd_compress, ppp_deflate;
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate struct compressor *compressors[] = {
409*0Sstevel@tonic-gate #if DO_BSD_COMPRESS
410*0Sstevel@tonic-gate     &ppp_bsd_compress,
411*0Sstevel@tonic-gate #endif
412*0Sstevel@tonic-gate #if DO_DEFLATE
413*0Sstevel@tonic-gate     &ppp_deflate,
414*0Sstevel@tonic-gate #endif
415*0Sstevel@tonic-gate     NULL
416*0Sstevel@tonic-gate };
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate handle_ccp(cp, dp, len)
419*0Sstevel@tonic-gate     struct pkt *cp;
420*0Sstevel@tonic-gate     u_char *dp;
421*0Sstevel@tonic-gate     int len;
422*0Sstevel@tonic-gate {
423*0Sstevel@tonic-gate     int clen;
424*0Sstevel@tonic-gate     struct compressor **comp;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate     if (len < CCP_HDRLEN)
427*0Sstevel@tonic-gate 	return;
428*0Sstevel@tonic-gate     clen = CCP_LENGTH(dp);
429*0Sstevel@tonic-gate     if (clen > len)
430*0Sstevel@tonic-gate 	return;
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate     switch (CCP_CODE(dp)) {
433*0Sstevel@tonic-gate     case CCP_CONFACK:
434*0Sstevel@tonic-gate 	cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
435*0Sstevel@tonic-gate 	if (clen < CCP_HDRLEN + CCP_OPT_MINLEN
436*0Sstevel@tonic-gate 	    || clen < CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN))
437*0Sstevel@tonic-gate 	    break;
438*0Sstevel@tonic-gate 	dp += CCP_HDRLEN;
439*0Sstevel@tonic-gate 	clen -= CCP_HDRLEN;
440*0Sstevel@tonic-gate 	for (comp = compressors; *comp != NULL; ++comp) {
441*0Sstevel@tonic-gate 	    if ((*comp)->compress_proto == dp[0]) {
442*0Sstevel@tonic-gate 		if (cp->state != NULL) {
443*0Sstevel@tonic-gate 		    (*cp->comp->decomp_free)(cp->state);
444*0Sstevel@tonic-gate 		    cp->state = NULL;
445*0Sstevel@tonic-gate 		}
446*0Sstevel@tonic-gate 		cp->comp = *comp;
447*0Sstevel@tonic-gate 		cp->state = (*comp)->decomp_alloc(dp, CCP_OPT_LENGTH(dp));
448*0Sstevel@tonic-gate 		cp->flags |= CCP_ISUP;
449*0Sstevel@tonic-gate 		if (cp->state != NULL
450*0Sstevel@tonic-gate 		    && (*cp->comp->decomp_init)
451*0Sstevel@tonic-gate 		        (cp->state, dp, clen, 0, 0, 8192, 1))
452*0Sstevel@tonic-gate 		    cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
453*0Sstevel@tonic-gate 		break;
454*0Sstevel@tonic-gate 	    }
455*0Sstevel@tonic-gate 	}
456*0Sstevel@tonic-gate 	break;
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate     case CCP_CONFNAK:
459*0Sstevel@tonic-gate     case CCP_CONFREJ:
460*0Sstevel@tonic-gate 	cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
461*0Sstevel@tonic-gate 	break;
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate     case CCP_RESETACK:
464*0Sstevel@tonic-gate 	if (cp->flags & CCP_ISUP) {
465*0Sstevel@tonic-gate 	    if (cp->state && (cp->flags & CCP_DECOMP_RUN)) {
466*0Sstevel@tonic-gate 		(*cp->comp->decomp_reset)(cp->state);
467*0Sstevel@tonic-gate 		cp->flags &= ~CCP_ERROR;
468*0Sstevel@tonic-gate 	    }
469*0Sstevel@tonic-gate 	}
470*0Sstevel@tonic-gate 	break;
471*0Sstevel@tonic-gate     }
472*0Sstevel@tonic-gate }
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate show_time(f, c)
475*0Sstevel@tonic-gate     FILE *f;
476*0Sstevel@tonic-gate     int c;
477*0Sstevel@tonic-gate {
478*0Sstevel@tonic-gate     time_t t;
479*0Sstevel@tonic-gate     int n;
480*0Sstevel@tonic-gate     struct tm *tm;
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate     if (c == RECMARK_TIMESTART) {
483*0Sstevel@tonic-gate 	t = getc(f);
484*0Sstevel@tonic-gate 	t = (t << 8) + getc(f);
485*0Sstevel@tonic-gate 	t = (t << 8) + getc(f);
486*0Sstevel@tonic-gate 	t = (t << 8) + getc(f);
487*0Sstevel@tonic-gate 	printf("start %s", ctime(&t));
488*0Sstevel@tonic-gate 	start_time = t;
489*0Sstevel@tonic-gate 	start_time_tenths = 0;
490*0Sstevel@tonic-gate 	tot_sent = tot_rcvd = 0;
491*0Sstevel@tonic-gate     } else {
492*0Sstevel@tonic-gate 	n = getc(f);
493*0Sstevel@tonic-gate 	if (c == RECMARK_TIMEDELTA32) {
494*0Sstevel@tonic-gate 	    for (c = 3; c > 0; --c)
495*0Sstevel@tonic-gate 		n = (n << 8) + getc(f);
496*0Sstevel@tonic-gate 	}
497*0Sstevel@tonic-gate 	if (abs_times) {
498*0Sstevel@tonic-gate 	    n += start_time_tenths;
499*0Sstevel@tonic-gate 	    start_time += n / 10;
500*0Sstevel@tonic-gate 	    start_time_tenths = n % 10;
501*0Sstevel@tonic-gate 	    tm = localtime(&start_time);
502*0Sstevel@tonic-gate 	    printf("time  %.2d:%.2d:%.2d.%d", tm->tm_hour, tm->tm_min,
503*0Sstevel@tonic-gate 		   tm->tm_sec, start_time_tenths);
504*0Sstevel@tonic-gate 	    printf("  (sent %d, rcvd %d)\n", tot_sent, tot_rcvd);
505*0Sstevel@tonic-gate 	} else
506*0Sstevel@tonic-gate 	    printf("time  %.1fs\n", (double) n / 10);
507*0Sstevel@tonic-gate     }
508*0Sstevel@tonic-gate }
509