code: plan9front

Download patch

ref: 1be331f2084e094f6322744083012b4e394f39fd
parent: cbf5d3dc340da5b96cd1282e622a3f862c5b103e
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun May 21 13:53:00 EDT 2023

ip/ppp, ip/pppoe: handle ipv6 address auto-configuration, call ip/ipconfig

Change ip/ppp to call ip/ipconfig to add and remove
addresses to avoid duplicating code for removing
ndb entries and handling default routes as well as
allow ipv6 address auto-configuration.

--- a/sys/man/8/ppp
+++ b/sys/man/8/ppp
@@ -20,6 +20,9 @@
 ] [
 .B -p
 .I dev
+|
+.B -e
+.I dev
 ] [
 .B -x
 .I netmntpt
@@ -27,6 +30,9 @@
 .B -t
 .I modemcmd
 ] [
+.B -U
+.I duid
+] [
 .I local
 [
 .I remote
@@ -35,32 +41,28 @@
 .B ip/pppoe
 [
 .B -PdcCr
-]
-[
+] [
 .B -A
 .I acname
-]
-[
+] [
 .B -S
 .I srvname
-]
-[
+] [
+.B -U
+.I duid
+] [
 .B -k
 .I keyspec
-]
-[
+] [
 .B -m
 .I mtu
-]
-[
+] [
 .B -b
 .I baud
-]
-[
+] [
 .B -x
 .I pppnetmntpt
-]
-[
+] [
 .I ether
 ]
 .PP
@@ -67,16 +69,13 @@
 .B ip/pptp
 [
 .B -dP
-]
-[
+] [
 .B -k
 .I keyspec
-]
-[
+] [
 .B -w
 .I window
-]
-[
+] [
 .B -x
 .I pppnetmntpt
 ]
@@ -98,7 +97,6 @@
 .I tcp-dir
 .SH DESCRIPTION
 The Point-to-Point Protocol is used to encapsulate Internet Protocol packets
-in IPv4 packets
 for transfer over serial lines or other protocol connections.
 .I Ppp
 can run either as a client or, with the
@@ -130,6 +128,12 @@
 .B C
 disallow IP header compression
 .TP
+.B e
+assigns
+.I dev
+to the packet interface device (for identification only),
+but otherwise communicates over standard I/O.
+.TP
 .B f
 make PPP add HDLC framing.  This is necessary when using
 PPP over a serial line or a TCP connection
@@ -169,6 +173,20 @@
 .I modemcmd
 to the device
 .TP
+.B U
+use
+.I duid
+as the DHCPv6 client identier.
+.I Pppoe
+creates the
+.I duid
+from the ethernet address (DUID-LL) of
+.I dev
+when not specified and passes it on to
+.IR ppp .
+See also
+.IR ipconfig (8)).
+.TP
 .B u
 before starting the PPP protocol with the remote end, shuttle
 bytes between the device and standard I/O until an EOF on standard
@@ -291,6 +309,8 @@
 .br
 .B /sys/src/cmd/ip/pppoe.c
 .SH SEE ALSO
+.IR ipconfig (8),
 .I gre
 in
 .IR ip (3)
+
--- a/sys/src/cmd/ip/ppp/ppp.c
+++ b/sys/src/cmd/ip/ppp/ppp.c
@@ -17,9 +17,9 @@
 static 	int	pppframing = 1;
 static	int	noipcompress;
 static	int	server;
-static	int noauth;
+static	int	noauth;
 static	int	dying;		/* flag to signal to all threads its time to go */
-static	int	primary;	/* this is the primary IP interface */
+static	int	primary;
 static	char	*chatfile;
 
 int	debug;
@@ -98,8 +98,6 @@
 static	void		ptimer(PPP*, Pstate*);
 static	int		putframe(PPP*, int, Block*);
 static	void		putlqm(PPP*);
-static	void		putndb(PPP*);
-static	void		refresh(char*);
 static	void		putpaprequest(PPP*);
 static	void		rcv(PPP*, Pstate*, Block*);
 static	void		rejopts(PPP*, Pstate*, Block*, int);
@@ -112,14 +110,14 @@
 static  void		dmppkt(char *s, uchar *a, int na);
 
 void
-pppopen(PPP *ppp, int mediain, int mediaout, char *net,
+pppopen(PPP *ppp, int mediain, int mediaout, int shellin, char *net, char *dev,
 	Ipaddr ipaddr[2], Ipaddr remip[2],
-	int mtu, int framing)
+	int mtu, int framing, char *duid)
 {
 	int i;
 
 	ppp->ipfd = -1;
-	ppp->ipcfd = -1;
+
 	invalidate(ppp->remote);
 	invalidate(ppp->local);
 	invalidate(ppp->curremote);
@@ -134,9 +132,14 @@
 	invalidate(ppp->curremote6);
 	invalidate(ppp->curlocal6);
 
+	ppp->dev = dev;
+	ppp->duid = duid;
+
 	ppp->mediain = mediain;
 	ppp->mediaout = mediaout;
 
+	ppp->shellin = shellin;
+
 	for(i=0; i<2; i++){
 		if(validv4(ipaddr[i])){
 			ipmove(ppp->local, ipaddr[i]);
@@ -160,14 +163,8 @@
 	ppp->net = net;
 
 	init(ppp);
-	switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
-	case -1:
-		terminate(ppp, "forking mediainproc", 1);
-	case 0:
-		mediainproc(ppp);
-		terminate(ppp, "mediainproc", 0);
-		exits(nil);
-	}
+	mediainproc(ppp);
+	terminate(ppp, "mediainproc", 0);
 }
 
 static void
@@ -781,10 +778,11 @@
 static void
 getipinfo(PPP *ppp)
 {
+	char buf[32];
 	char *av[3];
 	int ndns, nwins;
-	char ip[64];
 	Ndbtuple *t, *nt;
+	Ipaddr ip;
 
 	if(!validv4(ppp->local))
 		return;
@@ -791,16 +789,18 @@
 
 	av[0] = "dns";
 	av[1] = "wins";
-	sprint(ip, "%I", ppp->local);
-	t = csipinfo(ppp->net, "ip", ip, av, 2);
+	snprint(buf, sizeof buf, "%I", ppp->local);
+	t = csipinfo(ppp->net, "ip", buf, av, 2);
 	ndns = nwins = 0;
 	for(nt = t; nt != nil; nt = nt->entry){
+		if (parseip(ip, nt->val) == -1 || !validv4(ip))
+			continue;
 		if(strcmp(nt->attr, "dns") == 0){
 			if(ndns < 2)
-				parseip(ppp->dns[ndns++], nt->val);
+				ipmove(ppp->dns[ndns++], ip);
 		} else if(strcmp(nt->attr, "wins") == 0){
 			if(nwins < 2)
-				parseip(ppp->wins[nwins++], nt->val);
+				ipmove(ppp->wins[nwins++], ip);
 		}
 	}
 	if(t != nil)
@@ -1611,54 +1611,67 @@
 }
 
 static void
-defroute(char *net, char *verb, Ipaddr gate, Ipaddr local)
+ipconfig(int shell, char *net, char *dev, int mtu, Ipaddr gate, Ipaddr dns[2], char *duid)
 {
-	char path[128];
-	int fd;
+	fprint(shell, "ip/ipconfig -x %q ", net);
+	if(!primary){
+		/* don't write /net/ndb */
+		fprint(shell, "-P ");
+	} else {
+		/* write dns servers in /net/ndb */
+		if(dns != nil){
+			int i;
 
-	snprint(path, sizeof path, "%s/iproute", net);
-	fd = open(path, ORDWR);
-	if(fd < 0)
-		return;
-	fprint(fd, "tag ppp\n");
-	fprint(fd, "%s 0.0.0.0 0.0.0.0 %I %I 255.255.255.255\n", verb, gate, local);
-	close(fd);
+			for(i = 0; i < 2; i++){
+				if(validv4(dns[i]))
+					fprint(shell, "-s %I ", dns[i]);
+			}
+		}
+		/* set default gateway */
+		if(gate != nil)
+			fprint(shell, "-g %I ", gate);
+	}
+	/* allow dhcpv6 */
+	if(duid != nil)
+		fprint(shell, "-dU %q ", duid);
+	if(mtu > 0)
+		fprint(shell, "-m %d ", mtu);
+	fprint(shell, "pkt %q ", dev);
 }
 
-static int
-addip(int cfd, char *net, Ipaddr local, Ipaddr remote, int mtu)
+static void
+addip(int shell, char *net, char *dev, Ipaddr local, Ipaddr remote, int mtu, Ipaddr *dns)
 {
 	if(validv4(local) && validv4(remote)){
-		netlog("ppp: setting up IPv4 interface local %I remote %I\n", local, remote);
-
-		if(fprint(cfd, "add %I 255.255.255.255 %I %d proxy", local, remote, mtu-10) < 0)
-			return -1;
-
-		defroute(net, "add", remote, local);
-	} else if(validv6(local) && validv6(remote)){
-		netlog("ppp: setting up IPv6 interface local %I remote %I\n", local, remote);
-
-		if(fprint(cfd, "add %I /64 %I %d", local, remote, mtu-10) < 0)
-			return -1;
+		ipconfig(shell, net, dev, mtu, remote, dns, nil);
+		fprint(shell, "add %I 255.255.255.255 %I\n", local, remote);
+	} else if(validv6(local)){
+		ipconfig(shell, net, dev, mtu, nil, nil, nil);
+		fprint(shell, "add %I /64\n", local);
 	}
-	return 0;
 }
 
-static int
-removeip(int cfd, char *net, Ipaddr local, Ipaddr remote)
+static void
+removeip(int shell, char *net, char *dev, Ipaddr local, Ipaddr remote)
 {
 	if(validv4(local) && validv4(remote)){
-		defroute(net, "remove", remote, local);
-
-		if(fprint(cfd, "remove %I 255.255.255.255 %I", local, remote) < 0)
-			return -1;
-	} else if(validv6(local) && validv6(remote)){
-		if(fprint(cfd, "remove %I /64 %I", local, remote) < 0)
-			return -1;
+		ipconfig(shell, net, dev, 0, remote, nil, nil);
+		fprint(shell, "remove %I 255.255.255.255\n", local);
+	} else if(validv6(local)){
+		ipconfig(shell, net, dev, 0, nil, nil, nil);
+		fprint(shell, "remove %I /64\n", local);
 	}
-	return 0;
 }
 
+static void
+v6autoconfig(int shell, char *net, char *dev, Ipaddr remote, char *duid)
+{
+	if(server || !validv6(remote))
+		return;
+	ipconfig(shell, net, dev, 0, remote, nil, duid);
+	fprint(shell, "ra6 recvra 1\n");
+}
+
 static char*
 ipopen(PPP *ppp)
 {
@@ -1685,39 +1698,20 @@
 			close(cfd);
 			return "can't open ip interface";
 		}
-		if(fprint(cfd, "bind pkt") < 0){
+
+		if(ppp->dev == nil)
+			ppp->dev = smprint("%s/ipifc/%s", ppp->net, buf);
+
+		if(fprint(cfd, "bind pkt %s", ppp->dev) < 0){
 			close(fd);
 			close(cfd);
 			return "binding pkt to ip interface";
 		}
-		if(validv4(ppp->local)){
-			if(!validv4(ppp->remote))
-				ipmove(ppp->remote, ppp->local);
-			if(addip(cfd, ppp->net, ppp->local, ppp->remote, ppp->mtu) < 0){
-				close(fd);
-				close(cfd);
-				return "can't set addresses";
-			}
-			syslog(0, LOG, "%I/%I", ppp->local, ppp->remote);
-		}
-		if(validv6(ppp->local6) && validv6(ppp->remote6)){
-			if(addip(cfd, ppp->net, ppp->local6, ppp->remote6, ppp->mtu) < 0){
-				close(fd);
-				close(cfd);
-				return "can't set addresses";
-			}
-			syslog(0, LOG, "%I/%I", ppp->local6, ppp->remote6);
-		}
 		if(baud)
 			fprint(cfd, "speed %d", baud);
-		ppp->ipfd = fd;
-		ppp->ipcfd = cfd;
-		putndb(ppp);
-		refresh(ppp->net);
+		close(cfd);
 
-		/* signal main() that ip is configured */
-		rendezvous(ppp, 0);
-
+		ppp->ipfd = fd;
 		switch(ipinprocpid = rfork(RFPROC|RFMEM|RFNOWAIT)){
 		case -1:
 			terminate(ppp, "forking ipinproc", 1);
@@ -1726,24 +1720,38 @@
 			terminate(ppp, "ipinproc", 0);
 			exits(nil);
 		}
+
+		if(validv4(ppp->local)){
+			if(!validv4(ppp->remote))
+				ipmove(ppp->remote, ppp->local);
+			syslog(0, LOG, "%I/%I", ppp->local, ppp->remote);
+			addip(ppp->shellin, ppp->net, ppp->dev, ppp->local, ppp->remote, ppp->mtu, ppp->dns);
+		}
+		if(validv6(ppp->local6) && validv6(ppp->remote6)){
+			syslog(0, LOG, "%I/%I", ppp->local6, ppp->remote6);
+			addip(ppp->shellin, ppp->net, ppp->dev, ppp->local6, ppp->remote6, ppp->mtu, nil);
+			v6autoconfig(ppp->shellin, ppp->net, ppp->dev, ppp->remote6, ppp->duid);
+		}
+
+		/* fork in background, main returns */
+		fprint(ppp->shellin, "rc </fd/0 &; exit ''\n");
 	} else {
 		/* we may have changed addresses */
 		if(ipcmp(ppp->local, ppp->curlocal) != 0 || ipcmp(ppp->remote, ppp->curremote) != 0){
-			removeip(ppp->ipcfd, ppp->net, ppp->curlocal, ppp->curremote);
-			addip(ppp->ipcfd, ppp->net, ppp->local, ppp->remote, ppp->mtu);
-
+			if(!validv4(ppp->remote))
+				ipmove(ppp->remote, ppp->local);
 			syslog(0, LOG, "%I/%I -> %I/%I", ppp->curlocal, ppp->curremote,
 				ppp->local, ppp->remote);
+			removeip(ppp->shellin, ppp->net, ppp->dev, ppp->curlocal, ppp->curremote);
+			addip(ppp->shellin, ppp->net, ppp->dev, ppp->local, ppp->remote, ppp->mtu, ppp->dns);
 		}
 		if(ipcmp(ppp->local6, ppp->curlocal6) != 0 || ipcmp(ppp->remote6, ppp->curremote6) != 0){
-			removeip(ppp->ipcfd, ppp->net, ppp->curlocal6, ppp->curremote6);
-			addip(ppp->ipcfd, ppp->net, ppp->local6, ppp->remote6, ppp->mtu);
-
 			syslog(0, LOG, "%I/%I -> %I/%I", ppp->curlocal6, ppp->curremote6,
 				ppp->local6, ppp->remote6);
+			removeip(ppp->shellin, ppp->net, ppp->dev, ppp->curlocal6, ppp->curremote6);
+			addip(ppp->shellin, ppp->net, ppp->dev, ppp->local6, ppp->remote6, ppp->mtu, nil);
+			v6autoconfig(ppp->shellin, ppp->net, ppp->dev, ppp->remote6, ppp->duid);
 		}
-		putndb(ppp);
-		refresh(ppp->net);
 	}
 
 	ipmove(ppp->curlocal, ppp->local);
@@ -1956,26 +1964,23 @@
 
 	syslog(0, LOG, "ppp: terminated: %s", why);
 
-	if(validv4(ppp->curremote) && validv4(ppp->curlocal)){
-		defroute(ppp->net, "remove", ppp->curremote, ppp->curlocal);
-		invalidate(ppp->remote);
-		invalidate(ppp->local);
-		putndb(ppp);
+	if(ppp->dev != nil){
+		removeip(ppp->shellin, ppp->net, ppp->dev, ppp->curlocal, ppp->curremote);
+		removeip(ppp->shellin, ppp->net, ppp->dev, ppp->curlocal6, ppp->curremote6);
 	}
+	fprint(ppp->shellin, "exit %q\n", why);
+	close(ppp->shellin);
+	ppp->shellin = -1;
 
 	close(ppp->ipfd);
 	ppp->ipfd = -1;
-	close(ppp->ipcfd);
-	ppp->ipcfd = -1;
 	close(ppp->mediain);
 	close(ppp->mediaout);
 	ppp->mediain = -1;
 	ppp->mediaout = -1;
+
 	postnote(PNGROUP, getpid(), "die");
 
-	/* interface gone, notify cs */
-	refresh(ppp->net);
-
 	if(fatal)
 		sysfatal("%s", why);
 }
@@ -2840,7 +2845,7 @@
 usage(void)
 {
 	fprint(2, "usage: ppp [-CPSacdfu] [-b baud] [-k keyspec] [-m mtu] "
-		"[-M chatfile] [-p dev] [-x netmntpt] [-t modemcmd] "
+		"[-M chatfile] [-p dev | -e etherdev] [-x netmntpt] [-t modemcmd] [-U duid] "
 		"[local-addr [remote-addr]]\n");
 	exits("usage");
 }
@@ -2848,29 +2853,30 @@
 void
 main(int argc, char **argv)
 {
+	static PPP ppp[1];
 	int mtu, framing, user, mediain, mediaout, cfd;
 	Ipaddr ipaddr[2], remip[2];
-	char *dev, *modemcmd;
+	char *dev, *ether, *duid, *modemcmd;
 	char net[128];
-	PPP *ppp;
+	int pfd[2];
 	char buf[128];
 
-	rfork(RFREND|RFNOTEG|RFNAMEG);
-
+	quotefmtinstall();
 	fmtinstall('I', eipfmt);
 	fmtinstall('V', eipfmt);
 	fmtinstall('E', eipfmt);
 	fmtinstall('H', encodefmt);
 
-	dev = nil;
-
 	invalidate(ipaddr[0]);
 	invalidate(ipaddr[1]);
 	invalidate(remip[0]);
 	invalidate(remip[1]);
 
+	dev = nil;
+	ether = nil;
 	mtu = Defmtu;
 	framing = 0;
+	duid = nil;
 	setnetmtpt(net, sizeof(net), nil);
 	user = 0;
 	modemcmd = nil;
@@ -2893,6 +2899,9 @@
 	case 'd':
 		debug++;
 		break;
+	case 'e':
+		ether = EARGF(usage());
+		break;
 	case 'f':
 		framing = 1;
 		break;
@@ -2915,7 +2924,7 @@
 	case 'p':
 		dev = EARGF(usage());
 		break;
-	case 'P':
+	case 'P':	/* this seems reversed compared to ipconfig */
 		primary = 1;
 		break;
 	case 'S':
@@ -2924,6 +2933,9 @@
 	case 't':
 		modemcmd = EARGF(usage());
 		break;
+	case 'U':
+		duid = EARGF(usage());
+		break;
 	case 'u':
 		user = 1;
 		break;
@@ -2970,11 +2982,11 @@
 		if(mediain < 0){
 			if(strchr(dev, '!')){
 				if((mediain = dial(dev, 0, 0, &cfd)) == -1){
-					fprint(2, "ppp: couldn't dial %s: %r\n", dev);
+					fprint(2, "%s: couldn't dial %s: %r\n", argv0, dev);
 					exits(dev);
 				}
 			} else {
-				fprint(2, "ppp: couldn't open %s\n", dev);
+				fprint(2, "%s: couldn't open %s\n", argv0, dev);
 				exits(dev);
 			}
 		} else {
@@ -2997,30 +3009,52 @@
 			if(user || chatfile)
 				connect(mediain, -1);
 		}
-		mediaout = mediain;
+		mediaout = dup(mediain, -1);
 	} else {
 		mediain = open("/fd/0", OREAD);
 		if(mediain < 0){
-			fprint(2, "ppp: couldn't open /fd/0\n");
+			fprint(2, "%s: couldn't open /fd/0\n", argv0);
 			exits("/fd/0");
 		}
 		mediaout = open("/fd/1", OWRITE);
 		if(mediaout < 0){
-			fprint(2, "ppp: couldn't open /fd/0\n");
+			fprint(2, "%s: couldn't open /fd/0\n", argv0);
 			exits("/fd/1");
 		}
+		/* use the ethernet from pppoe to identify the interface */
+		dev = ether;
 	}
-
 	if(modemcmd != nil && mediaout >= 0)
 		fprint(mediaout, "%s\r", modemcmd);
 
-	ppp = mallocz(sizeof(*ppp), 1);
-	pppopen(ppp, mediain, mediaout, net, ipaddr, remip, mtu, framing);
+	if(pipe(pfd) < 0){
+		fprint(2, "%s: can't create pipe\n", argv0);
+		exits("pipe");
+	}
+	switch(rfork(RFFDG|RFREND|RFPROC|RFNOTEG|RFNOWAIT)){
+	case -1:
+		fprint(2, "%s: can't fork\n", argv0);
+		exits("fork");
+	case 0:
+		close(pfd[0]);
+		pppopen(ppp, mediain, mediaout, pfd[1], net, dev, ipaddr, remip, mtu, framing, duid);
+		exits(nil);
+	default:
+		/* read commands from pipe */
+		dup(pfd[0], 0);
 
-	/* wait until ip is configured */
-	rendezvous(ppp, 0);
+		close(pfd[0]);
+		close(pfd[1]);
+		close(mediain);
+		close(mediaout);
 
-	exits(nil);
+		/* stdout to stderr */
+		dup(2, 1);
+	}
+
+	/* become a shell, reading commands from pipe */
+	execl("/bin/rc", "rc", nil);
+	exits("exec");
 }
 
 void
@@ -3094,79 +3128,4 @@
 	ipmove(addr, v6llprefix);
 	memmove(&addr[IPaddrlen-len], data, len);
 	return memcmp(addr, v6llprefix, IPaddrlen) != 0;
-}
-
-/*
- *  make an ndb entry and put it into /net/ndb for the servers to see
- */
-static void
-putndb(PPP *ppp)
-{
-	static char buf[16*1024];
-	char file[128], *p, *e;
-	Ndbtuple *t, *nt;
-	Ndb *db;
-	int fd;
-
-	if(!primary)
-		return;
-
-	e = buf + sizeof(buf);
-	p = buf;
-
-	if(validv4(ppp->local) && validv4(ppp->remote)){
-		p = seprint(p, e, "ip=%I ipmask=255.255.255.255 ipgw=%I\n",
-			ppp->local, ppp->remote);
-		if(validv4(ppp->dns[0]))
-			p = seprint(p, e, "\tdns=%I\n", ppp->dns[0]);
-		if(validv4(ppp->dns[1]))
-			p = seprint(p, e, "\tdns=%I\n", ppp->dns[1]);
-		if(validv4(ppp->wins[0]))
-			p = seprint(p, e, "\twins=%I\n", ppp->wins[0]);
-		if(validv4(ppp->wins[1]))
-			p = seprint(p, e, "\twins=%I\n", ppp->wins[1]);
-	}
-
-	/* append preexisting entries not matching our old or new ip */
-	snprint(file, sizeof file, "%s/ndb", ppp->net);
-	db = ndbopen(file);
-	if(db != nil ){
-		while((t = ndbparse(db)) != nil){
-			uchar ip[IPaddrlen];
-
-			if((nt = ndbfindattr(t, t, "ip")) == nil
-			|| parseip(ip, nt->val) == -1
-			|| (ipcmp(ip, ppp->local) != 0 && ipcmp(ip, ppp->curlocal) != 0)){
-				p = seprint(p, e, "\n");
-				for(nt = t; nt != nil; nt = nt->entry)
-					p = seprint(p, e, "%s=%s%s", nt->attr, nt->val,
-						nt->entry==nil? "\n": nt->line!=nt->entry? "\n\t": " ");
-			}
-			ndbfree(t);
-		}
-		ndbclose(db);
-	}
-
-	if((fd = open(file, OWRITE|OTRUNC)) < 0)
-		return;
-	write(fd, buf, p-buf);
-	close(fd);
-}
-
-static void
-refresh(char *net)
-{
-	char file[128];
-	int fd;
-
-	snprint(file, sizeof file, "%s/cs", net);
-	if((fd = open(file, OWRITE)) >= 0){
-		write(fd, "refresh", 7);
-		close(fd);
-	}
-	snprint(file, sizeof file, "%s/dns", net);
-	if((fd = open(file, OWRITE)) >= 0){
-		write(fd, "refresh", 7);
-		close(fd);
-	}
 }
