Browse Source

Plan 9 from Bell Labs 2007-04-21

David du Colombier 17 years ago
parent
commit
f0a9266e4d

+ 11 - 6
dist/replica/_plan9.db

@@ -289,7 +289,6 @@
 386/bin/ip/dhcpd - 775 sys sys 1176488415 151225
 386/bin/ip/dhcpd - 775 sys sys 1176488415 151225
 386/bin/ip/dhcpleases - 775 sys sys 1169612024 86533
 386/bin/ip/dhcpleases - 775 sys sys 1169612024 86533
 386/bin/ip/ftpd - 775 sys sys 1169612025 170706
 386/bin/ip/ftpd - 775 sys sys 1169612025 170706
-386/bin/ip/gizzard - 775 sys sys 1081480408 101521
 386/bin/ip/gping - 775 sys sys 1168402319 183451
 386/bin/ip/gping - 775 sys sys 1168402319 183451
 386/bin/ip/hogports - 775 sys sys 1148500655 42914
 386/bin/ip/hogports - 775 sys sys 1148500655 42914
 386/bin/ip/httpd - 20000000775 sys sys 1068385801 0
 386/bin/ip/httpd - 20000000775 sys sys 1068385801 0
@@ -5493,6 +5492,7 @@ rc/bin/ipconf/lra - 775 sys sys 1058791152 1558
 rc/bin/ipconf/outside - 775 sys sys 1058790951 550
 rc/bin/ipconf/outside - 775 sys sys 1058790951 550
 rc/bin/ipconf/theworld - 775 sys sys 1058790940 1212
 rc/bin/ipconf/theworld - 775 sys sys 1058790940 1212
 rc/bin/ipso - 775 sys sys 1079377794 2838
 rc/bin/ipso - 775 sys sys 1079377794 2838
+rc/bin/ipv6on - 775 sys sys 1177099714 1872
 rc/bin/iwhois - 775 sys sys 1143979502 1637
 rc/bin/iwhois - 775 sys sys 1143979502 1637
 rc/bin/juke - 775 sys sys 1105565140 1131
 rc/bin/juke - 775 sys sys 1105565140 1131
 rc/bin/kill - 775 sys sys 1143389260 142
 rc/bin/kill - 775 sys sys 1143389260 142
@@ -7726,7 +7726,7 @@ sys/man/6/mnihongo - 664 sys sys 1158064572 716
 sys/man/6/mpictures - 664 sys sys 944959678 2899
 sys/man/6/mpictures - 664 sys sys 944959678 2899
 sys/man/6/ms - 664 sys sys 958249504 6815
 sys/man/6/ms - 664 sys sys 958249504 6815
 sys/man/6/namespace - 664 sys sys 1048637182 1576
 sys/man/6/namespace - 664 sys sys 1048637182 1576
-sys/man/6/ndb - 664 sys sys 1176932139 6671
+sys/man/6/ndb - 664 sys sys 1177100292 6745
 sys/man/6/plot - 664 sys sys 944959679 6739
 sys/man/6/plot - 664 sys sys 944959679 6739
 sys/man/6/plumb - 664 sys sys 969499892 10918
 sys/man/6/plumb - 664 sys sys 969499892 10918
 sys/man/6/regexp - 664 sys sys 954089523 2050
 sys/man/6/regexp - 664 sys sys 954089523 2050
@@ -7773,7 +7773,7 @@ sys/man/8/getflags - 664 sys sys 1159419702 1713
 sys/man/8/gpsfs - 664 sys sys 1165623047 4918
 sys/man/8/gpsfs - 664 sys sys 1165623047 4918
 sys/man/8/httpd - 664 sys sys 1165623004 6865
 sys/man/8/httpd - 664 sys sys 1165623004 6865
 sys/man/8/init - 664 sys sys 944959679 1430
 sys/man/8/init - 664 sys sys 944959679 1430
-sys/man/8/ipconfig - 664 sys sys 1176502409 6209
+sys/man/8/ipconfig - 664 sys sys 1177100280 7984
 sys/man/8/ipserv - 664 sys sys 1095862383 4375
 sys/man/8/ipserv - 664 sys sys 1095862383 4375
 sys/man/8/kfscmd - 664 sys sys 1068569797 4515
 sys/man/8/kfscmd - 664 sys sys 1068569797 4515
 sys/man/8/listen - 664 sys sys 1174792129 3826
 sys/man/8/listen - 664 sys sys 1174792129 3826
@@ -12440,7 +12440,7 @@ sys/src/cmd/iostats/statfs.h - 664 sys sys 1140099908 2626
 sys/src/cmd/iostats/statsrv.c - 664 sys sys 1166824341 10773
 sys/src/cmd/iostats/statsrv.c - 664 sys sys 1166824341 10773
 sys/src/cmd/ip - 20000000775 sys sys 1128605981 0
 sys/src/cmd/ip - 20000000775 sys sys 1128605981 0
 sys/src/cmd/ip/arp.h - 664 sys sys 944961005 751
 sys/src/cmd/ip/arp.h - 664 sys sys 944961005 751
-sys/src/cmd/ip/dhcp.h - 664 sys sys 1051206271 3368
+sys/src/cmd/ip/dhcp.h - 664 sys sys 1177099797 3420
 sys/src/cmd/ip/dhcpclient.c - 664 sys sys 1050714660 11978
 sys/src/cmd/ip/dhcpclient.c - 664 sys sys 1050714660 11978
 sys/src/cmd/ip/dhcpd - 20000000775 sys sys 1063897571 0
 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/dat.h - 664 sys sys 1084471353 2522
@@ -12509,9 +12509,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/store.c - 664 sys sys 1066317059 1910
 sys/src/cmd/ip/imap4d/utils.c - 664 sys sys 1168894057 2587
 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 - 20000000775 sys sys 1176933436 0
-sys/src/cmd/ip/ipconfig.c - 664 sys sys 1176502464 35429
+sys/src/cmd/ip/ipconfig/ipconfig.h - 664 sys sys 1177092388 5536
+sys/src/cmd/ip/ipconfig/ipv6.c - 664 sys sys 1177092388 19783
+sys/src/cmd/ip/ipconfig/main.c - 664 sys sys 1177092388 37908
+sys/src/cmd/ip/ipconfig/mkfile - 664 sys sys 1177092388 236
+sys/src/cmd/ip/ipconfig/ppp.c - 664 sys sys 1177092388 1128
+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/measure.c - 664 sys sys 944961011 3733
-sys/src/cmd/ip/mkfile - 664 sys sys 1169163575 1250
+sys/src/cmd/ip/mkfile - 664 sys sys 1177099797 1271
 sys/src/cmd/ip/ping.c - 664 sys sys 1175868270 9699
 sys/src/cmd/ip/ping.c - 664 sys sys 1175868270 9699
 sys/src/cmd/ip/ppp - 20000000775 sys sys 1065963823 0
 sys/src/cmd/ip/ppp - 20000000775 sys sys 1065963823 0
 sys/src/cmd/ip/ppp/block.c - 664 sys sys 1015090266 5353
 sys/src/cmd/ip/ppp/block.c - 664 sys sys 1015090266 5353

+ 11 - 6
dist/replica/plan9.db

@@ -289,7 +289,6 @@
 386/bin/ip/dhcpd - 775 sys sys 1176488415 151225
 386/bin/ip/dhcpd - 775 sys sys 1176488415 151225
 386/bin/ip/dhcpleases - 775 sys sys 1169612024 86533
 386/bin/ip/dhcpleases - 775 sys sys 1169612024 86533
 386/bin/ip/ftpd - 775 sys sys 1169612025 170706
 386/bin/ip/ftpd - 775 sys sys 1169612025 170706
-386/bin/ip/gizzard - 775 sys sys 1081480408 101521
 386/bin/ip/gping - 775 sys sys 1168402319 183451
 386/bin/ip/gping - 775 sys sys 1168402319 183451
 386/bin/ip/hogports - 775 sys sys 1148500655 42914
 386/bin/ip/hogports - 775 sys sys 1148500655 42914
 386/bin/ip/httpd - 20000000775 sys sys 1068385801 0
 386/bin/ip/httpd - 20000000775 sys sys 1068385801 0
@@ -5493,6 +5492,7 @@ rc/bin/ipconf/lra - 775 sys sys 1058791152 1558
 rc/bin/ipconf/outside - 775 sys sys 1058790951 550
 rc/bin/ipconf/outside - 775 sys sys 1058790951 550
 rc/bin/ipconf/theworld - 775 sys sys 1058790940 1212
 rc/bin/ipconf/theworld - 775 sys sys 1058790940 1212
 rc/bin/ipso - 775 sys sys 1079377794 2838
 rc/bin/ipso - 775 sys sys 1079377794 2838
+rc/bin/ipv6on - 775 sys sys 1177099714 1872
 rc/bin/iwhois - 775 sys sys 1143979502 1637
 rc/bin/iwhois - 775 sys sys 1143979502 1637
 rc/bin/juke - 775 sys sys 1105565140 1131
 rc/bin/juke - 775 sys sys 1105565140 1131
 rc/bin/kill - 775 sys sys 1143389260 142
 rc/bin/kill - 775 sys sys 1143389260 142
@@ -7726,7 +7726,7 @@ sys/man/6/mnihongo - 664 sys sys 1158064572 716
 sys/man/6/mpictures - 664 sys sys 944959678 2899
 sys/man/6/mpictures - 664 sys sys 944959678 2899
 sys/man/6/ms - 664 sys sys 958249504 6815
 sys/man/6/ms - 664 sys sys 958249504 6815
 sys/man/6/namespace - 664 sys sys 1048637182 1576
 sys/man/6/namespace - 664 sys sys 1048637182 1576
