Browse Source

Plan 9 from Bell Labs 2009-07-09

David du Colombier 15 years ago
parent
commit
b596bf9f6e

+ 3 - 3
sys/src/9/bitsy/mkfile

@@ -100,12 +100,12 @@ installkern:V:	$p$CONF
 <../port/portmkfile
 <|../port/mkbootrules $CONF
 
-init.h:	../port/initcode.c init9.s
+init.h:D:	../port/initcode.c init9.s
 	$CC ../port/initcode.c
 	$AS init9.s
-	$LD -l -R1 -o init.out init9.$O initcode.$O /arm/lib/libc.a
+	$LD -l -R1 -s -o init.out init9.$O initcode.$O /arm/lib/libc.a
 	{echo 'uchar initcode[]={'
-	 strip -o /fd/1 init.out | xd -1x |
+	 xd -1x <init.out |
 		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
 	 echo '};'} > init.h
 

+ 764 - 76
sys/src/9/ip/gre.c

@@ -10,8 +10,7 @@
 
 #include "ip.h"
 
-enum
-{
+enum {
 	GRE_IPONLY	= 12,		/* size of ip header */
 	GRE_IPPLUSGRE	= 12,		/* minimum size of GRE header */
 	IP_GREPROTO	= 47,
@@ -19,17 +18,40 @@ enum
 	GRErxms		= 200,
 	GREtickms	= 100,
 	GREmaxxmit	= 10,
+
+	K		= 1024,
+	GREqlen		= 256 * K,
+
+	GRE_cksum	= 0x8000,
+	GRE_routing	= 0x4000,
+	GRE_key		= 0x2000,
+	GRE_seq		= 0x1000,
+
+	Nring		= 1 << 10,	/* power of two, please */
+	Ringmask	= Nring - 1,
+
+	GREctlraw	= 0,
+	GREctlcooked,
+	GREctlretunnel,
+	GREctlreport,
+	GREctldlsuspend,
+	GREctlulsuspend,
+	GREctldlresume,
+	GREctlulresume,
+	GREctlforward,
+	GREctlulkey,
+	Ncmds,
 };
 
-typedef struct GREhdr
-{
+typedef struct GREhdr GREhdr;
+struct GREhdr{
 	/* ip header */
 	uchar	vihl;		/* Version and header length */
 	uchar	tos;		/* Type of service */
 	uchar	len[2];		/* packet length (including headers) */
 	uchar	id[2];		/* Identification */
 	uchar	frag[2];	/* Fragment information */
-	uchar	Unused;	
+	uchar	ttl;
 	uchar	proto;		/* Protocol */
 	uchar	cksum[2];	/* checksum */
 	uchar	src[4];		/* Ip source */
@@ -38,21 +60,115 @@ typedef struct GREhdr
 	/* gre header */
 	uchar	flags[2];
 	uchar	eproto[2];	/* encapsulation protocol */
-} GREhdr;
+};
 
 typedef struct GREpriv GREpriv;
-struct GREpriv
-{
-	int		raw;			/* Raw GRE mode */
-
+struct GREpriv{
 	/* non-MIB stats */
-	ulong		csumerr;		/* checksum errors */
-	ulong		lenerr;			/* short packet */
+	ulong	lenerr;			/* short packet */
+};
+
+typedef struct Bring	Bring;
+struct Bring{
+	Block	*ring[Nring];
+	long	produced;
+	long	consumed;
+};
+
+typedef struct GREconv	GREconv;
+struct GREconv{
+	int	raw;
+
+	/* Retunnelling information.  v4 only */
+	uchar	north[4];			/* HA */
+	uchar	south[4];			/* Base station */
+	uchar	hoa[4];				/* Home address */
+	uchar	coa[4];				/* Careof address */
+	ulong	seq;				/* Current sequence # */
+	int	dlsusp;				/* Downlink suspended? */
+	int	ulsusp;				/* Uplink suspended? */
+	ulong	ulkey;				/* GRE key */
+
+	QLock	lock;				/* Lock for rings */
+	Bring	dlpending;			/* Ring of pending packets */
+	Bring	dlbuffered;			/* Received while suspended */
+	Bring	ulbuffered;			/* Received while suspended */
+};
+
+typedef struct Metablock Metablock;
+struct Metablock{
+	uchar	*rp;
+	ulong	seq;
+};
+
+static char *grectlcooked(Conv *, int, char **);
+static char *grectldlresume(Conv *, int, char **);
+static char *grectldlsuspend(Conv *, int, char **);
+static char *grectlforward(Conv *, int, char **);
+static char *grectlraw(Conv *, int, char **);
+static char *grectlreport(Conv *, int, char **);
+static char *grectlretunnel(Conv *, int, char **);
+static char *grectlulkey(Conv *, int, char **);
+static char *grectlulresume(Conv *, int, char **);
+static char *grectlulsuspend(Conv *, int, char **);
+
+static struct{
+	char	*cmd;
+	int	argc;
+	char	*(*f)(Conv *, int, char **);
+} grectls[Ncmds] = {
+[GREctlraw]	=	{	"raw",		1,	grectlraw,	},
+[GREctlcooked]	=	{	"cooked",	1,	grectlcooked,	},
+[GREctlretunnel]=	{	"retunnel",	5,	grectlretunnel,	},
+[GREctlreport]	=	{	"report",	2,	grectlreport,	},
+[GREctldlsuspend]=	{	"dlsuspend",	1,	grectldlsuspend,},
+[GREctlulsuspend]=	{	"ulsuspend",	1,	grectlulsuspend,},
+[GREctldlresume]=	{	"dlresume",	1,	grectldlresume,	},
+[GREctlulresume]=	{	"ulresume",	1,	grectlulresume,	},
+[GREctlforward]	=	{	"forward",	2,	grectlforward,	},
+[GREctlulkey]	=	{	"ulkey",	2,	grectlulkey,	},
 };
 
+static uchar nulladdr[4];
+static char *sessend = "session end";
+
 static void grekick(void *x, Block *bp);
+static char *gresetup(Conv *, char *, char *, char *);
 
-static char*
+ulong grepdin, grepdout, grebdin, grebdout;
+ulong grepuin, grepuout, grebuin, grebuout;
+
+static Block *
+getring(Bring *r)
+{
+	Block *bp;
+
+	if(r->consumed == r->produced)
+		return nil;
+
+	bp = r->ring[r->consumed & Ringmask];
+	r->ring[r->consumed & Ringmask] = nil;
+	r->consumed++;
+	return bp;
+}
+
+static void
+addring(Bring *r, Block *bp)
+{
+	Block *tbp;
+
+	if(r->produced - r->consumed > Ringmask){
+		/* Full! */
+		tbp = r->ring[r->produced & Ringmask];
+		assert(tbp);
+		freeb(tbp);
+		r->consumed++;
+	}
+	r->ring[r->produced & Ringmask] = bp;
+	r->produced++;
+}
+
+static char *
 greconnect(Conv *c, char **argv, int argc)
 {
 	Proto *p;
@@ -92,47 +208,93 @@ greconnect(Conv *c, char **argv, int argc)
 static void
 grecreate(Conv *c)
 {
-	c->rq = qopen(64*1024, Qmsg, 0, c);
+	c->rq = qopen(GREqlen, Qmsg, 0, c);
 	c->wq = qbypass(grekick, c);
 }
 
 static int
 grestate(Conv *c, char *state, int n)
 {
-	USED(c);
-	return snprint(state, n, "%s\n", "Datagram");
+	GREconv *grec;
+	char *ep, *p;
+
+	grec = c->ptcl;
+	p    = state;
+	ep   = p + n;
+	p    = seprint(p, ep, "%s%s%s%shoa %V north %V south %V seq %ulx "
+	 "pending %uld  %uld buffered dl %uld %uld ul %uld %uld ulkey %.8ulx\n",
+			c->inuse? "Open ": "Closed ",
+			grec->raw? "raw ": "",
+			grec->dlsusp? "DL suspended ": "",
+			grec->ulsusp? "UL suspended ": "",
+			grec->hoa, grec->north, grec->south, grec->seq,
+			grec->dlpending.consumed, grec->dlpending.produced,
+			grec->dlbuffered.consumed, grec->dlbuffered.produced,
+			grec->ulbuffered.consumed, grec->ulbuffered.produced,
+			grec->ulkey);
+	return p - state;
 }
 
 static char*
 greannounce(Conv*, char**, int)
 {
-	return "pktifc does not support announce";
+	return "gre does not support announce";
 }
 
 static void
 greclose(Conv *c)
 {
-	qclose(c->rq);
-	qclose(c->wq);
-	qclose(c->eq);
+	GREconv *grec;
+	Block *bp;
+
+	grec = c->ptcl;
+
+	/* Make sure we don't forward any more packets */
+	memset(grec->hoa, 0, sizeof grec->hoa);
+	memset(grec->north, 0, sizeof grec->north);
+	memset(grec->south, 0, sizeof grec->south);
+
+	qlock(&grec->lock);
+	while((bp = getring(&grec->dlpending)) != nil)
+		freeb(bp);
+
+	while((bp = getring(&grec->dlbuffered)) != nil)
+		freeb(bp);
+
+	while((bp = getring(&grec->ulbuffered)) != nil)
+		freeb(bp);
+
+	grec->dlpending.produced = grec->dlpending.consumed = 0;
+	grec->dlbuffered.produced = grec->dlbuffered.consumed = 0;
+	grec->ulbuffered.produced = grec->ulbuffered.consumed = 0;
+	qunlock(&grec->lock);
+
+	grec->raw = 0;
+	grec->seq = 0;
+	grec->dlsusp = grec->ulsusp = 1;
+
+	qhangup(c->rq, sessend);
+	qhangup(c->wq, sessend);
+	qhangup(c->eq, sessend);
 	ipmove(c->laddr, IPnoaddr);
 	ipmove(c->raddr, IPnoaddr);
-	c->lport = 0;
-	c->rport = 0;
+	c->lport = c->rport = 0;
 }
 
-int drop;
-
 static void
 grekick(void *x, Block *bp)
 {
-	Conv *c = x;
-	GREhdr *ghp;
+	Conv *c;
+	GREconv *grec;
+	GREhdr *gre;
 	uchar laddr[IPaddrlen], raddr[IPaddrlen];
 
 	if(bp == nil)
 		return;
 
+	c    = x;
+	grec = c->ptcl;
+
 	/* Make space to fit ip header (gre header already there) */
 	bp = padblock(bp, GRE_IPONLY);
 	if(bp == nil)
@@ -143,75 +305,350 @@ grekick(void *x, Block *bp)
 	if(bp == nil)
 		return;
 
-	ghp = (GREhdr *)(bp->rp);
-	ghp->vihl = IP_VER4;
+	gre = (GREhdr *)bp->rp;
+	gre->vihl = IP_VER4;
 
-	if(!((GREpriv*)c->p->priv)->raw){
-		v4tov6(raddr, ghp->dst);
+	if(grec->raw == 0){
+		v4tov6(raddr, gre->dst);
 		if(ipcmp(raddr, v4prefix) == 0)
-			memmove(ghp->dst, c->raddr + IPv4off, IPv4addrlen);
-		v4tov6(laddr, ghp->src);
+			memmove(gre->dst, c->raddr + IPv4off, IPv4addrlen);
+		v4tov6(laddr, gre->src);
 		if(ipcmp(laddr, v4prefix) == 0){
 			if(ipcmp(c->laddr, IPnoaddr) == 0)
-				findlocalip(c->p->f, c->laddr, raddr); /* pick interface closest to dest */
-			memmove(ghp->src, c->laddr + IPv4off, IPv4addrlen);
+				/* pick interface closest to dest */
+				findlocalip(c->p->f, c->laddr, raddr);
+			memmove(gre->src, c->laddr + IPv4off, sizeof gre->src);
 		}
-		hnputs(ghp->eproto, c->rport);
+		hnputs(gre->eproto, c->rport);
 	}
 
-	ghp->proto = IP_GREPROTO;
-	ghp->frag[0] = 0;
-	ghp->frag[1] = 0;
+	gre->proto = IP_GREPROTO;
+	gre->frag[0] = gre->frag[1] = 0;
 
+	grepdout++;
+	grebdout += BLEN(bp);
 	ipoput4(c->p->f, bp, 0, c->ttl, c->tos, nil);
 }
 
 static void
-greiput(Proto *gre, Ipifc*, Block *bp)
+gredownlink(Conv *c, Block *bp)
 {
-	int len;
-	GREhdr *ghp;
-	Conv *c, **p;
-	ushort eproto;
+	Metablock *m;
+	GREconv *grec;
+	GREhdr *gre;
+	int hdrlen, suspended, extra;
+	ushort flags;
+	ulong seq;
+
+	gre = (GREhdr *)bp->rp;
+	if(gre->ttl == 1){
+		freeb(bp);
+		return;
+	}
+
+	/*
+	 * We've received a packet with a GRE header and we need to
+	 * re-adjust the packet header to strip all unwanted parts
+	 * but leave room for only a sequence number.
+	 */
+	grec   = c->ptcl;
+	flags  = nhgets(gre->flags);
+	hdrlen = 0;
+	if(flags & GRE_cksum)
+		hdrlen += 2;
+	if(flags & GRE_routing){
+		print("%V routing info present.  Discarding packet", gre->src);
+		freeb(bp);
+		return;
+	}
+	if(flags & (GRE_cksum|GRE_routing))
+		hdrlen += 2;			/* Offset field */
+	if(flags & GRE_key)
+		hdrlen += 4;
+	if(flags & GRE_seq)
+		hdrlen += 4;
+
+	/*
+	 * The outgoing packet only has the sequence number set.  Make room
+	 * for the sequence number.
+	 */
+	if(hdrlen != sizeof(ulong)){
+		extra = hdrlen - sizeof(ulong);
+		if(extra < 0 && bp->rp - bp->base < -extra){
+			print("gredownlink: cannot add sequence number\n");
+			freeb(bp);
+			return;
+		}
+		memmove(bp->rp + extra, bp->rp, sizeof(GREhdr));
+		bp->rp += extra;
+		assert(BLEN(bp) >= sizeof(GREhdr) + sizeof(ulong));
+		gre = (GREhdr *)bp->rp;
+	}
+	seq = grec->seq++;
+	hnputs(gre->flags, GRE_seq);
+	hnputl(bp->rp + sizeof(GREhdr), seq);
+
+	/*
+	 * Keep rp and seq at the base.  ipoput4 consumes rp for
+	 * refragmentation.
+	 */
+	assert(bp->rp - bp->base >= sizeof(Metablock));
+	m = (Metablock *)bp->base;
+	m->rp  = bp->rp;
+	m->seq = seq;
+
+	/*
+	 * Here we make a decision what we're doing with the packet.  We're
+	 * doing this w/o holding a lock which means that later on in the
+	 * process we may discover we've done the wrong thing.  I don't want
+	 * to call ipoput with the lock held.
+	 */
+restart:
+	suspended = grec->dlsusp;
+	if(suspended){
+		if(!canqlock(&grec->lock)){
+			/*
+			 * just give up.  too bad, we lose a packet.  this
+			 * is just too hard and my brain already hurts.
+			 */
+			freeb(bp);
+			return;
+		}
+
+		if(!grec->dlsusp){
+			/*
+			 * suspend race.  We though we were suspended, but
+			 * we really weren't.
+			 */
+			qunlock(&grec->lock);
+			goto restart;
+		}
+
+		/* Undo the incorrect ref count addition */
+		addring(&grec->dlbuffered, bp);
+		qunlock(&grec->lock);
+		return;
+	}
+
+	/*
+	 * When we get here, we're not suspended.  Proceed to send the
+	 * packet.
+	 */
+	memmove(gre->src, grec->coa, sizeof gre->dst);
+	memmove(gre->dst, grec->south, sizeof gre->dst);
+
+	/*
+	 * Make sure the packet does not go away.
+	 */
+	_xinc(&bp->ref);
+	assert(bp->ref == 2);
+
+	ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
+	grepdout++;
+	grebdout += BLEN(bp);
+
+	/*
+	 * Now make sure we didn't do the wrong thing.
+	 */
+	if(!canqlock(&grec->lock)){
+		freeb(bp);		/* The packet just goes away */
+		return;
+	}
+
+	/* We did the right thing */
+	addring(&grec->dlpending, bp);
+	qunlock(&grec->lock);
+}
+
+static void
+greuplink(Conv *c, Block *bp)
+{
+	GREconv *grec;
+	GREhdr *gre;
+	ushort flags;
+
+	gre = (GREhdr *)bp->rp;
+	if(gre->ttl == 1)
+		return;
+
+	grec = c->ptcl;
+	memmove(gre->src, grec->coa, sizeof gre->src);
+	memmove(gre->dst, grec->north, sizeof gre->dst);
+
+	/*
+	 * Add a key, if needed.
+	 */
+	if(grec->ulkey){
+		flags = nhgets(gre->flags);
+		if(flags & (GRE_cksum|GRE_routing)){
+			print("%V routing info present.  Discarding packet\n",
+				gre->src);
+			freeb(bp);
+			return;
+		}
+
+		if((flags & GRE_key) == 0){
+			/* Make room for the key */
+			if(bp->rp - bp->base < sizeof(ulong)){
+				print("%V can't add key\n", gre->src);
+				freeb(bp);
+				return;
+			}
+
+			bp->rp -= 4;
+			memmove(bp->rp, bp->rp + 4, sizeof(GREhdr));
+
+			gre = (GREhdr *)bp->rp;
+			hnputs(gre->flags, flags | GRE_key);
+		}
+
+		/* Add the key */
+		hnputl(bp->rp + sizeof(GREhdr), grec->ulkey);
+	}
+
+	if(!canqlock(&grec->lock)){
+		freeb(bp);
+		return;
+	}
+
+	if(grec->ulsusp)
+		addring(&grec->ulbuffered, bp);
+	else{
+		ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
+		grepuout++;
+		grebuout += BLEN(bp);
+	}
+	qunlock(&grec->lock);
+}
+
+static void
+greiput(Proto *proto, Ipifc *, Block *bp)
+{
+	int len, hdrlen;
+	ushort eproto, flags;
 	uchar raddr[IPaddrlen];
+	Conv *c, **p;
+	GREconv *grec;
+	GREhdr *gre;
 	GREpriv *gpriv;
+	Ip4hdr *ip;
 
-	gpriv = gre->priv;
-	ghp = (GREhdr*)(bp->rp);
+	/*
+	 * We don't want to deal with block lists.  Ever.  The problem is
+	 * that when the block is forwarded, devether.c puts the block into
+	 * a queue that also uses ->next.  Just do not use ->next here!
+	 */
+	if(bp->next){
+		len = blocklen(bp);
+		bp  = pullupblock(bp, len);
+		assert(BLEN(bp) == len && bp->next == nil);
+	}
 
-	v4tov6(raddr, ghp->src);
-	eproto = nhgets(ghp->eproto);
-	qlock(gre);
+	gre = (GREhdr *)bp->rp;
+	if(BLEN(bp) < sizeof(GREhdr) || gre->proto != IP_GREPROTO){
+		freeb(bp);
+		return;
+	}
 
-	/* Look for a conversation structure for this port and address */
-	c = nil;
-	for(p = gre->conv; *p; p++) {
+	v4tov6(raddr, gre->src);
+	eproto = nhgets(gre->eproto);
+	flags  = nhgets(gre->flags);
+	hdrlen = sizeof(GREhdr);
+
+	if(flags & GRE_cksum)
+		hdrlen += 2;
+	if(flags & GRE_routing){
+		print("%I routing info present.  Discarding packet\n", raddr);
+		freeb(bp);
+		return;
+	}
+	if(flags & (GRE_cksum|GRE_routing))
+		hdrlen += 2;			/* Offset field */
+	if(flags & GRE_key)
+		hdrlen += 4;
+	if(flags & GRE_seq)
+		hdrlen += 4;
+
+	if(BLEN(bp) - hdrlen < sizeof(Ip4hdr)){
+		print("greretunnel: packet too short (s=%V d=%V)\n",
+			gre->src, gre->dst);
+		freeb(bp);
+		return;
+	}
+	ip = (Ip4hdr *)(bp->rp + hdrlen);
+
+	qlock(proto);
+	/*
+	 * Look for a conversation structure for this port and address, or
+	 * match the retunnel part, or match on the raw flag.
+	 */
+	for(p = proto->conv; *p; p++) {
+		c = *p;
+
+		if(c->inuse == 0)
+			continue;
+
+		/*
+		 * Do not stop this session - blocking here
+		 * implies that etherread is blocked.
+		 */
+		grec = c->ptcl;
+		if(memcmp(ip->dst, grec->hoa, sizeof ip->dst) == 0){
+			grepdin++;
+			grebdin += BLEN(bp);
+			gredownlink(c, bp);
+			qunlock(proto);
+			return;
+		}
+
+		if(memcmp(ip->src, grec->hoa, sizeof ip->src) == 0){
+			grepuin++;
+			grebuin += BLEN(bp);
+			greuplink(c, bp);
+			qunlock(proto);
+			return;
+		}
+	}
+
+	/*
+	 * when we get here, none of the forwarding tunnels matched.  now
+	 * try to match on raw and conversational sessions.
+	 */
+	for(c = nil, p = proto->conv; *p; p++) {
 		c = *p;
+
 		if(c->inuse == 0)
 			continue;
-		if(c->rport == eproto && 
-			(gpriv->raw || ipcmp(c->raddr, raddr) == 0))
+
+		/*
+		 * Do not stop this session - blocking here
+		 * implies that etherread is blocked.
+		 */
+		grec = c->ptcl;
+		if(c->rport == eproto &&
+		    (grec->raw || ipcmp(c->raddr, raddr) == 0))
 			break;
 	}
 
-	if(*p == nil) {
-		qunlock(gre);
-		freeblist(bp);
+	qunlock(proto);
+
+	if(*p == nil){
+		freeb(bp);
 		return;
 	}
 
-	qunlock(gre);
-
 	/*
 	 * Trim the packet down to data size
 	 */
-	len = nhgets(ghp->len) - GRE_IPONLY;
+	len = nhgets(gre->len) - GRE_IPONLY;
 	if(len < GRE_IPPLUSGRE){
-		freeblist(bp);
+		freeb(bp);
 		return;
 	}
+
 	bp = trimblock(bp, GRE_IPONLY, len);
 	if(bp == nil){
+		gpriv = proto->priv;
 		gpriv->lenerr++;
 		return;
 	}
@@ -219,8 +656,8 @@ greiput(Proto *gre, Ipifc*, Block *bp)
 	/*
 	 *  Can't delimit packet so pull it all into one block.
 	 */
-	if(qlen(c->rq) > 64*1024)
-		freeblist(bp);
+	if(qlen(c->rq) > GREqlen)
+		freeb(bp);
 	else{
 		bp = concatblock(bp);
 		if(bp == 0)
@@ -235,27 +672,278 @@ grestats(Proto *gre, char *buf, int len)
 	GREpriv *gpriv;
 
 	gpriv = gre->priv;
+	return snprint(buf, len,
+		"gre: %lud %lud %lud %lud %lud %lud %lud %lud, lenerrs %lud\n",
+		grepdin, grepdout, grepuin, grepuout,
+		grebdin, grebdout, grebuin, grebuout, gpriv->lenerr);
+}
+
+static char *
+grectlraw(Conv *c, int, char **)
+{
+	GREconv *grec;
 
-	return snprint(buf, len, "gre: len %lud\n", gpriv->lenerr);
+	grec = c->ptcl;
+	grec->raw = 1;
+	return nil;
 }
 
-char*
-grectl(Conv *c, char **f, int n)
+static char *
+grectlcooked(Conv *c, int, char **)
 {
-	GREpriv *gpriv;
+	GREconv *grec;
+
+	grec = c->ptcl;
+	grec->raw = 0;
+	return nil;
+}
+
+static char *
+grectlretunnel(Conv *c, int, char **argv)
+{
+	GREconv *grec;
+	uchar ipaddr[4];
+
+	grec = c->ptcl;
+	if(memcmp(grec->hoa, nulladdr, sizeof grec->hoa))
+		return "tunnel already set up";
+
+	v4parseip(ipaddr, argv[1]);
+	if(memcmp(ipaddr, nulladdr, sizeof ipaddr) == 0)
+		return "bad hoa";
+	memmove(grec->hoa, ipaddr, sizeof grec->hoa);
+	v4parseip(ipaddr, argv[2]);
+	memmove(grec->north, ipaddr, sizeof grec->north);
+	v4parseip(ipaddr, argv[3]);
+	memmove(grec->south, ipaddr, sizeof grec->south);
+	v4parseip(ipaddr, argv[4]);
+	memmove(grec->coa, ipaddr, sizeof grec->coa);
+	grec->ulsusp = 1;
+	grec->dlsusp = 0;
+
+	return nil;
+}
+
+static char *
+grectlreport(Conv *c, int, char **argv)
+{
+	ulong seq;
+	Block *bp;
+	Bring *r;
+	GREconv *grec;
+	Metablock *m;
+
+	grec = c->ptcl;
+	seq  = strtoul(argv[1], nil, 0);
+
+	qlock(&grec->lock);
+	r = &grec->dlpending;
+	while(r->produced - r->consumed > 0){
+		bp = r->ring[r->consumed & Ringmask];
+
+		assert(bp && bp->rp - bp->base >= sizeof(Metablock));
+		m = (Metablock *)bp->base;
+		if((long)(seq - m->seq) <= 0)
+			break;
+
+		r->ring[r->consumed & Ringmask] = nil;
+		r->consumed++;
+
+		freeb(bp);
+	}
+	qunlock(&grec->lock);
+	return nil;
+}
+
+static char *
+grectldlsuspend(Conv *c, int, char **)
+{
+	GREconv *grec;
+
+	grec = c->ptcl;
+	if(grec->dlsusp)
+		return "already suspended";
+
+	grec->dlsusp = 1;
+	return nil;
+}
+
+static char *
+grectlulsuspend(Conv *c, int, char **)
+{
+	GREconv *grec;
 
-	gpriv = c->p->priv;
-	if(n == 1){
-		if(strcmp(f[0], "raw") == 0){
-			gpriv->raw = 1;
-			return nil;
+	grec = c->ptcl;
+	if(grec->ulsusp)
+		return "already suspended";
+
+	grec->ulsusp = 1;
+	return nil;
+}
+
+static char *
+grectldlresume(Conv *c, int, char **)
+{
+	GREconv *grec;
+	GREhdr *gre;
+	Block *bp;
+
+	grec = c->ptcl;
+
+	qlock(&grec->lock);
+	if(!grec->dlsusp){
+		qunlock(&grec->lock);
+		return "not suspended";
+	}
+
+	while((bp = getring(&grec->dlbuffered)) != nil){
+		gre = (GREhdr *)bp->rp;
+		qunlock(&grec->lock);
+
+		/*
+		 * Make sure the packet does not go away.
+		 */
+		_xinc(&bp->ref);
+		assert(bp->ref == 2);
+
+		ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
+
+		qlock(&grec->lock);
+		addring(&grec->dlpending, bp);
+	}
+	grec->dlsusp = 0;
+	qunlock(&grec->lock);
+	return nil;
+}
+
+static char *
+grectlulresume(Conv *c, int, char **)
+{
+	GREconv *grec;
+	GREhdr *gre;
+	Block *bp;
+
+	grec = c->ptcl;
+
+	qlock(&grec->lock);
+	while((bp = getring(&grec->ulbuffered)) != nil){
+		gre = (GREhdr *)bp->rp;
+
+		qunlock(&grec->lock);
+		ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
+		qlock(&grec->lock);
+	}
+	grec->ulsusp = 0;
+	qunlock(&grec->lock);
+	return nil;
+}
+
+static char *
+grectlforward(Conv *c, int, char **argv)
+{
+	int len;
+	Block *bp, *nbp;
+	GREconv *grec;
+	GREhdr *gre;
+	Metablock *m;
+
+	grec = c->ptcl;
+
+	v4parseip(grec->south, argv[1]);
+	memmove(grec->north, grec->south, sizeof grec->north);
+
+	qlock(&grec->lock);
+	if(!grec->dlsusp){
+		qunlock(&grec->lock);
+		return "not suspended";
+	}
+	grec->dlsusp = 0;
+	grec->ulsusp = 0;
+
+	while((bp = getring(&grec->dlpending)) != nil){
+
+		assert(bp->rp - bp->base >= sizeof(Metablock));
+		m = (Metablock *)bp->base;
+		assert(m->rp >= bp->base && m->rp < bp->lim);
+
+		/*
+		 * If the packet is still held inside the IP transmit
+		 * system, make a copy of the packet first.
+		 */
+		if(bp->ref > 1){
+			len = bp->wp - m->rp;
+			nbp = allocb(len);
+			memmove(nbp->wp, m->rp, len);
+			nbp->wp += len;
+			freeb(bp);
+			bp  = nbp;
 		}
-		else if(strcmp(f[0], "cooked") == 0){
-			gpriv->raw = 0;
-			return nil;
+		else{
+			/* Patch up rp */
+			bp->rp = m->rp;
 		}
+
+		gre = (GREhdr *)bp->rp;
+		memmove(gre->src, grec->coa, sizeof gre->dst);
+		memmove(gre->dst, grec->south, sizeof gre->dst);
+
+		qunlock(&grec->lock);
+		ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
+		qlock(&grec->lock);
+	}
+
+	while((bp = getring(&grec->dlbuffered)) != nil){
+		gre = (GREhdr *)bp->rp;
+		memmove(gre->src, grec->coa, sizeof gre->dst);
+		memmove(gre->dst, grec->south, sizeof gre->dst);
+
+		qunlock(&grec->lock);
+		ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
+		qlock(&grec->lock);
 	}
-	return "unknown control request";
+
+	while((bp = getring(&grec->ulbuffered)) != nil){
+		gre = (GREhdr *)bp->rp;
+
+		memmove(gre->src, grec->coa, sizeof gre->dst);
+		memmove(gre->dst, grec->south, sizeof gre->dst);
+
+		qunlock(&grec->lock);
+		ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
+		qlock(&grec->lock);
+	}
+	qunlock(&grec->lock);
+	return nil;
+}
+
+static char *
+grectlulkey(Conv *c, int, char **argv)
+{
+	GREconv *grec;
+
+	grec = c->ptcl;
+	grec->ulkey = strtoul(argv[1], nil, 0);
+	return nil;
+}
+
+char *
+grectl(Conv *c, char **f, int n)
+{
+	int i;
+
+	if(n < 1)
+		return "too few arguments";
+
+	for(i = 0; i < Ncmds; i++)
+		if(strcmp(f[0], grectls[i].cmd) == 0)
+			break;
+
+	if(i == Ncmds)
+		return "no such command";
+	if(grectls[i].argc != 0 && grectls[i].argc != n)
+		return "incorrect number of arguments";
+
+	return grectls[i].f(c, n, f);
 }
 
 void
@@ -277,7 +965,7 @@ greinit(Fs *fs)
 	gre->stats = grestats;
 	gre->ipproto = IP_GREPROTO;
 	gre->nc = 64;
-	gre->ptclsize = 0;
+	gre->ptclsize = sizeof(GREconv);
 
 	Fsproto(fs, gre);
 }

+ 30 - 22
sys/src/9/ip/igmp.c

@@ -1,3 +1,7 @@
+/*
+ * igmp - internet group management protocol
+ * unfinished.
+ */
 #include "u.h"
 #include "../port/lib.h"
 #include "mem.h"
@@ -24,24 +28,28 @@ typedef struct IGMPpkt IGMPpkt;
 struct IGMPpkt
 {
 	/* ip header */
-	byte	vihl;		/* Version and header length */
-	byte	tos;		/* Type of service */
-	byte	len[2];		/* packet length (including headers) */
-	byte	id[2];		/* Identification */
-	byte	frag[2];	/* Fragment information */
-	byte	Unused;	
-	byte	proto;		/* Protocol */
-	byte	cksum[2];	/* checksum of ip portion */
-	byte	src[IPaddrlen];		/* Ip source */
-	byte	dst[IPaddrlen];		/* Ip destination */
+	uchar	vihl;		/* Version and header length */
+	uchar	tos;		/* Type of service */
+	uchar	len[2];		/* packet length (including headers) */
+	uchar	id[2];		/* Identification */
+	uchar	frag[2];	/* Fragment information */
+	uchar	Unused;	
+	uchar	proto;		/* Protocol */
+	uchar	cksum[2];	/* checksum of ip portion */
+	uchar	src[IPaddrlen];		/* Ip source */
+	uchar	dst[IPaddrlen];		/* Ip destination */
 
 	/* igmp header */
-	byte	vertype;	/* version and type */
-	byte	unused;
-	byte	igmpcksum[2];		/* checksum of igmp portion */
-	byte	group[IPaddrlen];	/* multicast group */
+	uchar	vertype;	/* version and type */
+	uchar	unused;
+	uchar	igmpcksum[2];		/* checksum of igmp portion */
+	uchar	group[IPaddrlen];	/* multicast group */
+
+	uchar	payload[];
 };
 
+#define IGMPPKTSZ offsetof(IGMPpkt, payload[0])
+
 /*
  *  lists for group reports
  */
@@ -49,7 +57,7 @@ typedef struct IGMPrep IGMPrep;
 struct IGMPrep
 {
 	IGMPrep		*next;
-	Media		*m;
+	Medium		*m;
 	int		ticks;
 	Multicast	*multi;
 };
@@ -76,7 +84,7 @@ static struct Stats
 } stats;
 
 void
-igmpsendreport(Media *m, byte *addr)
+igmpsendreport(Medium *m, uchar *addr)
 {
 	IGMPpkt *p;
 	Block *bp;
@@ -86,9 +94,9 @@ igmpsendreport(Media *m, byte *addr)
 		return;
 	p = (IGMPpkt*)bp->wp;
 	p->vihl = IP_VER4;
-	bp->wp += sizeof(IGMPpkt);
-	memset(bp->rp, 0, sizeof(IGMPpkt));
-	hnputl(p->src, Mediagetaddr(m));
+	bp->wp += IGMPPKTSZ;
+	memset(bp->rp, 0, IGMPPKTSZ);
+	hnputl(p->src, Mediumgetaddr(m));
 	hnputl(p->dst, Ipallsys);
 	p->vertype = (1<<4) | IGMPreport;
 	p->proto = IP_IGMPPROTO;
@@ -112,7 +120,7 @@ igmpproc(void *a)
 {
 	IGMPrep *rp, **lrp;
 	Multicast *mp, **lmp;
-	byte ip[IPaddrlen];
+	uchar ip[IPaddrlen];
 
 	USED(a);
 
@@ -166,7 +174,7 @@ igmpproc(void *a)
 }
 
 void
-igmpiput(Media *m, Ipifc *, Block *bp)
+igmpiput(Medium *m, Ipifc *, Block *bp)
 {
 	int n;
 	IGMPpkt *ghp;
@@ -206,7 +214,7 @@ igmpiput(Media *m, Ipifc *, Block *bp)
 		if(rp != nil)
 			break;	/* already reporting */
 
-		mp = Mediacopymulti(m);
+		mp = Mediumcopymulti(m);
 		if(mp == nil)
 			break;
 

+ 15 - 7
sys/src/9/ip/ip.c

@@ -64,8 +64,12 @@ struct Ipfrag
 {
 	ushort	foff;
 	ushort	flen;
+
+	uchar	payload[];
 };
 
+#define IPFRAGSZ offsetof(Ipfrag, payload[0])
+
 /* an instance of IP */
 struct IP
 {
@@ -268,7 +272,10 @@ ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
 		goto raise;
 
 	/* If we dont need to fragment just send it */
-	medialen = ifc->maxtu - ifc->m->hsize;
+	if(c && c->maxfragsize && c->maxfragsize < ifc->maxtu)
+		medialen = c->maxfragsize - ifc->m->hsize;
+	else
+		medialen = ifc->maxtu - ifc->m->hsize;
 	if(len <= medialen) {
 		if(!gating)
 			hnputs(eh->id, incref(&ip->id4));
@@ -280,6 +287,7 @@ ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
 		eh->cksum[0] = 0;
 		eh->cksum[1] = 0;
 		hnputs(eh->cksum, ipcsum(&eh->vihl));
+		assert(bp->next == nil);
 		ifc->m->bwrite(ifc, bp, V4, gate);
 		runlock(ifc);
 		poperror();
@@ -388,6 +396,8 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
 	uchar *dp, v6dst[IPaddrlen];
 	IP *ip;
 	Route *r;
+	Conv conv;
+
 
 	if(BLKIPVER(bp) != IP_VER4) {
 		ipiput6(f, ifc, bp);
@@ -448,10 +458,8 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
 
 	/* route */
 	if(notforme) {
-		Conv conv;
-
 		if(!ip->iprouting){
-			freeb(bp);
+			freeblist(bp);
 			return;
 		}
 
@@ -590,9 +598,9 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
 		return bp;
 	}
 
-	if(bp->base+sizeof(Ipfrag) >= bp->rp){
-		bp = padblock(bp, sizeof(Ipfrag));
-		bp->rp += sizeof(Ipfrag);
+	if(bp->base+IPFRAGSZ >= bp->rp){
+		bp = padblock(bp, IPFRAGSZ);
+		bp->rp += IPFRAGSZ;
 	}
 
 	BKFG(bp)->foff = offset<<3;

+ 2 - 2
sys/src/9/ip/ipifc.c

@@ -15,7 +15,7 @@ enum {
 	Nself		= Maxmedia*5,
 	NHASH		= 1<<6,
 	NCACHE		= 256,
-	QMAX		= 64*1024-1,
+	QMAX		= 192*1024-1,
 };
 
 Medium *media[Maxmedia] = { 0 };
@@ -316,7 +316,7 @@ ipifccreate(Conv *c)
 	Ipifc *ifc;
 
 	c->rq = qopen(QMAX, 0, 0, 0);
-	c->sq = qopen(2*QMAX, 0, 0, 0);
+	c->sq = qopen(QMAX, 0, 0, 0);
 	c->wq = qopen(QMAX, Qkick, ipifckick, c);
 	ifc = (Ipifc*)c->ptcl;
 	ifc->conv = c;

+ 7 - 3
sys/src/9/ip/ipv6.c

@@ -105,8 +105,12 @@ struct Ipfrag
 {
 	ushort	foff;
 	ushort	flen;
+
+	uchar	payload[];
 };
 
+#define IPFRAGSZ offsetof(Ipfrag, payload[0])
+
 /* an instance of IP */
 struct IP
 {
@@ -601,9 +605,9 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih)
 		return bp;
 	}
 
-	if(bp->base+sizeof(Ipfrag) >= bp->rp){
-		bp = padblock(bp, sizeof(Ipfrag));
-		bp->rp += sizeof(Ipfrag);
+	if(bp->base+IPFRAGSZ >= bp->rp){
+		bp = padblock(bp, IPFRAGSZ);
+		bp->rp += IPFRAGSZ;
 	}
 
 	BKFG(bp)->foff = offset;

+ 3 - 2
sys/src/9/ip/ipv6.h

@@ -124,9 +124,10 @@ struct	Ip6hdr {
 	uchar	ttl;		/* hop limit */
 	uchar	src[IPaddrlen];
 	uchar	dst[IPaddrlen];
+	uchar	payload[];
 };
 
-struct	Opthdr {
+struct	Opthdr {		/* unused */
 	uchar	nexthdr;
 	uchar	len;
 };
@@ -137,7 +138,7 @@ struct	Opthdr {
  * Type 1 is unused.  Type 2 is for MIPv6 (mobile IPv6) filtering
  * against type 0 header.
  */
-struct	Routinghdr {
+struct	Routinghdr {		/* unused */
 	uchar	nexthdr;
 	uchar	len;
 	uchar	rtetype;

+ 1 - 1
sys/src/9/ip/rudp.c

@@ -690,7 +690,7 @@ rudpinit(Fs *fs)
 	rudp->advise = rudpadvise;
 	rudp->stats = rudpstats;
 	rudp->ipproto = IP_UDPPROTO;
-	rudp->nc = 16;
+	rudp->nc = 32;
 	rudp->ptclsize = sizeof(Rudpcb);
 
 	Fsproto(fs, rudp);

+ 33 - 8
sys/src/9/ip/tcp.c

@@ -41,13 +41,13 @@ enum
 	EOLOPT		= 0,
 	NOOPOPT		= 1,
 	MSSOPT		= 2,
-	MSS_LENGTH	= 4,		/* Mean segment size */
+	MSS_LENGTH	= 4,		/* Maximum segment size */
 	WSOPT		= 3,
 	WS_LENGTH	= 3,		/* Bits to scale window size by */
 	MSL2		= 10,
 	MSPTICK		= 50,		/* Milliseconds per timer tick */
-	DEF_MSS		= 1460,		/* Default mean segment */
-	DEF_MSS6	= 1280,		/* Default mean segment (min) for v6 */
+	DEF_MSS		= 1460,		/* Default maximum segment */
+	DEF_MSS6	= 1280,		/* Default maximum segment (min) for v6 */
 	DEF_RTT		= 500,		/* Default round trip */
 	DEF_KAT		= 120000,	/* Default time (ms) between keep alives */
 	TCP_LISTEN	= 0,		/* Listen connection */
@@ -226,9 +226,9 @@ struct Tcpctl
 	ushort	ssthresh;		/* Slow start threshold */
 	int	resent;			/* Bytes just resent */
 	int	irs;			/* Initial received squence */
-	ushort	mss;			/* Mean segment size */
+	ushort	mss;			/* Maximum segment size */
 	int	rerecv;			/* Overlap of data rerecevived */
-	ulong	window;			/* Recevive window */
+	ulong	window;			/* Receive window */
 	uchar	backoff;		/* Exponential backoff counter */
 	int	backedoff;		/* ms we've backed off for rexmits */
 	uchar	flags;			/* State flags */
@@ -290,6 +290,7 @@ ushort	tcp_mss = DEF_MSS;	/* Maximum segment size to be sent */
 enum {
 	/* MIB stats */
 	MaxConn,
+	Mss,
 	ActiveOpens,
 	PassiveOpens,
 	EstabResets,
@@ -313,6 +314,7 @@ enum {
 static char *statnames[] =
 {
 [MaxConn]	"MaxConn",
+[Mss]		"MaxSegment",
 [ActiveOpens]	"ActiveOpens",
 [PassiveOpens]	"PassiveOpens",
 [EstabResets]	"EstabResets",
@@ -578,6 +580,8 @@ tcprcvwin(Conv *s)				/* Call with tcb locked */
 	w = tcb->window - qlen(s->rq);
 	if(w < 0)
 		w = 0;
+	if(w == 0)
+		netlog(s->p->f, Logtcp, "tcprcvwim: window %d qlen %d\n", tcb->window, qlen(s->rq));
 	tcb->rcv.wnd = w;
 	if(w == 0)
 		tcb->rcv.blocked = 1;
@@ -798,6 +802,7 @@ inittcpctl(Conv *s, int mode)
 	Tcpctl *tcb;
 	Tcp4hdr* h4;
 	Tcp6hdr* h6;
+	Tcppriv *tpriv;
 	int mss;
 
 	tcb = (Tcpctl*)s->ptcl;
@@ -853,6 +858,8 @@ inittcpctl(Conv *s, int mode)
 	}
 
 	tcb->mss = tcb->cwind = mss;
+	tpriv = s->p->priv;
+	tpriv->stats[Mss] = tcb->mss;
 
 	/* default is no window scaling */
 	tcb->window = QMAX;
@@ -985,6 +992,7 @@ htontcp6(Tcp *tcph, Block *data, Tcp6hdr *ph, Tcpctl *tcb)
 			*opt++ = MSSOPT;
 			*opt++ = MSS_LENGTH;
 			hnputs(opt, tcph->mss);
+//			print("our outgoing mss %d\n", tcph->mss);
 			opt += 2;
 		}
 		if(tcph->ws != 0){
@@ -1197,8 +1205,10 @@ ntohtcp4(Tcp *tcph, Block **bpp)
 			break;
 		switch(*optr) {
 		case MSSOPT:
-			if(optlen == MSS_LENGTH)
+			if(optlen == MSS_LENGTH) {
 				tcph->mss = nhgets(optr+2);
+//				print("new incoming mss %d\n", tcph->mss);
+			}
 			break;
 		case WSOPT:
 			if(optlen == WS_LENGTH && *(optr+2) <= 14)
@@ -1218,6 +1228,8 @@ ntohtcp4(Tcp *tcph, Block **bpp)
 void
 tcpsndsyn(Conv *s, Tcpctl *tcb)
 {
+	Tcppriv *tpriv;
+
 	tcb->iss = (nrand(1<<16)<<16)|nrand(1<<16);
 	tcb->rttseq = tcb->iss;
 	tcb->snd.wl2 = tcb->iss;
@@ -1230,6 +1242,8 @@ tcpsndsyn(Conv *s, Tcpctl *tcb)
 
 	/* set desired mss and scale */
 	tcb->mss = tcpmtu(s->p, s->laddr, s->ipversion, &tcb->scale);
+	tpriv = s->p->priv;
+	tpriv->stats[Mss] = tcb->mss;
 }
 
 void
@@ -1404,6 +1418,8 @@ sndsynack(Proto *tcp, Limbo *lp)
 	seg.flags = SYN|ACK;
 	seg.urg = 0;
 	seg.mss = tcpmtu(tcp, lp->laddr, lp->version, &scale);
+//	if (seg.mss > lp->mss && lp->mss >= 512)
+//		seg.mss = lp->mss;
 	seg.wnd = QMAX;
 
 	/* if the other side set scale, we should too */
@@ -1664,8 +1680,10 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst, uchar version)
 	tcb->flags |= SYNACK;
 
 	/* our sending max segment size cannot be bigger than what he asked for */
-	if(lp->mss != 0 && lp->mss < tcb->mss)
+	if(lp->mss != 0 && lp->mss < tcb->mss) {
 		tcb->mss = lp->mss;
+		tpriv->stats[Mss] = tcb->mss;
+	}
 
 	/* window scaling */
 	tcpsetscale(new, tcb, lp->rcvscale, lp->sndscale);
@@ -2150,6 +2168,9 @@ reset:
 
 	/* Cut the data to fit the receive window */
 	if(tcptrim(tcb, &seg, &bp, &length) == -1) {
+		netlog(f, Logtcp, "tcptrim, not accept, seq %lud-%lud win %lud-%lud\n", 
+			seg.seq, seg.seq + length - 1, 
+			tcb->rcv.nxt, tcb->rcv.nxt + tcb->rcv.wnd-1);
 		netlog(f, Logtcp, "tcp len < 0, %lud %d\n", seg.seq, length);
 		update(s, &seg);
 		if(qlen(s->wq)+tcb->flgcnt == 0 && tcb->state == Closing) {
@@ -2834,6 +2855,7 @@ void
 procsyn(Conv *s, Tcp *seg)
 {
 	Tcpctl *tcb;
+	Tcppriv *tpriv;
 
 	tcb = (Tcpctl*)s->ptcl;
 	tcb->flags |= FORCE;
@@ -2843,8 +2865,11 @@ procsyn(Conv *s, Tcp *seg)
 	tcb->irs = seg->seq;
 
 	/* our sending max segment size cannot be bigger than what he asked for */
-	if(seg->mss != 0 && seg->mss < tcb->mss)
+	if(seg->mss != 0 && seg->mss < tcb->mss) {
 		tcb->mss = seg->mss;
+		tpriv = s->p->priv;
+		tpriv->stats[Mss] = tcb->mss;
+	}
 
 	/* the congestion window always starts out as a single segment */
 	tcb->snd.wnd = seg->wnd;

+ 1 - 1
sys/src/9/ip/udp.c

@@ -194,7 +194,7 @@ udpkick(void *x, Block *bp)
 	upriv = c->p->priv;
 	f = c->p->f;
 
-	netlog(c->p->f, Logudp, "udp: kick\n");
+//	netlog(c->p->f, Logudp, "udp: kick\n");	/* frequent and uninteresting */
 	if(bp == nil)
 		return;
 

+ 52 - 46
sys/src/9/pc/devlml.c

@@ -15,8 +15,9 @@
 #define DBGWRIT	0x02
 #define DBGINTR	0x04
 #define DBGINTS	0x08
+#define DBGFS	0x10
 
-int debug = 0;
+int debug = DBGREAD|DBGWRIT|DBGFS;
 
 enum{
 	Qdir,
@@ -28,11 +29,8 @@ enum{
 	Qraw1,
 };
 
-#define	QID(q)		((ulong)(q).path)
-#define	QIDLML(q)	((((ulong)(q).path)-1)>>1)
-
 static Dirtab lmldir[] = {
-	".",		{Qdir, 0, QTDIR},	0,	DMDIR|0555,
+	".",		{Qdir, 0, QTDIR},	0,	0555,
 	"lml0ctl",	{Qctl0},		0,	0666,
 	"lml0jpg",	{Qjpg0},		0,	0444,
 	"lml0raw",	{Qraw0},		0,	0444,
@@ -77,14 +75,13 @@ getbuffer(void *x)
 	LML *lml;
 
 	lml = x;
-	for (;;) {
+	for(;;){
 		last = (last+1) % NBUF;
-		if (lml->codedata->statCom[last] & STAT_BIT)
+		if(lml->codedata->statCom[last] & STAT_BIT)
 			return last + 1;
-		if (last == l)
+		if(last == l)
 			return 0;
 	}
-	return 0;
 }
 
 static long
@@ -97,17 +94,17 @@ jpgread(LML *lml, void *va, long nbytes, vlong, int dosleep)
 	 * reads should be of size 1 or sizeof(FrameHeader).
 	 * Frameno is the number of the buffer containing the data.
 	 */
-	while ((bufno = getbuffer(lml)) == 0 && dosleep)
+	while((bufno = getbuffer(lml)) == 0 && dosleep)
 		sleep(&lml->sleepjpg, getbuffer, lml);
-	if (--bufno < 0)
+	if(--bufno < 0)
 		return 0;
 
 	jpgheader = (FrameHeader*)(lml->codedata->frag[bufno].hdr+2);
-	if (nbytes == sizeof(FrameHeader)) {
+	if(nbytes == sizeof(FrameHeader)){
 		memmove(va, jpgheader, sizeof(FrameHeader));
 		return sizeof(FrameHeader);
 	}
-	if (nbytes == 1) {
+	if(nbytes == 1){
 		*(char *)va = bufno;
 		return 1;
 	}
@@ -123,7 +120,7 @@ prepbuf(LML *lml)
 	CodeData *cd;
 
 	cd = lml->codedata;
-	for (i = 0; i < NBUF; i++) {
+	for(i = 0; i < NBUF; i++){
 		cd->statCom[i] = PADDR(&(cd->fragdesc[i]));
 		cd->fragdesc[i].addr = PADDR(cd->frag[i].fb);
 		/* Length is in double words, in position 1..20 */
@@ -138,31 +135,26 @@ lmlreset(void)
 	ulong regpa;
 	char name[32];
 	void *regva;
-	ISAConf isa;
 	LML *lml;
 	Pcidev *pcidev;
 	Physseg segbuf;
 
 	pcidev = nil;
 
-	for (nlml = 0; nlml < NLML && (pcidev = pcimatch(pcidev, VENDOR_ZORAN,
+	for(nlml = 0; nlml < NLML && (pcidev = pcimatch(pcidev, VENDOR_ZORAN,
 	    ZORAN_36067)); nlml++){
-		if(isaconfig("lml", nlml, &isa) == 0) {
-			if (debug) print("lml %d not in plan9.ini\n", nlml);
-			break;
-		}
 		lml = &lmls[nlml];
 		lml->pcidev = pcidev;
 		lml->codedata = (CodeData*)(((ulong)xalloc(Codedatasize+ BY2PG)
 			+ BY2PG-1) & ~(BY2PG-1));
-		if (lml->codedata == nil) {
+		if(lml->codedata == nil){
 			print("devlml: xalloc(%ux, %ux, 0)\n", Codedatasize, BY2PG);
 			return;
 		}
 
 		print("Installing Motion JPEG driver %s, irq %d\n",
 			MJPG_VERSION, pcidev->intl);
-		print("MJPG buffer at 0x%.8lux, size 0x%.8ux\n", lml->codedata,
+		print("MJPG buffer at 0x%.8p, size 0x%.8ux\n", lml->codedata,
 			Codedatasize);
 
 		/* Get access to DMA memory buffer */
@@ -174,7 +166,7 @@ lmlreset(void)
 
 		regpa = pcidev->mem[0].bar & ~0x0F;
 		regva = vmap(regpa, pcidev->mem[0].size);
-		if (regva == 0) {
+		if(regva == 0){
 			print("lml: failed to map registers\n");
 			return;
 		}
@@ -187,7 +179,7 @@ lmlreset(void)
 		kstrdup(&segbuf.name, name);
 		segbuf.pa = PADDR(lml->codedata);
 		segbuf.size = Codedatasize;
-		if (addphysseg(&segbuf) == -1) {
+		if(addphysseg(&segbuf) == -1){
 			print("lml: physsegment: %s\n", name);
 			return;
 		}
@@ -198,7 +190,7 @@ lmlreset(void)
 		kstrdup(&segbuf.name, name);
 		segbuf.pa = (ulong)regpa;
 		segbuf.size = pcidev->mem[0].size;
-		if (addphysseg(&segbuf) == -1) {
+		if(addphysseg(&segbuf) == -1){
 			print("lml: physsegment: %s\n", name);
 			return;
 		}
@@ -211,19 +203,25 @@ lmlreset(void)
 static Chan*
 lmlattach(char *spec)
 {
-	return devattach('V', spec);
+	if(debug&DBGFS)
+		print("lmlattach\n");
+	return devattach(L'Λ', spec);
 }
 
 static Walkqid*
 lmlwalk(Chan *c, Chan *nc, char **name, int nname)
 {
-	return devwalk(c, nc, name, nname, lmldir, nelem(lmldir), devgen);
+	if(debug&DBGFS)
+		print("lmlwalk\n");
+	return devwalk(c, nc, name, nname, lmldir, 3*nlml+1, devgen);
 }
 
 static int
 lmlstat(Chan *c, uchar *db, int n)
 {
-	return devstat(c, db, n, lmldir, nelem(lmldir), devgen);
+	if(debug&DBGFS)
+		print("lmlstat\n");
+	return devstat(c, db, n, lmldir, 3*nlml+1, devgen);
 }
 
 static Chan*
@@ -232,7 +230,9 @@ lmlopen(Chan *c, int omode)
 	int i;
 	LML *lml;
 
-	if (omode != OREAD)
+	if(debug&DBGFS)
+		print("lmlopen\n");
+	if(omode != OREAD)
 		error(Eperm);
 	c->aux = 0;
 	i = 0;
@@ -241,7 +241,7 @@ lmlopen(Chan *c, int omode)
 		i++;
 		/* fall through */
 	case Qctl0:
-		if (i >= nlml)
+		if(i >= nlml)
 			error(Eio);
 		break;
 	case Qjpg1:
@@ -251,17 +251,17 @@ lmlopen(Chan *c, int omode)
 	case Qjpg0:
 	case Qraw0:
 		/* allow one open */
-		if (i >= nlml)
+		if(i >= nlml)
 			error(Eio);
 		lml = lmls+i;
-		if (lml->jpgopens)
+		if(lml->jpgopens)
 			error(Einuse);
 		lml->jpgopens = 1;
 		lml->jpgframeno = 0;
 		prepbuf(lml);
 		break;
 	}
-	return devopen(c, omode, lmldir, nelem(lmldir), devgen);
+	return devopen(c, omode, lmldir, 3*nlml+1, devgen);
 }
 
 static void
@@ -269,6 +269,8 @@ lmlclose(Chan *c)
 {
 	int i;
 
+	if(debug&DBGFS)
+		print("lmlclose\n");
 	i = 0;
 	switch((ulong)c->qid.path){
 	case Qjpg1:
@@ -294,21 +296,24 @@ lmlread(Chan *c, void *va, long n, vlong voff)
 	i = 0;
 	switch((ulong)c->qid.path){
 	case Qdir:
-		return devdirread(c, (char *)buf, n, lmldir, nelem(lmldir), devgen);
+		n = devdirread(c, (char *)buf, n, lmldir, 3*nlml+1, devgen);
+		if(debug&(DBGFS|DBGREAD))
+			print("lmlread %ld\n", n);
+		return n;
 	case Qctl1:
 		i++;
 		/* fall through */
 	case Qctl0:
-		if (i >= nlml)
+		if(i >= nlml)
 			error(Eio);
 		lml = lmls+i;
 		len = snprint(lmlinfo, sizeof lmlinfo, "lml%djpg	lml%draw\nlml%d.regs	0x%lux	0x%ux\nlml%d.mjpg	0x%lux	0x%ux\n",
 			i, i,
 			i, lml->pcidev->mem[0].bar & ~0x0F, lml->pcidev->mem[0].size,
 			i, PADDR(lml->codedata), Codedatasize);
-		if (voff > len)
+		if(voff > len)
 			return 0;
-		if (n > len - voff)
+		if(n > len - voff)
 			n = len - voff;
 		memmove(va, lmlinfo+voff, n);
 		return n;
@@ -316,17 +321,18 @@ lmlread(Chan *c, void *va, long n, vlong voff)
 		i++;
 		/* fall through */
 	case Qjpg0:
-		if (i >= nlml)
+		if(i >= nlml)
 			error(Eio);
 		return jpgread(lmls+i, buf, n, off, 1);
 	case Qraw1:
 		i++;
 		/* fall through */
 	case Qraw0:
-		if (i >= nlml)
+		if(i >= nlml)
 			error(Eio);
 		return jpgread(lmls+i, buf, n, off, 0);
 	}
+	return -1;
 }
 
 static long
@@ -337,7 +343,7 @@ lmlwrite(Chan *, void *, long, vlong)
 }
 
 Dev lmldevtab = {
-	'V',
+	L'Λ',
 	"video",
 
 	lmlreset,
@@ -369,19 +375,19 @@ lmlintr(Ureg *, void *x)
 	/* Reset all interrupts from 067 */
 	writel(0xff000000, lml->pciBaseAddr + INTR_STAT);
 
-	if(flags & INTR_JPEGREP) {
+	if(flags & INTR_JPEGREP){
 
-		if(debug&(DBGINTR))
+		if(debug&DBGINTR)
 			print("MjpgDrv_intrHandler stat=0x%.8lux\n", flags);
 
 		fstart = lml->jpgframeno & 3;
-		for (;;) {
+		for(;;){
 			lml->jpgframeno++;
 			fno = lml->jpgframeno & 3;
-			if (lml->codedata->statCom[fno] & STAT_BIT)
+			if(lml->codedata->statCom[fno] & STAT_BIT)
 				break;
-			if (fno == fstart) {
-				if (debug & DBGINTR)
+			if(fno == fstart){
+				if(debug & DBGINTR)
 					print("Spurious lml jpg intr?\n");
 				return;
 			}

+ 10 - 4
sys/src/boot/pc/load.c

@@ -16,7 +16,7 @@
  * "nvram" is for the benefit of AoE clients.
  */
 static char *diskparts[] = {
-	"dos", "9fat", "fs", "data", "cdboot", "cache", "nvram", 0
+	"dos", "plan9", "9fat", "fs", "data", "cdboot", "cache", "nvram", 0
 };
 static char *etherparts[] = { "*", 0 };
 
@@ -332,9 +332,11 @@ main(void)
 	if((ulong)&end > (KZERO|(640*1024)))
 		panic("i'm too big");
 
+	/*
+	 * find and read plan9.ini, setting configuration variables.
+	 */
 	if (debug)
-		print("initial probe, for plan9.ini...");
-	/* find and read plan9.ini, setting configuration variables */
+		print("plan9.ini probe...");
 	biosload = 1;			/* initially be optimistic */
 	for(tp = types; tp->type != Tnil; tp++){
 		/*
@@ -361,6 +363,8 @@ main(void)
 	/*
 	 * we should now have read plan9.ini, if any.
 	 */
+	if (!iniread)
+		print("no plan9.ini\n");
 	persist = getconf("*bootppersist");
 	debugload = getconf("*debugload") != nil;
 	/* hack for soekris-like machines */
@@ -411,16 +415,18 @@ done:
 		if((mp = probe(Tany, flag, Dany)) && mp->type->type != Tfloppy)
 			boot(mp, "");
 		if (debugload)
-			print("end auto probe\n");
+			print("end auto-boot probe\n");
 	}
 
 	def[0] = 0;
 	probe(Tany, Fnone, Dany);
 	if (debugload)
 		print("end final probe\n");
+
 	if(p = getconf("bootdef"))
 		strcpy(def, p);
 
+	/* print possible boot methods */
 	flag = 0;
 	for(tp = types; tp->type != Tnil; tp++){
 		for(mp = tp->media; mp; mp = mp->next){

+ 37 - 39
sys/src/boot/pc/sdbios.c

@@ -1,6 +1,6 @@
 /*
- * boot driver for BIOS devices with partitions
- * devbios must be called first
+ * boot driver for BIOS devices with partitions.
+ * devbios must be initialised first.
  */
 #include "u.h"
 #include "lib.h"
@@ -19,6 +19,30 @@ vlong	biosseek(Fs *fs, vlong off);
 
 extern SDifc sdbiosifc;
 
+uchar *
+putbeul(ulong ul, uchar *p)
+{
+	*p++ = ul >> 24;
+	*p++ = ul >> 16;
+	*p++ = ul >> 8;
+	*p++ = ul;
+	return p;
+}
+
+uchar *
+putbeuvl(uvlong uvl, uchar *p)
+{
+	*p++ = uvl >> 56;
+	*p++ = uvl >> 48;
+	*p++ = uvl >> 40;
+	*p++ = uvl >> 32;
+	*p++ = uvl >> 24;
+	*p++ = uvl >> 16;
+	*p++ = uvl >> 8;
+	*p++ = uvl;
+	return p;
+}
+
 int
 biosverify(SDunit* )
 {
@@ -32,8 +56,8 @@ biosonline(SDunit* unit)
 {
 	if (onlybios0 || !biosinited || !unit)
 		return 0;
-	unit->sectors = 1UL << 30;	/* a bunch */
-	unit->secsize = 512;		/* conventional */
+	unit->secsize = 512;			/* conventional */
+	unit->sectors = ~0ULL / unit->secsize;	/* all of them, and then some */
 	return 1;
 }
 
@@ -42,7 +66,7 @@ biosrio(SDreq* r)
 {
 	int nb;
 	long got;
-	vlong len, off;
+	vlong off;
 	uchar *p;
 	Fs fs;			/* just for fs->dev, which is zero */
 
@@ -63,8 +87,8 @@ biosrio(SDreq* r)
 		if (r->cmd[0] == 0x08)
 			panic("biosrio: 0x08 read op");
 		off = r->cmd[2]<<24 | r->cmd[3]<<16 | r->cmd[4]<<8 | r->cmd[5];
-		nb = r->cmd[7]<<8 | r->cmd[8];	/* often 4 */
-		USED(nb);		/* is nb*512 == r->dlen? */
+		nb =  r->cmd[7]<<8  | r->cmd[8];	/* often 4 */
+		USED(nb);			/* is nb*512 == r->dlen? */
 		memset(&fs, 0, sizeof fs);
 		biosseek(&fs, off*512);
 		got = biosread(&fs, r->data, r->dlen);
@@ -77,43 +101,17 @@ biosrio(SDreq* r)
 	case 0x2A:			/* write */
 		r->status = SDeio;	/* boot programs don't write */
 		break;
-	case 0x25:			/* read capacity */
+
 		/*
 		 * Read capacity returns the LBA of the last sector.
 		 */
-		len = r->unit->sectors - 1;
-		p = r->data;
-		*p++ = len>>24;
-		*p++ = len>>16;
-		*p++ = len>>8;
-		*p++ = len;
-		len = r->unit->secsize;
-		*p++ = len>>24;
-		*p++ = len>>16;
-		*p++ = len>>8;
-		*p = len;
-		r->data = (char *)r->data + 8;
+	case 0x25:			/* read capacity */
+		p = putbeul(r->unit->sectors - 1, r->data);
+		r->data = putbeul(r->unit->secsize, p);
 		return SDok;
 	case 0x9E:			/* long read capacity */
-		/*
-		 * Read capacity returns the LBA of the last sector.
-		 */
-		len = r->unit->sectors - 1;
-		p = r->data;
-		*p++ = len>>56;
-		*p++ = len>>48;
-		*p++ = len>>40;
-		*p++ = len>>32;
-		*p++ = len>>24;
-		*p++ = len>>16;
-		*p++ = len>>8;
-		*p++ = len;
-		len = r->unit->secsize;
-		*p++ = len>>24;
-		*p++ = len>>16;
-		*p++ = len>>8;
-		*p = len;
-		r->data = (char *)r->data + 8;
+		p = putbeuvl(r->unit->sectors - 1, r->data);
+		r->data = putbeul(r->unit->secsize, p);
 		return SDok;
 	/* ignore others */
 	}

+ 1 - 1
sys/src/cmd/auth/secstore/mkfile

@@ -1,6 +1,6 @@
 </$objtype/mkfile
 BIN=/$objtype/bin/auth
-CFLAGS=-Fw
+# CFLAGS=-Fw
 HFILES =\
 	SConn.h\
 	secstore.h\

+ 1 - 1
sys/src/cmd/auth/secstore/secstore.c

@@ -473,7 +473,7 @@ login(char *id, char *dest, int pass_stdin, int pass_nvram)
 		if(verbose)
 			fprint(2, "%ld\n", sn);
 		c->conn->write(c->conn, (uchar*)s, sn+3);
-		readstr(c->conn, s);
+		readstr(c->conn, s);	/* TODO: check for error? */
 	}
 	if(strcmp(s, "OK") != 0){
 		fprint(2, "%s\n", s);

+ 5 - 0
sys/src/cmd/cdfs/mmc.c

@@ -578,6 +578,11 @@ mmcreadtoc(Drive *drive, int type, int track, void *data, int nbytes)
 	cmd[7] = nbytes>>8;
 	cmd[8] = nbytes;
 
+	/*
+	 * printing iounit(drive->Scsi.rawfd) here yields
+	 *	iounit(3) = 0;		# for local access
+	 *	iounit(3) = 65512;	# for remote access via /mnt/term
+	 */
 	return scsi(drive, cmd, sizeof(cmd), data, nbytes, Sread);
 }
 

+ 24 - 2
sys/src/cmd/exportfs/exportfs.c

@@ -42,7 +42,7 @@ int	qidcnt;
 int	qfreecnt;
 int	ncollision;
 
-int	netfd;
+int	netfd;				/* initially stdin */
 int	srvfd = -1;
 int	nonone = 1;
 char	*filterp;
@@ -54,15 +54,34 @@ int	readonly;
 static void	mksecret(char *, uchar *);
 static int localread9pmsg(int, void *, uint, ulong *);
 static char *anstring  = "tcp!*!0";
+
+char *netdir = "", *local = "", *remote = "";
+
 int	filter(int, char *);
 
 void
 usage(void)
 {
-	fprint(2, "usage:	%s [-adnsR] [-f dbgfile] [-m msize] [-r root] [-S srvfile] [-e 'crypt hash'] [-P exclusion-file] [-A announce-string] [-B address]\n", argv0);
+	fprint(2, "usage: %s [-adnsR] [-f dbgfile] [-m msize] [-r root] "
+		"[-S srvfile] [-e 'crypt hash'] [-P exclusion-file] "
+		"[-A announce-string] [-B address]\n", argv0);
 	fatal("usage");
 }
 
+static void
+noteconn(int fd)
+{
+	NetConnInfo *nci;
+
+	nci = getnetconninfo(nil, fd);
+	if (nci == nil)
+		return;
+	netdir = strdup(nci->dir);
+	local = strdup(nci->lsys);
+	remote = strdup(nci->rsys);
+	freenetconninfo(nci);
+}
+
 void
 main(int argc, char **argv)
 {
@@ -183,6 +202,8 @@ main(int argc, char **argv)
 		if(srv == nil)
 			sysfatal("-B requires -s");
 
+		local = "me";
+		remote = na;
 		if((fd = dial(netmkaddr(na, 0, "importfs"), 0, 0, 0)) < 0)
 			sysfatal("can't dial %s: %r", na);
 	
@@ -238,6 +259,7 @@ main(int argc, char **argv)
 		strncpy(buf, srv, sizeof buf);
 	}
 	else {
+		noteconn(netfd);
 		buf[0] = 0;
 		n = read(0, buf, sizeof(buf)-1);
 		if(n < 0) {

+ 33 - 0
sys/src/cmd/exportfs/exportsrv.c

@@ -5,6 +5,8 @@
 #define Extern	extern
 #include "exportfs.h"
 
+extern char *netdir, *local, *remote;
+
 char Ebadfid[] = "Bad fid";
 char Enotdir[] = "Not a directory";
 char Edupfid[] = "Fid already in use";
@@ -425,6 +427,31 @@ Xwstat(Fsrpc *t)
 	t->busy = 0;
 }
 
+/*
+ * based on libthread's threadsetname, but drags in less library code.
+ * actually just sets the arguments displayed.
+ */
+void
+procsetname(char *fmt, ...)
+{
+	int fd;
+	char *cmdname;
+	char buf[128];
+	va_list arg;
+
+	va_start(arg, fmt);
+	cmdname = vsmprint(fmt, arg);
+	va_end(arg);
+	if (cmdname == nil)
+		return;
+	snprint(buf, sizeof buf, "#p/%d/args", getpid());
+	if((fd = open(buf, OWRITE)) >= 0){
+		write(fd, cmdname, strlen(cmdname)+1);
+		close(fd);
+	}
+	free(cmdname);
+}
+
 void
 slave(Fsrpc *f)
 {
@@ -468,6 +495,12 @@ slave(Fsrpc *f)
 			fatal("rfork");
 
 		case 0:
+			if (local[0] != '\0')
+				if (netdir[0] != '\0')
+					procsetname("%s: %s -> %s", netdir, 
+						local, remote);
+				else
+					procsetname("%s -> %s", local, remote);
 			blockingslave();
 			fatal("slave");
 

+ 1 - 1
sys/src/cmd/ip/ipconfig/main.c

@@ -620,7 +620,7 @@ doadd(int retry)
 	/* run dhcp if we need something */
 	if(dodhcp){
 		mkclientid();
-		for(tries = 0; tries < 6; tries++){
+		for(tries = 0; tries < 30; tries++){
 			dhcpquery(!noconfig, Sselecting);
 			if(conf.state == Sbound)
 				break;

+ 1 - 1
sys/src/cmd/ip/tftpd.c

@@ -245,7 +245,7 @@ sendfile(int fd, char *name, char *mode)
 		}
 
 		ret = write(fd, buf, 4+n);
-		if(ret < 0)
+		if(ret < 4+n)
 			sysfatal("tftpd: network write error: %r");
 
 		for(rxl = 0; rxl < 10; rxl++) {

+ 46 - 32
sys/src/cmd/lp/lpdsend.c

@@ -1,41 +1,47 @@
-#include <sys/types.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <stdlib.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
 #include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
 
 #define	REDIALTIMEOUT	15
 #ifdef PLAN9
 #include <Plan9libnet.h>
 #endif
-#define TIMEOUT 600
+
+enum {
+	TIMEOUT = 30*60,
+	SBSIZE = 8192,
+};
 
 char tmpfilename[L_tmpnam+1];
+unsigned char sendbuf[SBSIZE];
+
 int alarmstate = 0;
 int debugflag = 0;
 int killflag = 0;
 int statflag = 0;
 
 void
-cleanup(void) {
+cleanup(void)
+{
 	unlink(tmpfilename);
 }
 
-#define SBSIZE 8192
-unsigned char sendbuf[SBSIZE];
-
 void
-debug(char *str) {
+debug(char *str)
+{
 	if (debugflag)
 		fprintf(stderr, "%s", str);
 }
 
 void
-alarmhandler(int sig) {
+alarmhandler(int sig)
+{
 	fprintf(stderr, "timeout occurred, check printer.\n");
 	exit(2);
 }
@@ -44,7 +50,8 @@ alarmhandler(int sig) {
 #define WARNPC	5
 
 int
-copyfile(int in, int out, long tosend) {
+copyfile(int in, int out, long tosend)
+{
 	int n;
 	int sent = 0;
 	int percent = 0;
@@ -56,7 +63,8 @@ copyfile(int in, int out, long tosend) {
 		if (debugflag)
 			fprintf(stderr, "lpdsend: copyfile read %d bytes from %d\n",
 				n, in);
-		alarm(TIMEOUT); alarmstate = 1;
+		alarm(TIMEOUT);
+		alarmstate = 1;
 		if (write(out, sendbuf, n) != n) {
 			alarm(0);
 			fprintf(stderr, "write to fd %d failed\n", out);
@@ -67,7 +75,7 @@ copyfile(int in, int out, long tosend) {
 			fprintf(stderr, "lpdsend: copyfile wrote %d bytes to %d\n",
 				n, out);
 		sent += n;
-		if (tosend && ((sent*100/tosend)>=(percent+WARNPC))) {
+		if (tosend && sent*100/tosend >= percent+WARNPC) {
 			percent += WARNPC;
 			fprintf(stderr, ": %5.2f%% sent\n", sent*100.0/tosend);
 		}
@@ -86,8 +94,10 @@ int seqno = 0;
 char *seqfilename;
 
 void
-killjob(int printerfd) {
+killjob(int printerfd)
+{
 	int strlength;
+
 	if (printername==0) {
 		fprintf(stderr, "no printer name\n");
 		exit(1);
@@ -110,7 +120,8 @@ killjob(int printerfd) {
 }
 
 void
-checkqueue(int printerfd) {
+checkqueue(int printerfd)
+{
 	int n, strlength;
 	unsigned char sendbuf[1];
 
@@ -129,13 +140,16 @@ checkqueue(int printerfd) {
 }
 
 void
-getack(int printerfd, int as) {
+getack(int printerfd, int as)
+{
 	char resp;
 	int rv;
 
-	alarm(TIMEOUT); alarmstate = as;
-	if ((rv=read(printerfd, &resp, 1)) != 1 || resp != '\0') {
-		fprintf(stderr, "getack failed: read returned %d, read value (if any) %d, alarmstate=%d\n",
+	alarm(TIMEOUT);
+	alarmstate = as;
+	if ((rv = read(printerfd, &resp, 1)) != 1 || resp != '\0') {
+		fprintf(stderr, "getack failed: read returned %d, "
+			"read value (if any) %d, alarmstate=%d\n",
 			rv, resp, alarmstate);
 		exit(1);
 	}
@@ -144,7 +158,8 @@ getack(int printerfd, int as) {
 
 /* send control file */
 void
-sendctrl(int printerfd) {
+sendctrl(int printerfd)
+{
 	char cntrlstrbuf[256];
 	int strlength, cntrlen;
 
@@ -170,7 +185,8 @@ sendctrl(int printerfd) {
 
 /* send data file */
 void
-senddata(int inputfd, int printerfd, long size) {
+senddata(int inputfd, int printerfd, long size)
+{
 	int strlength;
 
 	sprintf(strbuf, "%c%d dfA%3.3d%s\n", '\3', size, seqno, hostname);
@@ -193,7 +209,8 @@ senddata(int inputfd, int printerfd, long size) {
 }
 
 void
-sendjob(int inputfd, int printerfd) {
+sendjob(int inputfd, int printerfd)
+{
 	struct stat statbuf;
 	int strlength;
 
@@ -261,13 +278,10 @@ netmkaddr(char *linear, char *defnet, char *defsrv)
 	return addr;
 }
 
-main(int argc, char *argv[]) {
-	int c, usgflg = 0;
-	char *desthostname;
-	char *hnend;
-	int printerfd;
-	int inputfd;
-	int sendport;
+main(int argc, char *argv[])
+{
+	int c, usgflg = 0, inputfd, printerfd, sendport;
+	char *desthostname, *hnend;
 	char portstr[4];
 
 	if (signal(SIGALRM, alarmhandler) == SIG_ERR) {

+ 5 - 4
sys/src/cmd/lp/lpsend.c

@@ -2,11 +2,12 @@
 
 #include <u.h>
 #include <libc.h>
-#define 	stderr	2
-
-#define RDNETIMEOUT	60000
-#define WRNETIMEOUT	60000
 
+enum {
+	stderr = 2,
+	RDNETIMEOUT = 30*60*1000,
+	WRNETIMEOUT = RDNETIMEOUT,
+};
 #else
 
 /* not for plan 9 */

+ 2 - 2
sys/src/cmd/unix/drawterm/Make.win32

@@ -10,8 +10,8 @@ CC=$(MING)gcc
 AS=$(MING)as
 RANLIB=$(MING)ranlib
 WINDRES=$(MING)windres
-CFLAGS=-Wall -Wno-missing-braces -I$(ROOT)/include -I$(ROOT) -I$(ROOT)/kern \
- -c -D_X86_ -DIS_32 -DWINDOWS -DUNICODE -O2 -Duintptr=unsigned
+CFLAGS=-Wall -Wno-missing-braces -I$(ROOT)/include -I$(ROOT) -I$(ROOT)/kern\
+ -c -D_X86_ -DIS_32 -DWINDOWS -DUNICODE -O2 # -Duintptr=unsigned
 O=o
 FS=fs-win32
 IP=win32