shithub: riscv

Download patch

ref: 8f5375fa61acb4da83e855e40402d12be01a8c68
parent: b15accceac5f79106bb6a115985eed63284171cf
author: cinap_lenrek <cinap_lenrek@centraldogma>
date: Mon Jan 16 13:42:16 EST 2012

cifs: updated cifs/smb client to quintiles latest version

--- a/sys/man/4/cifs
+++ b/sys/man/4/cifs
@@ -20,6 +20,9 @@
 ] [
 .B -m
 .I mntpnt
+] [
+.B -t
+.I dfs-timeout
 ]
 .I host
 [
@@ -32,8 +35,7 @@
 (shares or trees in MS terminology) published by such servers.
 .PP
 The root of the mounted directory contains one subdirectory per share,
-always named in lower case, and a few virtual files of mixed case which
-give additional server, session, share, and user information.
+and a few virtual files give additional information.
 The arguments are:
 .TF "-a\fI auth-method"
 .PD
@@ -71,6 +73,14 @@
 .B -D
 9P request debug.
 .TP
+.B -i 
+By default 
+.I cifs(4)
+attempts to enforce case significance file and directory names, though objects
+which differ only in their case still cannot co-exist in the same directory. The
+.B -i
+option disables this behaveiour.
+.TP
 .BI -k " keyparam"
 lists extra parameters which will be passed to
 .IR factotum (4)
@@ -112,6 +122,11 @@
 post the service as
 .BI /srv/ srvname.
 .TP
+.BI -t " dfs-timeout"
+sets the timeout in for DFS redirections - it defaults to 100ms.
+This is a reasonable minimum, it should have a value just greater than
+the RTT to the most distant server being accessed.
+.TP
 .I host
 The address of the remote server to connect to.
 .TP
@@ -126,7 +141,7 @@
 .TP
 .B Shares
 Contains a list of the currently attached shares,
-with fields giving the share name,  disk free space / capacity, the share type,
+with fields giving the share name, the share type, disk free space / capacity, 
 and a descriptive comment from the server.
 .TP
 .B Connection
@@ -161,27 +176,48 @@
 giving the features of that OS.
 .TP
 .B Dfsroot
-Top level DFS routing giving the DFS link type, time to live of the data,
-proximity of the server, the Netbios or DNS name and
-a physical path or a machine that this maps to.
-.IP
-DNS paths are usually assigned dynamicially as a form of load balancing.
+Lists the top level DFS domains and the servers that
+provision them.
+.TP
+.B Dfscache
+Contents of the DFS referal cache, giving the path prefix,
+the expiry time (or -1 for never), the measured RTT to the server
+in milliseconds, the server proximity (0 is local), the server name,
+and the share name on that server.
+.SH COMPATIBILITY
+.I Cifs
+has been tested against
+.IR aquarela (8),
+Windows 95, NT4.0sp6,
+Windows server 2003, Windows server 2003, WinXP pro, 
+Samba 2.0 (Pluto VideoSpace), and Samba 3.0.
+.LP
+Windows Vista require a hotfix (registry change)
+to support NTLMv2 without GSSAPI, see http://support.microsoft.com/kb/957441.
+Alternatively the
+.B -a
+option can be used to force
+.I cifs
+to use one of the less secure authentication mechnisms.
+.LP
+Windows 7 has dropped support for RAP, which is used to generate
+the synthetic files offered by
+.IR cifs .
+RAP is also used to enumerate the shares offered by the remote host so
+remote share names must always be specified on the command line.
+.LP
+The NetApp Filer was supported by earlier releases, however recent
+attempts to mount one have failed. Should a server be available it is
+likely that this could be easily fixed.
+.PP
 .SH SOURCE
 .B /sys/src/cmd/cifs
 .SH SEE ALSO
 .IR factotum (4),
-.IR cifsd (8)
+.IR aquarela (8)
 .SH BUGS
-NetApp Filer compatibility has not yet been tested; there may not be any.
+DFS support is unfinished, it will not follow referals that span servers.
 .PP
-DFS support is unfinished.
+Kerberos authentication is not supported.
 .PP
-Kerberos authentication is unfinished.
-.PP
 NetBios name resolution is not supported, though it is now rarely used.
-.PP
-.I Cifs
-has only been tested against
-aquarela, Windows 95, NT4.0sp6,
-Windows server 2003, WinXP pro, Samba 3.0, and Samba 2.0 (Pluto VideoSpace).
-No support is attempted for servers predating NT 4.0.
--- a/sys/src/cmd/cifs/auth-testcase.c
+++ b/sys/src/cmd/cifs/auth-testcase.c
@@ -137,31 +137,29 @@
 static int
 ntv2_blob(uchar *blob, int len, char *windom)
 {
-	int n;
-	uvlong nttime;
-	Rune r;
-	char *d;
+	uvlong t;
 	uchar *p;
 	enum {			/* name types */
 		Beof,		/* end of name list */
-		Bnetbios,	/* Netbios machine name */
+		Bhost,		/* Netbios host name */
 		Bdomain,	/* Windows Domain name (NT) */
-		Bdnsfqdn,	/* DNS Fully Qualified Domain Name */
-		Bdnsname,	/* DNS machine name (win2k) */
+		Bdnshost,	/* DNS host name */
+		Bdnsdomain,	/* DNS domain name */
 	};
 
 	p = blob;
-	*p++ = 1;		/* response type */
-	*p++ = 1;		/* max response type understood by client */
+	*p++ = 1;		/* 8bit: response type */
+	*p++ = 1;		/* 8bit: max response type understood by client */
 
+	*p++ = 0;		/* 16bit: reserved */
 	*p++ = 0;
-	*p++ = 0;		/* 2 bytes reserved */
 
+	*p++ = 0;		/* 32bit: unknown */
 	*p++ = 0;
 	*p++ = 0;
 	*p++ = 0;
-	*p++ = 0;		/* 4 bytes unknown */
 
+
 #ifdef NTLMV2_TEST
 	*p++ = 0xf0;
 	*p++ = 0x20;
@@ -172,18 +170,19 @@
 	*p++ = 0xbe;
 	*p++ = 0x01;
 #else
-	nttime = time(nil);	/* nt time now */
-	nttime = nttime + 11644473600LL;
-	nttime = nttime * 10000000LL;
-	*p++ = nttime & 0xff;
-	*p++ = (nttime >> 8) & 0xff;
-	*p++ = (nttime >> 16) & 0xff;
-	*p++ = (nttime >> 24) & 0xff;
-	*p++ = (nttime >> 32) & 0xff;
-	*p++ = (nttime >> 40) & 0xff;
-	*p++ = (nttime >> 48) & 0xff;
-	*p++ = (nttime >> 56) & 0xff;
+	t = time(nil);	/* 64bit: time in NT format */
+	t += 11644473600LL;
+	t *= 10000000LL;
+	*p++ = t;
+	*p++ = t >> 8;
+	*p++ = t >> 16;
+	*p++ = t >> 24;
+	*p++ = t >> 32;
+	*p++ = t >> 40;
+	*p++ = t >> 48;
+	*p++ = t >> 56;
 #endif
+
 #ifdef NTLMV2_TEST
 	*p++ = 0x05;
 	*p++ = 0x83;
@@ -195,38 +194,17 @@
 	*p++ = 0x6d;
 #else
 	genrandom(p, 8);
-	p += 8;			/* client nonce */
+	p += 8;			/* 64bit: client nonce */
 #endif
-	*p++ = 0x6f;
-	*p++ = 0;
-	*p++ = 0x6e;
-	*p++ = 0;		/* unknown data */
 
-	*p++ = Bdomain;
-	*p++ = 0;		/* name type */
-
-	n = utflen(windom) * 2;
-	*p++ = n;
-	*p++ = n >> 8;		/* name length */
-
-	d = windom;
-	while(*d && p - blob < len - 8){
-		d += chartorune(&r, d);
-		r = toupperrune(r);
-		*p++ = r;
-		*p++ = r >> 8;
-	}
-
+	*p++ = 0;		/* 32bit: unknown data */
 	*p++ = 0;
-	*p++ = Beof;		/* name type */
-
 	*p++ = 0;
-	*p++ = 0;		/* name length */
-
-	*p++ = 0x65;
 	*p++ = 0;
-	*p++ = 0;
-	*p++ = 0;		/* unknown data */
+
+	p += putname(p, len - (p-blob), windom, Bdomain);
+	p += putname(p, len - (p-blob), "", Beof);
+
 	return p - blob;
 }
 
--- a/sys/src/cmd/cifs/auth.c
+++ b/sys/src/cmd/cifs/auth.c
@@ -135,77 +135,80 @@
 
 
 static int
-ntv2_blob(uchar *blob, int len, char *windom)
+putname(uchar *buf, int len, char *name, int type)
 {
 	int n;
-	uvlong nttime;
 	Rune r;
 	char *d;
+	uchar *p = buf;
+
+	*p++ = type;
+	*p++ = 0;		/* 16bit: name type */
+
+	n = utflen(name) * 2;
+	*p++ = n;
+	*p++ = n >> 8;		/* 16bit: name length */
+
+	d = name;
+	while(*d != 0 && p-buf < len-8){
+		d += chartorune(&r, d);
+		r = toupperrune(r);
+		*p++ = r;
+			*p++ = r >> 8;
+	}			/* var: actual name */
+
+	return p - buf;
+}
+
+static int
+ntv2_blob(uchar *blob, int len, char *windom)
+{
+	uvlong t;
 	uchar *p;
 	enum {			/* name types */
 		Beof,		/* end of name list */
-		Bnetbios,	/* Netbios machine name */
+		Bhost,		/* Netbios host name */
 		Bdomain,	/* Windows Domain name (NT) */
-		Bdnsfqdn,	/* DNS Fully Qualified Domain Name */
-		Bdnsname,	/* DNS machine name (win2k) */
+		Bdnshost,	/* DNS host name */
+		Bdnsdomain,	/* DNS domain name */
 	};
 
 	p = blob;
-	*p++ = 1;		/* response type */
-	*p++ = 1;		/* max response type understood by client */
+	*p++ = 1;		/* 8bit: response type */
+	*p++ = 1;		/* 8bit: max response type understood by client */
 
+	*p++ = 0;		/* 16bit: reserved */
 	*p++ = 0;
-	*p++ = 0;		/* 2 bytes reserved */
 
+	*p++ = 0;		/* 32bit: unknown */
 	*p++ = 0;
 	*p++ = 0;
 	*p++ = 0;
-	*p++ = 0;		/* 4 bytes unknown */
 
-	nttime = time(nil);	/* nt time now */
-	nttime += 11644473600LL;
-	nttime *= 10000000LL;
-	*p++ = nttime;
-	*p++ = nttime >> 8;
-	*p++ = nttime >> 16;
-	*p++ = nttime >> 24;
-	*p++ = nttime >> 32;
-	*p++ = nttime >> 40;
-	*p++ = nttime >> 48;
-	*p++ = nttime >> 56;
+	t = time(nil);
+	t += 11644473600LL;
+	t *= 10000000LL;
 
+	*p++ = t;		/* 64bit: time in NT format */
+	*p++ = t >> 8;
+	*p++ = t >> 16;
+	*p++ = t >> 24;
+	*p++ = t >> 32;
+	*p++ = t >> 40;
+	*p++ = t >> 48;
+	*p++ = t >> 56;
+
 	genrandom(p, 8);
-	p += 8;			/* client nonce */
-	*p++ = 0x6f;
-	*p++ = 0;
-	*p++ = 0x6e;
-	*p++ = 0;		/* unknown data */
+	p += 8;			/* 64bit: client nonce */
 
-	*p++ = Bdomain;
-	*p++ = 0;		/* name type */
-
-	n = utflen(windom) * 2;
-	*p++ = n;
-	*p++ = n >> 8;		/* name length */
-
-	d = windom;
-	while(*d && p-blob < (len-8)){
-		d += chartorune(&r, d);
-		r = toupperrune(r);
-		*p++ = r;
-		*p++ = r >> 8;
-	}
-
+	*p++ = 0;		/* 32bit: unknown data */
 	*p++ = 0;
-	*p++ = Beof;		/* name type */
-
 	*p++ = 0;
-	*p++ = 0;		/* name length */
-
-	*p++ = 0x65;
 	*p++ = 0;
-	*p++ = 0;
-	*p++ = 0;		/* unknown data */
+
+	p += putname(p, len - (p-blob), windom, Bdomain);
+	p += putname(p, len - (p-blob), "", Beof);
+
 	return p - blob;
 }
 
@@ -293,7 +296,7 @@
 	memcpy(ap->mackey[0]+MD5dlen, ap->resp[0], MACkeylen-MD5dlen);
 
 	/* NTLM v2 */
-	n = ntv2_blob(blob, sizeof(blob), windom);
+	n = ntv2_blob(blob, sizeof blob, windom);
         ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
 	hmac_t64(blob, n, v2hash, MD5dlen, nt_hmac, ds);
 	ap->len[1] = MD5dlen+n;
--- a/sys/src/cmd/cifs/cifs.c
+++ b/sys/src/cmd/cifs/cifs.c
@@ -40,8 +40,12 @@
 	s->seqrun = 0;
 	s->secmode = SECMODE_SIGN_ENABLED;	/* hope for the best */
 	s->flags2 = FL2_KNOWS_LONG_NAMES | FL2_HAS_LONG_NAMES | FL2_PAGEING_IO;
+
 	s->macidx = -1;
 
+	if(s->mtu > MTU)
+		s->mtu = MTU;
+
 	return s;
 }
 