-sys/man/6/ndb - 664 sys sys 1176932139 6671
+sys/man/6/ndb - 664 sys sys 1177100292 6745
 sys/man/6/plot - 664 sys sys 944959679 6739
 sys/man/6/plot - 664 sys sys 944959679 6739
 sys/man/6/plumb - 664 sys sys 969499892 10918
 sys/man/6/plumb - 664 sys sys 969499892 10918
 sys/man/6/regexp - 664 sys sys 954089523 2050
 sys/man/6/regexp - 664 sys sys 954089523 2050
@@ -7773,7 +7773,7 @@ sys/man/8/getflags - 664 sys sys 1159419702 1713
 sys/man/8/gpsfs - 664 sys sys 1165623047 4918
 sys/man/8/gpsfs - 664 sys sys 1165623047 4918
 sys/man/8/httpd - 664 sys sys 1165623004 6865
 sys/man/8/httpd - 664 sys sys 1165623004 6865
 sys/man/8/init - 664 sys sys 944959679 1430
 sys/man/8/init - 664 sys sys 944959679 1430
-sys/man/8/ipconfig - 664 sys sys 1176502409 6209
+sys/man/8/ipconfig - 664 sys sys 1177100280 7984
 sys/man/8/ipserv - 664 sys sys 1095862383 4375
 sys/man/8/ipserv - 664 sys sys 1095862383 4375
 sys/man/8/kfscmd - 664 sys sys 1068569797 4515
 sys/man/8/kfscmd - 664 sys sys 1068569797 4515
 sys/man/8/listen - 664 sys sys 1174792129 3826
 sys/man/8/listen - 664 sys sys 1174792129 3826
@@ -12440,7 +12440,7 @@ sys/src/cmd/iostats/statfs.h - 664 sys sys 1140099908 2626
 sys/src/cmd/iostats/statsrv.c - 664 sys sys 1166824341 10773
 sys/src/cmd/iostats/statsrv.c - 664 sys sys 1166824341 10773
 sys/src/cmd/ip - 20000000775 sys sys 1128605981 0
 sys/src/cmd/ip - 20000000775 sys sys 1128605981 0
 sys/src/cmd/ip/arp.h - 664 sys sys 944961005 751
 sys/src/cmd/ip/arp.h - 664 sys sys 944961005 751
-sys/src/cmd/ip/dhcp.h - 664 sys sys 1051206271 3368
+sys/src/cmd/ip/dhcp.h - 664 sys sys 1177099797 3420
 sys/src/cmd/ip/dhcpclient.c - 664 sys sys 1050714660 11978
 sys/src/cmd/ip/dhcpclient.c - 664 sys sys 1050714660 11978
 sys/src/cmd/ip/dhcpd - 20000000775 sys sys 1063897571 0
 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/dat.h - 664 sys sys 1084471353 2522
@@ -12509,9 +12509,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/store.c - 664 sys sys 1066317059 1910
 sys/src/cmd/ip/imap4d/utils.c - 664 sys sys 1168894057 2587
 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 - 20000000775 sys sys 1176933436 0
-sys/src/cmd/ip/ipconfig.c - 664 sys sys 1176502464 35429
+sys/src/cmd/ip/ipconfig/ipconfig.h - 664 sys sys 1177092388 5536
+sys/src/cmd/ip/ipconfig/ipv6.c - 664 sys sys 1177092388 19783
+sys/src/cmd/ip/ipconfig/main.c - 664 sys sys 1177092388 37908
+sys/src/cmd/ip/ipconfig/mkfile - 664 sys sys 1177092388 236
+sys/src/cmd/ip/ipconfig/ppp.c - 664 sys sys 1177092388 1128
+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/measure.c - 664 sys sys 944961011 3733
-sys/src/cmd/ip/mkfile - 664 sys sys 1169163575 1250
+sys/src/cmd/ip/mkfile - 664 sys sys 1177099797 1271
 sys/src/cmd/ip/ping.c - 664 sys sys 1175868270 9699
 sys/src/cmd/ip/ping.c - 664 sys sys 1175868270 9699
 sys/src/cmd/ip/ppp - 20000000775 sys sys 1065963823 0
 sys/src/cmd/ip/ppp - 20000000775 sys sys 1065963823 0
 sys/src/cmd/ip/ppp/block.c - 664 sys sys 1015090266 5353
 sys/src/cmd/ip/ppp/block.c - 664 sys sys 1015090266 5353

+ 14 - 0
dist/replica/plan9.log

@@ -48430,3 +48430,17 @@
 1176960606 0 c sys/man/3/ip - 664 sys sys 1176959517 24540
 1176960606 0 c sys/man/3/ip - 664 sys sys 1176959517 24540
 1177005616 0 c sys/src/cmd/auth/cron.c - 664 sys sys 1177004942 12306
 1177005616 0 c sys/src/cmd/auth/cron.c - 664 sys sys 1177004942 12306
 1177012806 0 c 386/bin/auth/cron - 775 sys sys 1177012403 145052
 1177012806 0 c 386/bin/auth/cron - 775 sys sys 1177012403 145052
+1177093806 0 c sys/man/8/ipconfig - 664 sys sys 1177092354 7421
+1177093806 1 a sys/src/cmd/ip/ipconfig/ipconfig.h - 664 sys sys 1177092388 5536
+1177093806 2 a sys/src/cmd/ip/ipconfig/ipv6.c - 664 sys sys 1177092388 19783
+1177093806 3 a sys/src/cmd/ip/ipconfig/main.c - 664 sys sys 1177092388 37908
+1177093806 4 a sys/src/cmd/ip/ipconfig/mkfile - 664 sys sys 1177092388 236
+1177093806 5 a sys/src/cmd/ip/ipconfig/ppp.c - 664 sys sys 1177092388 1128
+1177093806 6 d sys/src/cmd/ip/ipconfig.c - 664 sys sys 1176502464 0
+1177101006 0 a rc/bin/ipv6on - 775 sys sys 1177099714 1872
+1177101006 1 c sys/man/6/ndb - 664 sys sys 1177100292 6745
+1177101006 2 c sys/man/8/ipconfig - 664 sys sys 1177100280 7984
+1177101006 3 c sys/src/cmd/ip/dhcp.h - 664 sys sys 1177099797 3420
+1177101006 4 a sys/src/cmd/ip/linklocal.c - 664 sys sys 1177099730 867
+1177101006 5 c sys/src/cmd/ip/mkfile - 664 sys sys 1177099797 1271
+1177101006 6 d 386/bin/ip/gizzard - 775 sys sys 1081480408 0

+ 88 - 0
rc/bin/ipv6on

