Browse Source

Plan 9 from Bell Labs 2007-08-01

David du Colombier 16 years ago
parent
commit
409f7e28b1

+ 10 - 8
dist/replica/_plan9.db

@@ -7299,6 +7299,7 @@ sys/log/httpd/pathstat - 666 sys sys 958933934 0
 sys/log/httpd/url - 666 sys sys 958933934 0
 sys/log/imap4d - 10000000666 sys sys 958934039 0
 sys/log/ipboot - 10000000666 sys sys 958934040 0
+sys/log/ipconfig - 10000000666 sys sys 1185923302 0
 sys/log/listen - 10000000666 sys sys 958934040 0
 sys/log/mail - 10000000666 sys sys 1080177666 724
 sys/log/nfs - 10000000666 sys sys 958934039 0
@@ -7317,6 +7318,7 @@ sys/log/ssh - 10000000666 sys sys 958934039 0
 sys/log/telnet - 10000000666 sys sys 958934039 0
 sys/log/timesync - 10000000666 sys sys 958934040 0
 sys/log/timesync.d - 20000000775 sys sys 1020896204 0
+sys/log/v6routeradv - 10000000666 sys sys 1185923299 0
 sys/man - 20000000775 sys sys 1041446473 0
 sys/man/1 - 20000000775 sys sys 1158800370 0
 sys/man/1/0intro - 664 sys sys 1101668050 9625
@@ -12464,16 +12466,16 @@ sys/src/cmd/iostats/statsrv.c - 664 sys sys 1166824341 10773
 sys/src/cmd/ip - 20000000775 sys sys 1128605981 0
 sys/src/cmd/ip/6in4.c - 664 sys sys 1185564832 7472
 sys/src/cmd/ip/arp.h - 664 sys sys 944961005 751
-sys/src/cmd/ip/dhcp.h - 664 sys sys 1184880651 3419
+sys/src/cmd/ip/dhcp.h - 664 sys sys 1184696111 3764
 sys/src/cmd/ip/dhcpclient.c - 664 sys sys 1178482836 11969
 sys/src/cmd/ip/dhcpd - 20000000775 sys sys 1063897571 0
 sys/src/cmd/ip/dhcpd/dat.h - 664 sys sys 1084471353 2522
 sys/src/cmd/ip/dhcpd/db.c - 664 sys sys 1143670612 7466
-sys/src/cmd/ip/dhcpd/dhcpd.c - 664 sys sys 1179429075 33386
+sys/src/cmd/ip/dhcpd/dhcpd.c - 664 sys sys 1185922538 35209
 sys/src/cmd/ip/dhcpd/dhcpleases.c - 664 sys sys 1032655001 779
 sys/src/cmd/ip/dhcpd/mkfile - 664 sys sys 1169162185 443
-sys/src/cmd/ip/dhcpd/ndb.c - 664 sys sys 1185389947 5739
-sys/src/cmd/ip/dhcpd/ping.c - 664 sys sys 1184887281 1177
+sys/src/cmd/ip/dhcpd/ndb.c - 664 sys sys 1185920230 5799
+sys/src/cmd/ip/dhcpd/ping.c - 664 sys sys 1185920220 1209
 sys/src/cmd/ip/dhcpd/testlook.c - 664 sys sys 950389140 4640
 sys/src/cmd/ip/dhcpd/testlookup.c - 664 sys sys 950389140 3195
 sys/src/cmd/ip/dhcpd/testping.c - 664 sys sys 950389141 352
@@ -12533,14 +12535,14 @@ sys/src/cmd/ip/imap4d/search.c - 664 sys sys 1015013077 4520
 sys/src/cmd/ip/imap4d/store.c - 664 sys sys 1066317059 1910
 sys/src/cmd/ip/imap4d/utils.c - 664 sys sys 1168894057 2587
 sys/src/cmd/ip/ipconfig - 20000000775 sys sys 1176933436 0
-sys/src/cmd/ip/ipconfig/ipconfig.h - 664 sys sys 1185390045 5683
-sys/src/cmd/ip/ipconfig/ipv6.c - 664 sys sys 1185390096 19652
-sys/src/cmd/ip/ipconfig/main.c - 664 sys sys 1185390323 38954
+sys/src/cmd/ip/ipconfig/ipconfig.h - 664 sys sys 1185922303 5738
+sys/src/cmd/ip/ipconfig/ipv6.c - 664 sys sys 1185923430 20620
+sys/src/cmd/ip/ipconfig/main.c - 664 sys sys 1185923495 39912
 sys/src/cmd/ip/ipconfig/mkfile - 664 sys sys 1184880750 233
 sys/src/cmd/ip/ipconfig/ppp.c - 664 sys sys 1184880751 1046
 sys/src/cmd/ip/linklocal.c - 664 sys sys 1177099730 867
 sys/src/cmd/ip/measure.c - 664 sys sys 944961011 3733
-sys/src/cmd/ip/mkfile - 664 sys sys 1177479927 1260
+sys/src/cmd/ip/mkfile - 664 sys sys 1185920805 1267
 sys/src/cmd/ip/ping.c - 664 sys sys 1184900703 10237
 sys/src/cmd/ip/ppp - 20000000775 sys sys 1065963823 0
 sys/src/cmd/ip/ppp/block.c - 664 sys sys 1015090266 5353

+ 10 - 8
dist/replica/plan9.db

@@ -7299,6 +7299,7 @@ sys/log/httpd/pathstat - 666 sys sys 958933934 0
 sys/log/httpd/url - 666 sys sys 958933934 0
 sys/log/imap4d - 10000000666 sys sys 958934039 0
 sys/log/ipboot - 10000000666 sys sys 958934040 0
+sys/log/ipconfig - 10000000666 sys sys 1185923302 0
 sys/log/listen - 10000000666 sys sys 958934040 0
 sys/log/mail - 10000000666 sys sys 1080177666 724
 sys/log/nfs - 10000000666 sys sys 958934039 0
@@ -7317,6 +7318,7 @@ sys/log/ssh - 10000000666 sys sys 958934039 0
 sys/log/telnet - 10000000666 sys sys 958934039 0
 sys/log/timesync - 10000000666 sys sys 958934040 0
 sys/log/timesync.d - 20000000775 sys sys 1020896204 0
+sys/log/v6routeradv - 10000000666 sys sys 1185923299 0
 sys/man - 20000000775 sys sys 1041446473 0
 sys/man/1 - 20000000775 sys sys 1158800370 0
 sys/man/1/0intro - 664 sys sys 1101668050 9625
@@ -12464,16 +12466,16 @@ sys/src/cmd/iostats/statsrv.c - 664 sys sys 1166824341 10773
 sys/src/cmd/ip - 20000000775 sys sys 1128605981 0
 sys/src/cmd/ip/6in4.c - 664 sys sys 1185564832 7472
 sys/src/cmd/ip/arp.h - 664 sys sys 944961005 751
-sys/src/cmd/ip/dhcp.h - 664 sys sys 1184880651 3419
+sys/src/cmd/ip/dhcp.h - 664 sys sys 1184696111 3764
 sys/src/cmd/ip/dhcpclient.c - 664 sys sys 1178482836 11969
 sys/src/cmd/ip/dhcpd - 20000000775 sys sys 1063897571 0
 sys/src/cmd/ip/dhcpd/dat.h - 664 sys sys 1084471353 2522
 sys/src/cmd/ip/dhcpd/db.c - 664 sys sys 1143670612 7466
