Browse Source

Plan 9 from Bell Labs 2007-04-21

David du Colombier 14 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/dhcpleases - 775 sys sys 1169612024 86533
 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/hogports - 775 sys sys 1148500655 42914
 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/theworld - 775 sys sys 1058790940 1212
 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/juke - 775 sys sys 1105565140 1131
 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/ms - 664 sys sys 958249504 6815
 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/plumb - 664 sys sys 969499892 10918
 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/httpd - 664 sys sys 1165623004 6865
 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/kfscmd - 664 sys sys 1068569797 4515
 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/ip - 20000000775 sys sys 1128605981 0
 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/dhcpd - 20000000775 sys sys 1063897571 0
 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/utils.c - 664 sys sys 1168894057 2587
 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/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/ppp - 20000000775 sys sys 1065963823 0
 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/dhcpleases - 775 sys sys 1169612024 86533
 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/hogports - 775 sys sys 1148500655 42914
 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/theworld - 775 sys sys 1058790940 1212
 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/juke - 775 sys sys 1105565140 1131
 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/ms - 664 sys sys 958249504 6815
 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/plumb - 664 sys sys 969499892 10918
 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/httpd - 664 sys sys 1165623004 6865
 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/kfscmd - 664 sys sys 1068569797 4515
 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/ip - 20000000775 sys sys 1128605981 0
 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/dhcpd - 20000000775 sys sys 1063897571 0
 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/utils.c - 664 sys sys 1168894057 2587
 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/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/ppp - 20000000775 sys sys 1065963823 0
 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
 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
+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
 .TP
 .B ip
-Internet address
+Internet address,
+v4 or v6.
+.TP
+.B ipv6
+IPv6 Internet address.
+For DNS, an
+.L AAAA
+record.
 .TP
 .B ether
 Ethernet address

+ 177 - 85
sys/man/8/ipconfig

@@ -1,53 +1,74 @@
 .TH IPCONFIG 8
 .SH NAME
-ipconfig, rip \- Internet configuration and routing
+ipconfig, rip, linklocal, ipv6on \- Internet configuration and routing
 .SH SYNOPSIS
+.in +0.25i
+.ti -0.25i
 .B ip/ipconfig
-.RB [ -DGNOPdnpr ]
+.RB [ -6DGNOPdnpruX ]
 .RB [ -b
 .IR baud ]
 .RB [ -c
 .IR ctl ]
-.RB [ -m
-.IR mtu ]
 .RB [ -g
 .IR gateway ]
 .RB [ -h
-.IR hostname ]
+.IR host ]
+.RB [ -m
+.IR mtu ]
+.RB [ -o
+.IR dhcp-opt ]
 .RB [ -x
 .IR netmtpt ]
-.RB [ -o
-.IR dhcpoption ]
+[
 .I type
+[
 .I device
-.br
-.ti +0.5i
+]\|]
 .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
 .B ip/rip
 .RB [ -bdr ]
 .RB [ -x
 .IR netmtpt ]