@@ -0,0 +1,88 @@
+#!/bin/rc
+# ipv6on [netdir ndbfile [gwv4]] - configure an interface for v6,
+#	once v4 is configured.
+if (! ~ $#* 0 2 3) {
+	echo usage: $0 '[netdir ndbfile [gw-v4-name]]' >[1=2]
+	exit usage
+}
+rfork e
+if (~ $#* 0) {
+	netdir=/net
+	ndbf=/lib/ndb/local
+	gw=`{ndb/ipquery sys $sysname ipgw | sed 's/ipgw=//'}
+}
+if not {
+	netdir=$1
+	ndbf=$2
+	if (~ $#* 2)
+		# gw=()
+		gw=`{ndb/ipquery sys $sysname ipgw | sed 's/ipgw=//'}
+	if not
+		gw=$3
+}
+if (~ $netdir /net) {
+	xsfx=()
+	xdir=()
+}
+if not {
+	xsfx=(-x `{echo $netdir | sed 's;^/net;;'})
+	xdir=(-x $netdir)
+}
+
+fn nonnil {	# name ip
+	if (~ $#2 0) {
+		echo no ip for $1
+		exit no-ip
+	}
+}
+
+#
+# configure v6 for link-local addresses (fe80::) & multicast (ff02::)
+#
+if (! ip/ipconfig -6 $xdir ether $netdir/ether?)
+	exit 'ipconfig -6 failed'
+ip/ipconfig ra6 recvra 1
+
+mev6=`{ndb/query -f $ndbf sys $sysname ipv6}
+mev4=`{ndb/query -f $ndbf sys $sysname ip}
+
+# for testing
+mylnk=`{ip/linklocal `{cat $netdir/ether?/addr}}
+nonnil mylnk $mylnk
+
+if (~ $#gw 1) {
+	if (~ $gw [0-9]*.[0-9]*.[0-9]*.[0-9]*)
+		gwv4 = $gw
+	if (~ $#gwv4 0 || ~ $gwv4 '')		# assume namev6 and name
+		gwv4=`{ndb/query -f $ndbf sys $gw ip}
+	gwv6=`{ndb/query -f $ndbf sys $gw ipv6}
+
+	if (! ~ $#gwv4 0) {
+		echo ping gw $gwv4...
+		# load arp cache with gw mac
+		ip/ping -qn 3 $netdir/icmp!$gwv4 >/dev/null >[2=1] &
+		sleep 3					# wait for ping
+
+		gweth=`{grep '* '^$gwv4^' ' $netdir/arp | awk '{print $4}' }
+		nonnil gweth $gweth
+		gwlnk=`{ip/linklocal $gweth}
+		nonnil gwlnk $gwlnk
+	}
+}
+nonnil mev6 $mev6
+#
+# configure my global v6 addresses
+#
+ip/ipconfig $xdir ether $netdir/ether?	add $mev6 /64
+ip/ipconfig $xdir loopback /dev/null	add $mev6 /128
+
+if (~ $#gw 1) {
+	if (~ $#gwv6 0 || ~ $gwv6 '')
+		gwv6=`{ip/linklocal $gweth}
+	nonnil gwv6 $gwv6
+	#
+	# add default v6 route to v6 addr of v4 gw
+	#
+	echo add :: /0 $gwv6 >$netdir/iproute	# need not be link-local
+}
+exit ''

+ 8 - 1
sys/man/6/ndb

@@ -164,7 +164,14 @@ system name
 Internet domain name
 Internet domain name
 .TP
 .TP
 .B ip
 .B ip
-Internet address
+Internet address,
+v4 or v6.
+.TP
+.B ipv6
+IPv6 Internet address.
+For DNS, an
+.L AAAA
+record.
 .TP
 .TP
 .B ether
 .B ether
 Ethernet address
 Ethernet address

+ 177 - 85
sys/man/8/ipconfig

@@ -1,53 +1,74 @@
 .TH IPCONFIG 8
 .TH IPCONFIG 8
 .SH NAME
 .SH NAME
-ipconfig, rip \- Internet configuration and routing
+ipconfig, rip, linklocal, ipv6on \- Internet configuration and routing
 .SH SYNOPSIS
 .SH SYNOPSIS
+.in +0.25i
+.ti -0.25i
 .B ip/ipconfig
 .B ip/ipconfig
-.RB [ -DGNOPdnpr ]
+.RB [ -6DGNOPdnpruX ]
 .RB [ -b
 .RB [ -b
 .IR baud ]
 .IR baud ]
 .RB [ -c
 .RB [ -c
 .IR ctl ]
 .IR ctl ]
-.RB [ -m
-.IR mtu ]
 .RB [ -g
 .RB [ -g
 .IR gateway ]
 .IR gateway ]
 .RB [ -h
 .RB [ -h
-.IR hostname ]
+.IR host ]
+.RB [ -m
+.IR mtu ]
+.RB [ -o
+.IR dhcp-opt ]
 .RB [ -x
 .RB [ -x
 .IR netmtpt ]
 .IR netmtpt ]
-.RB [ -o
-.IR dhcpoption ]
+[
 .I type
 .I type
+[
 .I device
 .I device
-.br
-.ti +0.5i
+]\|]
 .RI [ verb ]
 .RI [ verb ]
-.RI [ local-addr ]
-.RI [ mask ]
-.RI [ remote-addr ]
-.RI [ file-server-addr ]
-.RI [ auth-server-addr ]
+.br
+[
+.I local
+[
+.I mask
+[
+.I remote
+[
+.I file-server
+[
+.I auth
+]\|]\|]\|]\|]
 .PP
 .PP
 .B ip/rip
 .B ip/rip
 .RB [ -bdr ]
 .RB [ -bdr ]
 .RB [ -x
 .RB [ -x
 .IR netmtpt ]
 .IR netmtpt ]
+.PP
+.B ip/linklocal
+.I mac
+\&...
+.PP
+.B ipv6on
+[
+.I netmtpt
+.I ndbfile
+[
+.I gwv4
+]\|]
 .SH DESCRIPTION
 .SH DESCRIPTION
 .I Ipconfig
 .I Ipconfig
 binds a device interface (default
 binds a device interface (default
 .BR /net/ether0 )
 .BR /net/ether0 )
 to a mounted IP stack (default
 to a mounted IP stack (default
 .BR /net )
 .BR /net )
-and configures the interface with a local address, a
-mask, and a remote address.  The addresses can be specified
-in the command line or obtained via DHCP.  If DHCP is
-requested, it will also obtain the addresses of DNS
+and configures the interface with a local address and optionally
+a mask, a remote address, a file server and an authentication server address.
+The addresses can be specified in the command line or obtained via DHCP.
+If DHCP is requested, it will also obtain the addresses of DNS
 servers, NTP servers, gateways, a Plan 9 file server,
 servers, NTP servers, gateways, a Plan 9 file server,
-and a Plan 9 authentication server.  If this is the first
-non-loopback
-interface on the IP stack, the information will be
-written to
+and a Plan 9 authentication server.
+If this is the first non-loopback
+interface on the IP stack, the information will be written to
 .B /net/ndb
 .B /net/ndb
 in the form of an
 in the form of an
 .IR ndb (8)
 .IR ndb (8)
@@ -56,21 +77,22 @@ entry.
 .I Type
 .I Type
 may be
 may be
 .BR ether ,
 .BR ether ,
+.BR gbe ,
 .BR ppp ,
 .BR ppp ,
 or
 or
-.BR gbe .
+.BR loopback .
 The
 The
 .B gbe
 .B gbe
 type is equivalent to
 type is equivalent to
 .B ether
 .B ether
-except that it allows jumbo packets.
+except that it allows jumbo packets (up to ~9KB).
 For
 For
 .B ppp
 .B ppp
 the device can be any byte stream device.
 the device can be any byte stream device.
 .PP
 .PP
 The verb (default
 The verb (default
 .IR add )
 .IR add )
-determines the action performed.  The verbs are:
+determines the action performed.  The usual verbs are:
 .TF remove
 .TF remove
 .TP
 .TP
 .B add
 .B add
@@ -86,13 +108,62 @@ unbind the device interface and all its addresses from the
 IP stack.
 IP stack.
 .PD
 .PD
 .PP
 .PP
+The IPv6-specific verbs, which take different arguments, are:
+.TP
+.BI "add6 " "prefix pfx-len onlink auto validlt preflt"
+sets the named IPv6 parameters; see
+.IR ip (3)
+for more detail.
+.TP
+.BI "ra6 " "[ keyword value ] ..."
+sets IPv6 router advertisement parameter
+.IR keyword 's
+.IR value .
+See
+.IR ip (3)
+for more detail.
+Setting
+.I recvra
+non-zero also forks a process to
+receive and process router advertisements.
+Setting
+.I sendra
+non-zero also
+enables IP routing on the interface,
+forks a process to send router advertisements,
+and if no
+.I recvra
+process is running, forks one.
+.PD
+.PP
 The options are:
 The options are:
 .TF M
 .TF M
 .PD
 .PD
 .TP
 .TP
+.B 6
+if adding an address (the default action),
+add the IPv6 link-local address.
+.TP
+.B b
+the baud rate to use on a serial line
+when configuring
+.BR PPP .
+.TP
+.B c
+write the control string
+.I ctl
+to the ethernet device control file before starting to configure it.
+May be repeated to specify multiple control writes.
+.TP
+.B d
+use DHCP to determine any unspecified configuration parameters.
+.TP
 .B D
 .B D
 turn on debugging.
 turn on debugging.
 .TP
 .TP
+.B g
+the default gateway.
+.TP
 .B G
 .B G
 use only generic DHCP options.  Without this option,
 use only generic DHCP options.  Without this option,
 .I ipconfig
 .I ipconfig
@@ -103,6 +174,17 @@ interpret as the Plan 9 file server and auth server.
 Replies to these options contain a list of IP addresses for possible
 Replies to these options contain a list of IP addresses for possible
 file servers and auth servers.
 file servers and auth servers.
 .TP
 .TP
+.B h
+the hostname to add to DHCP requests.  Some DHCP
+servers, such as the one used by Comcast, will not respond
+unless a correct hostname is in the request.
+.TP
+.B m
+the maximum IP packet size to use on this interface.
+.TP
+.B n
+determine parameters but don't configure the interface.
+.TP
 .B N
 .B N
 look in
 look in
 .B /lib/ndb
 .B /lib/ndb
@@ -110,6 +192,10 @@ for the IP parameters.  This only works if the
 interface is an ethernet.  It uses the ethernet address to find
 interface is an ethernet.  It uses the ethernet address to find
 a matching entry.
 a matching entry.
 .TP
 .TP
+.B O
+addresses specified on the command line override those obtained via DHCP.
+A command line address of 0 implies no override.
+.TP
 .B p
 .B p
 write configuration information to
 write configuration information to
 .BR /net/ndb ,
 .BR /net/ndb ,
@@ -120,43 +206,18 @@ do not write configuration information to
 .BR /net/ndb ,
 .BR /net/ndb ,
 even if this is the first network interface to be configured
 even if this is the first network interface to be configured
 .TP
 .TP
-.B b
-the baud rate to use on a serial line
-when configuring
-.BR PPP .
-.TP
-.B c
-write the control string
-.I ctl
-to the ethernet device control file before starting to configure it.
-May be repeated to specify multiple control writes.
-.TP
-.B d
-use DHCP to determine any unspecified configuration parameters.
-.TP
-.B g
-the default gateway.
-.TP
-.B h
-the hostname to add to DHCP requests.  Some DHCP
-servers, such as the one used by COMCAST, will not respond
-unless a correct hostname is in the request.
-.TP
-.B m
-the maximum IP packet size to use on this
-interface.
-.TP
-.B n
-determine parameters but don't configure the interface.
-.TP
 .B r
 .B r
-by default, 
+by default,
 .I ipconfig
 .I ipconfig
 exits after trying DHCP for 15 seconds with no answer.
 exits after trying DHCP for 15 seconds with no answer.
 This option directs
 This option directs
 .I ipconfig
 .I ipconfig
-instead to fork a background
-process that keeps trying forever.
+instead to fork a background process that keeps trying forever.
+.TP
+.B u
+disable IPv6 duplicate discovery detection,
+which removes any existing ARP table entry for one of our IPv6 addresses
+before adding new ones.
 .TP
 .TP
 .B x
 .B x
 use the IP stack mounted at
 use the IP stack mounted at
@@ -164,6 +225,9 @@ use the IP stack mounted at
 instead of at
 instead of at
 .BR /net .
 .BR /net .
 .TP
 .TP
+.B X
+don't fork a process to keep the DHCP lease alive.
+.TP
 .B o
 .B o
 adds
 adds
 .I dhcpoption
 .I dhcpoption
@@ -171,25 +235,21 @@ to the list of paramters requested of the DHCP server.  The
 result will appear in
 result will appear in
 .B /net/ndb
 .B /net/ndb
 should this be the first interface.  The known options are:
 should this be the first interface.  The known options are:
-.TP 0.5i
-\&
-.ft CW
-ipmask, timeoff, ipgw, time, name, dns, log, cookie,
-lpr, impress, rl, sys, bflen, dumpfile, dom, swap,
-rootpath, extpath, ipforward, nonlocal, policyfilter,
-maxdatagram, ttl, pathtimeout, pathplateau, mtu,
-subnetslocal, baddr, discovermask, supplymask,
-discoverrouter, rs, staticroutes, trailerencap,
-arptimeout, etherencap, tcpttl, tcpka, tcpkag,
-nisdomain, ni, ntp, netbiosns, netbiosdds,
-netbiostype, netbiosscope, xfont, xdispmanager,
-nisplusdomain, nisplus, homeagent, smtp, pop3, nntp,
-www, finger, irc, st, stdar, ipaddr, lease,
-overload, type, serverid, params, message, maxmsg,
-renewaltime, rebindingtime, vendorclass, clientid,
-tftp, bootfile
-.PD
+.RS
 .LP
 .LP
+.ft L
+arptimeout, baddr, bflen, bootfile, clientid, cookie, discovermask,
+discoverrouter, dns, dom, dumpfile, etherencap, extpath, finger,
+homeagent, impress, ipaddr, ipforward, ipgw, ipmask, irc, lease, log,
+lpr, maxdatagram, maxmsg, message, mtu, name, netbiosdds, netbiosns,
+netbiosscope, netbiostype, ni, nisdomain, nisplus, nisplusdomain,
+nntp, nonlocal, ntp, overload, params, pathplateau, pathtimeout,
+policyfilter, pop3, rebindingtime, renewaltime, rl, rootpath, rs,
+serverid, smtp, st, staticroutes, stdar, subnetslocal, supplymask,
+swap, sys, tcpka, tcpkag, tcpttl, tftp, time, timeoff, trailerencap,
+ttl, type, vendorclass, www, xdispmanager, xfont
+.RE
+.IP
 The options
 The options
 .BR ipmask ,
 .BR ipmask ,
 .BR ipgw ,
 .BR ipgw ,
@@ -200,11 +260,6 @@ and
 are always requested.
 are always requested.
 .TF M
 .TF M
 .PD
 .PD
-.TP
-.B O
-addresses specified on the command line override those obtained
-via DHCP.
-A command line address of 0 implies no override.
 .PP
 .PP
 If DHCP is requested, a process is forked
 If DHCP is requested, a process is forked
 off to renew the lease before it
 off to renew the lease before it
@@ -217,6 +272,8 @@ runs the routing protocol RIP.
 It listens for RIP packets on connected networks and
 It listens for RIP packets on connected networks and
 updates the kernel routing tables.
 updates the kernel routing tables.
 The options are:
 The options are:
+.TF M
+.PD
 .TP
 .TP
 .B b
 .B b
 broadcasts routing information onto the networks.
 broadcasts routing information onto the networks.
@@ -236,7 +293,23 @@ instead of at
 .B d
 .B d
 turn on (voluminous) debugging.
 turn on (voluminous) debugging.
 .PP
 .PP
-.SH EXAMPLE
+.I Linklocal
+prints the IPv6 link-local address corresponding to the given
+.I mac
+address.
+.PP
+.I Ipv6on
+uses the network database at
+.I ndbfile
+to configure the network mounted on
+.I netmtpt
+with a link-local address (derived from its MAC address)
+and attempts to add a default IPv6 route to the local
+IPv4 gateway's IPv6 address.
+If
+.I gwv4
+is supplied, it will be used as the gateway IPv4 address.
+.SH EXAMPLES
 Configure Ethernet 0 as the primary IP interface.
 Configure Ethernet 0 as the primary IP interface.
 Get all addresses via DHCP.  Start up a connection server
 Get all addresses via DHCP.  Start up a connection server
 and DNS resolver for this IP stack.
 and DNS resolver for this IP stack.
@@ -255,7 +328,7 @@ Add a second address to the stack.
 % ip/ipconfig ether /net/ether0 add 12.1.1.2 255.255.255.0
 % ip/ipconfig ether /net/ether0 add 12.1.1.2 255.255.255.0
 .EE
 .EE
 .PP
 .PP
-At Lucent our primary IP stack is always to the company's internal
+At Bell Labs, our primary IP stack is always to the company's internal
 firewall-protected network.  The following creates an external
 firewall-protected network.  The following creates an external
 IP stack to directly access the outside Internet.  Note that the
 IP stack to directly access the outside Internet.  Note that the
 connection server uses a different set of
 connection server uses a different set of
@@ -271,11 +344,30 @@ bindings.
 % ndb/cs -x /net.alt -f /lib/ndb/external
 % ndb/cs -x /net.alt -f /lib/ndb/external
 % ndb/dns -sx /net.alt -f /lib/ndb/external
 % ndb/dns -sx /net.alt -f /lib/ndb/external
 % aux/listen -d /rc/bin/service.alt /net.alt/tcp
 % aux/listen -d /rc/bin/service.alt /net.alt/tcp
-% aux/listen -d /rc/bin/service.alt /net.alt/il
 .EE
 .EE
+.PP
+Get all addresses via DHCP.
+Configure the IPv6 link-local address automatically
+and listen for router announcements.
+.IP
+.EX
+ip/ipconfig -6 
+ip/ipconfig ra6 recvra 1
+.EE
+.SH FILES
+.B /sys/log/v6routeradv
 .SH SOURCE
 .SH SOURCE
-.B /sys/src/cmd/ip/ipconfig.c
+.B /sys/src/cmd/ip/ipconfig
 .br
 .br
 .B /sys/src/cmd/ip/rip.c
 .B /sys/src/cmd/ip/rip.c
+.br
+.B /sys/src/cmd/ip/linklocal.c
+.br
+.B /rc/bin/ipv6on
 .SH "SEE ALSO"
 .SH "SEE ALSO"
-.IR ndb (6)
+.IR ether (3),
+.IR ip (3),
+.IR loopback (3),
+.IR ndb (6),
+.IR dhcpd (8),
+.IR ppp (8)

+ 8 - 8
sys/src/cmd/ip/dhcp.h

@@ -1,4 +1,4 @@
-
+/* Dynamic Host Configuration Protocol / BOOTP */
 enum
 enum
 {
 {
 	OfferTimeout=	60,		/* when an offer times out */
 	OfferTimeout=	60,		/* when an offer times out */
@@ -21,7 +21,7 @@ enum
 	/* bootp flags */
 	/* bootp flags */
 	Fbroadcast=	1<<15,
 	Fbroadcast=	1<<15,
 
 
-	/* dhcp types */
+	/* dhcp v4 types */
 	Discover=	1,
 	Discover=	1,
 	Offer=		2,
 	Offer=		2,
 	Request=	3,
 	Request=	3,
@@ -74,7 +74,7 @@ enum
 	OBtcpka=		38,
 	OBtcpka=		38,
 	OBtcpkag=		39,
 	OBtcpkag=		39,
 	OBnisdomain=		40,
 	OBnisdomain=		40,
-	OBniserver=		41,	
+	OBniserver=		41,
 	OBntpserver=		42,
 	OBntpserver=		42,
 	OBvendorinfo=		43,	/* 0x2b */
 	OBvendorinfo=		43,	/* 0x2b */
 	OBnetbiosns=		44,
 	OBnetbiosns=		44,
@@ -95,7 +95,7 @@ enum
 	OBstserver=		75,
 	OBstserver=		75,
 	OBstdaserver=		76,
 	OBstdaserver=		76,
 
 
-	/* dhcp options */
+	/* dhcp v4 options */
 	ODipaddr=		50,	/* 0x32 */
 	ODipaddr=		50,	/* 0x32 */
 	ODlease=		51,
 	ODlease=		51,
 	ODoverload=		52,
 	ODoverload=		52,
@@ -112,12 +112,12 @@ enum
 	ODbootfile=		67,
 	ODbootfile=		67,
 
 
 	/* plan9 vendor info options */
 	/* plan9 vendor info options */
-	OP9fs=			128,	// plan9 file servers
-	OP9auth=		129,	// plan9 auth servers
+	OP9fs=			128,	/* plan9 file servers */
+	OP9auth=		129,	/* plan9 auth servers */
 };
 };
 
 
 /* a lease that never expires */
 /* a lease that never expires */
-#define Lforever	0xffffffffU
+#define Lforever	~0UL
 
 
 /* dhcp states */
 /* dhcp states */
 enum {
 enum {
@@ -127,7 +127,7 @@ enum {
 	Sbound,
 	Sbound,
 	Srenewing,
 	Srenewing,
 	Srebinding,
 	Srebinding,
-};	
+};
 
 
 typedef struct Bootp	Bootp;
 typedef struct Bootp	Bootp;
 struct Bootp
 struct Bootp

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

@@ -0,0 +1,276 @@
+typedef struct Conf Conf;
+typedef struct Ctl Ctl;
+
+struct Conf
+{
+	/* locally generated */
+	char	*type;
+	char	*dev;
+	char	mpoint[32];
+	int	cfd;			/* ifc control channel */
+	int	dfd;			/* ifc data channel (for ppp) */
+	char	*cputype;
+	uchar	hwa[32];		/* hardware address */
+	int	hwatype;
+	int	hwalen;
+	uchar	cid[32];
+	int	cidlen;
+	char	*baud;
+
+	/* learned info */
+	uchar	gaddr[IPaddrlen];
+	uchar	laddr[IPaddrlen];
+	uchar	mask[IPaddrlen];
+	uchar	raddr[IPaddrlen];
+	uchar	dns[2*IPaddrlen];
+	uchar	fs[2*IPaddrlen];
+	uchar	auth[2*IPaddrlen];
+	uchar	ntp[IPaddrlen];
+	int	mtu;
+
+	/* dhcp specific */
+	int	state;
+	int	fd;
+	ulong	xid;
+	ulong	starttime;
+	char	sname[64];
+	char	hostname[32];
+	char	domainname[64];
+	uchar	server[IPaddrlen];	/* server IP address */
+	ulong	offered;		/* offered lease time */
+	ulong	lease;			/* lease time */
+	ulong	resend;			/* # of resends for current state */
+	ulong	timeout;		/* time to timeout - seconds */
+
+	/*
+	 * IPv6
+	 */
+
+	/* solicitation specific - XXX add support for IPv6 leases */
+	ulong	solicit_retries;
+
+	/* router related */
+	uchar	sendra;
+	uchar	recvra;
+	uchar	mflag;
+	uchar	oflag;
+	int 	maxraint; /* rfc2461, p.39: 4sec ≤ maxraint ≤ 1800sec, def 600 */
+	int	minraint;	/* 3sec ≤ minraint ≤ 0.75*maxraint */
+	int	linkmtu;
+	int	reachtime;	/* 3,600,000 msec, default 0 */
+	int	rxmitra;	/* default 0 */
+	int	ttl;		/* default 0 (unspecified) */
+
+	/* def gateway params */
+	uchar	v6gaddr[IPaddrlen];
+	int	routerlt;	/* router life time */
+	int	force;
+
+	/* prefix related */
+	uchar	v6pref[IPaddrlen];
+	int	prefixlen;
+	uchar	onlink;
+	uchar	autoflag;
+	ulong	validlt;
+	ulong	preflt;
+};
+
+struct Ctl
+{
+	Ctl	*next;
+	char	*ctl;
+};
+
+extern Ctl *firstctl, **ctll;
+
+extern Conf conf;
+
+extern int	noconfig;
+extern int	ipv6auto;
+extern int	debug;
+extern int	dodhcp;
+extern int	nip;
+extern int	plan9;
+extern int	dupl_disc;
+
+extern Conf	conf;
+extern int	myifc;
+extern char	*vs;
+
+void	adddefroute(char*, uchar*);
+void	binddevice(void);
+void	bootprequest(void);
+void	controldevice(void);
+void	dhcpquery(int, int);
+void	dhcprecv(void);
+void	dhcpsend(int);
+int	dhcptimer(void);
+void	dhcpwatch(int);
+void	doadd(int);
+void	doremove(void);
+void	dounbind(void);
+int	getndb(void);
+int	ipconfig4(void);
+int	ipconfig6(int);
+void	lookforip(char*);
+void	mkclientid(void);
+int	nipifcs(char*);
+int	openlisten(void);
+uchar	*optaddaddr(uchar*, int, uchar*);
+uchar	*optaddbyte(uchar*, int, int);
+uchar	*optaddstr(uchar*, int, char*);
+uchar	*optadd(uchar*, int, void*, int);
+uchar	*optaddulong(uchar*, int, ulong);
+uchar	*optaddvec(uchar*, int, uchar*, int);
+int	optgetaddrs(uchar*, int, uchar*, int);
+int	optgetaddr(uchar*, int, uchar*);
+int	optgetbyte(uchar*, int);
+int	optgetstr(uchar*, int, char*, int);
+uchar	*optget(uchar*, int, int*);
+ulong	optgetulong(uchar*, int);
+int	optgetvec(uchar*, int, uchar*, int);
+int	parseoptions(uchar *p, int n);
+int	parseverb(char*);
+void	procsetname(char *fmt, ...);
+void	putndb(void);
+void	tweakservers(void);
+void	usage(void);
+int	validip(uchar*);
+void	writendb(char*, int, int);
+
+/*
+ * IPv6
+ */
+
+void	dov6stuff(int);
+int	ipconfig6(int);
+void	recvra6(void);
+void	sendra6(void);
+void	v6paraminit(void);
+
+typedef struct Headers Headers;
+typedef struct Ip4hdr  Ip4hdr;
+typedef struct Ip6hdr  Ip6hdr;
+typedef struct Lladdropt Lladdropt;
+typedef struct Mtuopt Mtuopt;
+typedef struct Prefixopt Prefixopt;
+typedef struct Routeradv Routeradv;
+typedef struct Routersol Routersol;
+
+enum {
+	IsRouter 	= 1,
+	IsHostRecv	= 2,
+	IsHostNoRecv	= 3,
+
+	MAClen		= 6,
+
+	IPv4		= 4,
+	IPv6		= 6,
+	Defmtu		= 1400,
+
+	IP_HOPBYHOP	= 0,
+	ICMPv4		= 1,
+	IP_IGMPPROTO	= 2,
+	IP_TCPPROTO	= 6,
+	IP_UDPPROTO	= 17,
+	IP_ILPROTO	= 40,
+	IP_v6ROUTE	= 43,
+	IP_v6FRAG	= 44,
+	IP_IPsecESP	= 50,
+	IP_IPsecAH	= 51,
+	IP_v6NOMORE	= 59,
+	ICMP6_RS	= 133,
+	ICMP6_RA	= 134,
+
+	IP_IN_IP	= 41,
+};
+
+enum {
+	MFMASK = 1 << 7,
+	OCMASK = 1 << 6,
+	OLMASK = 1 << 7,
+	AFMASK = 1 << 6,
+};
+
+enum {
+	MAXTTL		= 255,
+	IP4_VER		= 0x40,
+	IP6_VER		= 0x60,
+	D64HLEN		= IPV6HDR_LEN - IPV4HDR_LEN,
+	IP_MAX		= 32*1024,
+};
+
+struct Headers {
+	uchar	dst[IPaddrlen];
+	uchar	src[IPaddrlen];
+};
+
+struct Ip4hdr{
+	uchar	vihl;		/* Version and header length */
+	uchar	tos;		/* Type of service */
+	uchar	length[2];	/* packet length */
+	uchar	id[2];		/* ip->identification */
+	uchar	frag[2];	/* Fragment information */
+	uchar	ttl;		/* Time to live */
+	uchar	proto;		/* Protocol */
+	uchar	cksum[2];	/* Header checksum */
+	uchar	src[4];		/* IP source */
+	uchar	dst[4];		/* IP destination */
+};
+
+struct Routersol {
+	uchar	vcf[4];		/* version:4, traffic class:8, flow label:20 */
+	uchar	ploadlen[2];	/* payload length: packet length - 40 */
+	uchar	proto;		/* next header	type */
+	uchar	ttl;		/* hop limit */
+	uchar	src[IPaddrlen];
+	uchar	dst[IPaddrlen];
+	uchar	type;
+	uchar	code;
+	uchar	cksum[2];
+	uchar	res[4];
+};
+
+struct Routeradv {
+	uchar	vcf[4];		/* version:4, traffic class:8, flow label:20 */
+	uchar	ploadlen[2];	/* payload length: packet length - 40 */
+	uchar	proto;		/* next header	type */
+	uchar	ttl;		/* hop limit */
+	uchar	src[IPaddrlen];
+	uchar	dst[IPaddrlen];
+	uchar	type;
+	uchar	code;
+	uchar	cksum[2];
+	uchar	cttl;
+	uchar	mor;
+	uchar	routerlt[2];
+	uchar	rchbltime[4];
+	uchar	rxmtimer[4];
+};
+
+struct Lladdropt {
+	uchar	type;
+	uchar	len;
+	uchar	lladdr[MAClen];
+};
+
+struct Prefixopt {
+	uchar	type;
+	uchar	len;
+	uchar	plen;
+	uchar	lar;
+	uchar	validlt[4];
+	uchar	preflt[4];
+	uchar	reserv[4];
+	uchar	pref[IPaddrlen];
+};
+
+struct Mtuopt {
+	uchar	type;
+	uchar	len;
+	uchar	reserv[2];
+	uchar	mtu[4];
+};
+
+void	ea2lla(uchar *lla, uchar *ea);
+void	ipv62smcast(uchar *smcast, uchar *a);

+ 924 - 0
sys/src/cmd/ip/ipconfig/ipv6.c

@@ -0,0 +1,924 @@
+/*
+ * ipconfig for IPv6
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ip.h>
+typedef struct Block Block;
+typedef struct Fs Fs;
+#include "/sys/src/9/ip/ipv6.h"
+#include "ipconfig.h"
+#include "../icmp.h"
+
+#pragma varargck argpos ralog 1
+
+#define RALOG "v6routeradv"
+
+#define NetS(x) (((uchar*)x)[0]<< 8 | ((uchar*)x)[1])
+#define NetL(x) (((uchar*)x)[0]<<24 | ((uchar*)x)[1]<<16 | \
+		 ((uchar*)x)[2]<< 8 | ((uchar*)x)[3])
+
+enum {
+	ICMP6LEN=	4,
+};
+
+typedef struct Hdr Hdr;
+struct Hdr			/* ICMP v4 & v6 header */
+{
+	uchar	type;
+	uchar	code;
+	uchar	cksum[2];	/* Checksum */
+	uchar	data[1];
+};
+
+char *icmpmsg6[Maxtype6+1] =
+{
+[EchoReply]		"EchoReply",
+[UnreachableV6]		"UnreachableV6",
+[PacketTooBigV6]	"PacketTooBigV6",
+[TimeExceedV6]		"TimeExceedV6",
+[Redirect]		"Redirect",
+[EchoRequest]		"EchoRequest",
+[TimeExceed]		"TimeExceed",
+[InParmProblem]		"InParmProblem",
+[Timestamp]		"Timestamp",
+[TimestampReply]	"TimestampReply",
+[InfoRequest]		"InfoRequest",
+[InfoReply]		"InfoReply",
+[AddrMaskRequest]	"AddrMaskRequest",
+[AddrMaskReply]		"AddrMaskReply",
+[EchoRequestV6]		"EchoRequestV6",
+[EchoReplyV6]		"EchoReplyV6",
+[RouterSolicit]		"RouterSolicit",
+[RouterAdvert]		"RouterAdvert",
+[NbrSolicit]		"NbrSolicit",
+[NbrAdvert]		"NbrAdvert",
+[RedirectV6]		"RedirectV6",
+};
+
+static char *icmp6opts[] =
+{
+[0]		"unknown opt",
+[SRC_LLADDR]	"sll_addr",
+[TARGET_LLADDR]	"tll_addr",
+[PREFIX_INFO]	"pref_opt",
+[REDIR_HEADER]	"redirect",
+[MTU_OPTION]	"mtu_opt",
+};
+
+uchar v6allroutersL[IPaddrlen] = {
+	0xff, 0x02, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0x02
+};
+
+uchar v6allnodesL[IPaddrlen] = {
+	0xff, 0x02, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0x01
+};
+
+uchar v6Unspecified[IPaddrlen] = {
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0
+};
+
+uchar v6glunicast[IPaddrlen] = {
+	0x08, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0
+};
+
+uchar v6linklocal[IPaddrlen] = {
+	0xfe, 0x80, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 0
+};
+
+uchar v6solpfx[IPaddrlen] = {
+	0xff, 0x02, 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0, 1,
+	/* last 3 bytes filled with low-order bytes of addr being solicited */
+	0xff, 0, 0, 0,
+};
+
+uchar v6defmask[IPaddrlen] = {
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0, 0, 0, 0,
+	0, 0, 0, 0
+};
+
+enum
+{
+	Vadd,
+	Vremove,
+	Vunbind,
+	Vaddpref6,
+	Vra6,
+};
+
+static void
+ralog(char *fmt, ...)
+{
+	char msg[512];
+	va_list arg;
+
+	va_start(arg, fmt);
+	vseprint(msg, msg+sizeof msg, fmt, arg);
+	va_end(arg);
+	syslog(debug, RALOG, msg);
+}
+
+extern void
+ea2lla(uchar *lla, uchar *ea)
+{
+	assert(IPaddrlen == 16);
+	memset(lla, 0, IPaddrlen);
+	lla[0]  = 0xFE;
+	lla[1]  = 0x80;
+	lla[8]  = ea[0] | 0x2;
+	lla[9]  = ea[1];
+	lla[10] = ea[2];
+	lla[11] = 0xFF;
+	lla[12] = 0xFE;
+	lla[13] = ea[3];
+	lla[14] = ea[4];
+	lla[15] = ea[5];
+}
+
+extern void
+ipv62smcast(uchar *smcast, uchar *a)
+{
+	assert(IPaddrlen == 16);
+	memset(smcast, 0, IPaddrlen);
+	smcast[0]  = 0xFF;
+	smcast[1]  = 0x02;
+	smcast[11] = 0x1;
+	smcast[12] = 0xFF;
+	smcast[13] = a[13];
+	smcast[14] = a[14];
+	smcast[15] = a[15];
+}
+
+void
+v6paraminit(void)
+{
+	conf.sendra = conf.recvra = 0;
+	conf.mflag = 0;
+	conf.oflag = 0;
+	conf.maxraint = MAX_INIT_RTR_ADVERT_INTVL;
+	conf.minraint = MAX_INIT_RTR_ADVERT_INTVL / 4;
+	conf.linkmtu = 1500;
+	conf.reachtime = REACHABLE_TIME;
+	conf.rxmitra = RETRANS_TIMER;
+	conf.ttl = MAXTTL;
+
+	conf.routerlt = 0;
+	conf.force = 0;
+
+	conf.prefixlen = 64;
+	conf.onlink = 0;
+	conf.autoflag = 0;
+	conf.validlt = conf.preflt = ~0L;
+}
+
+static char*
+opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
+{
+	int otype, osz, pktsz;
+	uchar *a;
+	char *p = sps, *e = spe;
+
+	a = ps;
+	for (pktsz = pe - ps; pktsz > 0; pktsz -= osz) {
+		otype = a[0];
+		osz = a[1] * 8;
+
+		switch (otype) {
+		default:
+			return seprint(p, e, " option=%s ", icmp6opts[otype]);
+		case SRC_LLADDR:
+		case TARGET_LLADDR:
+			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);
+			break;
+		case PREFIX_INFO:
+			if (pktsz < osz || osz != 32)
+				return seprint(p, e, " option=%s: bad size=%d",
+					icmp6opts[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)),
+				(*(a+3) & (1 << 7)) != 0,
+				(*(a+3) & (1 << 6)) != 0,
+				(*(a+3) & 63) != 0,
+				NetL(a+4), NetL(a+8), NetL(a+12)!=0);
+			break;
+		}
+		a += osz;
+	}
+	return p;
+}
+
+static void
+pkt2str(uchar *ps, uchar *pe, char *sps, char *spe)
+{
+	int pktlen;
+	char *tn, *p, *e;
+	uchar *a;
+	Hdr *h;
+
+	h = (Hdr*)ps;
+	a = ps + 4;
+	p = sps;
+	e = spe;
+
+	pktlen = pe - ps;
+	if(pktlen < ICMP6LEN) {
+		seprint(sps, spe, "short pkt");
+		return;
+	}
+
+	tn = icmpmsg6[h->type];
+	if(tn == nil)
+		p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
+			h->code, (ushort)NetS(h->cksum));
+	else
+		p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
+			h->code, (ushort)NetS(h->cksum));
+
+	switch(h->type){
+	case RouterSolicit:
+		ps += 8;
+		p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0);
+		opt_seprint(ps, pe, p, e);
+		break;
+	case RouterAdvert:
+		ps += 16;
+		p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d"
+			" unused=%1.1d routerlt=%d reachtime=%d rxmtimer=%d",
+			a[0],
+			(*(a+1) & (1 << 7)) != 0,
+			(*(a+1) & (1 << 6)) != 0,
+			(*(a+1) & 63) != 0,
+			NetS(a+2), NetL(a+4), NetL(a+8));
+		opt_seprint(ps, pe, p, e);
+		break;
+	default:
+		seprint(p, e, " unexpected icmp6 pkt type");
+		break;
+	}
+}
+
+static void
+catch(void *a, char *msg)
+{
+	USED(a);
+	if(strstr(msg, "alarm"))
+		noted(NCONT);
+	else
+		noted(NDFLT);
+}
+
+/*
+ * 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);
+}
+
+int
+dialicmp(uchar *dst, int dport, int *ctlfd)
+{
+	int fd, cfd, n, m;
+	char cmsg[100], name[128], connind[40];
+	char hdrs[] = "headers";
+
+	snprint(name, sizeof name, "%s/icmpv6/clone", conf.mpoint);
+	cfd = open(name, ORDWR);
+	if(cfd < 0)
+		sysfatal("dialicmp: can't open %s: %r", name);
+
+	n = snprint(cmsg, sizeof cmsg, "connect %I!%d!r %d", dst, dport, dport);
+	m = write(cfd, cmsg, n);
+	if (m < n)
+		sysfatal("dialicmp: can't write %s to %s: %r", cmsg, name);
+
+	seek(cfd, 0, 0);
+	n = read(cfd, connind, sizeof connind);
+	if (n < 0)
+		connind[0] = 0;
+	else if (n < sizeof connind)
+		connind[n] = 0;
+	else
+		connind[sizeof connind - 1] = 0;
+
+	snprint(name, sizeof name, "%s/icmpv6/%s/data", conf.mpoint, connind);
+	fd = open(name, ORDWR);
+	if(fd < 0)
+		sysfatal("dialicmp: can't open %s: %r", name);
+
+	n = sizeof hdrs - 1;
+	if(write(cfd, hdrs, n) < n)
+		sysfatal("dialicmp: can't write `%s' to %s: %r", hdrs, name);
+	*ctlfd = cfd;
+	return fd;
+}
+
+/* add ipv6 addr to an interface */
+int
+ip6cfg(int autoconf)
+{
+	int dupfound = 0, n;
+	char *p;
+	char buf[256];
+	uchar ethaddr[6];
+	Biobuf *bp;
+
+	if (autoconf) {			/* create link-local addr */
+		if (myetheraddr(ethaddr, conf.dev) < 0)
+			sysfatal("myetheraddr w/ %s failed: %r", conf.dev);
+		ea2lla(conf.laddr, ethaddr);
+	}
+
+	if (dupl_disc)
+		n = sprint(buf, "try");
+	else
+		n = sprint(buf, "add");
+
+	n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
+	if(!validip(conf.mask))
+		ipmove(conf.mask, v6defmask);
+	n += snprint(buf+n, sizeof buf-n, " %M", conf.mask);
+	if(validip(conf.raddr)){
+		n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
+		if(conf.mtu != 0)
+			n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu);
+	}
+
+	if(write(conf.cfd, buf, n) < 0){
+		fprint(2, "%s: write(%s): %r\n", argv0, buf);
+		return -1;
+	}
+
+	if (!dupl_disc)
+		return 0;
+
+	sleep(3000);
+
+	/* read arp table, look for addr duplication */
+	snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
+	bp = Bopen(buf, OREAD);
+	if (bp == 0) {
+		fprint(2, "%s: couldn't open %s/arp: %r\n", argv0, conf.mpoint);
+		return -1;
+	}
+
+	snprint(buf, sizeof buf, "%I", conf.laddr);
+	while(p = Brdline(bp, '\n')){
+		p[Blinelen(bp)-1] = 0;
+		if(cistrstr(p, buf) != 0) {
+			fprint(2, "%s: found dup entry in arp cache\n", argv0);
+			dupfound = 1;
+			break;
+		}
+	}
+	Bterm(bp);
+
+	if (dupfound)
+		doremove();
+	else {
+		n = sprint(buf, "add %I %M", conf.laddr, conf.mask);
+		if(validip(conf.raddr)){
+			n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
+			if(conf.mtu != 0)
+				n += snprint(buf+n, sizeof buf-n, " %d",
+					conf.mtu);
+		}
+		write(conf.cfd, buf, n);
+	}
+	return 0;
+}
+
+static int
+recvra6on(char *net, int conn)
+{
+	Ipifc* ifc;
+
+	ifc = readipifc(net, nil, conn);
+	if (ifc == nil)
+		return 0;
+	else if (ifc->sendra6 > 0)
+		return IsRouter;
+	else if (ifc->recvra6 > 0)
+		return IsHostRecv;
+	else
+		return IsHostNoRecv;
+}
+
+static void
+sendrs(int fd)
+{
+	Routersol *rs;
+	uchar buff[sizeof *rs];
+
+	memset(buff, 0, sizeof buff);
+	rs = (Routersol *)buff;
+	memmove(rs->dst, v6allroutersL, IPaddrlen);
+	memmove(rs->src, v6Unspecified, IPaddrlen);
+	rs->type = ICMP6_RS;
+
+	if(write(fd, rs, sizeof buff) < sizeof buff)
+		ralog("sendrs: write failed, pkt size %d", sizeof buff);
+}
+
+/*
+ * a router receiving a router adv from another
+ * router calls this; it is basically supposed to
+ * log the information in the ra and raise a flag
+ * if any parameter value is different from its configured values.
+ *
+ * doing nothing for now since I don't know where to log this yet.
+ */
+static void
+recvrarouter(uchar buf[], int pktlen)
+{
+	USED(buf, pktlen);
+	ralog("i am a router and got a router advert");
+}
+
+/* host receiving a router advertisement calls this */
+
+static void
+recvrahost(uchar buf[], int pktlen)
+{
+	int arpfd, m, n;
+	char abuf[100], configcmd[256];
+	uchar optype;
+	Lladdropt *llao;
+	Mtuopt *mtuo;
+	Prefixopt *prfo;
+	Routeradv *ra;
+
+	ra = (Routeradv*)buf;
+	memmove(conf.v6gaddr, ra->src, IPaddrlen);
+	conf.force = 0;
+	conf.ttl = ra->cttl;
+	conf.mflag = (MFMASK & ra->mor);
+	conf.oflag = (OCMASK & ra->mor);
+	conf.routerlt =  nhgets(ra->routerlt);
+	conf.reachtime = nhgetl(ra->rchbltime);
+	conf.rxmitra =   nhgetl(ra->rxmtimer);
+
+	n = snprint(configcmd, sizeof configcmd, "%s %I %d %d %d %d %d %d %d",
+		"gate6", conf.v6gaddr, conf.force, conf.ttl, conf.mflag,
+		conf.oflag, conf.routerlt, conf.reachtime, conf.rxmitra);
+	if (write(conf.cfd, configcmd, n) < 0)
+		ralog("write (%s) failed", configcmd);
+
+	m = sizeof *ra;
+	while (pktlen - m > 0) {
+		optype = buf[m];
+		switch (optype) {
+		case SRC_LLADDR:
+			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);
+				return;
+			}
+			if (memcmp(ra->src, v6linklocal, 2) != 0) {
+				ralog(
+			"recvrahost: non-linklocal 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);
+				return;
+			}
+
+			n = snprint(abuf, sizeof abuf, "add ether %I %E",
+				ra->src, llao->lladdr);
+			if (write(arpfd, abuf, n) < n)
+				ralog("recvrahost: couldn't write to %s/arp",
+					conf.mpoint);
+			close(arpfd);
+			break;
+		case TARGET_LLADDR:
+		case REDIR_HEADER:
+			m += 8 * buf[m+1];
+			ralog("ignoring unexpected optype %s in Routeradv",
+				icmp6opts[optype]);
+			break;
+		case MTU_OPTION:
+			mtuo = (Mtuopt*)&buf[m];
+			m += 8 * mtuo->len;
+			conf.linkmtu = nhgetl(mtuo->mtu);
+			break;
+		case PREFIX_INFO:
+			prfo = (Prefixopt*)&buf[m];
+			m += 8 * prfo->len;
+			if (prfo->len != 4) {
+				ralog("illegal len(%d) for prefix option",
+					prfo->len);
+				return;
+			}
+			memmove(conf.v6pref, prfo->pref, IPaddrlen);
+			conf.prefixlen = prfo->plen;
+			conf.onlink =   ((prfo->lar & OLMASK) != 0);
+			conf.autoflag = ((prfo->lar & AFMASK) != 0);
+			conf.validlt = nhgetl(prfo->validlt);
+			conf.preflt =  nhgetl(prfo->preflt);
+			n = snprint(configcmd, sizeof configcmd,
+				"%s %I %d %d %d %uld %uld",
+				"addpref6", conf.v6pref, conf.prefixlen,
+				conf.onlink, conf.autoflag,
+				conf.validlt, conf.preflt);
+			if (write(conf.cfd, configcmd, n) < 0)
+				ralog("write (%s) failed", configcmd);
+			break;
+		default:
+			m += 8 * buf[m+1];
+			ralog("ignoring optype %s in Routeradv", icmp6opts[0]);
+			break;
+		}
+	}
+}
+
+/*
+ * daemon to receive router adverisements
+ */
+void
+recvra6(void)
+{
+	int fd, cfd, n, sendrscnt, sleepfor;
+	uchar buf[4096];
+
+	fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
+	if (fd < 0)
+		sysfatal("can't open icmp_ra connection: %r");
+
+	notify(catch);
+	sendrscnt = MAX_RTR_SOLICITS;
+
+	switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
+	case -1:
+		sysfatal("can't fork: %r");
+	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 = RTR_SOLICIT_INTVL+nrand(100);
+				}
+				if (sendrscnt == 0) {
+					sendrscnt--;
+					sleepfor = 0;
+					ralog(
+				"recvra6: no router advs after %d sols on %s",
+						 MAX_RTR_SOLICITS, conf.dev);
+				}
+				continue;
+			}
+
+			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;
+			}
+		}
+	}
+}
+
+/*
+ * return -1 -- error, reading/writing some file,
+ *         0 -- no arptable updates
+ *         1 -- successful arptable update
+ */
+int
+recvrs(uchar *buf, int pktlen, uchar *sol)
+{
+	int n, optsz, arpfd;
+	char abuf[256];
+	Routersol *rs;
+	Lladdropt *llao;
+
+	rs = (Routersol *)buf;
+	n = sizeof *rs;
+	optsz = pktlen - n;
+	pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf));
+
+	if (optsz != sizeof *llao)
+		return 0;
+	if (buf[n] != SRC_LLADDR || 8*buf[n+1] != sizeof *llao) {
+		ralog("rs opt err %s", abuf);
+		return -1;
+	}
+
+	ralog("rs recv %s", abuf);
+
+	if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0)
+		return 0;
+
+	snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
+	arpfd = open(abuf, OWRITE);
+	if (arpfd < 0) {
+		ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint);
+		return -1;
+	}
+
+	llao = (Lladdropt *)buf[n];
+	n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr);
+	if (write(arpfd, abuf, n) < n) {
+		ralog("recvrs: can't write to %s/arp: %r", conf.mpoint);
+		close(arpfd);
+		return -1;
+	}
+
+	memmove(sol, rs->src, IPaddrlen);
+	close(arpfd);
+	return 1;
+}
+
+void
+sendra(int fd, uchar *dst, int rlt)
+{
+	int pktsz, preflen;
+	char abuf[1024], tmp[40];
+	uchar buf[1024], macaddr[6], src[IPaddrlen];
+	Ipifc *ifc = nil;
+	Iplifc *lifc, *nlifc;
+	Lladdropt *llao;
+	Prefixopt *prfo;
+	Routeradv *ra;
+
+	memset(buf, 0, sizeof buf);
+	ra = (Routeradv *)buf;
+
+	myetheraddr(macaddr, conf.dev);
+	ea2lla(src, macaddr);
+	memmove(ra->src, src, IPaddrlen);
+	memmove(ra->dst, dst, IPaddrlen);
+	ra->type = ICMP6_RA;
+	ra->cttl = conf.ttl;
+
+	if (conf.mflag > 0)
+		ra->mor |= MFMASK;
+	if (conf.oflag > 0)
+		ra->mor |= OCMASK;
+	if (rlt > 0)
+		hnputs(ra->routerlt, conf.routerlt);
+	else
+		hnputs(ra->routerlt, 0);
+	hnputl(ra->rchbltime, conf.reachtime);
+	hnputl(ra->rxmtimer, conf.rxmitra);
+
+	pktsz = sizeof *ra;
+
+	/* include all global unicast prefixes on interface in prefix options */
+	ifc = readipifc(conf.mpoint, ifc, myifc);
+	for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) {
+		nlifc = lifc->next;
+		prfo = (Prefixopt *)(buf + pktsz);
+		if (isv6global(lifc->ip)) {
+			memmove(prfo->pref, lifc->net, IPaddrlen);
+
+			/* hack to find prefix length */
+			snprint(tmp, sizeof tmp, "%M", lifc->mask);
+			preflen = atoi(&tmp[1]);
+			prfo->plen = preflen & 0xff;
+			if (prfo->plen == 0)
+				continue;
+
+			prfo->type = PREFIX_INFO;
+			prfo->len = 4;
+			prfo->lar = AFMASK;
+			hnputl(prfo->validlt, lifc->validlt);
+			hnputl(prfo->preflt, lifc->preflt);
+			pktsz += sizeof *prfo;
+		}
+	}
+	/*
+	 * include link layer address (mac address for now) in
+	 * link layer address option
+	 */
+	llao = (Lladdropt *)(buf + pktsz);
+	llao->type = SRC_LLADDR;
+	llao->len = 1;
+	memmove(llao->lladdr, macaddr, sizeof macaddr);
+	pktsz += sizeof *llao;
+
+	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);
+}
+
+/*
+ * daemon to send router advertisements
+ */
+void
+sendra6(void)
+{
+	int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
+	long lastra, ctime;
+	uchar buf[4096], dst[IPaddrlen];
+	Ipifc *ifc = nil;
+
+	fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd);
+	if (fd < 0)
+		sysfatal("can't open icmp_rs connection: %r");
+
+	notify(catch);
+	sendracnt = MAX_INIT_RTR_ADVERTS;
+	nquitmsgs = MAX_FINAL_RTR_ADVERTS;
+
+	switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
+	case -1:
+		sysfatal("can't fork: %r");
+	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);
+				continue;
+			}
+
+			if (ifc->sendra6 <= 0)
+				if (nquitmsgs > 0) {
+					sendra(fd, v6allnodesL, 0);
+					nquitmsgs--;
+					sleepfor = MIN_DELAY_BETWEEN_RAS +
+						nrand(10);
+					continue;
+				} else {
+					ralog("sendra6: quitting");
+					exits(0);
+				}
+
+			nquitmsgs = MAX_FINAL_RTR_ADVERTS;
+
+			if (n <= 0) {		/* no router solicitations */
+				if (sendracnt > 0)
+					sendracnt--;
+				sleepfor = ifc->rp.minraint +
+					nrand(ifc->rp.maxraint + 1 -
+						ifc->rp.minraint);
+			} else {		/* respond to router solicit'n */
+				dstknown = recvrs(buf, n, dst);
+				ctime = time(0);
+
+				if (ctime - lastra < MIN_DELAY_BETWEEN_RAS) {
+					/* too close, skip */
+					sleepfor = lastra +
+						MIN_DELAY_BETWEEN_RAS +
+						nrand(10) - ctime;
+					continue;
+				}
+				sleepfor = ifc->rp.minraint +
+					nrand(ifc->rp.maxraint + 1 -
+						ifc->rp.minraint);
+				sleep(nrand(10));
+			}
+			if (dstknown > 0)
+				sendra(fd, dst, 1);
+			else
+				sendra(fd, v6allnodesL, 1);
+		}
+	}
+}
+
+void
+ra6(void)
+{
+	static char routeon[] = "iprouting 1";
+
+	if (conf.recvra > 0)
+		recvra6();
+
+	if (conf.sendra > 0) {
+		if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
+			fprint(2, "%s: write (iprouting 1) failed\n", argv0);
+			return;
+		}
+		sendra6();
+		if (conf.recvra <= 0)
+			recvra6();
+	}
+}
+
+void
+dov6stuff(int what)
+{
+	char buf[256];
+	int n;
+
+	nip = nipifcs(conf.mpoint);
+	if(!noconfig){
+		lookforip(conf.mpoint);
+		controldevice();
+		binddevice();
+	}
+
+	switch (what) {
+	default:
+		fprint(2, "%s: unknown IPv6 verb\n", argv0);
+		break;
+	case Vaddpref6:
+		n = snprint(buf, sizeof buf, "addpref6 %I %d %d %d %uld %uld",
+			conf.v6pref, conf.prefixlen, conf.onlink, conf.autoflag,
+			conf.validlt, conf.preflt);
+		if (write(conf.cfd, buf, n) < n)
+			fprint(2, "%s: write (%s) failed\n", argv0, buf);
+		break;
+	case Vra6:
+		n = snprint(buf, sizeof buf,
+			"ra6 sendra %d recvra %d mflag %d oflag %d"
+			" maxraint %d minraint %d linkmtu %d reachtime %d"
+			" rxmitra %d ttl %d routerlt %d",
+			conf.sendra, conf.recvra, conf.mflag, conf.oflag,
+			conf.maxraint, conf.minraint, conf.linkmtu,
+			conf.reachtime, conf.rxmitra, conf.ttl, conf.routerlt);
+		if (write(conf.cfd, buf, n) < n)
+			fprint(2, "%s: write (%s) failed\n", argv0, buf);
+		ra6();
+		break;
+	}
+}