-sys/src/cmd/ip/dhcpd/dhcpd.c - 664 sys sys 1179429075 33386
+sys/src/cmd/ip/dhcpd/dhcpd.c - 664 sys sys 1185922538 35209
 sys/src/cmd/ip/dhcpd/dhcpleases.c - 664 sys sys 1032655001 779
 sys/src/cmd/ip/dhcpd/mkfile - 664 sys sys 1169162185 443
-sys/src/cmd/ip/dhcpd/ndb.c - 664 sys sys 1185389947 5739
-sys/src/cmd/ip/dhcpd/ping.c - 664 sys sys 1184887281 1177
+sys/src/cmd/ip/dhcpd/ndb.c - 664 sys sys 1185920230 5799
+sys/src/cmd/ip/dhcpd/ping.c - 664 sys sys 1185920220 1209
 sys/src/cmd/ip/dhcpd/testlook.c - 664 sys sys 950389140 4640
 sys/src/cmd/ip/dhcpd/testlookup.c - 664 sys sys 950389140 3195
 sys/src/cmd/ip/dhcpd/testping.c - 664 sys sys 950389141 352
@@ -12533,14 +12535,14 @@ sys/src/cmd/ip/imap4d/search.c - 664 sys sys 1015013077 4520
 sys/src/cmd/ip/imap4d/store.c - 664 sys sys 1066317059 1910
 sys/src/cmd/ip/imap4d/utils.c - 664 sys sys 1168894057 2587
 sys/src/cmd/ip/ipconfig - 20000000775 sys sys 1176933436 0
-sys/src/cmd/ip/ipconfig/ipconfig.h - 664 sys sys 1185390045 5683
-sys/src/cmd/ip/ipconfig/ipv6.c - 664 sys sys 1185390096 19652
-sys/src/cmd/ip/ipconfig/main.c - 664 sys sys 1185390323 38954
+sys/src/cmd/ip/ipconfig/ipconfig.h - 664 sys sys 1185922303 5738
+sys/src/cmd/ip/ipconfig/ipv6.c - 664 sys sys 1185923430 20620
+sys/src/cmd/ip/ipconfig/main.c - 664 sys sys 1185923495 39912
 sys/src/cmd/ip/ipconfig/mkfile - 664 sys sys 1184880750 233
 sys/src/cmd/ip/ipconfig/ppp.c - 664 sys sys 1184880751 1046
 sys/src/cmd/ip/linklocal.c - 664 sys sys 1177099730 867
 sys/src/cmd/ip/measure.c - 664 sys sys 944961011 3733
-sys/src/cmd/ip/mkfile - 664 sys sys 1177479927 1260
+sys/src/cmd/ip/mkfile - 664 sys sys 1185920805 1267
 sys/src/cmd/ip/ping.c - 664 sys sys 1184900703 10237
 sys/src/cmd/ip/ppp - 20000000775 sys sys 1065963823 0
 sys/src/cmd/ip/ppp/block.c - 664 sys sys 1015090266 5353

+ 11 - 0
dist/replica/plan9.log

@@ -49702,3 +49702,14 @@
 1185652808 1 c sys/src/9/pc/wavelan.c - 664 sys sys 1185652512 27841
 1185681605 0 c sys/man/4/factotum - 664 sys sys 1185680600 14842
 1185813005 0 c sys/src/9/pc/ether8169.c - 664 sys sys 1185812348 26931
+1185921004 0 c sys/src/cmd/ip/dhcp.h - 664 sys sys 1184696111 3764
+1185921004 1 c sys/src/cmd/ip/dhcpd/dhcpd.c - 664 sys sys 1185920348 35144
+1185921004 2 c sys/src/cmd/ip/dhcpd/ndb.c - 664 sys sys 1185920230 5799
+1185921004 3 c sys/src/cmd/ip/dhcpd/ping.c - 664 sys sys 1185920220 1209
+1185921004 4 c sys/src/cmd/ip/mkfile - 664 sys sys 1185920805 1267
+1185922804 0 c sys/src/cmd/ip/dhcpd/dhcpd.c - 664 sys sys 1185922538 35209
+1185922804 1 c sys/src/cmd/ip/ipconfig/ipconfig.h - 664 sys sys 1185922303 5738
+1185924604 0 a sys/log/ipconfig - 10000000666 sys sys 1185923302 0
+1185924604 1 a sys/log/v6routeradv - 10000000666 sys sys 1185923299 0
+1185924604 2 c sys/src/cmd/ip/ipconfig/ipv6.c - 664 sys sys 1185923430 20620
+1185924604 3 c sys/src/cmd/ip/ipconfig/main.c - 664 sys sys 1185923495 39912

+ 0 - 0
sys/log/ipconfig


+ 0 - 0
sys/log/v6routeradv


+ 12 - 4
sys/src/cmd/ip/dhcp.h

@@ -45,7 +45,7 @@ enum
 	OBlprserver=		9,
 	OBimpressserver=	10,
 	OBrlserver=		11,
-	OBhostname=		12,	/* 0xc0 */
+	OBhostname=		12,	/* 0x0c */
 	OBbflen=		13,
 	OBdumpfile=		14,
 	OBdomainname=		15,
@@ -111,9 +111,17 @@ enum
 	ODtftpserver=		66,
 	ODbootfile=		67,
 
-	/* plan9 vendor info options */
-	OP9fs=			128,	/* plan9 file servers */
-	OP9auth=		129,	/* plan9 auth servers */
+	/* plan9 vendor info options, v4 addresses only (deprecated) */
+	OP9fsv4=		128,	/* plan9 file servers */
+	OP9authv4=		129,	/* plan9 auth servers */
+
+	/* plan9 vendor info options, textual addresses, thus v4 or v6 */
+	OP9fs=			130,	/* plan9 file servers */
+	OP9auth=		131,	/* plan9 auth servers */
+	OP9ipaddr=		132,	/* client's address */
+	OP9ipmask=		133,	/* client's subnet mask */
+	OP9ipgw=		134,	/* client's gateway */
+/*	OP9dns=			135,	/* dns servers */
 };
 
 /* a lease that never expires */

+ 105 - 29
sys/src/cmd/ip/dhcpd/dhcpd.c

@@ -9,6 +9,10 @@
  *	ala rfc2131
  */
 
+enum {
+	Maxloglen = 1024,
+};
+
 typedef struct Req Req;
 struct Req
 {
@@ -62,6 +66,8 @@ int	staticlease = StaticLease;
 
 ulong	start;
 
+static int v6opts;
+
 /* option magic */
 char plan9opt[4] = { 'p', '9', ' ', ' ' };
 char genericopt[4] = { 0x63, 0x82, 0x53, 0x63 };
@@ -170,6 +176,7 @@ void	longopt(Req*, int, long);
 void	maskopt(Req*, int, uchar*);
 void	miscoptions(Req*, uchar*);
 int	openlisten(char *net);
+void	p9addrsopt(Req *rp, int t, uchar **ip, int i);
 void	parseoptions(Req*);
 void	proto(Req*, int);
 void	rcvdecline(Req*);
@@ -220,6 +227,9 @@ main(int argc, char **argv)
 	fmtinstall('V', eipfmt);
 	fmtinstall('M', eipfmt);
 	ARGBEGIN {
+	case '6':
+		v6opts = 1;
+		break;
 	case 'd':
 		debug = 1;
 		break;
@@ -283,7 +293,8 @@ main(int argc, char **argv)
 	strcpy(mysysname, readsysname());
 
 	/* put process in background */
-	if(!debug) switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
+	if(!debug)
+	switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
 	case -1:
 		fatal(1, "fork");
 	case 0:
@@ -488,7 +499,9 @@ rcvrequest(Req *rp)
 		/* check for hard assignment */
 		if(rp->staticbinding){
 			if(forme(rp->server))
-				sendack(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease), 1);
+				sendack(rp, rp->ii.ipaddr,
+					(staticlease > minlease? staticlease:
+					minlease), 1);
 			else
 				warning(0, "!Request(%s via %I): for server %I not me",
 					rp->id, rp->gii.ipaddr, rp->server);
@@ -545,7 +558,8 @@ rcvrequest(Req *rp)
 					rp->id, rp->gii.ipaddr, rp->ip, rp->bp->chaddr);
 				sendnak(rp, "not valid");
 			}