+.PP
+.B ip/linklocal
+.I mac
+\&...
+.PP
+.B ipv6on
+[
+.I netmtpt
+.I ndbfile
+[
+.I gwv4
+]\|]
 .SH DESCRIPTION
 .I Ipconfig
 binds a device interface (default
 .BR /net/ether0 )
 to a mounted IP stack (default
 .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,
-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
 in the form of an
 .IR ndb (8)
@@ -56,21 +77,22 @@ entry.
 .I Type
 may be
 .BR ether ,
+.BR gbe ,
 .BR ppp ,
 or
-.BR gbe .
+.BR loopback .
 The
 .B gbe
 type is equivalent to
 .B ether
-except that it allows jumbo packets.
+except that it allows jumbo packets (up to ~9KB).
 For
 .B ppp
 the device can be any byte stream device.
 .PP
 The verb (default
 .IR add )
-determines the action performed.  The verbs are:
+determines the action performed.  The usual verbs are:
 .TF remove
 .TP
 .B add
@@ -86,13 +108,62 @@ unbind the device interface and all its addresses from the
 IP stack.
 .PD
 .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:
 .TF M
 .PD
 .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
 turn on debugging.
 .TP
+.B g
+the default gateway.
+.TP
 .B G
 use only generic DHCP options.  Without this option,
 .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
 file servers and auth servers.
 .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
 look in
 .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
 a matching entry.
 .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
 write configuration information to
 .BR /net/ndb ,
@@ -120,43 +206,18 @@ do not write configuration information to
 .BR /net/ndb ,
 even if this is the first network interface to be configured
 .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
-by default, 
+by default,
 .I ipconfig
 exits after trying DHCP for 15 seconds with no answer.
 This option directs
 .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
 .B x
 use the IP stack mounted at
@@ -164,6 +225,9 @@ use the IP stack mounted at
 instead of at
 .BR /net .
 .TP
+.B X
+don't fork a process to keep the DHCP lease alive.
+.TP
 .B o
 adds
 .I dhcpoption
@@ -171,25 +235,21 @@ to the list of paramters requested of the DHCP server.  The
 result will appear in
 .B /net/ndb
 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
+.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
 .BR ipmask ,
 .BR ipgw ,
@@ -200,11 +260,6 @@ and
 are always requested.
 .TF M
 .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
 If DHCP is requested, a process is forked
 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
 updates the kernel routing tables.
 The options are:
+.TF M
+.PD
 .TP
 .B b
 broadcasts routing information onto the networks.
@@ -236,7 +293,23 @@ instead of at
 .B d
 turn on (voluminous) debugging.
 .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.
 Get all addresses via DHCP.  Start up a connection server
 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
 .EE
 .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
 IP stack to directly access the outside Internet.  Note that the
 connection server uses a different set of
@@ -271,11 +344,30 @@ bindings.
 % ndb/cs -x /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/il
 .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
-.B /sys/src/cmd/ip/ipconfig.c
+.B /sys/src/cmd/ip/ipconfig
 .br
 .B /sys/src/cmd/ip/rip.c
+.br
+.B /sys/src/cmd/ip/linklocal.c
+.br
+.B /rc/bin/ipv6on
 .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
 {
 	OfferTimeout=	60,		/* when an offer times out */
@@ -21,7 +21,7 @@ enum
 	/* bootp flags */
 	Fbroadcast=	1<<15,
 
-	/* dhcp types */
+	/* dhcp v4 types */
 	Discover=	1,
 	Offer=		2,
 	Request=	3,
@@ -74,7 +74,7 @@ enum
 	OBtcpka=		38,
 	OBtcpkag=		39,
 	OBnisdomain=		40,
-	OBniserver=		41,	
+	OBniserver=		41,
 	OBntpserver=		42,
 	OBvendorinfo=		43,	/* 0x2b */
 	OBnetbiosns=		44,
@@ -95,7 +95,7 @@ enum
 	OBstserver=		75,
 	OBstdaserver=		76,
 
-	/* dhcp options */
+	/* dhcp v4 options */
 	ODipaddr=		50,	/* 0x32 */
 	ODlease=		51,
 	ODoverload=		52,
@@ -112,12 +112,12 @@ enum
 	ODbootfile=		67,
 
 	/* 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 */
-#define Lforever	0xffffffffU
+#define Lforever	~0UL
 
 /* dhcp states */
 enum {
@@ -127,7 +127,7 @@ enum {
 	Sbound,
 	Srenewing,
 	Srebinding,
-};	
+};
 
 typedef struct Bootp	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\
 	httpfile\
 	ipconfig\
+	linklocal\
 	ping\
 	pppoe\
 	pptp\
@@ -20,7 +21,7 @@ TARG = 	dhcpclient\
 	traceroute\
 	udpecho\
 
-DIRS=ftpfs dhcpd httpd ppp imap4d snoopy
+DIRS=ftpfs dhcpd httpd ipconfig ppp imap4d snoopy
 
 BIN=/$objtype/bin/ip
 HFILES=dhcp.h arp.h glob.h icmp.h telnet.h

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