File diff suppressed because it is too large
+ 388 - 269
sys/src/cmd/ip/ipconfig/main.c


+ 23 - 0
sys/src/cmd/ip/ipconfig/mkfile

@@ -0,0 +1,23 @@
+</$objtype/mkfile
+
+TARG=ipconfig\
+
+OFILES=\
+	main.$O\
+	ipv6.$O\
+	ppp.$O\
+
+HFILES=\
+	../dhcp.h\
+	../icmp.h\
+	ipconfig.h\
+	/sys/src/9/ip/ipv6.h\
+
+BIN=/$objtype/bin/ip
+
+UPDATE=\
+	mkfile\
+	$HFILES\
+	${OFILES:%.$O=%.c}\
+
+</sys/src/cmd/mkone

+ 63 - 0
sys/src/cmd/ip/ipconfig/ppp.c

@@ -0,0 +1,63 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+#include <bio.h>
+#include <ndb.h>
+#include "../dhcp.h"
+typedef struct Block Block;
+typedef struct Fs Fs;
+#include "/sys/src/9/ip/ipv6.h"
+#include "ipconfig.h"
+
+void
+pppbinddev(void)
+{
+	int ac, pid;
+	char *av[12];
+	Waitmsg *w;
+
+	/* ppp does the binding */
+
+	/* start with an empty config file */
+	if(nip == 0)
+		writendb("", 0, 0);
+
+	switch(pid = rfork(RFPROC|RFFDG|RFMEM)){
+	case -1:
+		sysfatal("can't start ppp: %r");
+	case 0:
+		ac = 0;
+		av[ac++] = "ppp";
+		av[ac++] = "-uf";
+		av[ac++] = "-p";
+		av[ac++] = conf.dev;
+		av[ac++] = "-x";
+		av[ac++] = conf.mpoint;
+		if(conf.baud != nil){
+			av[ac++] = "-b";
+			av[ac++] = conf.baud;
+		}
+		av[ac] = nil;
+		exec("/bin/ip/ppp", av);
+		exec("/ppp", av);
+		sysfatal("execing /ppp: %r");
+	}
+
+	/* wait for ppp to finish connecting and configuring */
+	while((w = wait()) != nil){
+		if(w->pid == pid){
+			if(w->msg[0] != 0)
+				sysfatal("/ppp exited with status: %s", w->msg);
+			free(w);
+			break;
+		}
+		free(w);
+	}
+	if(w == nil)
+		sysfatal("/ppp disappeared");
+
+	/* ppp sets up the configuration itself */
+	noconfig = 1;
+	getndb();
+}
+