-			sendack(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease), 1);
+			sendack(rp, rp->ii.ipaddr, (staticlease > minlease?
+				staticlease: minlease), 1);
 			return;
 		}
 
@@ -558,7 +572,7 @@ rcvrequest(Req *rp)
 		}
 		b = iptobinding(rp->ip, 0);
 		if(b == nil){
-			warning(0, "!Request(%s via %I): no binding for %I for",
+			warning(0, "!Request(%s via %I): no binding for %I",
 				rp->id, rp->gii.ipaddr, rp->ip);
 			return;
 		}
@@ -587,7 +601,8 @@ rcvrequest(Req *rp)
 					rp->id, rp->gii.ipaddr, rp->ciaddr);
 				sendnak(rp, "not valid");
 			}
-			sendack(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease), 1);
+			sendack(rp, rp->ii.ipaddr, (staticlease > minlease?
+				staticlease: minlease), 1);
 			return;
 		}
 
@@ -918,11 +933,11 @@ bootp(Req *rp)
 
 	/* ignore if we don't know what file to load */
 	if(*bp->file == 0){
-		if(rp->genrequest && *iip->bootf2)	/* if not plan 9 and we have an alternate file... */
+		if(rp->genrequest && *iip->bootf2) /* if not plan 9 & have alternate file... */
 			strncpy(bp->file, iip->bootf2, sizeof(bp->file));
 		else if(*iip->bootf)
 			strncpy(bp->file, iip->bootf, sizeof(bp->file));
-		else if(*bp->sname)		/* if we were asked, respond no matter what */
+		else if(*bp->sname) /* if we were asked, respond no matter what */
 			bp->file[0] = '\0';
 		else {
 			warning(0, "no bootfile for %I", iip->ipaddr);
@@ -1110,14 +1125,12 @@ remrequested(Req *rp, int opt)
 void
 miscoptions(Req *rp, uchar *ip)
 {
-	char *p;
-	int i, j;
-	uchar *addrs[2];
-	uchar x[2*IPaddrlen];
-	uchar vopts[64];
+	int i, j, na;
+	uchar x[2*IPaddrlen], vopts[Maxoptlen];
 	uchar *op, *omax;
+	uchar *addrs[2];
+	char *p;
 	char *attr[100], **a;
-	int na;
 	Ndbtuple *t;
 
 	addrs[0] = x;
@@ -1243,18 +1256,24 @@ miscoptions(Req *rp, uchar *ip)
 	/* add plan9 specific options */
 	if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0
 	|| strncmp((char*)rp->vendorclass, "p9-", 3) == 0){
-	/* point to temporary area */
+		/* point to temporary area */
 		op = rp->p;
 		omax = rp->max;
+		/* stash encoded options in vopts */
 		rp->p = vopts;
 		rp->max = vopts + sizeof(vopts) - 1;
 
-		j = lookupserver("fs", addrs, t);
-		addrsopt(rp, OP9fs, addrs, j);
-		j = lookupserver("auth", addrs, t);
-		addrsopt(rp, OP9auth, addrs, j);
+		/* emit old v4 addresses first to make sure that they fit */
+		addrsopt(rp, OP9fsv4, addrs, lookupserver("fs", addrs, t));
+		addrsopt(rp, OP9authv4, addrs, lookupserver("auth", addrs, t));
 
-	/* point back */
+		p9addrsopt(rp, OP9fs, addrs, lookupserver("fs", addrs, t));
+		p9addrsopt(rp, OP9auth, addrs, lookupserver("auth", addrs, t));
+		p9addrsopt(rp, OP9ipaddr, addrs, lookupserver("ip", addrs, t));
+		p9addrsopt(rp, OP9ipmask, addrs, lookupserver("ipmask", addrs, t));
+		p9addrsopt(rp, OP9ipgw, addrs, lookupserver("ipgw", addrs, t));
+
+		/* point back to packet, encapsulate vopts into packet */
 		j = rp->p - vopts;
 		rp->p = op;
 		rp->max = omax;
@@ -1287,7 +1306,7 @@ openlisten(char *net)
 void
 fatal(int syserr, char *fmt, ...)
 {
-	char buf[ERRMAX];
+	char buf[Maxloglen];
 	va_list arg;
 
 	va_start(arg, fmt);
@@ -1300,10 +1319,10 @@ fatal(int syserr, char *fmt, ...)
 	exits(buf);
 }
 
-extern void
+void
 warning(int syserr, char *fmt, ...)
 {
-	char buf[256];
+	char buf[Maxloglen];
 	va_list arg;
 
 	va_start(arg, fmt);
@@ -1370,6 +1389,11 @@ addropt(Req *rp, int t, uchar *ip)
 {
 	if(rp->p + 6 > rp->max)
 		return;
+	if (!isv4(ip)) {
+		if (debug)
+			warning(0, "not a v4 %s server: %I", optname[t], ip);
+		return;
+	}
 	*rp->p++ = t;
 	*rp->p++ = 4;
 	memmove(rp->p, ip+IPv4off, 4);
@@ -1394,14 +1418,29 @@ maskopt(Req *rp, int t, uchar *ip)
 void
 addrsopt(Req *rp, int t, uchar **ip, int i)
 {
+	int v4s, n;
+
 	if(i <= 0)
 		return;
 	if(rp->p + 2 + 4*i > rp->max)
 		return;
+	v4s = 0;
+	for(n = i; n-- > 0; )
+		if (isv4(ip[n]))
+			v4s++;
+	if (v4s <= 0) {
+		if (debug)
+			warning(0, "no v4 %s servers", optname[t]);
+		return;
+	}
 	*rp->p++ = t;
-	*rp->p++ = 4*i;
-	op = seprint(op, oe, "%s(", optname[t]);
+	*rp->p++ = 4*v4s;
+	op = seprint(op, oe, " %s(", optname[t]);
 	while(i-- > 0){
+		if (!isv4(*ip)) {
+			op = seprint(op, oe, " skipping %I ", *ip);
+			continue;
+		}
 		v6tov4(rp->p, *ip);
 		rp->p += 4;
 		op = seprint(op, oe, "%I", *ip);
@@ -1412,6 +1451,40 @@ addrsopt(Req *rp, int t, uchar **ip, int i)
 	op = seprint(op, oe, ")");
 }
 
+void
+p9addrsopt(Req *rp, int t, uchar **ip, int i)
+{
+	char *pkt, *payload;
+
+	if(i <= 0 || !v6opts)
+		return;
+	pkt = (char *)rp->p;
+	*pkt++ = t;			/* option */
+	pkt++;				/* fill in payload length below */
+	payload = pkt;
+	*pkt++ = i;			/* plan 9 address count */
+	op = seprint(op, oe, " %s(", optname[t]);
+	while(i-- > 0){
+		pkt = seprint(pkt, (char *)rp->max, "%I", *ip);
+		if ((uchar *)pkt+1 >= rp->max) {
+			op = seprint(op, oe, "<out of mem1>)");
+			return;
+		}
+		pkt++;			/* leave NUL as terminator */
+		op = seprint(op, oe, "%I", *ip);
+		ip++;
+		if(i > 0)
+			op = seprint(op, oe, " ");
+	}
+	if ((uchar *)pkt - rp->p > 0377) {
+		op = seprint(op, oe, "<out of mem2>)");
+		return;
+	}
+	op = seprint(op, oe, ")");
+	rp->p[1] = pkt - payload;	/* payload length */
+	rp->p = (uchar *)pkt;
+}
+
 void
 byteopt(Req *rp, int t, uchar v)
 {
@@ -1455,8 +1528,10 @@ vectoropt(Req *rp, int t, uchar *v, int n)
 {
 	int i;
 
-	if(n > 255)
+	if(n > 255) {
 		n = 255;
+		op = seprint(op, oe, "vectoropt len %d > 255 ", n);
+	}
 	if(rp->p+n+2 > rp->max)
 		return;
 	*rp->p++ = t;
@@ -1466,9 +1541,10 @@ vectoropt(Req *rp, int t, uchar *v, int n)
 
 	op = seprint(op, oe, "%s(", optname[t]);
 	if(n > 0)
-		op = seprint(op, oe, "%ud", 0);
+		op = seprint(op, oe, "%ud", v[0]);
 	for(i = 1; i < n; i++)
 		op = seprint(op, oe, " %ud", v[i]);
+	op = seprint(op, oe, ")");
 }
 
 int
@@ -1506,7 +1582,6 @@ arpenter(uchar *ip, uchar *ether)
 	int f;
 	char buf[256];
 
-	/* brazil */
 	sprint(buf, "%s/arp", net);
 	f = open(buf, OWRITE);
 	if(f < 0){
@@ -1579,9 +1654,10 @@ logdhcpout(Req *rp, char *type)
 /*
  *  if we get behind, it's useless to try answering since the sender
  *  will probably have retransmitted with a differnt sequence number.
- *  So dump all the last message in the queue.
+ *  So dump all but the last message in the queue.
  */
-void ding(void*, char *msg)
+void
+ding(void*, char *msg)
 {
 	if(strstr(msg, "alarm"))
 		noted(NCONT);

+ 4 - 2
sys/src/cmd/ip/dhcpd/ndb.c

@@ -197,9 +197,11 @@ lookup(Bootp *bp, Info *iip, Info *riip)
 	/* client knows its address? */
 	v4tov6(ciaddr, bp->ciaddr);
 	if(validip(ciaddr)){
-		if(lookupip(ciaddr, iip, 0) < 0)
+		if(lookupip(ciaddr, iip, 0) < 0) {
+			if (debug)
+				warning(0, "don't know %I", ciaddr);
 			return -1;	/* don't know anything about it */
-
+		}
 		if(!samenet(riip->ipaddr, iip)){
 			warning(0, "%I not on %I", ciaddr, riip->ipnet);
 			return -1;

+ 3 - 2
sys/src/cmd/ip/dhcpd/ping.c

@@ -17,7 +17,7 @@ catch(void *a, char *msg)
 
 /*
  *  make sure noone is using the address
- *  IPv4 only
+ *  TODO: ipv6 ping
  */
 int
 icmpecho(uchar *a)
@@ -30,7 +30,8 @@ icmpecho(uchar *a)
 	int rv;
 
 	rv = 0;
-
+	if (!isv4(a))
+		return 0;
 	sprint(buf, "%I", a);
 	fd = dial(netmkaddr(buf, "icmp", "1"), 0, 0, 0);
 	if(fd < 0){

+ 2 - 0
sys/src/cmd/ip/ipconfig/ipconfig.h

@@ -111,6 +111,7 @@ void	dounbind(void);
 int	getndb(void);
 int	ipconfig4(void);
 int	ipconfig6(int);
+long	jitter(void);
 void	lookforip(char*);
 void	mkclientid(void);
 int	nipifcs(char*);
@@ -132,6 +133,7 @@ int	parseoptions(uchar *p, int n);
 int	parseverb(char*);
 void	procsetname(char *fmt, ...);
 void	putndb(void);
+ulong	randint(ulong low, ulong hi);
 void	tweakservers(void);
 void	usage(void);
 int	validip(uchar*);

+ 162 - 125
sys/src/cmd/ip/ipconfig/ipv6.c

@@ -60,11 +60,17 @@ char *icmpmsg6[Maxtype6+1] =
 static char *icmp6opts[] =
 {
 [0]			"unknown option",
-[V6nd_srclladdr]	"sll_addr",
-[V6nd_targlladdr]	"tll_addr",
-[V6nd_pfxinfo]		"pref_opt",
+[V6nd_srclladdr]	"srcll_addr",
+[V6nd_targlladdr]	"targll_addr",
+[V6nd_pfxinfo]		"prefix",
 [V6nd_redirhdr]		"redirect",
-[V6nd_mtu]		"mtu_opt",
+[V6nd_mtu]		"mtu",
+[V6nd_home]		"home",
+[V6nd_srcaddrs]		"src_addrs",
+[V6nd_ip]		"ip",
+[V6nd_rdns]		"rdns",
+[V6nd_9fs]		"9fs",
+[V6nd_9auth]		"9auth",
 };
 
 uchar v6allroutersL[IPaddrlen] = {
@@ -197,6 +203,18 @@ v6paraminit(Conf *cf)
 	cf->validlt = cf->preflt = ~0L;
 }
 
+static char *
+optname(unsigned opt)
+{
+	static char buf[32];
+
+	if (opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) {
+		snprint(buf, sizeof buf, "unknown option %d", opt);
+		return buf;
+	} else
+		return icmp6opts[opt];
+}
+
 static char*
 opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
 {
@@ -211,24 +229,24 @@ opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
 
 		switch (otype) {
 		default:
-			return seprint(p, e, " option=%s ", icmp6opts[otype]);
+			return seprint(p, e, " option=%s ", optname(otype));
 		case V6nd_srclladdr:
 		case V6nd_targlladdr:
 			if (pktsz < osz || osz != 8)
 				return seprint(p, e, " option=%s bad size=%d",
-					icmp6opts[otype], osz);
-			p = seprint(p, e, " option=%s maddr=%E",
-				icmp6opts[otype], a+2);
+					optname(otype), osz);
+			p = seprint(p, e, " option=%s maddr=%E", optname(otype),
+				a+2);
 			break;
 		case V6nd_pfxinfo:
 			if (pktsz < osz || osz != 32)
 				return seprint(p, e, " option=%s: bad size=%d",
-					icmp6opts[otype], osz);
+					optname(otype), osz);
 
 			p = seprint(p, e, " option=%s pref=%I preflen=%3.3d"
 				" lflag=%1.1d aflag=%1.1d unused1=%1.1d"
 				" validlt=%ud preflt=%ud unused2=%1.1d",
-				icmp6opts[otype], a+16, (int)(*(a+2)),
+				optname(otype), a+16, (int)(*(a+2)),
 				(*(a+3) & (1 << 7)) != 0,
 				(*(a+3) & (1 << 6)) != 0,
 				(*(a+3) & 63) != 0,
@@ -454,6 +472,7 @@ recvra6on(char *net, int conn)
 		return IsHostNoRecv;
 }
 
+/* send icmpv6 router solicitation to multicast address for all routers */
 static void
 sendrs(int fd)
 {
@@ -468,6 +487,9 @@ sendrs(int fd)
 
 	if(write(fd, rs, sizeof buff) < sizeof buff)
 		ralog("sendrs: write failed, pkt size %d", sizeof buff);
+	else
+		ralog("sendrs: sent solicitation to %I from %I on %s",
+			rs->dst, rs->src, conf.dev);
 }
 
 /*
@@ -544,6 +566,7 @@ recvrahost(uchar buf[], int pktlen)
 	Mtuopt *mtuo;
 	Prefixopt *prfo;
 	Routeradv *ra;
+	static int first = 1;
 
 	ra = (Routeradv*)buf;
 //	memmove(conf.v6gaddr, ra->src, IPaddrlen);
@@ -554,7 +577,7 @@ recvrahost(uchar buf[], int pktlen)
 	conf.reachtime = nhgetl(ra->rchbltime);
 	conf.rxmitra =   nhgetl(ra->rxmtimer);
 
-	// issueadd6(&conf);	// for conf.v6gaddr?
+//	issueadd6(&conf);		/* for conf.v6gaddr? */
 	if (fprint(conf.cfd, "ra6 recvra 1") < 0)
 		ralog("write(ra6 recvra 1) failed: %r");
 	issuebasera6(&conf);
@@ -567,24 +590,21 @@ recvrahost(uchar buf[], int pktlen)
 			llao = (Lladdropt *)&buf[m];
 			m += 8 * buf[m+1];
 			if (llao->len != 1) {
-				ralog(
-	"recvrahost: illegal len(%d) for source link layer address option",
-					llao->len);
+				ralog("recvrahost: illegal len (%d) for source "
+					"link layer address option", llao->len);
 				return;
 			}
-			if (memcmp(ra->src, v6linklocal, 2) != 0) {
-				ralog(
-			"recvrahost: non-linklocal src addr for router adv %I",
-					ra->src);
+			if (!ISIPV6LINKLOCAL(ra->src)) {
+				ralog("recvrahost: non-link-local src addr for "
+					"router adv %I", ra->src);
 				return;
 			}
 
 			snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
 			arpfd = open(abuf, OWRITE);
 			if (arpfd < 0) {
-				ralog(
-				"recvrahost: couldn't open %s/arp to write: %r",
-					conf.mpoint);
+				ralog("recvrahost: couldn't open %s to write: %r",
+					abuf);
 				return;
 			}
 
@@ -598,8 +618,8 @@ recvrahost(uchar buf[], int pktlen)
 		case V6nd_targlladdr:
 		case V6nd_redirhdr:
 			m += 8 * buf[m+1];
-			ralog("ignoring unexpected optype %s in Routeradv",
-				icmp6opts[optype]);
+			ralog("ignoring unexpected option type `%s' in Routeradv",
+				optname(optype));
 			break;
 		case V6nd_mtu:
 			mtuo = (Mtuopt*)&buf[m];
@@ -621,6 +641,15 @@ recvrahost(uchar buf[], int pktlen)
 			conf.validlt = nhgetl(prfo->validlt);
 			conf.preflt =  nhgetl(prfo->preflt);
 			issueadd6(&conf);
+			if (first) {
+				first = 0;
+				ralog("got initial RA from %I on %s; pfx %I",
+					ra->src, conf.dev, prfo->pref);
+			}
+			break;
+		case V6nd_srcaddrs:
+			/* netsbd sends this, so quietly ignore it for now */
+			m += 8 * buf[m+1];
 			break;
 		default:
 			m += 8 * buf[m+1];
@@ -631,7 +660,7 @@ recvrahost(uchar buf[], int pktlen)
 }
 
 /*
- * daemon to receive router adverisements
+ * daemon to receive router advertisements from routers
  */
 void
 recvra6(void)
@@ -639,6 +668,7 @@ recvra6(void)
 	int fd, cfd, n, sendrscnt, sleepfor;
 	uchar buf[4096];
 
+	/* TODO: why not v6allroutersL? */
 	fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
 	if (fd < 0)
 		sysfatal("can't open icmp_ra connection: %r");
@@ -652,57 +682,64 @@ recvra6(void)
 	default:
 		return;
 	case 0:
-		procsetname("recvra6 on %s", conf.dev);
-		ralog("recvra6 on %s", conf.dev);
-		sleepfor = nrand(10);
-		for (;;) {
-			alarm(sleepfor);
-			n = read(fd, buf, sizeof buf);
-			alarm(0);
-			if (n <= 0) {
-				if (sendrscnt > 0) {
-					sendrscnt--;
-					if (recvra6on(conf.mpoint, myifc) ==
-					    IsHostRecv)
-						sendrs(fd);
-					sleepfor = V6rsintvl+nrand(100);
-				}
-				if (sendrscnt == 0) {
-					sendrscnt--;
-					sleepfor = 0;
-					ralog(
-				"recvra6: no router advs after %d sols on %s",
-						 Maxv6rss, conf.dev);
-				}
-				continue;
-			}
+		break;
+	}
 
-			sleepfor = 0;
-			switch (recvra6on(conf.mpoint, myifc)) {
-			case IsRouter:
-				recvrarouter(buf, n);
-				break;
-			case IsHostRecv:
-				recvrahost(buf, n);
-				break;
-			case IsHostNoRecv:
-				ralog("recvra6: recvra off, quitting");
-				close(fd);
-				exits(0);
-			default:
-				ralog(
-				"recvra6: unable to read router status on %s",
-					conf.dev);
-				break;
+	procsetname("recvra6 on %s", conf.dev);
+	ralog("recvra6 on %s", conf.dev);
+	sleepfor = jitter();
+	for (;;) {
+		/*
+		 * We only get 3 (Maxv6rss) tries, so make sure we
+		 * wait long enough to be certain that at least one RA
+		 * will be transmitted.
+		 */
+		if (sleepfor < 7000)
+			sleepfor = 7000;
+		alarm(sleepfor);
+		n = read(fd, buf, sizeof buf);
+		alarm(0);
+		if (n <= 0) {
+			if (sendrscnt > 0) {
+				sendrscnt--;
+				if (recvra6on(conf.mpoint, myifc) == IsHostRecv)
+					sendrs(fd);
+				sleepfor = V6rsintvl + nrand(100);
 			}
+			if (sendrscnt == 0) {
+				sendrscnt--;
+				sleepfor = 0;
+				ralog("recvra6: no router advs after %d sols on %s",
+					Maxv6rss, conf.dev);
+			}
+			continue;
+		}
+
+		sleepfor = 0;
+		sendrscnt = -1;		/* got at least initial ra; no whining */
+		switch (recvra6on(conf.mpoint, myifc)) {
+		case IsRouter:
+			recvrarouter(buf, n);
+			break;
+		case IsHostRecv:
+			recvrahost(buf, n);
+			break;
+		case IsHostNoRecv:
+			ralog("recvra6: recvra off, quitting on %s", conf.dev);
+			close(fd);
+			exits(0);
+		default:
+			ralog("recvra6: unable to read router status on %s",
+				conf.dev);
+			break;
 		}
 	}
 }
 
 /*
  * return -1 -- error, reading/writing some file,
- *         0 -- no arptable updates
- *         1 -- successful arptable update
+ *         0 -- no arp table updates
+ *         1 -- successful arp table update
  */
 int
 recvrs(uchar *buf, int pktlen, uchar *sol)
@@ -792,7 +829,8 @@ sendra(int fd, uchar *dst, int rlt)
 		/* global unicast address? */
 		if (!ISIPV6LINKLOCAL(lifc->ip) && !ISIPV6MCAST(lifc->ip) &&
 		    memcmp(lifc->ip, IPnoaddr, IPaddrlen) != 0 &&
-		    memcmp(lifc->ip, v6loopback, IPaddrlen) != 0) {
+		    memcmp(lifc->ip, v6loopback, IPaddrlen) != 0 &&
+		    !isv4(lifc->ip)) {
 			memmove(prfo->pref, lifc->net, IPaddrlen);
 
 			/* hack to find prefix length */
@@ -822,19 +860,19 @@ sendra(int fd, uchar *dst, int rlt)
 
 	pkt2str(buf+40, buf+pktsz, abuf, abuf+1024);
 	if(write(fd, buf, pktsz) < pktsz)
-		ralog("ra wr fail %s", abuf);
-	else
-		ralog("ra wr succ %s", abuf);
+		ralog("sendra fail %s: %r", abuf);
+	else if (debug)
+		ralog("sendra succ %s", abuf);
 }
 
 /*
- * daemon to send router advertisements
+ * daemon to send router advertisements to hosts
  */
 void
 sendra6(void)
 {
 	int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
-	long lastra, ctime;
+	long lastra, now;
 	uchar buf[4096], dst[IPaddrlen];
 	Ipifc *ifc = nil;
 
@@ -852,63 +890,61 @@ sendra6(void)
 	default:
 		return;
 	case 0:
-		procsetname("sendra6 on %s", conf.dev);
-		ralog("sendra6 on %s", conf.dev);
-		sleepfor = nrand(10);
-		for (;;) {
-			lastra = time(0);
-			alarm(sleepfor);
-			n = read(fd, buf, sizeof buf);
-			alarm(0);
-
-			ifc = readipifc(conf.mpoint, ifc, myifc);
-			if (ifc == nil) {
-				ralog("sendra6: unable to read router pars on %s",
-					conf.mpoint);
+		break;
+	}
+
+	procsetname("sendra6 on %s", conf.dev);
+	ralog("sendra6 on %s", conf.dev);
+	sleepfor = jitter();
+	for (;;) {
+		lastra = time(0);
+		if (sleepfor < 0)
+			sleepfor = 0;
+		alarm(sleepfor);
+		n = read(fd, buf, sizeof buf);
+		alarm(0);
+
+		ifc = readipifc(conf.mpoint, ifc, myifc);
+		if (ifc == nil) {
+			ralog("sendra6: can't read router params on %s",
+				conf.mpoint);
+			continue;
+		}
+
+		if (ifc->sendra6 <= 0)
+			if (nquitmsgs > 0) {
+				sendra(fd, v6allnodesL, 0);
+				nquitmsgs--;
+				sleepfor = Minv6interradelay + jitter();
 				continue;
+			} else {
+				ralog("sendra6: sendra off, quitting on %s",
+					conf.dev);
+				exits(0);
 			}
 
-			if (ifc->sendra6 <= 0)
-				if (nquitmsgs > 0) {
-					sendra(fd, v6allnodesL, 0);
-					nquitmsgs--;
-					sleepfor = Minv6interradelay +
-						nrand(10);
-					continue;
-				} else {
-					ralog("sendra6: quitting");
-					exits(0);
-				}
-
-			nquitmsgs = Maxv6finalras;
-
-			if (n <= 0) {			/* no RS */
-				if (sendracnt > 0)
-					sendracnt--;
-				sleepfor = ifc->rp.minraint +
-					nrand(ifc->rp.maxraint + 1 -
-						ifc->rp.minraint);
-			} else {			/* respond to RS */
-				dstknown = recvrs(buf, n, dst);
-				ctime = time(0);
-
-				if (ctime - lastra < Minv6interradelay) {
-					/* too close, skip */
-					sleepfor = lastra +
-						Minv6interradelay +
-						nrand(10) - ctime;
-					continue;
-				}
-				sleepfor = ifc->rp.minraint +
-					nrand(ifc->rp.maxraint + 1 -
-						ifc->rp.minraint);
-				sleep(nrand(10));
+		nquitmsgs = Maxv6finalras;
+
+		if (n <= 0) {			/* no RS */
+			if (sendracnt > 0)
+				sendracnt--;
+		} else {			/* respond to RS */
+			dstknown = recvrs(buf, n, dst);
+			now = time(0);
+
+			if (now - lastra < Minv6interradelay) {
+				/* too close, skip */
+				sleepfor = lastra + Minv6interradelay +
+					jitter() - now;
+				continue;
 			}
-			if (dstknown > 0)
-				sendra(fd, dst, 1);
-			else
-				sendra(fd, v6allnodesL, 1);
+			sleep(jitter());
 		}
+		sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint);
+		if (dstknown > 0)
+			sendra(fd, dst, 1);
+		else
+			sendra(fd, v6allnodesL, 1);
 	}
 }
 
@@ -950,6 +986,7 @@ doipv6(int what)
 	case Vra6:
 		issuebasera6(&conf);
 		issuerara6(&conf);
+		dolog = 1;
 		startra6();
 		break;
 	}

+ 92 - 64
sys/src/cmd/ip/ipconfig/main.c

@@ -9,7 +9,7 @@
 #include "../dhcp.h"
 #include "ipconfig.h"
 
-#define DEBUG if(debug)print
+#define DEBUG if(debug)warning
 
 /* possible verbs */
 enum
@@ -219,7 +219,6 @@ void	usage(void);
 int	validip(uchar*);
 void	writendb(char*, int, int);
 
-/* TODO: verify against code & ipconfig(8) */
 void
 usage(void)
 {
@@ -303,8 +302,7 @@ parse6pref(int argc, char **argv)
 		parseip(conf.v6pref, argv[0]);
 		break;
 	}
-	if (1)
-		print("pref %I len %d\n", conf.v6pref, conf.prefixlen);
+	DEBUG("parse6pref: pref %I len %d", conf.v6pref, conf.prefixlen);
 }
 
 /* parse router advertisement (keyword, value) pairs */
@@ -344,7 +342,7 @@ parse6ra(int argc, char **argv)
 		else if (strcmp(kw, "routerlt") == 0)
 			conf.routerlt = atoi(val);
 		else {
-			fprint(2, "%s: bad ra6 keyword %s\n", argv0, kw);
+			warning("bad ra6 keyword %s", kw);
 			usage();
 		}
 		i += 2;
@@ -567,7 +565,7 @@ havendb(char *net)
 	char buf[128];
 
 	snprint(buf, sizeof buf, "%s/ndb", net);
-	if((d = dirstat("/net/ndb")) == nil)
+	if((d = dirstat(buf)) == nil)
 		return 0;
 	if(d->length == 0){
 		free(d);
@@ -627,8 +625,7 @@ doadd(int retry)
 
 	if(!validip(conf.laddr))
 		if(retry && dodhcp && !noconfig){
-			fprint(2, "%s: couldn't determine ip address, retrying\n",
-				argv0);
+			warning("couldn't determine ip address, retrying");
 			dhcpwatch(1);
 			return;
 		} else
@@ -675,13 +672,12 @@ doremove(void)
 				conf.mpoint, nifc->index);
 			cfd = open(file, ORDWR);
 			if(cfd < 0){
-				fprint(2, "%s: can't open %s: %r\n",
-					argv0, conf.mpoint);
+				warning("can't open %s: %r", conf.mpoint);
 				continue;
 			}
 			if(fprint(cfd, "remove %I %M", lifc->ip, lifc->mask) < 0)
-				fprint(2, "%s: can't remove %I %M from %s: %r\n",
-					argv0, lifc->ip, lifc->mask, file);
+				warning("can't remove %I %M from %s: %r",
+					lifc->ip, lifc->mask, file);
 		}
 	}
 }
@@ -700,13 +696,11 @@ dounbind(void)
 				conf.mpoint, nifc->index);
 			cfd = open(file, ORDWR);
 			if(cfd < 0){
-				fprint(2, "%s: can't open %s: %r\n",
-					argv0, conf.mpoint);
+				warning("can't open %s: %r", conf.mpoint);
 				break;
 			}
 			if(fprint(cfd, "unbind") < 0)
-				fprint(2, "%s: can't unbind from %s: %r\n",
-					argv0, file);
+				warning("can't unbind from %s: %r", file);
 			break;
 		}
 	}
@@ -803,14 +797,13 @@ binddevice(void)
 
 		/* specify medium as ethernet, bind the interface to it */
 		if(fprint(conf.cfd, "bind %s %s", conf.type, conf.dev) < 0)
-			sysfatal("binding device: %r");
+			sysfatal("%s: bind %s %s: %r", buf, conf.type, conf.dev);
 	} else {
 		/* open the old interface */
 		snprint(buf, sizeof buf, "%s/ipifc/%d/ctl", conf.mpoint, myifc);
 		conf.cfd = open(buf, ORDWR);
 		if(conf.cfd < 0)
-			sysfatal("opening %s/ipifc/%d/ctl: %r",
-				conf.mpoint, myifc);
+			sysfatal("open %s: %r", buf);
 	}
 
 }
@@ -839,7 +832,7 @@ ip4cfg(void)
 	}
 
 	if(write(conf.cfd, buf, n) < 0){
-		fprint(2, "ipconfig: write(%s): %r\n", buf);
+		warning("write(%s): %r", buf);
 		return -1;
 	}
 
@@ -858,7 +851,7 @@ ipunconfig(void)
 
 	if(!validip(conf.laddr))
 		return;
-	DEBUG("couldn't renew IP lease, releasing %I\n", conf.laddr);
+	DEBUG("couldn't renew IP lease, releasing %I", conf.laddr);
 	n = sprint(buf, "remove");
 	n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
 
@@ -954,7 +947,7 @@ dhcpwatch(int needconfig)
 		break;
 	}
 
-	dolog = 1;
+	dolog = 1;			/* log, don't print */
 	procsetname("dhcpwatch");
 	/* keep trying to renew the lease */
 	for(;;){
@@ -1132,7 +1125,7 @@ dhcpsend(int type)
 	 *  is truncated.
 	 */
 	if(write(conf.fd, &bp, sizeof bp) != sizeof bp)
-		fprint(2, "dhcpsend: write failed: %r\n");
+		warning("dhcpsend: write failed: %r");
 }
 
 void
@@ -1141,7 +1134,7 @@ dhcprecv(void)
 	int i, n, type;
 	ulong lease;
 	char err[ERRMAX];
-	uchar buf[8000], vopts[256];
+	uchar buf[8000], vopts[256], taddr[IPaddrlen];
 	Bootp *bp;
 
 	alarm(1000);
@@ -1151,27 +1144,27 @@ dhcprecv(void)
 	if(n < 0){
 		errstr(err, sizeof err);
 		if(strstr(err, "interrupt") == nil)
-			fprint(2, "ipconfig: bad read: %s\n", err);
+			warning("dhcprecv: bad read: %s", err);
 		else
-			DEBUG("read timed out\n");
+			DEBUG("dhcprecv: read timed out");
 		return;
 	}
 
 	bp = parsebootp(buf, n);
 	if(bp == 0) {
-		DEBUG("parsebootp failed: dropping packet\n");
+		DEBUG("parsebootp failed: dropping packet");
 		return;
 	}
 
 	type = optgetbyte(bp->optdata, ODtype);
 	switch(type) {
 	default:
-		fprint(2, "%s: unknown type: %d\n", argv0, type);
+		warning("dhcprecv: unknown type: %d", type);
 		break;
 	case Offer:
 		DEBUG("got offer from %V ", bp->siaddr);
 		if(conf.state != Sselecting){
-			DEBUG("\n");
+//			DEBUG("");
 			break;
 		}
 		lease = optgetulong(bp->optdata, ODlease);
@@ -1180,21 +1173,19 @@ dhcprecv(void)
 			 * The All_Aboard NAT package from Internet Share
 			 * doesn't give a lease time, so we have to assume one.
 			 */
-			fprint(2, "%s: Offer with %lud lease, using %d\n",
-				argv0, lease, MinLease);
+			warning("Offer with %lud lease, using %d", lease, MinLease);
 			lease = MinLease;
 		}
 		DEBUG("lease=%lud ", lease);
 		if(!optgetaddr(bp->optdata, ODserverid, conf.server)) {
-			fprint(2, "%s: Offer from server with invalid serverid\n",
-				argv0);
+			warning("Offer from server with invalid serverid");
 			break;
 		}
 
 		v4tov6(conf.laddr, bp->yiaddr);
 		memmove(conf.sname, bp->sname, sizeof conf.sname);
 		conf.sname[sizeof conf.sname-1] = 0;
-		DEBUG("server=%I sname=%s\n", conf.server, conf.sname);
+		DEBUG("server=%I sname=%s", conf.server, conf.sname);
 		conf.offered = lease;
 		conf.state = Srequesting;
 		dhcpsend(Request);
@@ -1214,8 +1205,7 @@ dhcprecv(void)
 			 * The All_Aboard NAT package from Internet Share
 			 * doesn't give a lease time, so we have to assume one.
 			 */
-			fprint(2, "%s: Ack with %lud lease, using %d\n",
-				argv0, lease, MinLease);
+			warning("Ack with %lud lease, using %d", lease, MinLease);
 			lease = MinLease;
 		}
 		DEBUG("lease=%lud ", lease);