--- a/sys/src/cmd/ip/ppp/ppp.h
+++ b/sys/src/cmd/ip/ppp/ppp.h
@@ -262,15 +262,20 @@
 	QLock;
 
 	int		ipfd;		/* fd to ip stack */
-	int		ipcfd;		/* fd to control channel of ip stack */
 	int		mediain;	/* fd to media */
 	int		mediaout;	/* fd to media */
+	int		shellin;	/* fd to rc shell for running ipconfig */
+
 	char		*net;		/* ip stack to use */
+	char		*dev;		/* the device */
+	char		*duid;		/* dhcpv6 uid */	
+
 	int		framing;	/* non-zero to use framing characters */
 	Ipaddr		local;
 	Ipaddr		curlocal;
 	Ipaddr		remote;
 	Ipaddr		curremote;
+
 	Ipaddr		local6;
 	Ipaddr		curlocal6;
 	Ipaddr		remote6;
@@ -345,7 +350,7 @@
 
 extern Block*	pppread(PPP*);
 extern int	pppwrite(PPP*, Block*);
-extern void	pppopen(PPP*, int, int, char*, Ipaddr[2], Ipaddr[2], int, int);
+extern void	pppopen(PPP*, int, int, int, char*, char *dev, Ipaddr[2], Ipaddr[2], int, int, char*);
 
 struct Lcpmsg
 {
--- a/sys/src/cmd/ip/pppoe.c
+++ b/sys/src/cmd/ip/pppoe.c
@@ -12,15 +12,16 @@
 void hexdump(uchar*, int);
 int malformed(uchar*, int, int);
 int pppoe(char*);
-void execppp(int);
+void execppp(char*, int);
 
+int primary;
 int forked;
 int alarmed;
 int debug;
 int rflag;
 int sessid;
+char *duid;
 char *keyspec;
-int primary;
 char *pppnetmtpt;
 char *acname;
 char *pppname = "/bin/ip/ppp";
@@ -29,6 +30,7 @@
 uchar *cookie;
 int cookielen;
 uchar etherdst[6];
+uchar ethersrc[6];
 int mtu = 1492;
 int pktcompress, hdrcompress;
 char *baud;
@@ -36,7 +38,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-rPdcC] [-A acname] [-S srvname] [-k keyspec] [-m mtu] [-b baud] [-x pppnet] [ether0]\n", argv0);
+	fprint(2, "usage: %s [-rPdcC] [-A acname] [-S srvname] [-U duid] [-k keyspec] [-m mtu] [-b baud] [-x pppnet] [/net/ether0]\n", argv0);
 	exits("usage");
 }
 