+ 55 - 0
sys/src/cmd/ip/linklocal.c

@@ -0,0 +1,55 @@
+/*
+ * linklocal - print ipv6 linklocal address of a mac address
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+void
+ea2lla(uchar *lla, uchar *ea)
+{
+	assert(IPaddrlen == 16);
+	memset(lla, 0, IPaddrlen);
+	lla[0]  = 0xFE;
+	lla[1]  = 0x80;
+	lla[8]  = ea[0] | 0x2;
+	lla[9]  = ea[1];
+	lla[10] = ea[2];
+	lla[11] = 0xFF;
+	lla[12] = 0xFE;
+	lla[13] = ea[3];
+	lla[14] = ea[4];
+	lla[15] = ea[5];
+}
+
+static void
+process(char *ether)
+{
+	uchar ethaddr[6], ipaddr[16];
+
+	if (parseether(ethaddr, ether) < 0)
+		sysfatal("%s: not an ether address\n", ether);
+	ea2lla(ipaddr, ethaddr);
+	print("%I\n", ipaddr);
+}
+
+void
+main(int argc, char *argv[])
+{
+	int i, errflg = 0;
+
+	ARGBEGIN {
+	default:
+		errflg++;
+		break;
+	} ARGEND
+
+	fmtinstall('I', eipfmt);
+	if (argc <= 0 || errflg)
+		sysfatal("usage: %s ether...", argv0);
+
+	for (i = 0; i < argc; i++)
+		process(argv[i]);
+	exits(0);
+}

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

@@ -6,6 +6,7 @@ TARG = 	dhcpclient\
 	hogports\
 	hogports\
 	httpfile\
 	httpfile\
 	ipconfig\
 	ipconfig\
+	linklocal\
 	ping\
 	ping\
 	pppoe\
 	pppoe\
 	pptp\
 	pptp\
@@ -20,7 +21,7 @@ TARG = 	dhcpclient\
 	traceroute\
 	traceroute\
 	udpecho\
 	udpecho\
 
 
-DIRS=ftpfs dhcpd httpd ppp imap4d snoopy
+DIRS=ftpfs dhcpd httpd ipconfig ppp imap4d snoopy
 
 
 BIN=/$objtype/bin/ip
 BIN=/$objtype/bin/ip
 HFILES=dhcp.h arp.h glob.h icmp.h telnet.h
 HFILES=dhcp.h arp.h glob.h icmp.h telnet.h

Some files were not shown because too many files changed in this diff