@@ -1271,9 +1261,9 @@ dhcprecv(void)
 			if(validip(conf.fs) && Oflag)
 				n = 1;
 			else {
-//				n = optgetp9addrs(vopts, OP9fs, conf.fs, 2);
-//				if (n == 0)
-					n = optgetaddrs(vopts, OP9fs,
+				n = optgetp9addrs(vopts, OP9fs, conf.fs, 2);
+				if (n == 0)
+					n = optgetaddrs(vopts, OP9fsv4,
 						conf.fs, 2);
 			}
 			for(i = 0; i < n; i++)
@@ -1282,25 +1272,52 @@ dhcprecv(void)
 			if(validip(conf.auth) && Oflag)
 				n = 1;
 			else {
-//				n = optgetp9addrs(vopts, OP9auth, conf.auth, 2);
-//				if (n == 0)
-					n = optgetaddrs(vopts, OP9auth,
+				n = optgetp9addrs(vopts, OP9auth, conf.auth, 2);
+				if (n == 0)
+					n = optgetaddrs(vopts, OP9authv4,
 						conf.auth, 2);
 			}
 			for(i = 0; i < n; i++)
 				DEBUG("auth=%I ", conf.auth + i*IPaddrlen);
+
+			n = optgetp9addrs(vopts, OP9ipaddr, taddr, 1);
+			if (n > 0)
+				memmove(conf.laddr, taddr, IPaddrlen);
+			n = optgetp9addrs(vopts, OP9ipmask, taddr, 1);
+			if (n > 0)
+				memmove(conf.mask, taddr, IPaddrlen);
+			n = optgetp9addrs(vopts, OP9ipgw, taddr, 1);
+			if (n > 0)
+				memmove(conf.gaddr, taddr, IPaddrlen);
+			DEBUG("new ipaddr=%I new ipmask=%M new ipgw=%I",
+				conf.laddr, conf.mask, conf.gaddr);
 		}
 		conf.lease = lease;
 		conf.state = Sbound;
-		DEBUG("server=%I sname=%s\n", conf.server, conf.sname);
+		DEBUG("server=%I sname=%s", conf.server, conf.sname);
 		break;
 	case Nak:
 		conf.state = Sinit;
-		fprint(2, "%s: recved dhcpnak on %s\n", argv0, conf.mpoint);
+		warning("recved dhcpnak on %s", conf.mpoint);
 		break;
 	}
 }
 