@@ -110,6 +112,9 @@
 	case 'x':
 		pppnetmtpt = EARGF(usage());
 		break;
+	case 'U':
+		duid = EARGF(usage());
+		break;
 	default:
 		usage();
 	}ARGEND
@@ -118,7 +123,7 @@
 	default:
 		usage();
 	case 0:
-		dev = "ether0";
+		dev = "/net/ether0";
 		break;
 	case 1:
 		dev = argv[0];
@@ -127,8 +132,15 @@
 
 	fmtinstall('E', eipfmt);
 
+	/* generate DUID-LL when not specified */
+	if(myetheraddr(ethersrc, dev) != -1 && duid == nil){
+		static char buf[32];
+		snprint(buf, sizeof buf, "00030001%E", ethersrc);
+		duid = buf;
+	}
+
 	atnotify(catchalarm, 1);
-	execppp(pppoe(dev));
+	execppp(dev, pppoe(dev));
 }
 
 typedef struct Etherhdr Etherhdr;
@@ -604,11 +616,11 @@
 }
 
 void
-execppp(int fd)
+execppp(char *dev, int fd)
 {
-	char *argv[16];
-	int argc;
 	char smtu[10];
+	char *argv[20];
+	int argc;
 
 	argc = 0;
 	argv[argc++] = pppname;
@@ -617,6 +629,10 @@
 	argv[argc++] = "-F";
 	if(debug)
 		argv[argc++] = "-d";
+	if(dev){
+		argv[argc++] = "-e";
+		argv[argc++] = dev;
+	}
 	if(primary)
 		argv[argc++] = "-P";
 	if(baud){
@@ -634,6 +650,10 @@
 	if(keyspec){
 		argv[argc++] = "-k";
 		argv[argc++] = keyspec;
+	}
+	if(duid){
+		argv[argc++] = "-U";
+		argv[argc++] = duid;
 	}
 	argv[argc] = nil;