xref: /plan9/sys/src/cmd/cifs/netbios.c (revision 671dfc474d1a5bcbeda8be1356d2abfa05b91489)
1*671dfc47SDavid du Colombier /*
2*671dfc47SDavid du Colombier  * netbios dial, read, write
3*671dfc47SDavid du Colombier  */
4*671dfc47SDavid du Colombier 
5*671dfc47SDavid du Colombier #include <u.h>
6*671dfc47SDavid du Colombier #include <libc.h>
7*671dfc47SDavid du Colombier #include <ctype.h>
8*671dfc47SDavid du Colombier #include <fcall.h>
9*671dfc47SDavid du Colombier #include <thread.h>
10*671dfc47SDavid du Colombier #include <9p.h>
11*671dfc47SDavid du Colombier #include "cifs.h"
12*671dfc47SDavid du Colombier 
13*671dfc47SDavid du Colombier enum {
14*671dfc47SDavid du Colombier 	MAXNBPKT		= 8096,		/* max netbios packet size */
15*671dfc47SDavid du Colombier 	NBquery			= 0,		/* packet type - query */
16*671dfc47SDavid du Colombier 
17*671dfc47SDavid du Colombier 	NBAdapterStatus		= 0x21,		/* get host interface info */
18*671dfc47SDavid du Colombier 	NBInternet		= 1,		/* scope for info */
19*671dfc47SDavid du Colombier 
20*671dfc47SDavid du Colombier 	NBmessage 		= 0x00,		/* Netbios packet types */
21*671dfc47SDavid du Colombier 	NBrequest 		= 0x81,
22*671dfc47SDavid du Colombier 	NBpositive,
23*671dfc47SDavid du Colombier 	NBnegative,
24*671dfc47SDavid du Colombier 	NBretarget,
25*671dfc47SDavid du Colombier 	NBkeepalive,
26*671dfc47SDavid du Colombier 
27*671dfc47SDavid du Colombier 	ISgroup			= 0x8000,
28*671dfc47SDavid du Colombier };
29*671dfc47SDavid du Colombier 
30*671dfc47SDavid du Colombier 
31*671dfc47SDavid du Colombier static char *NBerr[] = {
32*671dfc47SDavid du Colombier 	[0]	"not listening on called name",
33*671dfc47SDavid du Colombier 	[1]	"not listening for calling name",
34*671dfc47SDavid du Colombier 	[2]	"called name not present",
35*671dfc47SDavid du Colombier 	[3]	"insufficient resources",
36*671dfc47SDavid du Colombier 	[15]	"unspecified error"
37*671dfc47SDavid du Colombier };
38*671dfc47SDavid du Colombier 
39*671dfc47SDavid du Colombier 
40*671dfc47SDavid du Colombier static ulong
GL32(uchar ** p)41*671dfc47SDavid du Colombier GL32(uchar **p)
42*671dfc47SDavid du Colombier {
43*671dfc47SDavid du Colombier 	ulong n;
44*671dfc47SDavid du Colombier 
45*671dfc47SDavid du Colombier 	n  = *(*p)++;
46*671dfc47SDavid du Colombier 	n |= *(*p)++ << 8;
47*671dfc47SDavid du Colombier 	n |= *(*p)++ << 16;
48*671dfc47SDavid du Colombier 	n |= *(*p)++ << 24;
49*671dfc47SDavid du Colombier 	return n;
50*671dfc47SDavid du Colombier }
51*671dfc47SDavid du Colombier 
52*671dfc47SDavid du Colombier static ushort
GL16(uchar ** p)53*671dfc47SDavid du Colombier GL16(uchar **p)
54*671dfc47SDavid du Colombier {
55*671dfc47SDavid du Colombier 	ushort n;
56*671dfc47SDavid du Colombier 
57*671dfc47SDavid du Colombier 	n  = *(*p)++;
58*671dfc47SDavid du Colombier 	n |= *(*p)++ << 8;
59*671dfc47SDavid du Colombier 	return n;
60*671dfc47SDavid du Colombier }
61*671dfc47SDavid du Colombier 
62*671dfc47SDavid du Colombier void
Gmem(uchar ** p,void * v,int n)63*671dfc47SDavid du Colombier Gmem(uchar **p, void *v, int n)
64*671dfc47SDavid du Colombier {
65*671dfc47SDavid du Colombier 	uchar *str = v;
66*671dfc47SDavid du Colombier 
67*671dfc47SDavid du Colombier 	while(n--)
68*671dfc47SDavid du Colombier 		*str++ = *(*p)++;
69*671dfc47SDavid du Colombier }
70*671dfc47SDavid du Colombier 
71*671dfc47SDavid du Colombier 
72*671dfc47SDavid du Colombier static ulong
GB32(uchar ** p)73*671dfc47SDavid du Colombier GB32(uchar **p)
74*671dfc47SDavid du Colombier {
75*671dfc47SDavid du Colombier 	ulong n;
76*671dfc47SDavid du Colombier 
77*671dfc47SDavid du Colombier 	n  = *(*p)++ << 24;
78*671dfc47SDavid du Colombier 	n |= *(*p)++ << 16;
79*671dfc47SDavid du Colombier 	n |= *(*p)++ << 8;
80*671dfc47SDavid du Colombier 	n |= *(*p)++;
81*671dfc47SDavid du Colombier 	return n;
82*671dfc47SDavid du Colombier }
83*671dfc47SDavid du Colombier 
84*671dfc47SDavid du Colombier static ushort
GB16(uchar ** p)85*671dfc47SDavid du Colombier GB16(uchar **p)
86*671dfc47SDavid du Colombier {
87*671dfc47SDavid du Colombier 	ushort n;
88*671dfc47SDavid du Colombier 
89*671dfc47SDavid du Colombier 	n  = *(*p)++ << 8;
90*671dfc47SDavid du Colombier 	n |= *(*p)++;
91*671dfc47SDavid du Colombier 	return n;
92*671dfc47SDavid du Colombier }
93*671dfc47SDavid du Colombier 
94*671dfc47SDavid du Colombier static uchar
G8(uchar ** p)95*671dfc47SDavid du Colombier G8(uchar **p)
96*671dfc47SDavid du Colombier {
97*671dfc47SDavid du Colombier 	return *(*p)++;
98*671dfc47SDavid du Colombier }
99*671dfc47SDavid du Colombier 
100*671dfc47SDavid du Colombier static void
PB16(uchar ** p,uint n)101*671dfc47SDavid du Colombier PB16(uchar **p, uint n)
102*671dfc47SDavid du Colombier {
103*671dfc47SDavid du Colombier 	*(*p)++ = n >> 8;
104*671dfc47SDavid du Colombier 	*(*p)++ = n;
105*671dfc47SDavid du Colombier }
106*671dfc47SDavid du Colombier 
107*671dfc47SDavid du Colombier static void
P8(uchar ** p,uint n)108*671dfc47SDavid du Colombier P8(uchar **p, uint n)
109*671dfc47SDavid du Colombier {
110*671dfc47SDavid du Colombier 	*(*p)++ = n;
111*671dfc47SDavid du Colombier }
112*671dfc47SDavid du Colombier 
113*671dfc47SDavid du Colombier 
114*671dfc47SDavid du Colombier static void
nbname(uchar ** p,char * name,char pad)115*671dfc47SDavid du Colombier nbname(uchar **p, char *name, char pad)
116*671dfc47SDavid du Colombier {
117*671dfc47SDavid du Colombier 	char c;
118*671dfc47SDavid du Colombier 	int i;
119*671dfc47SDavid du Colombier 	int done = 0;
120*671dfc47SDavid du Colombier 
121*671dfc47SDavid du Colombier 	*(*p)++ = 0x20;
122*671dfc47SDavid du Colombier 	for(i = 0; i < 16; i++) {
123*671dfc47SDavid du Colombier 		c = pad;
124*671dfc47SDavid du Colombier 		if(!done && name[i] == '\0')
125*671dfc47SDavid du Colombier 			done = 1;
126*671dfc47SDavid du Colombier 		if(!done)
127*671dfc47SDavid du Colombier 			c = toupper(name[i]);
128*671dfc47SDavid du Colombier 		*(*p)++ = ((uchar)c >> 4) + 'A';
129*671dfc47SDavid du Colombier 		*(*p)++ = (c & 0xf) + 'A';
130*671dfc47SDavid du Colombier 	}
131*671dfc47SDavid du Colombier 	*(*p)++ = 0;
132*671dfc47SDavid du Colombier }
133*671dfc47SDavid du Colombier 
134*671dfc47SDavid du Colombier int
calledname(char * host,char * name)135*671dfc47SDavid du Colombier calledname(char *host, char *name)
136*671dfc47SDavid du Colombier {
137*671dfc47SDavid du Colombier 	char *addr;
138*671dfc47SDavid du Colombier 	uchar buf[1024], *p;
139*671dfc47SDavid du Colombier 	static char tmp[20];
140*671dfc47SDavid du Colombier 	int num, flg, svs, j, i, fd, trn;
141*671dfc47SDavid du Colombier 
142*671dfc47SDavid du Colombier 	trn = (getpid() ^ time(0)) & 0xffff;
143*671dfc47SDavid du Colombier 	if((addr = netmkaddr(host, "udp", "137")) == nil)
144*671dfc47SDavid du Colombier 		return -1;
145*671dfc47SDavid du Colombier 
146*671dfc47SDavid du Colombier 	if((fd = dial(addr, "137", 0, 0)) < 0)
147*671dfc47SDavid du Colombier 		return -1;
148*671dfc47SDavid du Colombier 	p = buf;
149*671dfc47SDavid du Colombier 
150*671dfc47SDavid du Colombier 	PB16(&p, trn);			/* TRNid */
151*671dfc47SDavid du Colombier 	P8(&p, 0);			/* flags */
152*671dfc47SDavid du Colombier 	P8(&p, 0x10);			/* type */
153*671dfc47SDavid du Colombier 	PB16(&p, 1);			/* # questions */
154*671dfc47SDavid du Colombier 	PB16(&p, 0);			/* # answers */
155*671dfc47SDavid du Colombier 	PB16(&p, 0);			/* # authority RRs */
156*671dfc47SDavid du Colombier 	PB16(&p, 0);			/* # Aditional RRs */
157*671dfc47SDavid du Colombier 	nbname(&p, "*", 0);
158*671dfc47SDavid du Colombier 	PB16(&p, NBAdapterStatus);
159*671dfc47SDavid du Colombier 	PB16(&p, NBInternet);
160*671dfc47SDavid du Colombier 
161*671dfc47SDavid du Colombier 	if(Debug && strstr(Debug, "dump"))
162*671dfc47SDavid du Colombier 		xd(nil, buf, p-buf);
163*671dfc47SDavid du Colombier 
164*671dfc47SDavid du Colombier 	if(write(fd, buf, p-buf) != p-buf)
165*671dfc47SDavid du Colombier 		return -1;
166*671dfc47SDavid du Colombier 
167*671dfc47SDavid du Colombier 	p = buf;
168*671dfc47SDavid du Colombier 	for(i = 0; i < 3; i++){
169*671dfc47SDavid du Colombier 		memset(buf, 0, sizeof(buf));
170*671dfc47SDavid du Colombier 		alarm(NBNSTOUT);
171*671dfc47SDavid du Colombier 		read(fd, buf, sizeof(buf));
172*671dfc47SDavid du Colombier 		alarm(0);
173*671dfc47SDavid du Colombier 		if(GB16(&p) == trn)
174*671dfc47SDavid du Colombier 			break;
175*671dfc47SDavid du Colombier 	}
176*671dfc47SDavid du Colombier 	close(fd);
177*671dfc47SDavid du Colombier 	if(i >= 3)
178*671dfc47SDavid du Colombier 		return -1;
179*671dfc47SDavid du Colombier 
180*671dfc47SDavid du Colombier 	p = buf +56;
181*671dfc47SDavid du Colombier 	num = G8(&p);			/* number of names */
182*671dfc47SDavid du Colombier 
183*671dfc47SDavid du Colombier 	for(i = 0; i < num; i++){
184*671dfc47SDavid du Colombier 		memset(tmp, 0, sizeof(tmp));
185*671dfc47SDavid du Colombier 		Gmem(&p, tmp, 15);
186*671dfc47SDavid du Colombier 		svs = G8(&p);
187*671dfc47SDavid du Colombier 		flg = GB16(&p);
188*671dfc47SDavid du Colombier 		for(j = 14; j >= 0 && tmp[j] == ' '; j--)
189*671dfc47SDavid du Colombier 			tmp[j] = 0;
190*671dfc47SDavid du Colombier 		if(svs == 0 && !(flg & ISgroup))
191*671dfc47SDavid du Colombier 			strcpy(name, tmp);
192*671dfc47SDavid du Colombier 	}
193*671dfc47SDavid du Colombier 	return 0;
194*671dfc47SDavid du Colombier }
195*671dfc47SDavid du Colombier 
196*671dfc47SDavid du Colombier 
197*671dfc47SDavid du Colombier int
nbtdial(char * addr,char * called,char * sysname)198*671dfc47SDavid du Colombier nbtdial(char *addr, char *called, char *sysname)
199*671dfc47SDavid du Colombier {
200*671dfc47SDavid du Colombier 	char redir[20];
201*671dfc47SDavid du Colombier 	uchar *p, *lenp, buf[1024];
202*671dfc47SDavid du Colombier 	int type, len, err, fd, nkeepalive, nretarg;
203*671dfc47SDavid du Colombier 
204*671dfc47SDavid du Colombier 	nretarg = 0;
205*671dfc47SDavid du Colombier 	nkeepalive = 0;
206*671dfc47SDavid du Colombier Redial:
207*671dfc47SDavid du Colombier 	if((addr = netmkaddr(addr, "tcp", "139")) == nil ||
208*671dfc47SDavid du Colombier 	    (fd = dial(addr, 0, 0, 0)) < 0)
209*671dfc47SDavid du Colombier 		return -1;
210*671dfc47SDavid du Colombier 
211*671dfc47SDavid du Colombier 	memset(buf, 0, sizeof(buf));
212*671dfc47SDavid du Colombier 
213*671dfc47SDavid du Colombier 	p = buf;
214*671dfc47SDavid du Colombier 	P8(&p, NBrequest);		/* type */
215*671dfc47SDavid du Colombier 	P8(&p, 0);			/* flags */
216*671dfc47SDavid du Colombier 	lenp = p; PB16(&p, 0);		/* length placeholder */
217*671dfc47SDavid du Colombier 	nbname(&p, called, ' ');	/* remote NetBios name */
218*671dfc47SDavid du Colombier 	nbname(&p, sysname, ' ');	/* our machine name */
219*671dfc47SDavid du Colombier 	PB16(&lenp, p-lenp -2);		/* length re-write */
220*671dfc47SDavid du Colombier 
221*671dfc47SDavid du Colombier 	if(Debug && strstr(Debug, "dump"))
222*671dfc47SDavid du Colombier 		xd(nil, buf, p-buf);
223*671dfc47SDavid du Colombier 	if(write(fd, buf, p-buf) != p-buf)
224*671dfc47SDavid du Colombier 		goto Error;
225*671dfc47SDavid du Colombier Reread:
226*671dfc47SDavid du Colombier 	p = buf;
227*671dfc47SDavid du Colombier 	memset(buf, 0, sizeof(buf));
228*671dfc47SDavid du Colombier 	if(readn(fd, buf, 4) < 4)
229*671dfc47SDavid du Colombier 		goto Error;
230*671dfc47SDavid du Colombier 
231*671dfc47SDavid du Colombier 	type = G8(&p);
232*671dfc47SDavid du Colombier 	G8(&p);				/* flags */
233*671dfc47SDavid du Colombier 	len = GB16(&p);
234*671dfc47SDavid du Colombier 
235*671dfc47SDavid du Colombier 	if(readn(fd, buf +4, len -4) < len -4)
236*671dfc47SDavid du Colombier 		goto Error;
237*671dfc47SDavid du Colombier 
238*671dfc47SDavid du Colombier 	if(Debug && strstr(Debug, "dump"))
239*671dfc47SDavid du Colombier 		xd(nil, buf, len+4);
240*671dfc47SDavid du Colombier 
241*671dfc47SDavid du Colombier 	switch(type) {
242*671dfc47SDavid du Colombier 	case NBpositive:
243*671dfc47SDavid du Colombier 		return fd;
244*671dfc47SDavid du Colombier 	case NBnegative:
245*671dfc47SDavid du Colombier 		if(len < 1) {
246*671dfc47SDavid du Colombier 			werrstr("nbdial: bad error pkt");
247*671dfc47SDavid du Colombier 			goto Error;
248*671dfc47SDavid du Colombier 		}
249*671dfc47SDavid du Colombier 		err = G8(&p);
250*671dfc47SDavid du Colombier 		if(err < 0 || err > nelem(NBerr) || NBerr[err] == nil)
251*671dfc47SDavid du Colombier 			werrstr("NBT: %d - unknown error", err);
252*671dfc47SDavid du Colombier 		else
253*671dfc47SDavid du Colombier 			werrstr("NBT: %s", NBerr[err]);
254*671dfc47SDavid du Colombier 
255*671dfc47SDavid du Colombier 		goto Error;
256*671dfc47SDavid du Colombier 	case NBkeepalive:
257*671dfc47SDavid du Colombier 		if(++nkeepalive >= 16){
258*671dfc47SDavid du Colombier 			werrstr("nbdial: too many keepalives");
259*671dfc47SDavid du Colombier 			goto Error;
260*671dfc47SDavid du Colombier 		}
261*671dfc47SDavid du Colombier 		goto Reread;
262*671dfc47SDavid du Colombier 
263*671dfc47SDavid du Colombier 	case NBretarget:
264*671dfc47SDavid du Colombier 		if(++nretarg >= 16) {
265*671dfc47SDavid du Colombier 			werrstr("nbdial: too many redirects");
266*671dfc47SDavid du Colombier 			goto Error;
267*671dfc47SDavid du Colombier 		}
268*671dfc47SDavid du Colombier 		if(len < 4) {
269*671dfc47SDavid du Colombier 			werrstr("nbdial: bad redirect pkt");
270*671dfc47SDavid du Colombier 			goto Error;
271*671dfc47SDavid du Colombier 		}
272*671dfc47SDavid du Colombier 		sprint(redir, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
273*671dfc47SDavid du Colombier 		addr = redir;
274*671dfc47SDavid du Colombier 		goto Redial;
275*671dfc47SDavid du Colombier 
276*671dfc47SDavid du Colombier 	default:
277*671dfc47SDavid du Colombier 		werrstr("nbdial: 0x%x - unknown packet in netbios handshake", type);
278*671dfc47SDavid du Colombier 		goto Error;
279*671dfc47SDavid du Colombier 	}
280*671dfc47SDavid du Colombier Error:
281*671dfc47SDavid du Colombier 	close(fd);
282*671dfc47SDavid du Colombier 	return -1;
283*671dfc47SDavid du Colombier }
284*671dfc47SDavid du Colombier 
285*671dfc47SDavid du Colombier void
nbthdr(Pkt * p)286*671dfc47SDavid du Colombier nbthdr(Pkt *p)
287*671dfc47SDavid du Colombier {
288*671dfc47SDavid du Colombier 	p->pos = p->buf;
289*671dfc47SDavid du Colombier 	memset(p->buf, 0xa5, MTU);
290*671dfc47SDavid du Colombier 
291*671dfc47SDavid du Colombier 	p8(p, NBmessage);		/* type */
292*671dfc47SDavid du Colombier 	p8(p, 0);			/* flags */
293*671dfc47SDavid du Colombier 	pb16(p, 0);			/* length (filled in later) */
294*671dfc47SDavid du Colombier }
295*671dfc47SDavid du Colombier 
296*671dfc47SDavid du Colombier int
nbtrpc(Pkt * p)297*671dfc47SDavid du Colombier nbtrpc(Pkt *p)
298*671dfc47SDavid du Colombier {
299*671dfc47SDavid du Colombier 	int len, got, type, nkeep;
300*671dfc47SDavid du Colombier 
301*671dfc47SDavid du Colombier 	len = p->pos - p->buf;
302*671dfc47SDavid du Colombier 
303*671dfc47SDavid du Colombier 	p->pos = p->buf +2;
304*671dfc47SDavid du Colombier 	pb16(p, len - NBHDRLEN);	/* length */
305*671dfc47SDavid du Colombier 
306*671dfc47SDavid du Colombier 	if(Debug && strstr(Debug, "dump"))
307*671dfc47SDavid du Colombier 		xd("tx", p->buf, len);
308*671dfc47SDavid du Colombier 
309*671dfc47SDavid du Colombier 	alarm(NBRPCTOUT);
310*671dfc47SDavid du Colombier 	if(write(p->s->fd, p->buf, len) != len){
311*671dfc47SDavid du Colombier 		werrstr("nbtrpc: write failed - %r");
312*671dfc47SDavid du Colombier 		alarm(0);
313*671dfc47SDavid du Colombier 		return -1;
314*671dfc47SDavid du Colombier 	}
315*671dfc47SDavid du Colombier 
316*671dfc47SDavid du Colombier 	nkeep = 0;
317*671dfc47SDavid du Colombier retry:
318*671dfc47SDavid du Colombier 	p->pos = p->buf;
319*671dfc47SDavid du Colombier 	memset(p->buf, 0xa5, MTU);
320*671dfc47SDavid du Colombier 
321*671dfc47SDavid du Colombier 	got = readn(p->s->fd, p->buf, NBHDRLEN);
322*671dfc47SDavid du Colombier 
323*671dfc47SDavid du Colombier 	if(got < NBHDRLEN){
324*671dfc47SDavid du Colombier 		werrstr("nbtrpc: short read - %r");
325*671dfc47SDavid du Colombier 		alarm(0);
326*671dfc47SDavid du Colombier 		return -1;
327*671dfc47SDavid du Colombier 	}
328*671dfc47SDavid du Colombier 	p->eop = p->buf + got;
329*671dfc47SDavid du Colombier 
330*671dfc47SDavid du Colombier 	type = g8(p);			/* NBT type (session) */
331*671dfc47SDavid du Colombier 	if(type == NBkeepalive){
332*671dfc47SDavid du Colombier 		if(++nkeep > 16) {
333*671dfc47SDavid du Colombier 			werrstr("nbtrpc: too many keepalives (%d attempts)", nkeep);
334*671dfc47SDavid du Colombier 			alarm(0);
335*671dfc47SDavid du Colombier 			return -1;
336*671dfc47SDavid du Colombier 		}
337*671dfc47SDavid du Colombier 		goto retry;
338*671dfc47SDavid du Colombier 	}
339*671dfc47SDavid du Colombier 
340*671dfc47SDavid du Colombier 	g8(p);				/* NBT flags (none) */
341*671dfc47SDavid du Colombier 
342*671dfc47SDavid du Colombier 	len = gb16(p);			/* NBT payload length */
343*671dfc47SDavid du Colombier 	if((len +NBHDRLEN) > MTU){
344*671dfc47SDavid du Colombier 		werrstr("nbtrpc: packet bigger than MTU, (%d > %d)", len, MTU);
345*671dfc47SDavid du Colombier 		alarm(0);
346*671dfc47SDavid du Colombier 		return -1;
347*671dfc47SDavid du Colombier 	}
348*671dfc47SDavid du Colombier 
349*671dfc47SDavid du Colombier 	got = readn(p->s->fd, p->buf +NBHDRLEN, len);
350*671dfc47SDavid du Colombier 	alarm(0);
351*671dfc47SDavid du Colombier 
352*671dfc47SDavid du Colombier 	if(Debug && strstr(Debug, "dump"))
353*671dfc47SDavid du Colombier 		xd("rx", p->buf, got +NBHDRLEN);
354*671dfc47SDavid du Colombier 
355*671dfc47SDavid du Colombier 	if(got < 0)
356*671dfc47SDavid du Colombier 		return -1;
357*671dfc47SDavid du Colombier 	p->eop = p->buf + got +NBHDRLEN;
358*671dfc47SDavid du Colombier 	return got+NBHDRLEN;
359*671dfc47SDavid du Colombier }
360*671dfc47SDavid du Colombier 
361*671dfc47SDavid du Colombier 
362*671dfc47SDavid du Colombier void
xd(char * str,void * buf,int n)363*671dfc47SDavid du Colombier xd(char *str, void *buf, int n)
364*671dfc47SDavid du Colombier {
365*671dfc47SDavid du Colombier 	int fd, flg, flags2, cmd;
366*671dfc47SDavid du Colombier 	uint sum;
367*671dfc47SDavid du Colombier 	long err;
368*671dfc47SDavid du Colombier 	uchar *p, *end;
369*671dfc47SDavid du Colombier 
370*671dfc47SDavid du Colombier 	if(n == 0)
371*671dfc47SDavid du Colombier 		return;
372*671dfc47SDavid du Colombier 
373*671dfc47SDavid du Colombier 	p = buf;
374*671dfc47SDavid du Colombier 	end = (uchar *)buf +n;
375*671dfc47SDavid du Colombier 
376*671dfc47SDavid du Colombier 	if(Debug && strstr(Debug, "log") != nil){
377*671dfc47SDavid du Colombier 		if((fd = open("pkt.log", ORDWR)) == -1)
378*671dfc47SDavid du Colombier 			return;
379*671dfc47SDavid du Colombier 		seek(fd, 0, 2);
380*671dfc47SDavid du Colombier 		fprint(fd, "%d	", 0);
381*671dfc47SDavid du Colombier 		while(p < end)
382*671dfc47SDavid du Colombier 			fprint(fd, "%02x ", *p++);
383*671dfc47SDavid du Colombier 		fprint(fd, "\n");
384*671dfc47SDavid du Colombier 		close(fd);
385*671dfc47SDavid du Colombier 		return;
386*671dfc47SDavid du Colombier 	}
387*671dfc47SDavid du Colombier 
388*671dfc47SDavid du Colombier 	if(!str)
389*671dfc47SDavid du Colombier 		goto Raw;
390*671dfc47SDavid du Colombier 
391*671dfc47SDavid du Colombier 	p = (uchar *)buf + 4;
392*671dfc47SDavid du Colombier 	if(GL32(&p) == 0x424d53ff){
393*671dfc47SDavid du Colombier 		buf = (uchar *)buf + 4;
394*671dfc47SDavid du Colombier 		n -= 4;
395*671dfc47SDavid du Colombier 	}
396*671dfc47SDavid du Colombier 	end = (uchar *)buf + n;
397*671dfc47SDavid du Colombier 
398*671dfc47SDavid du Colombier 	sum = 0;
399*671dfc47SDavid du Colombier 	p = buf;
400*671dfc47SDavid du Colombier 	while(p < end)
401*671dfc47SDavid du Colombier 		sum += *p++;
402*671dfc47SDavid du Colombier 	p = buf;
403*671dfc47SDavid du Colombier 
404*671dfc47SDavid du Colombier 	fprint(2, "%s : len=%ud sum=%d\n", str, n, sum);
405*671dfc47SDavid du Colombier 
406*671dfc47SDavid du Colombier 	fprint(2, "mag=0x%ulx ", GL32(&p));
407*671dfc47SDavid du Colombier 	fprint(2, "cmd=0x%ux ", cmd = G8(&p));
408*671dfc47SDavid du Colombier 	fprint(2, "err=0x%ulx ", err=GL32(&p));
409*671dfc47SDavid du Colombier 	fprint(2, "flg=0x%02ux ", flg = G8(&p));
410*671dfc47SDavid du Colombier 	fprint(2, "flg2=0x%04ux\n", flags2= GL16(&p));
411*671dfc47SDavid du Colombier 	fprint(2, "dfs=%s\n", (flags2 & FL2_DFS)? "y": "n");
412*671dfc47SDavid du Colombier 
413*671dfc47SDavid du Colombier 	fprint(2, "pidl=%ud ", GL16(&p));
414*671dfc47SDavid du Colombier 	fprint(2, "res=%uld ", GL32(&p));
415*671dfc47SDavid du Colombier 	fprint(2, "sid=%ud ", GL16(&p));
416*671dfc47SDavid du Colombier 	fprint(2, "seq=0x%ux ", GL16(&p));
417*671dfc47SDavid du Colombier 	fprint(2, "pad=%ud ", GL16(&p));
418*671dfc47SDavid du Colombier 
419*671dfc47SDavid du Colombier 	fprint(2, "tid=%ud ", GL16(&p));
420*671dfc47SDavid du Colombier 	fprint(2, "pid=%ud ", GL16(&p));
421*671dfc47SDavid du Colombier 	fprint(2, "uid=%ud ", GL16(&p));
422*671dfc47SDavid du Colombier 	fprint(2, "mid=%ud\n", GL16(&p));
423*671dfc47SDavid du Colombier 
424*671dfc47SDavid du Colombier 	if(cmd == 0x32 && (flg & 0x80) == 0){		/* TRANS 2, TX */
425*671dfc47SDavid du Colombier 		fprint(2, "words=%ud ", G8(&p));
426*671dfc47SDavid du Colombier 		fprint(2, "totparams=%ud ", GL16(&p));
427*671dfc47SDavid du Colombier 		fprint(2, "totdata=%ud ", GL16(&p));
428*671dfc47SDavid du Colombier 		fprint(2, "maxparam=%ud ", GL16(&p));
429*671dfc47SDavid du Colombier 		fprint(2, "maxdata=%ud\n", GL16(&p));
430*671dfc47SDavid du Colombier 		fprint(2, "maxsetup=%ud ", G8(&p));
431*671dfc47SDavid du Colombier 		fprint(2, "reserved=%ud ", G8(&p));
432*671dfc47SDavid du Colombier 		fprint(2, "flags=%ud ", GL16(&p));
433*671dfc47SDavid du Colombier 		fprint(2, "timeout=%uld\n", GL32(&p));
434*671dfc47SDavid du Colombier 		fprint(2, "reserved=%ud ", GL16(&p));
435*671dfc47SDavid du Colombier 		fprint(2, "paramcnt=%ud ", GL16(&p));
436*671dfc47SDavid du Colombier 		fprint(2, "paramoff=%ud ", GL16(&p));
437*671dfc47SDavid du Colombier 		fprint(2, "datacnt=%ud ", GL16(&p));
438*671dfc47SDavid du Colombier 		fprint(2, "dataoff=%ud ", GL16(&p));
439*671dfc47SDavid du Colombier 		fprint(2, "setupcnt=%ud ", G8(&p));
440*671dfc47SDavid du Colombier 		fprint(2, "reserved=%ud\n", G8(&p));
441*671dfc47SDavid du Colombier 		fprint(2, "trans2=0x%02x ", GL16(&p));
442*671dfc47SDavid du Colombier 		fprint(2, "data-words=%d ", G8(&p));
443*671dfc47SDavid du Colombier 		fprint(2, "padding=%d\n", G8(&p));
444*671dfc47SDavid du Colombier 	}
445*671dfc47SDavid du Colombier 	if(cmd == 0x32 && (flg & 0x80) == 0x80){	/* TRANS 2, RX */
446*671dfc47SDavid du Colombier 		fprint(2, "words=%ud ", G8(&p));
447*671dfc47SDavid du Colombier 		fprint(2, "totparams=%ud ", GL16(&p));
448*671dfc47SDavid du Colombier 		fprint(2, "totdata=%ud ", GL16(&p));
449*671dfc47SDavid du Colombier 		fprint(2, "reserved=%ud ", GL16(&p));
450*671dfc47SDavid du Colombier 		fprint(2, "paramcnt=%ud\n", GL16(&p));
451*671dfc47SDavid du Colombier 		fprint(2, "paramoff=%ud ", GL16(&p));
452*671dfc47SDavid du Colombier 		fprint(2, "paramdisp=%ud ", GL16(&p));
453*671dfc47SDavid du Colombier 		fprint(2, "datacnt=%ud\n", GL16(&p));
454*671dfc47SDavid du Colombier 		fprint(2, "dataoff=%ud ", GL16(&p));
455*671dfc47SDavid du Colombier 		fprint(2, "datadisp=%ud ", GL16(&p));
456*671dfc47SDavid du Colombier 		fprint(2, "setupcnt=%ud ", G8(&p));
457*671dfc47SDavid du Colombier 		fprint(2, "reserved=%ud\n", G8(&p));
458*671dfc47SDavid du Colombier 	}
459*671dfc47SDavid du Colombier 	if(err)
460*671dfc47SDavid du Colombier 		if(flags2 & FL2_NT_ERRCODES)
461*671dfc47SDavid du Colombier 			fprint(2, "err=%s\n", nterrstr(err));
462*671dfc47SDavid du Colombier 		else
463*671dfc47SDavid du Colombier 			fprint(2, "err=%s\n", doserrstr(err));
464*671dfc47SDavid du Colombier Raw:
465*671dfc47SDavid du Colombier 	fprint(2, "\n");
466*671dfc47SDavid du Colombier 	for(; p < end; p++){
467*671dfc47SDavid du Colombier 		if((p - (uchar *)buf) % 16 == 0)
468*671dfc47SDavid du Colombier 			fprint(2, "\n%06lx\t", p - (uchar *)buf);
469*671dfc47SDavid du Colombier 		if(isprint((char)*p))
470*671dfc47SDavid du Colombier 			fprint(2, "%c  ", (char )*p);
471*671dfc47SDavid du Colombier 		else
472*671dfc47SDavid du Colombier 			fprint(2, "%02ux ", *p);
473*671dfc47SDavid du Colombier 	}
474*671dfc47SDavid du Colombier 	fprint(2, "\n");
475*671dfc47SDavid du Colombier }
476