+/* return pseudo-random integer in range low...(hi-1) */
+ulong
+randint(ulong low, ulong hi)
+{
+	if (hi < low)
+		return low;
+	return low + nrand(hi - low);
+}
+
+long
+jitter(void)		/* compute small pseudo-random delay in ms */
+{
+	return randint(0, 10*1000);
+}
+
 int
 openlisten(void)
 {
@@ -1317,8 +1334,8 @@ openlisten(void)
 			sysfatal("can't announce for dhcp: %r");
 
 		/* might be another client - wait and try again */
-		fprint(2, "%s: can't announce: %r\n", argv0);
-		sleep((nrand(10)+1)*1000);
+		warning("can't announce %s: %r", data);
+		sleep(jitter());
 		if(n > 10)
 			return -1;
 	}
@@ -1392,7 +1409,11 @@ optaddstr(uchar *p, int op, char *v)
 	return p+2+n;
 }
 
-/* parse p, looking for option `op'; return ptr to opt, store length via np */
+/*
+ * parse p, looking for option `op'.  if non-nil, np points to minimum length.
+ * return nil if option is too small, else ptr to opt, and
+ * store actual length via np if non-nil.
+ */
 uchar*
 optget(uchar *p, int op, int *np)
 {
@@ -1407,8 +1428,9 @@ optget(uchar *p, int op, int *np)
 			continue;
 		}
 		if(np != nil){
-			if(*np > len)
+			if(*np > len) {
 				return 0;
+			}
 			*np = len;
 		}
 		return p;