@@ -76,6 +80,7 @@
 
 	p->buf = (uchar *)p + sizeof(Pkt);
 	p->s = s;
+	p->request = cmd;				/* for debug */
 
 	qlock(&s->seqlock);
 	if(s->seqrun){
@@ -137,11 +142,12 @@
 int
 cifsrpc(Pkt *p)
 {
-	int flags2, got, err;
+	int reply, got, err;
 	uint tid, uid, seq;
 	uchar *pos;
 	char m[nelem(magic)];
 
+
 	pos = p->pos;
 	if(p->bytebase){
 		p->pos = p->bytebase;
@@ -155,20 +161,23 @@
 	qlock(&p->s->rpclock);
 	got = nbtrpc(p);
 	qunlock(&p->s->rpclock);
-	if(got == -1)
+
+	if(got < 32+NBHDRLEN){
+		werrstr("cifs packet too small (%d < %d)\n", got, 32+NBHDRLEN);
 		return -1;
+	}
 
 	gmem(p, m, nelem(magic));
 	if(memcmp(m, magic, nelem(magic)) != 0){
-		werrstr("cifsrpc: bad magic number in packet %20ux%02ux%02ux%02ux",
+		werrstr("cifsrpc: bad magic number in packet 0x%02ux%02ux%02ux%02ux",
 			m[0], m[1], m[2], m[3]);
 		return -1;
 	}
 
-	g8(p);				/* cmd */
+	reply = g8(p);			/* cmd */
 	err = gl32(p);			/* errcode */
 	g8(p);				/* flags */
-	flags2 = gl16(p);		/* flags2 */
+	p->flags2 = gl16(p);		/* flags2 */
 	gl16(p);			/* PID MS bits */
 	seq = gl32(p);			/* reserved */
 	gl32(p);			/* MAC (if in use) */
@@ -179,6 +188,12 @@
 	gl16(p);			/* mid */
 	g8(p);				/* word count */
 
+	if(reply != p->request){
+		fprint(2, "unexpected reply (cmd=%x/%x seq=%d/%d)\n",
+			reply, p->request, seq, p->seq);
+		return -1;
+	}
+
 	if(p->s->secmode & SECMODE_SIGN_ENABLED){
 		if(macsign(p, p->seq+1) != 0 && p->s->seqrun){
 			werrstr("cifsrpc: invalid packet signature");
@@ -196,7 +211,7 @@
 		 * catch that too.
 		 */
 		if(p->s->seqrun && seq != p->seq && seq != 0){
-			print("%ux != %ux bad sequence number\n", seq, p->seq);
+			werrstr("bad sequence number (%d != %d)\n", p->seq, seq);
 			return -1;
 		}
 	}
@@ -205,7 +220,7 @@
 	if(p->s->uid == NO_UID)
 		p->s->uid = uid;
 
-	if(flags2 & FL2_NT_ERRCODES){
+	if(p->flags2 & FL2_NT_ERRCODES){
 		/* is it a real error rather than info/warning/chatter? */
 		if((err & 0xF0000000) == 0xC0000000){
 			werrstr("%s", nterrstr(err));
@@ -243,11 +258,26 @@
 	};
 	Pkt *p;
 
+	/*
+	 * This should not be necessary, however the XP seems to use
+	 * Unicode strings in its Negoiate response, but not set the
+	 * Flags2 UNICODE flag.
+	 *
+	 * It does however echo back the FL_UNICODE flag we set in the
+	 * flags2 negoiate request.
+	 *
+	 * The bodge is to force FL_UNICODE for this single request, 
+	 * clearing it after. Later we set FL2_UNICODE if the server 
+	 * agrees to CAP_UNICODE as it "should" be done.
+	 */
+	s->flags2 |= FL2_UNICODE;
 	p = cifshdr(s, nil, SMB_COM_NEGOTIATE);
+	s->flags2 &= ~FL2_UNICODE;
+
 	pbytes(p);
 	for(i = 0; i < nelem(dialects); i++){
 		p8(p, STR_DIALECT);
-		pstr(p, dialects[i]);
+		pascii(p, dialects[i]);
 	}
 
 	if(cifsrpc(p) == -1){
@@ -277,7 +307,7 @@
 	gl32(p);				/* Session key */
 	s->caps = gl32(p);			/* Server capabilities */
 	*svrtime = gvtime(p);			/* fileserver time */
-	s->tz = (short)gl16(p) * 60; /* TZ in mins, is signed (SNIA doc is wrong) */
+	s->tz = (short)gl16(p) * 60; 		/* TZ in mins, is signed (SNIA doc is wrong) */
 	s->challen = g8(p);			/* Encryption key length */
 	gl16(p);
 	gmem(p, s->chal, s->challen);		/* Get the challenge */
@@ -368,7 +398,7 @@
 	gl16(p);
 	gl16(p);
 	/* no security blob here - we don't understand extended security anyway */
-	gstr(p, os, sizeof(os));
+	gstr(p, os, sizeof os);
 	s->remos = estrdup9p(os);
 
 	free(p);
@@ -386,9 +416,9 @@
 	resp = Sess->auth->resp[0];
 	len  = Sess->auth->len[0];
 	if((s->secmode & SECMODE_USER) != SECMODE_USER){
-		memset(zeros, 0, sizeof(zeros));
+		memset(zeros, 0, sizeof zeros);
 		resp = zeros;
-		len = sizeof(zeros);
+		len = sizeof zeros;
 	}
 
 	p = cifshdr(s, nil, SMB_COM_TREE_CONNECT_ANDX);
@@ -408,11 +438,11 @@
 	}
 
 	path = smprint("//%s/%s", cname, tree);
-	strupr(path);
+
 	ppath(p, path);			/* path */
 	free(path);
 
-	pascii(p, "?????");	/* service type any (so we can do RAP calls) */
+	pascii(p, "?????");		/* service type any (so we can do RAP calls) */
 
 	if(cifsrpc(p) == -1){
 		free(p);
--- a/sys/src/cmd/cifs/cifs.h
+++ b/sys/src/cmd/cifs/cifs.h
@@ -350,10 +350,10 @@
 	int	uid;		/* user (authentication) ID  */
 	int	seq;		/* sequence number */
 	int	seqrun;		/* sequence numbering active */
-	int	caps;		/* server capabilities */
+	int	caps;		/* server's capabilities */
 	int	support;	/* support bits */
-	int	flags;		/* SMB flags  */
-	int	flags2;		/* SMB flags 2  */
+	int	flags;		/* SMB flags that we will send in the next packet   */
+	int	flags2;		/* SMB flags 2 that we will send in the next packet */
 	int	nocache;	/* disable write behind caching in server */
 	int	pid;		/* process ID  */
 	int	mid;		/* multiplex ID */
@@ -378,6 +378,8 @@
 
 	int tid;		/* tree ID received from server */
 	int seq;		/* sequence number expected in reply */
+	int request;		/* request cmd no (for debug) */
+	int flags2;		/* flags2 received with this packet */
 
 	uchar *seqbase; 	/* cifs: pos of sequence number in packet */
 	uchar *wordbase; 	/* cifs: base of words section of data  */
@@ -483,156 +485,150 @@
 extern Share Shares[MAX_SHARES];
 extern int Nshares;
 
-/* main.c */
-Qid	mkqid(char *, int, long, int, long);
-
 /* auth.c */
-Auth	*getauth(char *, char *, char *, int, uchar *, int);
-void	autherr(void);
-int	macsign(Pkt *, int);
+extern void autherr(void);
+extern Auth *getauth(char *name, char *windom, char *keyp, int secmode, uchar *chal, int len);
+extern int macsign(Pkt *p, int seq);
 
 /* cifs.c */
-Session	*cifsdial(char *, char *, char *);
-void	cifsclose(Session *);
-Pkt	*cifshdr(Session *, Share *, int);
-void	pbytes(Pkt *);
-int	cifsrpc(Pkt *);
-int	CIFSnegotiate(Session *, long *, char *, int, char *, int);
-int	CIFSsession(Session *);
-int	CIFStreeconnect(Session *, char *, char *, Share *);
-int	CIFSlogoff(Session *);
-int	CIFStreedisconnect(Session *, Share *);
-int	CIFSdeletefile(Session *, Share *, char *);
-int	CIFSdeletedirectory(Session *, Share *, char *);
-int	CIFScreatedirectory(Session *, Share *, char *);
-int	CIFSrename(Session *, Share *, char *, char *);
-int	CIFS_NT_opencreate(Session *, Share *, char *, int, int, int, int, int, int, int *, FInfo *);
-int	CIFS_SMB_opencreate(Session *, Share *, char *, int, int, int, int *);
-vlong	CIFSwrite(Session *, Share *, int, uvlong, void *, vlong);
-vlong	CIFSread(Session *, Share *, int, uvlong, void *, vlong, vlong);
-int	CIFSflush(Session *, Share *, int);
-int	CIFSclose(Session *, Share *, int);
-int	CIFSfindclose2(Session *, Share *, int);
-int	CIFSecho(Session *);
-int	CIFSsetinfo(Session *, Share *, char *, FInfo *);
-void	goff(Pkt *, uchar *, char *, int);
+extern Session *cifsdial(char *host, char *called, char *sysname);
+extern void cifsclose(Session *s);
+extern Pkt *cifshdr(Session *s, Share *sp, int cmd);
+extern void pbytes(Pkt *p);
+extern int cifsrpc(Pkt *p);
+extern int CIFSnegotiate(Session *s, long *svrtime, char *domain, int domlen, char *cname, int cnamlen);
+extern int CIFSsession(Session *s);
+extern int CIFStreeconnect(Session *s, char *cname, char *tree, Share *sp);
+extern int CIFSlogoff(Session *s);
+extern int CIFStreedisconnect(Session *s, Share *sp);
+extern int CIFSdeletefile(Session *s, Share *sp, char *name);
+extern int CIFSdeletedirectory(Session *s, Share *sp, char *name);
+extern int CIFScreatedirectory(Session *s, Share *sp, char *name);
+extern int CIFSrename(Session *s, Share *sp, char *old, char *new);
+extern int CIFS_NT_opencreate(Session *s, Share *sp, char *name, int flags, int options, int attrs, int access, int share, int action, int *result, FInfo *fi);
+extern int CIFS_SMB_opencreate(Session *s, Share *sp, char *name, int access, int attrs, int action, int *result);
+extern vlong CIFSwrite(Session *s, Share *sp, int fh, uvlong off, void *buf, vlong n);
+extern vlong CIFSread(Session *s, Share *sp, int fh, uvlong off, void *buf, vlong n, vlong minlen);
+extern int CIFSflush(Session *s, Share *sp, int fh);
+extern int CIFSclose(Session *s, Share *sp, int fh);
+extern int CIFSfindclose2(Session *s, Share *sp, int sh);
+extern int CIFSecho(Session *s);
+extern int CIFSsetinfo(Session *s, Share *sp, char *path, FInfo *fip);
 
 /* dfs.c */
-char	*mapfile(char *);
-int	mapshare(char *, Share **);
-int	redirect(Session *, Share *s, char *);
-int	dfscacheinfo(Fmt *);
-char	*trimshare(char *);
+extern int dfscacheinfo(Fmt *f);
+extern char *trimshare(char *s);
+extern char *mapfile(char *opath);
+extern int mapshare(char *path, Share **osp);
+extern int redirect(Session *s, Share *sp, char *path);
 
 /* doserrstr.c */
-char	*doserrstr(uint);
+extern char *doserrstr(uint err);
 
 /* fs.c */
-int	shareinfo(Fmt *);
-int	conninfo(Fmt *);
-int	sessioninfo(Fmt *);
-int	userinfo(Fmt *);
-int	groupinfo(Fmt *);
-int	domaininfo(Fmt *);
-int	workstationinfo(Fmt *);
-int	dfsrootinfo(Fmt *);
-int	openfileinfo(Fmt *);
-int	dfsrootinfo(Fmt *);
-int	filetableinfo(Fmt *); 	/* is in main.c due to C scope */
+extern int shareinfo(Fmt *f);
+extern int openfileinfo(Fmt *f);
+extern int conninfo(Fmt *f);
+extern int sessioninfo(Fmt *f);
+extern int dfsrootinfo(Fmt *f);
+extern int userinfo(Fmt *f);
+extern int groupinfo(Fmt *f);
+extern int domaininfo(Fmt *f);
+extern int workstationinfo(Fmt *f);
 
 /* info.c */
-int	walkinfo(char *);
-int	numinfo(void);
-int	dirgeninfo(int, Dir *);
-int	makeinfo(int);
-int	readinfo(int, char *, int, int);
-void	freeinfo(int);
+extern int walkinfo(char *name);
+extern int numinfo(void);
+extern int dirgeninfo(int slot, Dir *d);
+extern int makeinfo(int path);
+extern int readinfo(int path, char *buf, int len, int off);
+extern void freeinfo(int path);
 
 /* main.c */
-void	usage(void);
-void	dmpkey(char *, void *, int);
-void	main(int, char **);
+extern void setup(void);
+extern int filetableinfo(Fmt *f);
+extern Qid mkqid(char *s, int is_dir, long vers, int subtype, long path);
+extern int rdonly(Session *s, Share *sp, char *path, int rdonly);
+extern void usage(void);
+extern void dmpkey(char *s, void *v, int n);
+extern void main(int argc, char **argv);
 
 /* misc.c */
-char	*strupr(char *);
-char	*strlwr(char *);
+extern char *strupr(char *s);
+extern char *strlwr(char *s);
 
 /* netbios.c */
-void	Gmem(uchar **, void *, int);
-int	calledname(char *, char *);
-int	nbtdial(char *, char *, char *);
-void	nbthdr(Pkt *);
-int	nbtrpc(Pkt *);
-void	xd(char *, void *, int);
+extern void Gmem(uchar **p, void *v, int n);
+extern int calledname(char *host, char *name);
+extern int nbtdial(char *addr, char *called, char *sysname);
+extern void nbthdr(Pkt *p);
+extern int nbtrpc(Pkt *p);
+extern void xd(char *str, void *buf, int n);
 
 /* nterrstr.c */
-char	*nterrstr(uint);
+extern char *nterrstr(uint err);
 
 /* pack.c */
-void	*pmem(Pkt *, void *, int);
-void	*ppath(Pkt *, char *);
-void	*pstr(Pkt *, char *);
-void	*pascii(Pkt *, char *);
-void	*pl64(Pkt *, uvlong);
-void	*pb32(Pkt *, uint);
-void	*pl32(Pkt *, uint);
-void	*pb16(Pkt *, uint);
-void	*pl16(Pkt *, uint);
-void	*p8(Pkt *, uint);
-void	*pname(Pkt *, char *, char);
-void	*pvtime(Pkt *, uvlong);
-void	*pdatetime(Pkt *, long);
-void	gmem(Pkt *, void *, int);
-void	gstr(Pkt *, char *, int);
-void	gascii(Pkt *, char *, int);
-uvlong	gl64(Pkt *);
-uvlong	gb48(Pkt *);
-uint	gb32(Pkt *);
-uint	gl32(Pkt *);
-uint	gb16(Pkt *);
-uint	gl16(Pkt *);
-uint	g8(Pkt *);
-long	gdatetime(Pkt *);
-long	gvtime(Pkt *);
-void	gconv(Pkt *, int, char *, int);
+extern void *pmem(Pkt *p, void *v, int len);
+extern void *ppath(Pkt *p, char *str);
+extern void *pstr(Pkt *p, char *str);
+extern void *pascii(Pkt *p, char *str);
+extern void *pl64(Pkt *p, uvlong n);
+extern void *pb32(Pkt *p, uint n);
+extern void *pl32(Pkt *p, uint n);
+extern void *pb16(Pkt *p, uint n);
+extern void *pl16(Pkt *p, uint n);
+extern void *p8(Pkt *p, uint n);
+extern void *pname(Pkt *p, char *name, char pad);
+extern void *pvtime(Pkt *p, uvlong n);
+extern void *pdatetime(Pkt *p, long utc);
+extern void gmem(Pkt *p, void *v, int n);
+extern void gstr(Pkt *p, char *str, int n);
+extern void gascii(Pkt *p, char *str, int n);
+extern uvlong gl64(Pkt *p);
+extern uvlong gb48(Pkt *p);
+extern uint gb32(Pkt *p);
+extern uint gl32(Pkt *p);
+extern uint gb16(Pkt *p);
+extern uint gl16(Pkt *p);
+extern uint g8(Pkt *p);
+extern long gdatetime(Pkt *p);
+extern long gvtime(Pkt *p);
+extern void gconv(Pkt *p, int conv, char *str, int n);
+extern void goff(Pkt *p, uchar *base, char *str, int n);
 
+/* ping.c */
+extern int ping(char *host, int timeout);
+
 /* raperrstr.c */
-char	*raperrstr(uint);
+extern char *raperrstr(uint err);
 
 /* sid2name.c */
-void	upd_names(Session *, Share *, char *, Dir *);
+extern void upd_names(Session *s, Share *sp, char *path, Dir *d);
 
 /* trans.c */
-int	RAPshareenum(Session *, Share *, Share **);
-int	RAPshareinfo(Session *, Share *, char *, Shareinfo2 *);
+extern int RAPshareenum(Session *s, Share *sp, Share **ent);
+extern int RAPshareinfo(Session *s, Share *sp, char *share, Shareinfo2 *si2p);
+extern int RAPsessionenum(Session *s, Share *sp, Sessinfo **sip);
+extern int RAPgroupenum(Session *s, Share *sp, Namelist **nlp);
+extern int RAPgroupusers(Session *s, Share *sp, char *group, Namelist **nlp);
+extern int RAPuserenum(Session *s, Share *sp, Namelist **nlp);
+extern int RAPuserenum2(Session *s, Share *sp, Namelist **nlp);
+extern int RAPuserinfo(Session *s, Share *sp, char *user, Userinfo *uip);
+extern int RAPServerenum2(Session *s, Share *sp, char *workgroup, int type, int *more, Serverinfo **si);
+extern int RAPServerenum3(Session *s, Share *sp, char *workgroup, int type, int last, Serverinfo *si);
+extern int RAPFileenum2(Session *s, Share *sp, char *user, char *path, Fileinfo **fip);
 
-int	RAPsessionenum(Session *, Share *, Sessinfo **);
-
-int	RAPgroupenum(Session *, Share *, Namelist **);
-int	RAPgroupusers(Session *, Share *, char *, Namelist **);
-
-int	RAPuserenum(Session *, Share *, Namelist **);
-int	RAPuserenum2(Session *, Share *, Namelist **);
-int	RAPuserinfo(Session *, Share *, char *, Userinfo *);
-
-int	RAPServerenum2(Session *, Share *, char *, int, int *, Serverinfo **);
-int	RAPServerenum3(Session *, Share *, char *, int, int, Serverinfo *);
-
-int	RAPFileenum2(Session *, Share *, char *, char *, Fileinfo **);
-
 /* trans2.c */
-int	T2findfirst(Session *, Share *, int, char *, int *, long *, FInfo *);
-int	T2findnext(Session *, Share *, int, char *, int *, long *, FInfo *, int);
-int	T2queryall(Session *, Share *, char *, FInfo *);
-int	T2querystandard(Session *, Share *, char *, FInfo *);
-int	T2setpathinfo(Session *, Share *, char *, FInfo *);
-int	T2setfilelength(Session *, Share *, int, FInfo *);
-int	T2fsvolumeinfo(Session *, Share *, long *, long *, char *, int);
-int	T2fssizeinfo(Session *, Share *, uvlong *, uvlong *);
-int	T2getdfsreferral(Session *, Share *, char *, int *, int *, Refer *, int);
+extern int T2findfirst(Session *s, Share *sp, int slots, char *path, int *got, long *resume, FInfo *fip);
+extern int T2findnext(Session *s, Share *sp, int slots, char *path, int *got, long *resume, FInfo *fip, int sh);
+extern int T2queryall(Session *s, Share *sp, char *path, FInfo *fip);
+extern int T2querystandard(Session *s, Share *sp, char *path, FInfo *fip);
+extern int T2setpathinfo(Session *s, Share *sp, char *path, FInfo *fip);
+extern int T2setfilelength(Session *s, Share *sp, int fh, FInfo *fip);
+extern int T2fsvolumeinfo(Session *s, Share *sp, long *created, long *serialno, char *label, int labellen);
+extern int T2fssizeinfo(Session *s, Share *sp, uvlong *total, uvlong *unused);
+extern int T2getdfsreferral(Session *s, Share *sp, char *path, int *gflags, int *used, Refer *re, int nent);
 
 /* transnt.c */
-int	TNTquerysecurity(Session *, Share *, int, char **, char **);
-
-/* ping.c */
-int	ping(char *, int);
+extern int TNTquerysecurity(Session *s, Share *sp, int fh, char **usid, char **gsid);
--- a/sys/src/cmd/cifs/info.c
+++ b/sys/src/cmd/cifs/info.c
@@ -8,22 +8,22 @@
 
 
 struct {
-	char	*name;
-	int	(*func)(Fmt *f);
-	char	*buf;
-	int	len;
+	char *name;
+	int (*func)(Fmt *f);
+	char *buf;
+	int len;
 } Infdir[] = {
-	{ "Users",	userinfo },	
-	{ "Groups",	groupinfo },	
-	{ "Shares",	shareinfo },	
-	{ "Connection",	conninfo },	
-	{ "Sessions",	sessioninfo },	
-	{ "Dfsroot",	dfsrootinfo },	
-	{ "Dfscache",	dfscacheinfo },	
-	{ "Domains",	domaininfo },	
-	{ "Openfiles",	openfileinfo },	
-	{ "Workstations", workstationinfo },	
-	{ "Filetable",	filetableinfo },	
+	{ "Users" , userinfo },
+	{ "Groups" , groupinfo },
+	{ "Shares" , shareinfo },
+	{ "Connection" , conninfo },
+	{ "Sessions" , sessioninfo },
+	{ "Dfsroot" , dfsrootinfo },
+	{ "Dfscache" , dfscacheinfo },
+	{ "Domains" , domaininfo },
+	{ "Openfiles" , openfileinfo },
+	{ "Workstations" , workstationinfo },
+	{ "Filetable" , filetableinfo },
 };
 
 int
@@ -63,6 +63,7 @@
 	d->qid.vers = 1;
 	d->qid.path = slot;
 	d->qid.type = 0;
+
 	return 0;
 }
 
@@ -76,10 +77,12 @@
 	if(Infdir[path].buf != nil)
 		return 0;
 	fmtstrinit(&f);
-	if((*Infdir[path].func)(&f) == -1l)
+	if((*Infdir[path].func)(&f) == -1)
 		return -1;
-	Infdir[path].buf = fmtstrflush(&f);
-	Infdir[path].len = strlen(Infdir[path].buf);
+	if((Infdir[path].buf = fmtstrflush(&f)) == nil)
+		return -1;
+	if((Infdir[path].len = strlen(Infdir[path].buf)) <= 0)
+		return -1;
 	return 0;
 }
 
@@ -104,3 +107,4 @@
 	free(Infdir[path].buf);
 	Infdir[path].buf = nil;
 }
+
--- a/sys/src/cmd/cifs/main.c
+++ b/sys/src/cmd/cifs/main.c
@@ -198,8 +198,10 @@
 	Aux *a = aux;
 	char *npath;
 	int numinf = numinfo();
-	int slots = min(Sess->mtu, MTU) / sizeof(FInfo);
+	int slots;
 
+	slots = 128;		/* number of dir entries to fetch at one time */
+
 	if(strcmp(a->path, "/") == 0){
 		if(slot < numinf){
 			dirgeninfo(slot, d);
@@ -1103,6 +1105,7 @@
 		sleep(6000);
 		if(Active-- != 0)
 			continue;
+
 		for(i = 0; i < Nshares; i++){
 			if((rc = T2fssizeinfo(Sess, &Shares[slot], &tot, &fre)) == 0)
 				break;
@@ -1253,6 +1256,8 @@
 			memcpy(Shares+Nshares, sip+i, sizeof(Share));
 			if(CIFStreeconnect(Sess, Sess->cname,
 			    Shares[Nshares].name, Shares+Nshares) == -1){
+				fprint(2, "%s: %s %q - can't connect to share"
+					", %r\n", argv0, Host, Shares[Nshares].name);
 				free(Shares[Nshares].name);
 				continue;
 			}
@@ -1263,7 +1268,7 @@
 		for(i = 1; i < argc; i++){
 			if(CIFStreeconnect(Sess, Sess->cname, argv[i],
 			    Shares+Nshares) == -1){
-				fprint(2, "%s: %s  %q - can't connect to share"
+				fprint(2, "%s: %s %q - can't connect to share"
 					", %r\n", argv0, Host, argv[i]);
 				continue;
 			}
--- a/sys/src/cmd/cifs/mkfile
+++ b/sys/src/cmd/cifs/mkfile
@@ -11,10 +11,3 @@
 	auth.$O dfs.$O ping.$O
 
 </sys/src/cmd/mkone
-
-install:V:
-	# cp $TARG.man /sys/man/4/$TARG
-
-
-test:V: 8.out
-	8.out se-00 root && ls /n/se-00/root/eng/design/conversion/* && p /n/se-00/Shares
--- a/sys/src/cmd/cifs/nterrstr.c
+++ b/sys/src/cmd/cifs/nterrstr.c
@@ -3,14 +3,14 @@
 
 /*
  * some lines commented 4APE have been changed to
- * make them the same as plan9 error messages.  This is not
+ * make them the same as plan9 error messages. This is not
  * a problem for native programs but those built on APE
  * will give unhelpful errors if this is not done
- */
+*/
 
 static struct {
-	char	*msg;
-	int	err;
+	char *msg;
+	int err;
 } NTerrs[] = {
 	{ "success",					0x0 },
 	{ "wait 1",					0x1 },
@@ -261,8 +261,8 @@
 	{ "password restriction",			0xc000006c },
 	{ "logon failure",				0xc000006d },
 	{ "account restriction",			0xc000006e },
-	{ "invalid logon hours",			0xc000006f },
-	{ "invalid workstation",			0xc0000070 },
+	{ "login disallowed at this time",		0xc000006f },
+	{ "login disallowed from this workstation",	0xc0000070 },
 	{ "password expired",				0xc0000071 },
 	{ "account disabled",				0xc0000072 },
 	{ "none mapped",				0xc0000073 },
@@ -959,7 +959,7 @@
 	{ "SXS multiple deactivation",			0xc0150011 },
 	{ "SXS system default activation context empty",0xc0150012 },
 	{ "SXS process termination requested",		0xc0150013 },
-};
+ };
 
 char *
 nterrstr(uint err)
@@ -1006,14 +1006,13 @@
 			match = i;
 
 	why = "";
-	if(!(err & 0x80000000))
+	if(! (err & 0x80000000))
 		why = "warning, ";
 
 	if(match != -1)
-		snprint(buf, sizeof buf, "%s%s%s", why, facility,
-			NTerrs[match].msg);
+		snprint(buf, sizeof(buf), "%s%s%s", why, facility, NTerrs[match].msg);
 	else
-		snprint(buf, sizeof buf, "%s%s%d/0x%ux - unknown NT error",
-			why, facility, err, err);
+		snprint(buf, sizeof(buf), "%s%s%d/0x%ux - unknown NT error", why, facility, err, err);
 	return buf;
 }
+
--- a/sys/src/cmd/cifs/pack.c
+++ b/sys/src/cmd/cifs/pack.c
@@ -27,7 +27,7 @@
 	if(!str)
 		return s;
 
-	if(p->s->caps & CAP_UNICODE){
+	if(p->s->flags2 & FL2_UNICODE){
 		if(((p->pos - p->buf) % 2) != 0)	/* pad to even offset */
 			p8(p, 0);
 		while(*str){
@@ -57,7 +57,7 @@
 	if(!str)
 		return s;
 
-	if(p->s->caps & CAP_UNICODE){
+	if(p->s->flags2 & FL2_UNICODE){
 		if(((p->pos - p->buf) % 2) != 0)
 			p8(p, 0);		/* pad to even offset */
 		while(*str){
@@ -238,7 +238,10 @@
 	if(!n || !str)
 		return;
 
-	if(p->s->caps & CAP_UNICODE){
+	if(p->flags2 & FL2_UNICODE){
+		if(((p->pos - p->buf) % 2) != 0)
+			g8(p);		/* strip padding to even offset */
+
 		i = 0;
 		while(*p->pos && n && p->pos < p->eop){
 			r = gl16(p);
--- a/sys/src/cmd/cifs/remsmb.h
+++ b/sys/src/cmd/cifs/remsmb.h
@@ -48,11 +48,11 @@
 
 #ifndef _REMDEF_
 #define _REMDEF_
-/*
- * ====================================================================
- * SMB XACT message descriptors.
- * ====================================================================
- */
+//====================================================================
+//
+/* SMB XACT message descriptors. */
+//
+//====================================================================
 
 #define	REMSmb_share_info_0		"B13"
 #define	REMSmb_share_info_1		"B13BWz"
@@ -402,11 +402,11 @@
 
 #define	REMSmb_LocalOnlyCall		""
 
-/*
- * The following definitions exist for DOS LANMAN--Windows 3.0.
- * Normally, there is a  const char far * servername
- * as the first parameter, but this will be ignored (sort of).
- */
+//
+/* The following definitions exist for DOS LANMAN--Windows 3.0 */
+/* Normally, there is a const char far * servername */
+/* as the first parameter, but this will be ignored (sort of) */
+//
 #define	REMSmb_DosPrintJobGetId_P	"WrL"
 #define	REMSmb_GetPrintId		"WB16B13B"
 #define	REMSmb_NetRemoteCopy_P		"zzzzWWrL"
@@ -458,9 +458,9 @@
 #define	REMSmb_NetAccountConfirmUpd_P	"b12g12D"
 #define	REMSmb_update_info_0	"K"
 
-/*
- * SamrOemChangePasswordUser2 api support
- */
-#define	REMSmb_SamOEMChgPasswordUser2	"B516B16"  /* data that is passed */
+//
+/* SamrOemChangePasswordUser2 api support */
+//
+#define	REMSmb_SamOEMChgPasswordUser2	"B516B16"	/* data that is passed */
 
 #endif	/* ndef	_REMDEF_ */
--- a/sys/src/cmd/cifs/trans.c
+++ b/sys/src/cmd/cifs/trans.c
@@ -16,7 +16,7 @@
 	p->tbase = pl16(p, 0);	/* 0  Total parameter bytes to be sent, filled later */
 	pl16(p, 0);		/* 2  Total data bytes to be sent, filled later */
 	pl16(p, 64);			/* 4  Max parameter to return */
-	pl16(p, MTU - T2HDRLEN - 128);	/* 6  Max data to return */
+	pl16(p, s->mtu - T2HDRLEN - 128);	/* 6  Max data to return */
 	pl16(p, 1);			/* 8  Max setup count to return */
 	pl16(p, 0);			/* 10 Flags */
 	pl32(p, 1000);			/* 12 Timeout (ms) */
@@ -126,7 +126,7 @@
 	pascii(p, REMSmb_NetShareEnum_P);	/* request descriptor */
 	pascii(p, REMSmb_share_info_0);		/* reply descriptor */
 	pl16(p, 0);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 	ptdata(p);
 
 	if(trpc(p) == -1){
@@ -183,7 +183,7 @@
 	pascii(p, REMSmb_share_info_2);		/* reply descriptor */
 	pascii(p, share);
 	pl16(p, 1);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 
 	ptdata(p);
 
@@ -252,7 +252,7 @@
 	pascii(p, REMSmb_NetSessionEnum_P);	/* request descriptor */
 	pascii(p, REMSmb_session_info_10);	/* reply descriptor */
 	pl16(p, 10);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 	ptdata(p);
 
 	if(trpc(p) == -1){
@@ -312,7 +312,7 @@
 	pascii(p, REMSmb_NetGroupEnum_P);	/* request descriptor */
 	pascii(p, REMSmb_group_info_0);		/* reply descriptor */
 	pl16(p, 0);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 	ptdata(p);
 
 	if(trpc(p) == -1){
@@ -368,7 +368,7 @@
 	pascii(p, REMSmb_user_info_0);		/* reply descriptor */
 	pascii(p, group);			/* group name for list */
 	pl16(p, 0);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 	ptdata(p);
 
 	if(trpc(p) == -1){
@@ -422,7 +422,7 @@
 	pascii(p, REMSmb_NetUserEnum_P);	/* request descriptor */
 	pascii(p, REMSmb_user_info_0);		/* reply descriptor */
 	pl16(p, 0);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 	ptdata(p);
 
 	if(trpc(p) == -1){
@@ -478,7 +478,7 @@
 	pascii(p, REMSmb_NetUserEnum2_P);	/* request descriptor */
 	pascii(p, REMSmb_user_info_0);		/* reply descriptor */
 	pl16(p, 0);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 	pl32(p, resume);			/* resume key to allow multiple fetches */
 	ptdata(p);
 
@@ -536,7 +536,7 @@
 	pascii(p, REMSmb_user_info_10);		/* reply descriptor */
 	pascii(p, user);			/* username */
 	pl16(p, 10);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 	ptdata(p);
 
 	if(trpc(p) == -1){
@@ -592,7 +592,7 @@
 	pascii(p, REMSmb_NetServerEnum2_P);	/* request descriptor */
 	pascii(p, REMSmb_server_info_1);	/* reply descriptor */
 	pl16(p, 1);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 	pl32(p, type);
 	pascii(p, workgroup);
 
@@ -655,7 +655,7 @@
 	pascii(p, REMSmb_NetServerEnum3_P);	/* request descriptor */
 	pascii(p, REMSmb_server_info_1);	/* reply descriptor */
 	pl16(p, 1);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 	pl32(p, type);
 	pascii(p, workgroup);
 	pascii(p, first);
@@ -731,7 +731,7 @@
 	pascii(p, path);
 	pascii(p, user);
 	pl16(p, 1);				/* detail level */
-	pl16(p, MTU - 200);			/* receive buffer length */
+	pl16(p, s->mtu - 1024);			/* receive buffer length */
 	pl32(p, resume);			/* resume key */
 /* FIXME: maybe the padding and resume key are the wrong way around? */
 	pl32(p, 0);				/* padding ? */
--- a/sys/src/cmd/cifs/trans2.c
+++ b/sys/src/cmd/cifs/trans2.c
@@ -15,7 +15,7 @@
 	p->tbase = pl16(p, 0);	/* 0  Total parameter bytes to be sent, filled later */
 	pl16(p, 0);		/* 2  Total data bytes to be sent, filled later */
 	pl16(p, 64);			/* 4  Max parameter to return */
-	pl16(p, (MTU - T2HDRLEN)-64);	/* 6  Max data to return */
+	pl16(p, (s->mtu - T2HDRLEN)-64); /* 6  Max data to return */
 	p8(p, 0);			/* 8  Max setup count to return */
 	p8(p, 0);			/* 9  Reserved */
 	pl16(p, 0);			/* 10 Flags */