@@ -1453,6 +1475,7 @@ optgetaddr(uchar *p, int op, uchar *ip)
 	return 1;
 }
 
+/* expect at most n addresses; ip[] only has room for that many */
 int
 optgetaddrs(uchar *p, int op, uchar *ip, int n)
 {
@@ -1470,22 +1493,27 @@ optgetaddrs(uchar *p, int op, uchar *ip, int n)
 	return i;
 }
 
+/* expect at most n addresses; ip[] only has room for that many */
 int
 optgetp9addrs(uchar *ap, int op, uchar *ip, int n)
 {
-	int len, i, slen;
+	int len, i, slen, addrs;
 	char *p;
 
+	len = 1;			/* minimum bytes needed */
 	p = (char *)optget(ap, op, &len);
 	if(p == nil)
 		return 0;
-	for (i = 0; i < n && len > 0; i++) {
+	addrs = *p++;			/* first byte is address count */
+	for (i = 0; i < n  && i < addrs && len > 0; i++) {
 		slen = strlen(p) + 1;
 		parseip(&ip[i*IPaddrlen], p);
+		DEBUG("got plan 9 option %d addr %I (%s)",
+			op, &ip[i*IPaddrlen], p);
 		p += slen;
 		len -= slen;
 	}
-	return i;
+	return addrs;
 }
 
 int
@@ -1537,25 +1565,25 @@ parseoptions(uchar *p, int n)
 		if(code == OBpad)
 			continue;
 		if(n == 0) {
-			fprint(2,
-		"%s: parse: bad option: 0x%ux: truncated: opt length = %d\n",
-				argv0, code, nin);
+			warning("parseoptions: bad option: 0x%ux: truncated: "
+				"opt length = %d", code, nin);
 			return -1;
 		}
 
 		len = *p++;
 		n--;
+		DEBUG("parseoptions: %s(%d) len %d, bytes left %d",
+			option[code].name, code, len, n);
 		if(len > n) {
-			fprint(2,
-		"%s: parse: bad option: 0x%ux: %d > %d: opt length = %d\n",
-				argv0, code, len, n, nin);
+			warning("parseoptions: bad option: 0x%ux: %d > %d: "
+				"opt length = %d", code, len, n, nin);
 			return -1;
 		}
 		p += len;
 		n -= len;
 	}
 
-	/* make sure packet ends with an OBend all the optget code */
+	/* make sure packet ends with an OBend after all the optget code */
 	*p = OBend;
 	return 0;
 }
@@ -1572,7 +1600,7 @@ parsebootp(uchar *p, int n)
 
 	bp = (Bootp*)p;
 	if(n < bp->optmagic - p) {
-		fprint(2, "%s: parse: short bootp packet\n", argv0);
+		warning("parsebootp: short bootp packet");
 		return nil;
 	}
 
@@ -1580,7 +1608,7 @@ parsebootp(uchar *p, int n)
 		return nil;
 
 	if(bp->op != Bootreply) {
-		fprint(2, "%s: parse: bad op\n", argv0);
+		warning("parsebootp: bad op %d", bp->op);
 		return nil;
 	}
 
@@ -1588,16 +1616,17 @@ parsebootp(uchar *p, int n)
 	p = bp->optmagic;
 
 	if(n < 4) {
-		fprint(2, "%s: parse: not option data\n", argv0);
+		warning("parsebootp: no option data");
 		return nil;
 	}
 	if(memcmp(optmagic, p, 4) != 0) {
-		fprint(2, "%s: parse: bad opt magic %ux %ux %ux %ux\n", argv0,
+		warning("parsebootp: bad opt magic %ux %ux %ux %ux",
 			p[0], p[1], p[2], p[3]);
 		return nil;
 	}
 	p += 4;
 	n -= 4;
+	DEBUG("parsebootp: new packet");
 	if(parseoptions(p, n) < 0)
 		return nil;
 	return bp;
@@ -1618,8 +1647,6 @@ writendb(char *s, int n, int append)
 		fd = open(file, OWRITE|OTRUNC);
 	write(fd, s, n);
 	close(fd);
-	if (debug)
-		write(1, s, n);
 }
 
 /* put server addresses into the ndb entry */
@@ -1879,6 +1906,7 @@ optgetx(uchar *p, uchar opt)
 	case Tvec:
 		n = optgetvec(p, opt, vec, sizeof vec);
 		if(n > 0)
+			/* what's %H?  it's not installed */
 			s = smprint("%s=%.*H", o->name, n, vec);
 		break;
 	}

+ 2 - 1
sys/src/cmd/ip/mkfile

@@ -1,6 +1,7 @@
 </$objtype/mkfile
 
-TARG = 	dhcpclient\
+TARG = 	6in4\
+	dhcpclient\
 	ftpd\
 	gping\
 	hogports\