From 4f4d9f7a0e48ee9caa58a9e6ec62485a917a3924 Mon Sep 17 00:00:00 2001
From: Rene Mayrhofer <rene@mayrhofer.eu.org>
Date: Mon, 6 Nov 2006 19:05:06 +0000
Subject: - New upstream release.

---
 CHANGES                                            |   10 +
 Makefile                                           |    4 +-
 Makefile.ver                                       |    2 +-
 README                                             |   42 +-
 debian/changelog                                   |    6 +
 doc/src/draft-richardson-ipsec-opportunistic.html  | 2456 -------------------
 doc/src/draft-richardson-ipsec-opportunistic.xml   | 2519 --------------------
 doc/src/draft-richardson-ipsec-rr.html             |  659 -----
 doc/src/draft-richardson-ipsec-rr.xml              |  560 -----
 doc/utils/rfc_pg.c                                 |    2 +-
 lib/Makefile                                       |    5 +-
 programs/Makefile                                  |    4 +-
 programs/pluto/connections.c                       |    9 +-
 programs/pluto/connections.h                       |    3 +-
 programs/pluto/constants.c                         |    7 +-
 programs/pluto/constants.h                         |   28 +-
 programs/pluto/demux.c                             |   47 +-
 programs/pluto/log.c                               |    4 +-
 programs/pluto/modecfg.c                           |  779 +++---
 programs/pluto/modecfg.h                           |   19 +-
 programs/pluto/state.c                             |   17 +-
 programs/pluto/state.h                             |    6 +-
 programs/pluto/vendor.c                            |   10 +-
 programs/pluto/vendor.h                            |    6 +-
 programs/pluto/whack.h                             |    3 +-
 programs/starter/args.c                            |    4 +-
 programs/starter/confread.c                        |   26 +-
 programs/starter/confread.h                        |    9 +-
 programs/starter/keywords.c                        |  179 +-
 programs/starter/keywords.h                        |    8 +-
 programs/starter/keywords.txt                      |    5 +-
 programs/starter/starterwhack.c                    |    3 +-
 testing/INSTALL                                    |   10 +-
 testing/do-tests                                   |   14 +-
 testing/hosts/alice/etc/conf.d/net                 |    7 +-
 testing/hosts/alice/etc/init.d/net.eth0            | 1266 ++++++++--
 testing/hosts/alice/etc/ipsec.conf                 |    2 -
 testing/hosts/alice/etc/runlevels/default/net.eth0 | 1266 ++++++++--
 testing/hosts/bob/etc/conf.d/net                   |    6 +-
 testing/hosts/bob/etc/init.d/net.eth0              | 1266 ++++++++--
 testing/hosts/bob/etc/ipsec.conf                   |    2 -
 testing/hosts/bob/etc/runlevels/default/net.eth0   | 1266 ++++++++--
 testing/hosts/carol/etc/conf.d/net                 |    6 +-
 testing/hosts/carol/etc/init.d/net.eth0            | 1266 ++++++++--
 testing/hosts/carol/etc/ipsec.conf                 |    2 -
 .../hosts/carol/etc/ipsec.d/private/carolKey.pem   |   53 +-
 testing/hosts/carol/etc/ipsec.secrets              |    6 +-
 testing/hosts/carol/etc/runlevels/default/net.eth0 | 1266 ++++++++--
 testing/hosts/dave/etc/conf.d/net                  |    6 +-
 testing/hosts/dave/etc/init.d/net.eth0             | 1266 ++++++++--
 testing/hosts/dave/etc/ipsec.conf                  |    2 -
 testing/hosts/dave/etc/runlevels/default/net.eth0  | 1266 ++++++++--
 testing/hosts/default/etc/hosts                    |   59 +-
 testing/hosts/moon/etc/conf.d/net                  |    9 +-
 testing/hosts/moon/etc/init.d/net.eth0             | 1266 ++++++++--
 testing/hosts/moon/etc/init.d/net.eth1             | 1266 ++++++++--
 testing/hosts/moon/etc/ipsec.conf                  |    8 +-
 testing/hosts/moon/etc/runlevels/default/net.eth0  | 1266 ++++++++--
 testing/hosts/moon/etc/runlevels/default/net.eth1  | 1266 ++++++++--
 testing/hosts/sun/etc/conf.d/net                   |    9 +-
 testing/hosts/sun/etc/init.d/net.eth0              | 1266 ++++++++--
 testing/hosts/sun/etc/init.d/net.eth1              | 1266 ++++++++--
 testing/hosts/sun/etc/ipsec.conf                   |    2 -
 testing/hosts/sun/etc/runlevels/default/net.eth0   | 1266 ++++++++--
 testing/hosts/sun/etc/runlevels/default/net.eth1   | 1266 ++++++++--
 testing/hosts/venus/etc/conf.d/net                 |    7 +-
 testing/hosts/venus/etc/init.d/net.eth0            | 1266 ++++++++--
 testing/hosts/venus/etc/ipsec.conf                 |    2 -
 testing/hosts/venus/etc/runlevels/default/net.eth0 | 1266 ++++++++--
 testing/hosts/winnetou/etc/conf.d/apache2          |    2 +-
 testing/hosts/winnetou/etc/conf.d/net              |    6 +-
 testing/hosts/winnetou/etc/init.d/net.eth0         | 1266 ++++++++--
 testing/hosts/winnetou/etc/init.d/slapd            |    2 +-
 testing/hosts/winnetou/etc/openldap/slapd.conf     |    2 +-
 testing/hosts/winnetou/etc/openssl/index.txt       |    3 +
 testing/hosts/winnetou/etc/openssl/index.txt.attr  |    2 +-
 .../hosts/winnetou/etc/openssl/index.txt.attr.old  |    2 +-
 testing/hosts/winnetou/etc/openssl/index.txt.old   |    3 +
 testing/hosts/winnetou/etc/openssl/newcerts/10.pem |   25 +
 testing/hosts/winnetou/etc/openssl/newcerts/11.pem |   25 +
 testing/hosts/winnetou/etc/openssl/newcerts/12.pem |   25 +
 testing/hosts/winnetou/etc/openssl/serial          |    2 +-
 testing/hosts/winnetou/etc/openssl/serial.old      |    2 +-
 .../hosts/winnetou/etc/runlevels/default/net.eth0  | 1266 ++++++++--
 testing/scripts/build-hostconfig                   |   59 +-
 testing/scripts/build-sshkeys                      |    8 +-
 testing/scripts/build-umlrootfs                    |   10 +-
 testing/scripts/load-testconfig                    |    6 +-
 testing/scripts/restore-defaults                   |    4 +-
 testing/testing.conf                               |   68 +-
 testing/tests/crl-ldap/pretest.dat                 |    1 +
 testing/tests/dpd-clear/evaltest.dat               |    1 +
 testing/tests/mode-config-push/description.txt     |   10 +
 testing/tests/mode-config-push/evaltest.dat        |   16 +
 .../mode-config-push/hosts/carol/etc/ipsec.conf    |   31 +
 .../mode-config-push/hosts/dave/etc/ipsec.conf     |   31 +
 .../mode-config-push/hosts/moon/etc/ipsec.conf     |   34 +
 testing/tests/mode-config-push/posttest.dat        |   11 +
 testing/tests/mode-config-push/pretest.dat         |    9 +
 testing/tests/mode-config-push/test.conf           |   21 +
 testing/tests/mode-config-swapped/evaltest.dat     |    8 +-
 testing/tests/mode-config/evaltest.dat             |    8 +-
 .../hosts/carol/etc/ipsec.secrets                  |    3 +
 .../hosts/carol/etc/ipsec.secrets                  |    3 +
 .../hosts/carol/etc/ipsec.secrets                  |    3 +
 .../multi-level-ca/hosts/carol/etc/ipsec.secrets   |    3 +
 testing/tests/starter-also-loop/pretest.dat        |    1 +
 testing/tests/starter-includes/evaltest.dat        |    8 +-
 testing/tests/virtual-ip-swapped/evaltest.dat      |    4 +-
 testing/tests/virtual-ip/evaltest.dat              |    4 +-
 testing/tests/wlan/evaltest.dat                    |    2 +-
 111 files changed, 21845 insertions(+), 11596 deletions(-)
 delete mode 100644 doc/src/draft-richardson-ipsec-opportunistic.html
 delete mode 100644 doc/src/draft-richardson-ipsec-opportunistic.xml
 delete mode 100644 doc/src/draft-richardson-ipsec-rr.html
 delete mode 100644 doc/src/draft-richardson-ipsec-rr.xml
 create mode 100644 testing/hosts/winnetou/etc/openssl/newcerts/10.pem
 create mode 100644 testing/hosts/winnetou/etc/openssl/newcerts/11.pem
 create mode 100644 testing/hosts/winnetou/etc/openssl/newcerts/12.pem
 create mode 100644 testing/tests/mode-config-push/description.txt
 create mode 100644 testing/tests/mode-config-push/evaltest.dat
 create mode 100755 testing/tests/mode-config-push/hosts/carol/etc/ipsec.conf
 create mode 100755 testing/tests/mode-config-push/hosts/dave/etc/ipsec.conf
 create mode 100755 testing/tests/mode-config-push/hosts/moon/etc/ipsec.conf
 create mode 100644 testing/tests/mode-config-push/posttest.dat
 create mode 100644 testing/tests/mode-config-push/pretest.dat
 create mode 100644 testing/tests/mode-config-push/test.conf
 create mode 100644 testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.secrets
 create mode 100644 testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.secrets
 create mode 100644 testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.secrets
 create mode 100644 testing/tests/multi-level-ca/hosts/carol/etc/ipsec.secrets

diff --git a/CHANGES b/CHANGES
index 3d92f229a..38ed3f184 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,13 @@
+strongswan-2.8.0
+----------------
+
+- Implementation of ModeConfig push mode via the new connection keyword
+  modeconfig=push allows interoperability with Cisco VPN gateways.
+
+- The command ipsec statusall now shows "DPD active" for all ISAKMP SAs
+  that are under active Dead Peer Detection control.
+
+
 strongswan-2.7.3
 ----------------
 
diff --git a/Makefile b/Makefile
index e24377652..d77302267 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 #
-# RCSID $Id: Makefile,v 1.4 2004/11/14 21:50:59 as Exp $
+# RCSID $Id: Makefile,v 1.5 2006/08/28 11:12:36 as Exp $
 
 
 FREESWANSRCDIR=$(shell pwd)
@@ -244,7 +244,7 @@ programs install clean checkprograms::
 	@for d in $(SUBDIRS) ; \
 	do \
 		(cd $$d && $(MAKE) FREESWANSRCDIR=.. $@ ) || exit 1; \
-	done; \
+	done;
 
 clean::
 	rm -rf $(RPMTMPDIR) $(RPMDEST)
diff --git a/Makefile.ver b/Makefile.ver
index b8f0d8ffd..c13d3a0da 100644
--- a/Makefile.ver
+++ b/Makefile.ver
@@ -1 +1 @@
-IPSECVERSION=2.7.3
+IPSECVERSION=2.8.0
diff --git a/README b/README
index 415c002ef..c0480b069 100644
--- a/README
+++ b/README
@@ -41,7 +41,7 @@ Contents
 	6.1 Loading private key files in PKCS#1 format
 	6.2 Entering passphrases interactively
 	6.3 Multiple private keys
-   7. Configuring CA properties - ipsec.conf
+   7. Configuring CA properties - ipsec.onf
    8. Smartcard support
 	8.1 Configuring a smartcard-based connection
 	8.2 Entering the PIN code
@@ -69,7 +69,8 @@ Contents
        14.1 Authentication and encryption algorithms
        14.2 NAT traversal
        14.3 Dead peer detection
-       14.4 IKE Mode Config
+       14.4 IKE Mode Config Pull Mode
+       14.5 IKE Mode Config Push Mode
   15. Copyright statement and acknowledgements
 
 
@@ -2918,8 +2919,8 @@ even if they might be supported by the responder.
 
 Currently please refer to README.NAT-Traversal document in the strongSwan
 distribution.
-     
-     
+
+
 14.3 Dead peer detection
     --------------------
 
@@ -2969,14 +2970,15 @@ dpdaction=clear for dynamic roadwarrior connections. The default value is
 dpdaction=none, which disables DPD.
 
 
-14.4 IKE Mode Config
-     ---------------
-     
+14.4 IKE Mode Config Pull Mode
+     -------------------------
+
 The IKE Mode Config protocol <draft-ietf-ipsec-isakmp-mode-cfg-04.txt> allows
 the dynamic assignment of virtual IP addresses and optional DNS and WINS server
-information to IPsec clients. Currently only "Mode Config Pull Mode" is
-implemented where the client actively sends a Mode Config request to the server
-in order to obtain a virtual IP.
+information to IPsec clients. As a default the "Mode Config Pull Mode" is
+used where the client actively sends a Mode Config request to the server
+in order to obtain a virtual IP. The server answers with a Mode Config reply
+message containing the requested information.
 
 Client side configuration (carol):
 
@@ -3008,6 +3010,22 @@ the virtual IP address defined by the rightsourceip parameter. In the future
 an LDAP-based lookup mechanism will be supported.
 
 
+14.5 IKE Mode Config Push Mode
+     -------------------------
+
+Cisco VPN equipment uses the alternative "Mode Config Push Mode" where the
+initiating clients waits for the server to push down a virtual address via
+a Mode Config set message. The receipt is acknowledged by the client with a
+Mode Config ack message.
+
+Mode Config Push Mode is activated by the parameter
+
+  modeconfig=push
+
+as part of the connection definition in ipsec.conf. The default value is 
+modeconfig=pull.
+
+
 15. Copyright statement and acknowledgements
     ----------------------------------------
 
@@ -3058,7 +3076,7 @@ an LDAP-based lookup mechanism will be supported.
 	               Copyright (c) 2000, Kai Martius
 
 		   X.509, OCSP and smartcard functionality:
-
+�
   Copyright (c) 2000, Andreas Hess, Patric Lichtsteiner, Roger Wegmann
   Copyright (c) 2001, Marco Bertossa, Andreas Schleiss
   Copyright (c) 2002, Uli Galizzi, Ariane Seiler, Mario Strasser
@@ -3087,5 +3105,5 @@ an LDAP-based lookup mechanism will be supported.
   for more details.
 -----------------------------------------------------------------------------
 
-This file is RCSID $Id: README,v 1.34 2006/04/26 18:19:34 as Exp $
+This file is RCSID $Id: README,v 1.36 2006/10/20 15:43:51 as Exp $
 
diff --git a/debian/changelog b/debian/changelog
index 1329b6f5c..15abbffd6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+strongswan (2.8.0+dfsg-1) UNRELEASED; urgency=low
+
+  * (NOT RELEASED YET) New upstream release
+
+ -- Rene Mayrhofer <rmayr@debian.org>  Mon,  6 Nov 2006 19:01:58 +0000
+
 strongswan (2.7.3+dfsg-1) unstable; urgency=low
 
   * New upstream release. Another try on getting it into unstable.
diff --git a/doc/src/draft-richardson-ipsec-opportunistic.html b/doc/src/draft-richardson-ipsec-opportunistic.html
deleted file mode 100644
index 87a13365a..000000000
--- a/doc/src/draft-richardson-ipsec-opportunistic.html
+++ /dev/null
@@ -1,2456 +0,0 @@
-<html><head><title>Opportunistic Encryption using The Internet Key Exchange (IKE)</title>
-<STYLE type='text/css'>
-    .title { color: #990000; font-size: 22px; line-height: 22px; font-weight: bold; text-align: right;
-             font-family: helvetica, arial, sans-serif }
-    .filename { color: #666666; font-size: 18px; line-height: 28px; font-weight: bold; text-align: right;
-                  font-family: helvetica, arial, sans-serif }
-    p.copyright { color: #000000; font-size: 10px;
-                  font-family: verdana, charcoal, helvetica, arial, sans-serif }
-    p { margin-left: 2em; margin-right: 2em; }
-    li { margin-left: 3em;  }
-    ol { margin-left: 2em; margin-right: 2em; }
-    ul.text { margin-left: 2em; margin-right: 2em; }
-    pre { margin-left: 3em; color: #333333 }
-    ul.toc { color: #000000; line-height: 16px;
-             font-family: verdana, charcoal, helvetica, arial, sans-serif }
-    H3 { color: #333333; font-size: 16px; line-height: 16px; font-family: helvetica, arial, sans-serif }
-    H4 { color: #000000; font-size: 14px; font-family: helvetica, arial, sans-serif }
-    TD.header { color: #ffffff; font-size: 10px; font-family: arial, helvetica, san-serif; valign: top }
-    TD.author-text { color: #000000; font-size: 10px;
-                     font-family: verdana, charcoal, helvetica, arial, sans-serif }
-    TD.author { color: #000000; font-weight: bold; margin-left: 4em; font-size: 10px; font-family: verdana, charcoal, helvetica, arial, sans-serif }
-     A:link { color: #990000; font-weight: bold;
-              font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
-     A:visited { color: #333333; font-weight: bold;
-                 font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
-     A:name { color: #333333; font-weight: bold;
-              font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
-    .link2 { color:#ffffff; font-weight: bold; text-decoration: none;
-             font-family: monaco, charcoal, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
-             font-size: 9px }
-    .RFC { color:#666666; font-weight: bold; text-decoration: none;
-           font-family: monaco, charcoal, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
-           font-size: 9px }
-    .hotText { color:#ffffff; font-weight: normal; text-decoration: none;
-               font-family: charcoal, monaco, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
-               font-size: 9px }
-</style>
-</head>
-<body bgcolor="#ffffff" text="#000000" alink="#000000" vlink="#666666" link="#990000">
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<table width="66%" border="0" cellpadding="0" cellspacing="0"><tr><td><table width="100%" border="0" cellpadding="2" cellspacing="1">
-<tr valign="top"><td width="33%" bgcolor="#666666" class="header">Independent submission</td><td width="33%" bgcolor="#666666" class="header">M. Richardson</td></tr>
-<tr valign="top"><td width="33%" bgcolor="#666666" class="header">Internet-Draft</td><td width="33%" bgcolor="#666666" class="header">SSW</td></tr>
-<tr valign="top"><td width="33%" bgcolor="#666666" class="header">Expires: November 19, 2003</td><td width="33%" bgcolor="#666666" class="header">D. Redelmeier</td></tr>
-<tr valign="top"><td width="33%" bgcolor="#666666" class="header">&nbsp;</td><td width="33%" bgcolor="#666666" class="header">Mimosa</td></tr>
-<tr valign="top"><td width="33%" bgcolor="#666666" class="header">&nbsp;</td><td width="33%" bgcolor="#666666" class="header">May 21, 2003</td></tr>
-</table></td></tr></table>
-<div align="right"><font face="monaco, MS Sans Serif" color="#990000" size="+3"><b><br><span class="title">Opportunistic Encryption using The Internet Key Exchange (IKE)</span></b></font></div>
-<div align="right"><font face="monaco, MS Sans Serif" color="#666666" size="+2"><b><span class="filename">draft-richardson-ipsec-opportunistic-11.txt</span></b></font></div>
-<font face="verdana, helvetica, arial, sans-serif" size="2">
-
-<h3>Status of this Memo</h3>
-<p>
-This document is an Internet-Draft and is in full conformance with all provisions of Section 10 of RFC2026.</p>
-<p>
-Internet-Drafts are working documents of the Internet Engineering
-Task Force (IETF), its areas, and its working groups.
-Note that other groups may also distribute working documents as
-Internet-Drafts.</p>
-<p>
-Internet-Drafts are draft documents valid for a maximum of six months
-and may be updated, replaced, or obsoleted by other documents at any time.
-It is inappropriate to use Internet-Drafts as reference material or to cite
-them other than as "work in progress."</p>
-<p>
-The list of current Internet-Drafts can be accessed at
-<a href='http://www.ietf.org/ietf/1id-abstracts.txt'>http://www.ietf.org/ietf/1id-abstracts.txt</a>.</p>
-<p>
-The list of Internet-Draft Shadow Directories can be accessed at
-<a href='http://www.ietf.org/shadow.html'>http://www.ietf.org/shadow.html</a>.</p>
-<p>
-This Internet-Draft will expire on November 19, 2003.</p>
-
-<h3>Copyright Notice</h3>
-<p>
-Copyright (C) The Internet Society (2003). All Rights Reserved.</p>
-
-<h3>Abstract</h3>
-
-<p>
-This document describes opportunistic encryption (OE) using the Internet Key
-Exchange (IKE) and IPsec.  
-Each system administrator adds new
-resource records to his or her Domain Name System (DNS) to support
-opportunistic encryption. The objective is to allow encryption for secure communication without
-any pre-arrangement specific to the pair of systems involved.
-  
-</p>
-<p>
-DNS is used to distribute the public keys of each
-system involved. This is resistant to passive attacks. The use of DNS
-Security (DNSSEC) secures this system against active attackers as well. 
-  
-</p>
-<p>
-As a result, the administrative overhead is reduced
-from the square of the number of systems to a linear dependence, and it becomes  
-possible to make secure communication the default even
-when the partner is not known in advance.
-  
-</p>
-<p>
-This document is offered up as an Informational RFC.
-  
-</p><a name="toc"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<h3>Table of Contents</h3>
-<ul compact class="toc">
-<b><a href="#anchor1">1.</a>&nbsp;
-Introduction<br></b>
-<b><a href="#anchor6">2.</a>&nbsp;
-Overview<br></b>
-<b><a href="#anchor13">3.</a>&nbsp;
-Specification<br></b>
-<b><a href="#anchor31">4.</a>&nbsp;
-Impacts on IKE<br></b>
-<b><a href="#anchor38">5.</a>&nbsp;
-DNS issues<br></b>
-<b><a href="#anchor42">6.</a>&nbsp;
-Network address translation interaction<br></b>
-<b><a href="#anchor46">7.</a>&nbsp;
-Host implementations<br></b>
-<b><a href="#anchor47">8.</a>&nbsp;
-Multi-homing<br></b>
-<b><a href="#anchor48">9.</a>&nbsp;
-Failure modes<br></b>
-<b><a href="#anchor52">10.</a>&nbsp;
-Unresolved issues<br></b>
-<b><a href="#anchor54">11.</a>&nbsp;
-Examples<br></b>
-<b><a href="#securityconsiderations">12.</a>&nbsp;
-Security considerations<br></b>
-<b><a href="#anchor79">13.</a>&nbsp;
-IANA Considerations<br></b>
-<b><a href="#anchor80">14.</a>&nbsp;
-Acknowledgments<br></b>
-<b><a href="#rfc.references1">&#167;</a>&nbsp;
-Normative references<br></b>
-<b><a href="#rfc.authors">&#167;</a>&nbsp;
-Authors' Addresses<br></b>
-<b><a href="#rfc.copyright">&#167;</a>&nbsp;
-Full Copyright Statement<br></b>
-</ul>
-<br clear="all">
-
-<a name="anchor1"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.1"></a><h3>1.&nbsp;Introduction</h3>
-
-<a name="rfc.section.1.1"></a><h4><a name="anchor2">1.1</a>&nbsp;Motivation</h4>
-
-<p>
-The objective of opportunistic encryption is to allow encryption without
-any pre-arrangement specific to the pair of systems involved. Each
-system administrator adds
-public key information to DNS records to support opportunistic
-encryption and then enables this feature in the nodes' IPsec stack. 
-Once this is done, any two such nodes can communicate securely.
-
-</p>
-<p>
-This document describes opportunistic encryption as designed and
-mostly implemented by the Linux FreeS/WAN project.
-For project information, see http://www.freeswan.org.
-
-</p>
-<p>
-The Internet Architecture Board (IAB) and Internet Engineering
-Steering Group (IESG) have taken a strong stand that the Internet
-should use powerful encryption to provide security and
-privacy <a href="#RFC1984">[4]</a>.
-The Linux FreeS/WAN project attempts to provide a practical means to implement this policy. 
-  
-</p>
-<p>
-The project uses the IPsec, ISAKMP/IKE, DNS and DNSSEC
-protocols because they are
-standardized, widely available and can often be deployed very easily
-without changing hardware or software or retraining users. 
-  
-</p>
-<p>
-The extensions to support opportunistic encryption are simple.  No
-changes to any on-the-wire formats are needed.  The only changes are to 
-the policy decision making system.  This means that opportunistic
-encryption can be implemented with very minimal changes to an existing 
-IPsec implementation.
-  
-</p>
-<p>
-Opportunistic encryption creates a "fax effect". The proliferation
-of the fax machine was possible because it did not require that everyone
-buy one overnight. Instead, as each person installed one, the value
-of having one increased - as there were more people that could receive faxes.
-Once opportunistic encryption is installed it
-automatically recognizes 
-other boxes using opportunistic encryption, without any further configuration
-by the network 
-administrator. So, as opportunistic encryption software is installed on more
-boxes, its value 
-as a tool increases.
-
-</p>
-<p>
-This document describes the infrastructure to permit deployment of
-Opportunistic Encryption.
-
-</p>
-<p>
-The term S/WAN is a trademark of RSA Data Systems, and is used with permission
-by this project.
-  
-</p>
-<a name="rfc.section.1.2"></a><h4><a name="anchor3">1.2</a>&nbsp;Types of network traffic</h4>
-
-<p>
-    To aid in understanding the relationship between security processing and IPsec
-    we divide network traffic into four categories:
-    
-<blockquote class="text"><dl>
-<dt>* Deny:</dt>
-<dd> networks to which traffic is always forbidden.
-</dd>
-<dt>* Permit:</dt>
-<dd> networks to which traffic in the clear is permitted.
-</dd>
-<dt>* Opportunistic tunnel:</dt>
-<dd> networks to which traffic is encrypted if possible, but otherwise is in the clear  
-	    or fails depending on the default policy in place.	
-      
-</dd>
-<dt>* Configured tunnel:</dt>
-<dd> networks to which traffic must be encrypted, and traffic in the clear is never permitted.
-</dd>
-</dl></blockquote><p>
-</p>
-<p>
-Traditional firewall devices handle the first two categories. No authentication is required.
-The permit policy is currently the default on the Internet. 
-
-</p>
-<p>
-This document describes the third category - opportunistic tunnel, which is
-proposed as the new default for the Internet.
-
-</p>
-<p>
-  Category four, encrypt traffic or drop it, requires authentication of the
-  end points. As the number of end points is typically bounded and is typically
-  under a single authority, arranging for distribution of
-  authentication material, while difficult, does not require any new
-  technology. The mechanism described here provides an additional way to
-  distribute the authentication materials, that of a public key method that does not
-  require deployment of an X.509 based infrastructure.  
-
-</p>
-<p>
-Current Virtual Private Networks can often be replaced by an "OE paranoid"
-policy as described herein. 
-
-</p>
-<a name="rfc.section.1.3"></a><h4><a name="anchor4">1.3</a>&nbsp;Peer authentication in opportunistic encryption</h4>
-
-<p>
-  Opportunistic encryption creates tunnels between nodes that
-  are essentially strangers. This is done without any prior bilateral
-  arrangement. 
-  There is, therefore, the difficult question of how one knows to whom one is
-  talking.
-  
-</p>
-<p>
-  One possible answer is that since no useful
-  authentication can be done, none should be tried. This mode of operation is
-  named "anonymous encryption".  An active man-in-the-middle attack can be
-  used to thwart the privacy of this type of communication. 
-  Without peer authentication, there is no way to prevent this kind of attack.
-  
-</p>
-<p>
-Although a useful mode, anonymous encryption is not the goal of this
-project. Simpler methods are available that can achieve anonymous
-encryption only, but authentication of the peer is a desireable goal.
-The latter is achieved through key distribution in DNS, leveraging upon
-the authentication of the DNS in DNSSEC.
-
-</p>
-<p>
-  Peers are, therefore, authenticated with DNSSEC when available. Local policy 
-determines how much trust to extend when DNSSEC is not available.
-  
-</p>
-<p>
-  However, an essential premise of building private connections with
-  strangers is that datagrams received through opportunistic tunnels
-  are no more special than datagrams that arrive in the clear.
-  Unlike in a VPN, these datagrams should not be given any special
-  exceptions when it comes to auditing, further authentication or
-  firewalling.
-  
-</p>
-<p>
-  When initiating outbound opportunistic encryption, local 
-  configuration determines what happens if tunnel setup fails. It may be that
-  the packet goes out in the clear, or it may be dropped.
-  
-</p>
-<a name="rfc.section.1.4"></a><h4><a name="anchor5">1.4</a>&nbsp;Use of RFC2119 terms</h4>
-
-<p>
-   The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD,
-   SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this
-   document, are to be interpreted as described in <a href="#RFC2119">[5]</a>
-</p>
-<a name="anchor6"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.2"></a><h3>2.&nbsp;Overview</h3>
-
-<a name="rfc.section.2.1"></a><h4><a name="anchor7">2.1</a>&nbsp;Reference diagram</h4>
-<br><hr size="1" shade="0">
-<a name="networkdiagram"></a>
-
-<p>The following network diagram is used in the rest of
-		this document as the canonical diagram:
-</p></font><pre>
-                          [Q]  [R]          
-                           .    .              AS2                 
-  [A]----+----[SG-A].......+....+.......[SG-B]-------[B]
-         |                 ......
-     AS1 |                 ..PI..
-         |                 ......
-  [D]----+----[SG-D].......+....+.......[C] AS3
-             
-
-           </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-
-<p>
-</p><table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Reference Network Diagram&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
-
-<p>
-    In this diagram, there are four end-nodes: A, B, C and D. 
-    There are three gateways, SG-A, SG-B, SG-D. A, D, SG-A and SG-D are part
-    of the same administrative authority, AS1. SG-A and SG-D are on two different exit
-    paths from organization 1. SG-B/B is an independent organization, AS2.
-    Nodes Q and R are nodes on the Internet. PI is the Public
-    Internet ("The Wild").
-    
-</p>
-<a name="rfc.section.2.2"></a><h4><a name="anchor8">2.2</a>&nbsp;Terminology</h4>
-
-<p>
-  The following terminology is used in this document:
-  
-</p>
-<blockquote class="text"><dl>
-<dt>Security gateway:</dt>
-<dd> a system that performs IPsec tunnel
-    mode encapsulation/decapsulation. [SG-x] in the diagram.
-</dd>
-<dt>Alice:</dt>
-<dd> node [A] in the diagram. When an IP address is needed, this is 192.1.0.65.
-</dd>
-<dt>Bob:</dt>
-<dd> node [B] in the diagram. When an IP address is needed, this is 192.2.0.66.
-</dd>
-<dt>Carol:</dt>
-<dd> node [C] in the diagram. When an IP address is needed, this is 192.1.1.67.
-</dd>
-<dt>Dave:</dt>
-<dd> node [D] in the diagram. When an IP address is needed, this is 192.3.0.68.
-</dd>
-<dt>SG-A:</dt>
-<dd> Alice's security gateway. Internally it is 192.1.0.1, externally it is 192.1.1.4.
-</dd>
-<dt>SG-B:</dt>
-<dd> Bob's security gateway. Internally it is 192.2.0.1, externally it is 192.1.1.5.
-</dd>
-<dt>SG-D:</dt>
-<dd> Dave's security gateway. Also Alice's backup security gateway. Internally it is 192.3.0.1, externally it is 192.1.1.6.
-</dd>
-<dt>-</dt>
-<dd> A single dash represents clear-text datagrams.
-</dd>
-<dt>=</dt>
-<dd> An equals sign represents phase 2 (IPsec) cipher-text
-        datagrams.
-</dd>
-<dt>~</dt>
-<dd> A single tilde represents clear-text phase 1 datagrams.
-</dd>
-<dt>#</dt>
-<dd> A hash sign represents phase 1 (IKE) cipher-text
-        datagrams.
-</dd>
-<dt>.</dt>
-<dd> A period represents an untrusted network of unknown
-        type.
-</dd>
-<dt>Configured tunnel:</dt>
-<dd> a tunnel that
-		  is directly and deliberately hand configured on participating gateways.
-		  Configured tunnels are typically given a higher level of
-		  trust than opportunistic tunnels.
-</dd>
-<dt>Road warrior tunnel:</dt>
-<dd> a configured tunnel connecting one
-		  node with a fixed IP address and one node with a variable IP address.
-		  A road warrior (RW) connection must be initiated by the
-		  variable node, since the fixed node cannot know the
-		  current address for the road warrior. 
-</dd>
-<dt>Anonymous encryption:</dt>
-<dd>
-	the process of encrypting a session without any knowledge of who the
-	other parties are. No authentication of identities is done.
-</dd>
-<dt>Opportunistic encryption:</dt>
-<dd>
-	the process of encrypting a session with authenticated knowledge of
-	who the other parties are.
-</dd>
-<dt>Lifetime:</dt>
-<dd>
-        the period in seconds (bytes or datagrams) for which a security
-	association will remain alive before needing to be re-keyed.
-</dd>
-<dt>Lifespan:</dt>
-<dd>
-        the effective time for which a security association remains useful. A
-	security association with a lifespan shorter than its lifetime would
-	be removed when no longer needed. A security association with a
-	lifespan longer than its lifetime would need to be re-keyed one or
-	more times.
-</dd>
-<dt>Phase 1 SA:</dt>
-<dd> an ISAKMP/IKE security association sometimes
-      referred to as a keying channel.
-</dd>
-<dt>Phase 2 SA:</dt>
-<dd> an IPsec security association.
-</dd>
-<dt>Tunnel:</dt>
-<dd> another term for a set of phase 2 SA (one in each direction).
-</dd>
-<dt>NAT:</dt>
-<dd> Network Address Translation
-    (see <a href="#RFC2663">[20]</a>).
-</dd>
-<dt>NAPT:</dt>
-<dd> Network Address and Port Translation
-    (see <a href="#RFC2663">[20]</a>).
-</dd>
-<dt>AS:</dt>
-<dd> an autonomous system (AS) is a group of systems (a network) that
-		are under the administrative control of a single organization.
-</dd>
-<dt>Default-free zone:</dt>
-<dd> 
-    a set of routers that maintain a complete set of routes to
-    all currently reachable destinations. Having such a list, these routers
-    never make use of a default route. A datagram with a destination address
-    not matching any route will be dropped by such a router.
-    
-</dd>
-</dl></blockquote><p>
-<a name="rfc.section.2.3"></a><h4><a name="anchor9">2.3</a>&nbsp;Model of operation</h4>
-
-<p>
-The opportunistic encryption security gateway (OE gateway) is a regular
-gateway node as described in <a href="#RFC0791">[2]</a> section 2.4 and  
-<a href="#RFC1009">[3]</a> with the additional capabilities described here and
-in <a href="#RFC2401">[7]</a>.  
-The algorithm described here provides a way to determine, for each datagram,
-whether or not to encrypt and tunnel the datagram. Two important things
-that must be determined are whether or not to encrypt and tunnel and, if
-so, the destination address or name of the tunnel end point which should be used. 
-
-</p>
-<a name="rfc.section.2.3.1"></a><h4><a name="anchor10">2.3.1</a>&nbsp;Tunnel authorization</h4>
-
-<p>
-The OE gateway determines whether or not to create a tunnel based on 
-the destination address of each packet. Upon receiving a packet with a destination
-address not recently seen, the OE gateway performs a lookup in DNS for an
-authorization resource record (see <a href="#TXT">Use of TXT delegation record</a>). The record is located using
-the IP address to perform a search in the in-addr.arpa (IPv4) or ip6.arpa
-(IPv6) maps. If an authorization record is found, the OE gateway 
-interprets this as a request for a tunnel to be formed.
-
-</p>
-<a name="rfc.section.2.3.2"></a><h4><a name="anchor11">2.3.2</a>&nbsp;Tunnel end-point discovery</h4>
-
-<p>
-The authorization resource record also provides the address or name of the tunnel
-end point which should be used.
-
-</p>
-<p>
-The record may also provide the public RSA key of the tunnel end point
-itself. This is provided for efficiency only. If the public RSA key is not 
-present, the OE gateway performs a second lookup to find a KEY 
-resource record for the end point address or name.
-
-</p>
-<p>
-Origin and integrity protection of the resource records is provided by 
-DNSSEC (<a href="#RFC2535">[16]</a>). <a href="#nodnssec">Restriction on unauthenticated TXT delegation records</a>
-documents an optional restriction on the tunnel end point if DNSSEC signatures
-are not available for the relevant records. 
-
-</p>
-<a name="rfc.section.2.3.3"></a><h4><a name="anchor12">2.3.3</a>&nbsp;Caching of authorization results</h4>
-
-<p>
-The OE gateway maintains a cache, in the forwarding plane, of
-source/destination pairs for which opportunistic encryption has been
-attempted. This cache maintains a record of whether or not OE was
-successful so that subsequent datagrams can be forwarded properly
-without additional delay. 
-
-</p>
-<p>
-Successful negotiation of OE instantiates a new security association. 
-Failure to negotiate OE results in creation of a 
-forwarding policy entry either to drop or transmit in the clear future
-datagrams. This negative cache is necessary to avoid the possibly lengthy process of repeatedly looking 
-up the same information.
-
-</p>
-<p>
-The cache is timed out periodically, as described in <a href="#teardown">Renewal and teardown</a>.
-This removes entries that are no longer
-being used and permits the discovery of changes in authorization policy.
-
-</p>
-<a name="anchor13"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.3"></a><h3>3.&nbsp;Specification</h3>
-
-<p>
-The OE gateway is modeled to have a forwarding plane and a control
-plane. A control channel, such as PF_KEY, connects the two planes. 
-(See <a href="#RFC2367">[6]</a>.)
-The forwarding plane performs per datagram operations. The control plane
-contains a keying 
-daemon, such as ISAKMP/IKE, and performs all authorization, peer authentication and
-key derivation functions.  
-
-</p>
-<a name="rfc.section.3.1"></a><h4><a name="anchor14">3.1</a>&nbsp;Datagram state machine</h4>
-
-<p>
-Let the OE gateway maintain a collection of objects -- a superset of the
-security policy database (SPD) specified in <a href="#RFC2401">[7]</a>. For
-each combination of source and destination address, an SPD
-object exists in one of five following states.
-Prior to forwarding each datagram, the
-responder uses the source and destination addresses to pick an entry from the SPD.
-The SPD then determines if and how the packet is forwarded.
-
-</p>
-<a name="rfc.section.3.1.1"></a><h4><a name="anchor15">3.1.1</a>&nbsp;Non-existent policy</h4>
-
-<p>
-If the responder does not find an entry, then this policy applies.
-The responder creates an entry with an initial state of "hold policy" and requests 
-keying material from the keying daemon. The responder does not forward the datagram,
-rather it attaches the datagram to the SPD entry as the  "first" datagram and retains it
-for eventual transmission in a new state. 
-
-
-</p>
-<a name="rfc.section.3.1.2"></a><h4><a name="anchor16">3.1.2</a>&nbsp;Hold policy</h4>
-
-<p>
-The responder requests keying material. If the interface to the keying
-system is lossy (PF_KEY, for instance, can be), the implementation 
-SHOULD include a mechanism to retransmit the
-keying request at a rate limited to less than 1 request per second.
-The responder does not forward the datagram. It attaches the 
-datagram to the SPD entry as the "last" datagram where it is retained 
-for eventual transmission. If there is
-a datagram already so stored, then that already stored datagram is discarded.
-
-</p>
-<p>
-Because the "first" datagram is probably a TCP SYN packet, the 
-responder retains the "first" datagram in an attempt to avoid waiting for a
-TCP retransmit. The responder retains the "last"
-datagram in deference to streaming protocols that find it useful to know
-how much data has been lost. These are recommendations to 
-decrease latency. There are no operational requirements for this.
-
-</p>
-<a name="rfc.section.3.1.3"></a><h4><a name="anchor17">3.1.3</a>&nbsp;Pass-through policy</h4>
-
-<p>
-The responder forwards the datagram using the normal forwarding table. 
-The responder enters this state only by command from the keying daemon, 
-and upon entering this state, also forwards the "first" and "last" datagrams.
-
-</p>
-<a name="rfc.section.3.1.4"></a><h4><a name="anchor18">3.1.4</a>&nbsp;Deny policy</h4>
-
-<p>
-The responder discards the datagram. The responder enters this state only by
-command  
-from the keying daemon, and upon entering this state, discards the "first"
-and "last" datagrams.  
-Local administration decides if further datagrams cause ICMP messages
-to be generated (i.e. ICMP Destination Unreachable, Communication
-Administratively Prohibited. type=3, code=13). 
-
-</p>
-<a name="rfc.section.3.1.5"></a><h4><a name="anchor19">3.1.5</a>&nbsp;Encrypt policy</h4>
-
-<p>
-The responder encrypts the datagram using the indicated security association database
-(SAD) entry.  The responder enters this state only by command from the keying daemon, and upon entering
-this state, releases and forwards the "first" and "last" datagrams using the
-new encrypt policy.  
-
-</p>
-<p>
-If the associated SAD entry expires because of byte, packet or time limits, then
-the entry returns to the Hold policy, and an expire message is sent to the keying daemon.
-
-</p>
-<p>
-All states may be created directly by the keying daemon while acting as a
-responder. 
-
-</p>
-<a name="rfc.section.3.2"></a><h4><a name="initclasses">3.2</a>&nbsp;Keying state machine - initiator</h4>
-
-<p>
-Let the keying daemon maintain a collection of objects. Let them be
-called "connections" or "conn"s. There are two categories of
-connection objects: classes and instances. A class represents an
-abstract policy - what could be. An instance represents an actual connection -  
-what is implemented at the time.
-
-</p>
-<p>
-Let there be two further subtypes of connections: keying channels (Phase
-1 SAs) and data channels (Phase 2 SAs). Each data channel object may have 
-a corresponding SPD and SAD entry maintained by the datagram state machine.
-
-</p>
-<p>
-For the purposes of opportunistic encryption, there MUST, at least, be
-connection classes known as "deny", "always-clear-text", "OE-permissive", and 
-"OE-paranoid".  
-The latter two connection classes define a set of source and/or destination
-addresses for which opportunistic encryption will be attempted. The administrator MAY set policy
-options in a number of additional places.  An implementation MAY create additional connection classes to further refine
-these policies.
-
-</p>
-<p>
-The simplest system may need only the "OE-permissive" connection, and would
-list its own (single) IP address as the source address of this policy and
-the wild-card address 0.0.0.0/0 as the destination IPv4 address. That is, the
-simplest policy is to try opportunistic encryption with all destinations. 
-
-</p>
-<p>
-The distinction between permissive and paranoid OE use will become clear 
-in the state transition differences. In general a permissive OE will, on
-failure, install a pass-through policy, while a paranoid OE will, on failure, 
-install a drop policy.
-
-</p>
-<p>
-In this description of the keying machine's state transitions, the states
-associated with the keying system itself are omitted because they are best documented in the keying system 
-(<a href="#RFC2407">[8]</a>, 
-<a href="#RFC2408">[9]</a> and <a href="#RFC2409">[10]</a> for ISAKMP/IKE),
-and the details are keying system specific. Opportunistic encryption is not
-dependent upon any specific keying protocol, but this document does provide
-requirements for those using ISAKMP/IKE to assure that implementations inter-operate.
-
-</p>
-<p>
-The state transitions that may be involved in communicating with the
-forwarding plane are omitted. PF_KEY and similar protocols have their own
-set of states required for message sends and completion notifications.
-
-</p>
-<p>
-Finally, the retransmits and recursive lookups that are normal for DNS are 
-not included in this description of the state machine.
-
-</p>
-<a name="rfc.section.3.2.1"></a><h4><a name="anchor20">3.2.1</a>&nbsp;Nonexistent connection</h4>
-
-<p>
-There is no connection instance for a given source/destination address pair.
-Upon receipt of a request for keying material for this
-source/destination pair, the initiator searches through the connection classes to
-determine the most appropriate policy. Upon determining an appropriate
-connection class, an instance object is created of that type. 
-Both of the OE types result in a potential OE connection.
-
-</p>
-<p>Failure to find an appropriate connection class results in an
-administrator defined default. 
-
-</p>
-<p>
-In each case, when the initiator finds an appropriate class for the new flow, 
-an instance connection is made of the class which matched.
-
-</p>
-<a name="rfc.section.3.2.2"></a><h4><a name="anchor21">3.2.2</a>&nbsp;Clear-text connection</h4>
-
-<p>
-The non-existent connection makes a transition to this state when an
-always-clear-text class is instantiated, or when an OE-permissive 
-connection fails. During the transition, the initiator creates a pass-through
-policy object in the forwarding plane for the appropriate flow.
-
-</p>
-<p>
-Timing out is the only way to leave this state
-(see <a href="#expiring">Expiring connection</a>).
-
-</p>
-<a name="rfc.section.3.2.3"></a><h4><a name="anchor22">3.2.3</a>&nbsp;Deny connection</h4>
-
-<p>
-The empty connection makes a transition to this state when a
-deny class is instantiated, or when an OE-paranoid connection fails. 
-During the transition, the initiator creates a deny policy object in the forwarding plane 
-for the appropriate flow.  
-
-</p>
-<p>
-Timing out is the only way to leave this state 
-(see <a href="#expiring">Expiring connection</a>).
-
-</p>
-<a name="rfc.section.3.2.4"></a><h4><a name="anchor23">3.2.4</a>&nbsp;Potential OE connection</h4>
-
-<p>
-The empty connection makes a transition to this state when one of either OE class is instantiated.
-During the transition to this state, the initiator creates a hold policy object in the 
-forwarding plane for the appropriate flow.  
-
-</p>
-<p>
-In addition, when making a transition into this state, DNS lookup is done in
-the reverse-map for a TXT delegation resource record (see <a href="#TXT">Use of TXT delegation record</a>).
-The lookup key is the destination address of the flow.
-
-</p>
-<p>
-There are three ways to exit this state: 
-
-<ol class="text">
-<li>DNS lookup finds a TXT delegation resource record.
-</li>
-<li>DNS lookup does not find a TXT delegation resource record.
-</li>
-<li>DNS lookup times out.
-</li>
-</ol><p>
-</p>
-<p>
-Based upon the results of the DNS lookup, the potential OE connection makes a
-transition to the pending OE connection state.  The conditions for a
-successful DNS look are:
-
-<ol class="text">
-<li>DNS finds an appropriate resource record
-</li>
-<li>It is properly formatted according to <a href="#TXT">Use of TXT delegation record</a>
-</li>
-<li> if DNSSEC is enabled, then the signature has been vouched for.
-</li>
-</ol><p>
-
-Note that if the initiator does not find the public key 
-present in the TXT delegation record, then the public key must 
-be looked up as a sub-state. Only successful completion of all the 
-DNS lookups is considered a success.
-
-</p>
-<p>
-If DNS lookup does not find a resource record or DNS times out, then the 
-initiator considers the receiver not OE capable. If this is an OE-paranoid instance, 
-then the potential OE connection makes a transition to the deny connection state.
-If this is an OE-permissive instance, then the potential OE connection makes a transition to the
-clear-text connection state.
-
-</p>
-<p>
-If the initiator finds a resource record but it is not properly formatted, or
-if DNSSEC is 
-enabled and reports a failure to authenticate, then the potential OE
-connection should make a 
-transition to the deny connection state. This action SHOULD be logged. If the
-administrator wishes to override this transition between states, then an
-always-clear class can be installed for this flow. An implementation MAY make
-this situation a new class.
-
-</p>
-<a name="rfc.section.3.2.4.1"></a><h4><a name="nodnssec">3.2.4.1</a>&nbsp;Restriction on unauthenticated TXT delegation records</h4>
-
-<p>
-An implementation SHOULD also provide an additional administrative control
-on delegation records and DNSSEC. This control would apply to delegation
-records (the TXT records in the reverse-map) that are not protected by
-DNSSEC.
-Records of this type are only permitted to delegate to their own address as
-a gateway. When this option is enabled, an active attack on DNS will be
-unable to redirect packets to other than the original destination.
-
-</p>
-<a name="rfc.section.3.2.5"></a><h4><a name="anchor24">3.2.5</a>&nbsp;Pending OE connection</h4>
-
-<p>
-The potential OE connection makes a transition to this state when 
-the initiator determines that all the information required from the DNS lookup is present.
-Upon entering this state, the initiator attempts to initiate keying to the gateway
-provided.  
-
-</p>
-<p>
-Exit from this state occurs either with a successfully created IPsec SA, or
-with a failure of some kind.  Successful SA creation results in a transition
-to the key connection state.
-
-</p>
-<p>
-Three failures have caused significant problems. They are clearly not the
-only possible failures from keying.
-
-</p>
-<p>
-Note that if there are multiple gateways available in the TXT delegation
-records, then a failure can only be declared after all have been
-tried. Further, creation of a phase 1 SA does not constitute success. A set
-of phase 2 SAs (a tunnel) is considered success.
-
-</p>
-<p>
-The first failure occurs when an ICMP port unreachable is consistently received
-without any other communication, or when there is silence from the remote
-end. This usually means that either the gateway is not alive, or the
-keying daemon is not functional. For an OE-permissive connection, the initiator makes a transition
-to the clear-text connection but with a low lifespan. For an OE-pessimistic connection,
-the initiator makes a transition to the deny connection again with a low lifespan. The lifespan in both 
-cases is kept low because the remote gateway may
-be in the process of rebooting or be otherwise temporarily unavailable. 
-
-</p>
-<p>
-The length of time to wait for the remote keying daemon to wake up is
-a matter of some debate. If there is a routing failure, 5 minutes is usually long enough for the network to
-re-converge. Many systems can reboot in that amount of
-time as well. However, 5 minutes is far too long for most users to wait to
-hear that they can not connect using OE. Implementations SHOULD make this a
-tunable parameter.
-
-</p>
-<p>
-The second failure occurs after a phase 1 SA has been created, but there is 
-either no response to the phase 2 proposal, or the initiator receives a 
-negative notify (the notify must be 
-authenticated). The remote gateway is not prepared to do OE at this time. 
-As before, the initiator makes a transition to the clear-text or the deny 
-connection based upon connection class, but this
-time with a normal lifespan. 
-
-</p>
-<p>
-The third failure occurs when there is signature failure while authenticating
-the remote gateway. This can occur when there has been a 
-key roll-over, but DNS has not caught up. In this case again, the initiator makes a 
-transition to the clear-text or the deny connection based
-upon the connection class. However, the lifespan depends upon the remaining
-time to live in the DNS. (Note that DNSSEC signed resource records have a different
-expiry time than non-signed records.) 
-
-</p>
-<a name="rfc.section.3.2.6"></a><h4><a name="keyed">3.2.6</a>&nbsp;Keyed connection</h4>
-
-<p>
-The pending OE connection makes a transition to this state when 
-session keying material (the phase 2 SAs) is derived. The initiator creates an encrypt
-policy in the forwarding plane for this flow.
-
-</p>
-<p>
-There are three ways to exit this state. The first is by receipt of an
-authenticated delete message (via the keying channel) from the peer. This is
-normal teardown and results in a transition to the expired connection state.
-
-</p>
-<p>
-The second exit is by expiry of the forwarding plane keying material. This
-starts a re-key operation with a transition back to pending OE
-connection. In general, the soft expiry occurs with sufficient time left
-to continue to use the keys. A re-key can fail, which may
-result in the connection failing to clear-text or deny as
-appropriate. In the event of a failure, the forwarding plane
-policy does not change until the phase 2 SA (IPsec SA) reaches its
-hard expiry.
-
-</p>
-<p>
-The third exit is in response to a negotiation from a remote
-gateway. If the forwarding plane signals the control plane that it has received an
-unknown SPI from the remote gateway, or an ICMP is received from the remote gateway
-indicating an unknown SPI, the initiator should consider that 
-the remote gateway has rebooted or restarted. Since these 
-indications are easily forged, the implementation must 
-exercise care.  The initiator should make a cautious 
-(rate-limited) attempt to re-key the connection. 
-
-</p>
-<a name="rfc.section.3.2.7"></a><h4><a name="expiring">3.2.7</a>&nbsp;Expiring connection</h4>
-
-<p>
-The initiator will periodically place each of the deny, clear-text, and keyed
-connections into this  
-sub-state. See <a href="#teardown">Renewal and teardown</a> for more details of how often this
-occurs. 
-The initiator queries the forwarding plane for last use time of the
-appropriate 
-policy. If the last use time is relatively recent, then the connection
-returns to the 
-previous deny, clear-text or keyed connection state. If not, then the
-connection enters 
-the expired connection state. 
-
-</p>
-<p>
-The DNS query and answer that lead to the expiring connection state are also
-examined. The DNS query may become stale. (A negative, i.e. no such record, answer
-is valid for the period of time given by the MINIMUM field in an attached SOA 
-record. See <a href="#RFC1034">[12]</a> section 4.3.4.)
-If the DNS query is stale, then a new query is made. If the results change, then the connection 
-makes a transition to a new state as described in potential OE connection state.
-
-</p>
-<p> 
-Note that when considering how stale a connection is, both outgoing SPD and
-incoming SAD must be queried as some flows may be unidirectional for some time.
-
-</p>
-<p>
-Also note that the policy at the forwarding plane is not updated unless there
-is a conclusion that there should be a change.
-
-</p>
-<a name="rfc.section.3.2.8"></a><h4><a name="anchor25">3.2.8</a>&nbsp;Expired connection</h4>
-
-<p>
-Entry to this state occurs when no datagrams have been forwarded recently via the
-appropriate SPD and SAD objects. The objects in the forwarding plane are
-removed (logging any final byte and packet counts if appropriate) and the
-connection instance in the keying plane is deleted. 
-
-</p>
-<p>
-The initiator sends an ISAKMP/IKE delete to clean up the phase 2 SAs as described in
-<a href="#teardown">Renewal and teardown</a>. 
-
-</p>
-<p>
-Whether or not to delete the phase 1 SAs
-at this time is left as a local implementation issue. Implementations
-that do delete the phase 1 SAs MUST send authenticated delete messages to
-indicate that they are doing so.  There is an advantage to keeping
-the phase 1 SAs until they expire - they may prove useful again in the 
-near future.
-
-</p>
-<a name="rfc.section.3.3"></a><h4><a name="anchor26">3.3</a>&nbsp;Keying state machine - responder</h4>
-
-<p>
-The responder has a set of objects identical to those of the initiator.
-
-</p>
-<p>
-The responder receives an invitation to create a keying channel from an initiator. 
-
-</p>
-<a name="rfc.section.3.3.1"></a><h4><a name="anchor27">3.3.1</a>&nbsp;Unauthenticated OE peer</h4>
-
-<p>
-Upon entering this state, the responder starts a DNS lookup for a KEY record for the
-initiator. 
-The responder looks in the reverse-map for a KEY record for the initiator if the
-initiator has offered an ID_IPV4_ADDR, and in the forward map if the
-initiator has offered an ID_FQDN type. (See <a href="#RFC2407">[8]</a> section 
-4.6.2.1.)
-
-</p>
-<p>
-The responder exits this state upon successful receipt of a KEY from DNS, and use of the key 
-to verify the signature of the initiator.
-
-</p>
-<p>
-Successful authentication of the peer results in a transition to the
-authenticated OE Peer state.
-
-</p>
-<p>
-Note that the unauthenticated OE peer state generally occurs in the middle of the key negotiation
-protocol. It is really a form of pseudo-state.
-
-</p>
-<a name="rfc.section.3.3.2"></a><h4><a name="anchor28">3.3.2</a>&nbsp;Authenticated OE Peer</h4>
-
-<p>
-The peer will eventually propose one or more phase 2 SAs. The responder uses the source and
-destination address in the proposal to 
-finish instantiating the connection state
-using the connection class table.
-The responder MUST search for an identical connection object at this point. 
-
-</p>
-<p> 
-If an identical connection is found, then the responder deletes the old instance, 
-and the new object makes a transition to the pending OE connection state. This means
-that new ISAKMP connections with a given peer will always use the latest
-instance, which is the correct one if the peer has rebooted in the interim.
-
-</p>
-<p> 
-If an identical connection is not found, then the responder makes the transition according to the 
-rules given for the initiator.
-
-</p>
-<p> 
-Note that if the initiator is in OE-paranoid mode and the responder is in 
-either always-clear-text or deny, then no communication is possible according
-to policy. An implementation is permitted to create new types of policies 
-such as "accept OE but do not initiate it". This is a local matter.
- 
-</p>
-<a name="rfc.section.3.4"></a><h4><a name="teardown">3.4</a>&nbsp;Renewal and teardown</h4>
-
-<a name="rfc.section.3.4.1"></a><h4><a name="anchor29">3.4.1</a>&nbsp;Aging</h4>
-
-<p>
-A potentially unlimited number of tunnels may exist. In practice, only a few
-tunnels are used during a period of time. Unused tunnels MUST, therefore, be
-torn down. Detecting when tunnels are no longer in use is the subject of this section.
-
-</p>
-<p>
-There are two methods for removing tunnels: explicit deletion or expiry. 
-
-</p>
-<p>
-Explicit deletion requires an IKE delete message. As the deletes
-MUST be authenticated, both ends of the tunnel must maintain the 
-key channel (phase 1 ISAKMP SA). An implementation which refuses to either maintain or
-recreate the keying channel SA will be unable to use this method.
-
-</p>
-<p>
-The tunnel expiry method, simply allows the IKE daemon to
-expire normally without attempting to re-key it.
-
-</p>
-<p>
-Regardless of which method is used to remove tunnels, the implementation requires 
-a method to determine if the tunnel is still in use.  The specifics are a
-local matter, but  the FreeS/WAN project uses the following criteria. These
-criteria are currently implemented in the key management daemon, but could
-also be implemented at the SPD layer using an idle timer.
-
-</p>
-<p>
-Set a short initial (soft) lifespan of 1 minute since many net flows last
-only a few seconds.
-
-</p>
-<p>
-At the end of the lifespan, check to see if the tunnel was used by
-traffic in either direction during the last 30 seconds. If so, assign a
-longer tentative lifespan of 20 minutes after which, look again. If the
-tunnel is not in use, then close the tunnel.
-
-</p>
-<p>
-The expiring state in the key management
-system (see <a href="#expiring">Expiring connection</a>) implements these timeouts.
-The timer above may be in the forwarding plane, 
-but then it must be re-settable. 
-
-</p>
-<p>
-The tentative lifespan is independent of re-keying; it is just the time when
-the tunnel's future is next considered. 
-(The term lifespan is used here rather than lifetime for this reason.) 
-Unlike re-keying, this tunnel use check is not costly and should happen
-reasonably frequently.
-
-</p>
-<p>
-A multi-step back-off algorithm is not considered worth the effort here.
-
-</p>
-<p>
-If the security gateway and the client host are the
-same and not a Bump-in-the-Stack or Bump-in-the-Wire implementation, tunnel
-teardown decisions MAY pay attention to TCP connection status as reported
-by the local TCP layer.  A still-open TCP connection is almost a guarantee that more traffic is
-expected. Closing of the only TCP connection through a tunnel is a
-strong hint that no more traffic is expected.
-
-</p>
-<a name="rfc.section.3.4.2"></a><h4><a name="anchor30">3.4.2</a>&nbsp;Teardown and cleanup</h4>
-
-<p>
-Teardown should always be coordinated between the two ends of the tunnel by 
-interpreting and sending delete notifications. There is a
-detailed sub-state in the expired connection state of the key manager that
-relates to retransmits of the delete notifications, but this is considered to 
-be a keying system detail.
-
-</p>
-<p>
-On receiving a delete for the outbound SAs of a tunnel (or some subset of
-them), tear down the inbound ones also and notify the remote end with a
-delete. If the local system receives a delete for a tunnel which is no longer in
-existence, then two delete messages have crossed paths. Ignore the delete.
-The operation has already been completed. Do not generate any messages in this
-situation. 
-
-</p>
-<p>
-Tunnels are to be considered as bidirectional entities, even though the
-low-level protocols don't treat them this way. 
-
-</p>
-<p>
-When the deletion is initiated locally, rather than as a
-response to a received delete, send a delete for (all) the
-inbound SAs of a tunnel.  If the local system does not receive a responding delete 
-for the outbound SAs, try re-sending the original
-delete. Three tries spaced 10 seconds apart seems a reasonable
-level of effort. A failure of the other end to respond after 3 attempts, 
-indicates that the possibility of further communication is unlikely. Remove the outgoing SAs.
-(The remote system may be a mobile node that is no longer present or powered on.)
-
-</p>
-<p>
-After re-keying, transmission should switch to using the new
-outgoing SAs (ISAKMP or IPsec) immediately, and the old leftover
-outgoing SAs should be cleared out promptly (delete should be sent
-for the outgoing SAs) rather than waiting for them to expire. This
-reduces clutter and minimizes confusion for the operator doing diagnostics.
-
-</p>
-<a name="anchor31"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.4"></a><h3>4.&nbsp;Impacts on IKE</h3>
-
-<a name="rfc.section.4.1"></a><h4><a name="anchor32">4.1</a>&nbsp;ISAKMP/IKE protocol</h4>
-
-<p>
-    The IKE wire protocol needs no modifications. The major changes are
-    implementation issues relating to how the proposals are interpreted, and from
-    whom they may come.
-    
-</p>
-<p>
-    As opportunistic encryption is designed to be useful between peers without
-    prior operator configuration, an IKE daemon must be prepared to negotiate
-    phase 1 SAs with any node. This may require a large amount of resources to 
-    maintain cookie state, as well as large amounts of entropy for nonces,
-    cookies and so on. 
-    
-</p>
-<p>
-    The major changes to support opportunistic encryption are at the IKE daemon
-    level. These changes relate to handling of key acquisition requests, lookup
-    of public keys and TXT records, and interactions with firewalls and other
-    security facilities that may be co-resident on the same gateway.
-    
-</p>
-<a name="rfc.section.4.2"></a><h4><a name="anchor33">4.2</a>&nbsp;Gateway discovery process</h4>
-
-<p>
-  In a typical configured tunnel, the address of SG-B is provided
-  via configuration. Furthermore, the mapping of an SPD entry to a gateway is
-  typically a 1:1 mapping. When the 0.0.0.0/0 SPD entry technique is used, then
-  the mapping to a gateway is determined by the reverse DNS records.
-  
-</p>
-<p>
-  The need to do a DNS lookup and wait for a reply will typically introduce a
-  new state and a new event source (DNS replies) to IKE. Although a
-synchronous DNS request can be implemented for proof of concept, experience
-is that it can cause very high latencies when a queue of queries must
-all timeout in series. 
-  
-</p>
-<p> 
-  Use of an asynchronous DNS lookup will also permit overlap of DNS lookups with
-  some of the protocol steps.
-  
-</p>
-<a name="rfc.section.4.3"></a><h4><a name="anchor34">4.3</a>&nbsp;Self identification</h4>
-
-<p>
-     SG-A will have to establish its identity. Use an
-     IPv4 ID in phase 1. 
-  
-</p>
-<p> There are many situations where the administrator of SG-A may not be
-      able to control the reverse DNS records for SG-A's public IP address.
-      Typical situations include dialup connections and most residential-type broadband Internet access 
-      (ADSL, cable-modem) connections. In these situations, a fully qualified domain
-      name that is under the control of SG-A's administrator may be used
-      when acting as an initiator only.
-      The FQDN ID should be used in phase 1. See <a href="#fqdn">Use of FQDN IDs</a>
-      for more details and restrictions.
-  
-</p>
-<a name="rfc.section.4.4"></a><h4><a name="anchor35">4.4</a>&nbsp;Public key retrieval process</h4>
-
-<p>
-     Upon receipt of a phase 1 SA proposal with either an IPv4 (IPv6) ID or
-     an FQDN ID, an IKE daemon needs to examine local caches and
-     configuration files to determine if this is part of a configured tunnel.
-     If no configured tunnels are found, then the implementation should attempt to retrieve
-     a KEY record from the reverse DNS in the case of an IPv4/IPv6 ID, or 
-     from the forward DNS in the case of FQDN ID.
-  
-</p>
-<p> 
-     It is reasonable that if other non-local sources of policy are used
-     (COPS, LDAP), they be consulted concurrently but some
-     clear ordering of policy be provided. Note that due to variances in
-     latency, implementations must wait for positive or negative replies from all sources
-     of policy before making any decisions.
-  
-</p>
-<a name="rfc.section.4.5"></a><h4><a name="anchor36">4.5</a>&nbsp;Interactions with DNSSEC</h4>
-
-<p>
-     The implementation described (1.98) neither uses DNSSEC directly to
-     explicitly verify the authenticity of zone information, nor uses the NXT
-     records to provide authentication of the absence of a TXT or KEY
-     record. Rather, this implementation uses a trusted path to a DNSSEC
-     capable caching resolver. 
-  
-</p>
-<p> 
-     To distinguish between an authenticated and an unauthenticated DNS
-     resource record, a stub resolver capable of returning DNSSEC
-     information MUST be used.
-  
-</p>
-<a name="rfc.section.4.6"></a><h4><a name="anchor37">4.6</a>&nbsp;Required proposal types</h4>
-
-<a name="rfc.section.4.6.1"></a><h4><a name="phase1id">4.6.1</a>&nbsp;Phase 1 parameters</h4>
-
-<p>
-        Main mode MUST be used.
-      
-</p>
-<p>
-	The initiator MUST offer at least one proposal using some combination
-	of: 3DES, HMAC-MD5 or HMAC-SHA1, DH group 2 or 5. Group 5 SHOULD be
-	proposed first.
-	<a href="#RFC3526">[11]</a>
-</p>
-<p>
-	The initiator MAY offer additional proposals, but the cipher MUST not
-	be weaker than 3DES. The initiator SHOULD limit the number of proposals
-	such that the IKE datagrams do not need to be fragmented.
-      
-</p>
-<p>
-	The responder MUST accept one of the proposals. If any configuration
-	of the responder is required then the responder is not acting in an
-	opportunistic way. 
-      
-</p>
-<p>
-        SG-A SHOULD use an ID_IPV4_ADDR (ID_IPV6_ADDR for IPv6) of the external
-        interface of SG-A for phase 1. (There is an exception, see <a href="#fqdn">Use of FQDN IDs</a>.) The authentication method MUST be RSA public key signatures. 
-        The RSA key for SG-A SHOULD be placed into a DNS KEY record in
-	the reverse space of SG-A (i.e. using in-addr.arpa).
-      
-</p>
-<a name="rfc.section.4.6.2"></a><h4><a name="phase2id">4.6.2</a>&nbsp;Phase 2 parameters</h4>
-
-<p>
-        SG-A MUST propose a tunnel between Alice and Bob, using 3DES-CBC
-        mode, MD5 or SHA1 authentication. Perfect Forward Secrecy MUST be specified.
-      
-</p>
-<p>
-        Tunnel mode MUST be used.
-      
-</p>
-<p>
-        Identities MUST be ID_IPV4_ADDR_SUBNET with the mask being /32.
-      
-</p>
-<p>
-        Authorization for SG-A to act on Alice's behalf is determined by
-        looking for a TXT record in the reverse-map at Alice's address.
-      
-</p>
-<p>
-        Compression SHOULD NOT be mandatory. It may be offered as an option.
-      
-</p>
-<a name="anchor38"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.5"></a><h3>5.&nbsp;DNS issues</h3>
-
-<a name="rfc.section.5.1"></a><h4><a name="KEY">5.1</a>&nbsp;Use of KEY record</h4>
-
-<p>
-    In order to establish their own identities, SG-A and SG-B SHOULD publish
-    their public keys in their reverse DNS via 
-    DNSSEC's KEY record.
-    See section 3 of <a href="#RFC2535">RFC 2535</a>[16].
-  
-</p>
-<p>
-<p>For example:
-</p></font><pre>
-KEY 0x4200 4 1 AQNJjkKlIk9...nYyUkKK8
-</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-
-<blockquote class="text"><dl>
-<dt>0x4200:</dt>
-<dd> The flag bits, indicating that this key is prohibited
-    for confidentiality use (it authenticates the peer only, a separate
-    Diffie-Hellman exchange is used for
-    confidentiality), and that this key is associated with the non-zone entity
-    whose name is the RR owner name. No other flags are set.
-</dd>
-<dt>4:</dt>
-<dd>This indicates that this key is for use by IPsec.
-</dd>
-<dt>1:</dt>
-<dd>An RSA key is present.
-</dd>
-<dt>AQNJjkKlIk9...nYyUkKK8:</dt>
-<dd>The public key of the host as described in <a href="#RFC3110">[17]</a>.
-</dd>
-</dl></blockquote><p>
-</p>
-<p>Use of several KEY records allows for key rollover. The SIG Payload in
-  IKE phase 1 SHOULD be accepted if the public key given by any KEY RR
-  validates it.
-  
-</p>
-<a name="rfc.section.5.2"></a><h4><a name="TXT">5.2</a>&nbsp;Use of TXT delegation record</h4>
-
-<p>
-Alice publishes a TXT record to provide authorization for SG-A to act on
-Alice's behalf. 
-
-Bob publishes a TXT record to provide authorization for SG-B to act on Bob's
-behalf.  
-
-These records are located in the reverse DNS (in-addr.arpa) for their
-respective IP addresses.  The reverse DNS SHOULD be secured by DNSSEC, when
-it is deployed. DNSSEC is required to defend against active attacks.
-    
-</p>
-<p>
-      If Alice's address is P.Q.R.S, then she can authorize another node to
-      act on her behalf by publishing records at:
-           </p>
-</font><pre>
-S.R.Q.P.in-addr.arpa
-          </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-
-</p>
-<p>
-    The contents of the resource record are expected to be a string that
-    uses the following syntax, as suggested in <a href="#RFC1464">[15]</a>.
-    (Note that the reply to query may include other TXT resource
-    records used by other applications.)
-
-    <br><hr size="1" shade="0">
-<a name="txtformat"></a>
-</p>
-</font><pre>
-X-IPsec-Server(P)=A.B.C.D KEY
-          </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Format of reverse delegation record&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
-
-</p>
-<blockquote class="text"><dl>
-<dt>P:</dt>
-<dd> Specifies a precedence for this record.  This is
-      similar to MX record preferences.  Lower numbers have stronger
-      preference. 
-      
-</dd>
-<dt>A.B.C.D:</dt>
-<dd> Specifies the IP address of the Security Gateway
-      for this client machine.
-      
-</dd>
-<dt>KEY:</dt>
-<dd> Is the encoded RSA Public key of the Security
-      Gateway. The key is provided here to avoid a second DNS lookup. If this
-      field is absent, then a KEY resource record should be looked up in the
-      reverse-map of A.B.C.D. The key is transmitted in base64 format.
-      
-</dd>
-</dl></blockquote><p>
-<p>
-  	The pieces of the record are separated by any whitespace
-	(space, tab, newline, carriage return). An ASCII space SHOULD
-	be used.
-    
-</p>
-<p>
-	In the case where Alice is located at a public address behind a 
-	security gateway that has no fixed address (or no control over its
-	reverse-map), then Alice may delegate to a public key by domain name.
-
-    <br><hr size="1" shade="0">
-<a name="txtfqdnformat"></a>
-</p>
-</font><pre>
-X-IPsec-Server(P)=@FQDN KEY
-          </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Format of reverse delegation record (FQDN version)&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
-
-</p>
-<blockquote class="text"><dl>
-<dt>P:</dt>
-<dd> Is as above.
-      
-</dd>
-<dt>FQDN:</dt>
-<dd> Specifies the FQDN that the Security Gateway
-      will identify itself with. 
-      
-</dd>
-<dt>KEY:</dt>
-<dd> Is the encoded RSA Public key of the Security
-      Gateway. 
-</dd>
-</dl></blockquote><p>
-<p>
-	If there is more than one such TXT record with strongest (lowest
-	numbered) precedence, one Security Gateway is picked arbitrarily from
-	those specified in the strongest-preference records. 
-    
-</p>
-<a name="rfc.section.5.2.1"></a><h4><a name="anchor39">5.2.1</a>&nbsp;Long TXT records</h4>
-
-<p>
-  When packed into transport format, TXT records which are longer than 255
-  characters are divided into smaller &lt;character-strings&gt;.
-  (See <a href="#RFC1035">[13]</a> section 3.3 and 3.3.14.) These MUST
-  be reassembled into a single string for processing.
-  Whitespace characters in the base64 encoding are to be ignored.
-  
-</p>
-<a name="rfc.section.5.2.2"></a><h4><a name="anchor40">5.2.2</a>&nbsp;Choice of TXT record</h4>
-
-<p>
-	It has been suggested to use the KEY, OPT, CERT, or KX records
-	instead of a TXT record. None is satisfactory.
-  
-</p>
-<p> The KEY RR has a protocol field which could be used to indicate a new protocol, 
-and an algorithm field which could be used to
-        indicate different contents in the key data. However, the KEY record
-	is clearly not intended for storing what are really authorizations,
-	it is just for identities. Other uses have been discouraged.
-  
-</p>
-<p> OPT resource records, as defined in <a href="#RFC2671">[14]</a> are not 
-  intended to be used for storage of information. They are not to be loaded, 
-	cached or forwarded.  They are, therefore, inappropriate for use here.
-  
-</p>
-<p>
-    CERT records <a href="#RFC2538">[18]</a> can encode almost any set of
-    information. A custom type code could be used permitting any suitable
-    encoding to be stored, not just X.509.  According to
-    the RFC, the certificate RRs are to be signed internally which may add undesirable 
-and unnecessary bulk. Larger DNS records may require TCP instead of UDP transfers.
-  
-</p>
-<p>
-    At the time of protocol design, the CERT RR was not widely deployed and
-    could not be counted upon. Use of CERT records will be investigated,
-    and may be proposed in a future revision of this document.
-  
-</p>
-<p>
-    KX records are ideally suited for use instead of TXT records, but had not been deployed at
-    the time of implementation.
-
-</p>
-<a name="rfc.section.5.3"></a><h4><a name="fqdn">5.3</a>&nbsp;Use of FQDN IDs</h4>
-
-<p>
-      Unfortunately, not every administrator has control over the contents
-      of the reverse-map.  Where the initiator (SG-A) has no suitable reverse-map, the
-      authorization record present in the reverse-map of Alice may refer to a
-      FQDN instead of an IP address.
-    
-</p>
-<p>
-      In this case, the client's TXT record gives the fully qualified domain
-      name (FQDN) in place of its security gateway's IP address. 
-      The initiator should use the ID_FQDN ID-payload in phase 1.
-      A forward lookup for a KEY record on the FQDN must yield the
-      initiator's public key. 
-    
-</p>
-<p>
-      This method can also be used when the external address of SG-A is
-      dynamic. 
-    
-</p>
-<p>
-      If SG-A is acting on behalf of Alice, then Alice must still delegate
-      authority for SG-A to do so in her reverse-map. When Alice and SG-A
-      are one and the same (i.e. Alice is acting as an end-node) then there
-      is no need for this when initiating only. 
-</p>
-<p>However, Alice must still delegate to  herself if she wishes others to
-       initiate OE to her.  See <a href="#txtfqdnformat">Format of reverse delegation record (FQDN version)</a>.
-    
-</p>
-<a name="rfc.section.5.4"></a><h4><a name="anchor41">5.4</a>&nbsp;Key roll-over</h4>
-
-<p>
-Good cryptographic hygiene says that one should replace public/private key pairs
-periodically. Some administrators may wish to do this as often as daily. Typical DNS
-propagation delays are determined by the SOA Resource Record MINIMUM
-parameter, which controls how long DNS replies may be cached. For reasonable
-operation of DNS servers, administrators usually want this value to be at least several 
-hours, sometimes as a long as a day. This presents a problem - a new key MUST
-not be used prior to it propagating through DNS.
-
-</p>
-<p>
-This problem is dealt with by having the Security Gateway generate a new
-public/private key pair at least MINIMUM seconds in advance of using it. It
-then adds this key to the DNS (both as a second KEY record and in additional TXT
-delegation records) at key generation time. Note: only one key is allowed in
-each TXT record.
-
-</p>
-<p>
-When authenticating, all gateways MUST have available all public keys 
-that are found in DNS for this entity. This permits the authenticating end
-to check both the key for "today" and the key for "tomorrow". Note that it is 
-the end which is creating the signature (possesses the private key) that
-determines which key is to be used.
-
-</p>
-<a name="anchor42"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.6"></a><h3>6.&nbsp;Network address translation interaction</h3>
-
-<p>
-     There are no fundamentally new issues for implementing opportunistic encryption
-     in the presence of network address translation. Rather there are 
-     only the regular IPsec issues with NAT traversal.
-  
-</p>
-<p>
-     There are several situations to consider for NAT.
-  
-</p>
-<a name="rfc.section.6.1"></a><h4><a name="anchor43">6.1</a>&nbsp;Co-located NAT/NAPT</h4>
-
-<p>
-       If SG-A is also performing network address translation on
-       behalf of Alice, then the packet should be translated prior to
-       being subjected to opportunistic encryption. This is in contrast to
-       typically configured tunnels which often exist to bridge islands of 
-       private network address space. SG-A will use the translated source
-       address for phase 2, and so SG-B will look up that address to
-       confirm SG-A's authorization. 
-    
-</p>
-<p> In the case of NAT (1:1), the address space into which the
-        translation is done MUST be globally unique, and control over the
-	reverse-map is assumed.
-        Placing of TXT records is possible.
-    
-</p>
-<p> In the case of NAPT (m:1), the address will be SG-A. The ability to get
-        KEY and TXT records in place will again depend upon whether or not
-	there is administrative control over the reverse-map. This is
-	identical to situations involving a single host acting on behalf of
-	itself. 
-
-	FQDN style can be used to get around a lack of a reverse-map for
-	initiators only.
-    
-</p>
-<a name="rfc.section.6.2"></a><h4><a name="anchor44">6.2</a>&nbsp;SG-A behind NAT/NAPT</h4>
-
-<p>
-       If there is a NAT or NAPT between SG-A and SG-B, then normal IPsec
-       NAT traversal rules apply. In addition to the transport problem
-       which may be solved by other mechanisms, there
-       is the issue of what phase 1 and phase 2 IDs to use. While FQDN could
-       be used during phase 1 for SG-A, there is no appropriate ID for phase 2
-	that permits SG-B to determine that SG-A is in fact authorized to speak for Alice. 
-    
-</p>
-<a name="rfc.section.6.3"></a><h4><a name="anchor45">6.3</a>&nbsp;Bob is behind a NAT/NAPT</h4>
-
-<p>
-       If Bob is behind a NAT (perhaps SG-B), then there is, in fact, no way for
-       Alice to address a packet to Bob. Not only is opportunistic encryption
-       impossible, but it is also impossible for Alice to initiate any
-       communication to Bob. It may be possible for Bob to initiate in such
-       a situation. This creates an asymmetry, but this is common for 
-       NAPT.
-    
-</p>
-<a name="anchor46"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.7"></a><h3>7.&nbsp;Host implementations</h3>
-
-<p>
-  When Alice and SG-A are components of the same system, they are
-  considered to be a host implementation. The packet sequence scenario remains unchanged.
-
-</p>
-<p>
-  Components marked Alice are the upper layers (TCP, UDP, the
-  application), and SG-A is the IP layer.
-
-</p>
-<p>
-  Note that tunnel mode is still required. 
-
-</p>
-<p>
-  As Alice and SG-A are acting on behalf of themselves, no TXT based delegation
-  record is necessary for Alice to initiate. She can rely on FQDN in a
-  forward map. This is particularly attractive to mobile nodes such as 
-  notebook computers at conferences.
-  To respond, Alice/SG-A will still need an entry in Alice's reverse-map.
-
-</p>
-<a name="anchor47"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.8"></a><h3>8.&nbsp;Multi-homing</h3>
-
-<p> 
-If there are multiple paths between Alice and Bob (as illustrated in
-the diagram with SG-D), then additional DNS records are required to establish
-authorization. 
-
-</p>
-<p>
-In <a href="#networkdiagram">Reference Network Diagram</a>, Alice has two ways to
-exit her network: SG-A and SG-D. Previously SG-D has been ignored. Postulate
-that there are routers between Alice and her set of security gateways
-(denoted by the + signs and the marking of an autonomous system number for
-Alice's network). Datagrams may, therefore, travel to either SG-A or SG-D en
-route to Bob.
-
-</p>
-<p>
-As long as all network connections are in good order, it does not matter how
-datagrams exit Alice's network. When they reach either security gateway, the
-security gateway will find the TXT delegation record in Bob's reverse-map,
-and establish an SA with SG-B. 
-
-</p>
-<p>
-SG-B has no problem establishing that either of SG-A or SG-D may speak for
-Alice, because Alice has published two equally weighted TXT delegation records:
-    <br><hr size="1" shade="0">
-<a name="txtmultiexample"></a>
-</p>
-</font><pre>
-X-IPsec-Server(10)=192.1.1.5 AQMM...3s1Q==
-X-IPsec-Server(10)=192.1.1.6 AAJN...j8r9==
-          </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Multiple gateway delegation example for Alice&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
-
-</p>
-<p>
-Alice's routers can now do any kind of load sharing needed. Both SG-A and SG-D send datagrams addressed to Bob through
-their tunnel to SG-B. 
-
-</p>
-<p>
-Alice's use of non-equal weight delegation records to show preference of one gateway over another, has relevance only when SG-B 
-is initiating to Alice. 
-
-</p>
-<p>
-If the precedences are the same, then SG-B has a more difficult time. It
-must decide which of the two tunnels to use. SG-B has no information about
-which link is less loaded, nor which security gateway has more cryptographic
-resources available. SG-B, in fact, has no knowledge of whether both gateways
-are even reachable.  
-
-</p>
-<p>
-The Public Internet's default-free zone may well know a good route to Alice,
-but the datagrams that SG-B creates must be addressed to either SG-A or SG-D;
-they can not be addressed to Alice directly.
-
-</p>
-<p>
-SG-B may make a number of choices:
-
-<ol class="text">
-<li>It can ignore the problem and round robin among the tunnels. This
-      causes losses during times when one or the other security gateway is
-      unreachable. If this worries Alice, she can change the weights in her
-      TXT delegation records.
-</li>
-<li>It can send to the gateway from which it most recently received datagrams. 
-      This assumes that routing and reachability are symmetrical.
-</li>
-<li>It can listen to BGP information from the Internet to decide which
-      system is currently up. This is clearly much more complicated, but if SG-B is already participating
-      in the BGP peering system to announce Bob, the results data may already
-      be available to it. 
-</li>
-<li>It can refuse to negotiate the second tunnel. (It is unclear whether or
-not this is even an option.)
-</li>
-<li>It can silently replace the outgoing portion of the first tunnel with the
-second one while still retaining the incoming portions of both. SG-B can,
-thus, accept datagrams from either SG-A or SG-D, but
-send only to the gateway that most recently re-keyed with it.
-</li>
-</ol><p>
-</p>
-<p>
-Local policy determines which choice SG-B makes. Note that even if SG-B has perfect
-knowledge about the reachability of SG-A and SG-D, Alice may not be reachable
-from either of these security gateways because of internal reachability
-issues. 
-
-</p>
-<p>
-FreeS/WAN implements option 5.  Implementing a different option is
-being considered. The multi-homing aspects of OE are not well developed and may
-be the subject of a future document.
-
-</p>
-<a name="anchor48"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.9"></a><h3>9.&nbsp;Failure modes</h3>
-
-<a name="rfc.section.9.1"></a><h4><a name="anchor49">9.1</a>&nbsp;DNS failures</h4>
-
-<p>
-  If a DNS server fails to respond, local policy decides
-  whether or not to permit communication in the clear as embodied in
-  the connection classes in <a href="#initclasses">Keying state machine - initiator</a>.
-  It is easy to mount a denial of service attack on the DNS server
-  responsible for a particular network's reverse-map.
-  Such an attack may cause all communication with that network to go in
-  the clear if the policy is permissive, or fail completely 
-  if the policy is paranoid. Please note that this is an active attack.
-  
-</p>
-<p>
-  There are still many networks
-  that do not have properly configured reverse-maps. Further, if the policy is not to communicate,
-  the above denial of service attack isolates the target network. Therefore, the decision of whether 
-or not to permit communication in the clear MUST be a matter of local policy.
-  
-</p>
-<a name="rfc.section.9.2"></a><h4><a name="anchor50">9.2</a>&nbsp;DNS configured, IKE failures</h4>
-
-<p>
-  DNS records claim that opportunistic encryption should
-  occur, but the target gateway either does not respond on port 500, or
-  refuses the proposal. This may be because of a crash or reboot, a
-  faulty configuration, or a firewall filtering port 500.  
-  
-</p>
-<p>
-  The receipt of ICMP port, host or network unreachable
-  messages indicates a potential problem, but MUST NOT cause communication
-  to fail 
-  immediately. ICMP messages are easily forged by attackers. If such a
-  forgery caused immediate failure, then an active attacker could easily
-  prevent any 
-  encryption from ever occurring, possibly preventing all communication.
-  
-</p>
-<p>
-  In these situations a clear log should be produced
-  and local policy should dictate if communication is then
-  permitted in the clear.
-  
-</p>
-<a name="rfc.section.9.3"></a><h4><a name="anchor51">9.3</a>&nbsp;System reboots</h4>
-
-<p>
-Tunnels sometimes go down because the remote end crashes,
-disconnects, or has a network link break.  In general there is no
-notification of this.  Even in the event of a crash and successful reboot, 
-other SGs don't hear about it unless the rebooted SG has specific 
-reason to talk to them immediately.  Over-quick response to temporary 
-network outages is undesirable.  Note that a tunnel can be torn
-down and then re-established without any effect visible to the user
-except a pause in traffic. On the other hand, if one end reboots,
-the other end can't get datagrams to it at all (except via
-IKE) until the situation is noticed.  So a bias toward quick
-response is appropriate even at the cost of occasional
-false alarms.
-
-</p>
-<p>
-A mechanism for recovery after reboot is a topic of current research and is not specified in this
-document.
-
-</p>
-<p>
-A deliberate shutdown should include an attempt, using deletes, to notify all other SGs
-currently connected by phase 1 SAs that communication is
-about to fail.  Again, a remote SG will assume this is a teardown.  Attempts by the
-remote SGs to negotiate new tunnels as replacements should be ignored. When possible, 
-SGs should attempt to preserve information about currently-connected SGs in non-volatile storage, so
-that after a crash, an Initial-Contact can be sent to previous partners to
-indicate loss of all previously established connections.
-
-</p>
-<a name="anchor52"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.10"></a><h3>10.&nbsp;Unresolved issues</h3>
-
-<a name="rfc.section.10.1"></a><h4><a name="anchor53">10.1</a>&nbsp;Control of reverse DNS</h4>
-
-<p>
-  The method of obtaining information by reverse DNS lookup causes
-  problems for people who cannot control their reverse DNS
-  bindings. This is an unresolved problem in this version, and is out
-  of scope.
-  
-</p>
-<a name="anchor54"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.11"></a><h3>11.&nbsp;Examples</h3>
-
-<a name="rfc.section.11.1"></a><h4><a name="anchor55">11.1</a>&nbsp;Clear-text usage (permit policy)</h4>
-
-<p>
-Two example scenarios follow. In the first example GW-A
-(Gateway A) and GW-B (Gateway B) have always-clear-text policies, and in the second example they have an OE
-policy.
-
-</p><br><hr size="1" shade="0">
-<a name="regulartiming"></a>
-</font><pre>
-  Alice         SG-A       DNS       SG-B           Bob
-   (1)
-    ------(2)-------------->
-    &lt;-----(3)---------------
-   (4)----(5)----->
-                   ----------(6)------>
-                                       ------(7)----->
-                                      &lt;------(8)------
-                   &lt;----------(9)------
-    &lt;----(10)-----
-   (11)----------->
-                   ----------(12)----->
-                                       -------------->
-                                      &lt;---------------
-                   &lt;-------------------
-    &lt;-------------
-          </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Timing of regular transaction&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
-
-<p>
-Alice wants to communicate with Bob. Perhaps she wants to retrieve a
-web page from Bob's web server. In the absence of opportunistic
-encryptors, the following events occur: 
-
-<blockquote class="text"><dl>
-<dt>(1)</dt>
-<dd>Human or application 'clicks' with a name.
-</dd>
-<dt>(2)</dt>
-<dd>Application looks up name in DNS to get IP address.
-</dd>
-<dt>(3)</dt>
-<dd>Resolver returns A record to application.
-</dd>
-<dt>(4)</dt>
-<dd>Application starts a TCP session or UDP session and OS sends datagram.
-</dd>
-<dt>(5)</dt>
-<dd>Datagram is seen at first gateway from Alice (SG-A). (SG-A
-makes a transition through Empty connection to always-clear connection and
-instantiates a pass-through policy at the forwarding plane.)
-</dd>
-<dt>(6)</dt>
-<dd>Datagram is seen at last gateway before Bob (SG-B).
-</dd>
-<dt>(7)</dt>
-<dd>First datagram from Alice is seen by Bob.
-</dd>
-<dt>(8)</dt>
-<dd>First return datagram is sent by Bob.
-</dd>
-<dt>(9)</dt>
-<dd>Datagram is seen at Bob's gateway. (SG-B makes a transition through
-Empty connection to always-clear connection and instantiates a pass-through
-policy at the forwarding plane.)
-</dd>
-<dt>(10)</dt>
-<dd>Datagram is seen at Alice's gateway.
-</dd>
-<dt>(11)</dt>
-<dd>OS hands datagram to application. Alice sends another datagram.
-</dd>
-<dt>(12)</dt>
-<dd>A second datagram traverses the Internet.
-</dd>
-</dl></blockquote><p>
-</p>
-<a name="rfc.section.11.2"></a><h4><a name="anchor56">11.2</a>&nbsp;Opportunistic encryption</h4>
-
-<p>
-In the presence of properly configured opportunistic encryptors, the
-event list is extended.
-
-<br><hr size="1" shade="0">
-<a name="opportunistictiming"></a>
-</p>
-</font><pre>
-  Alice          SG-A      DNS       SG-B           Bob
-   (1)
-    ------(2)-------------->
-    &lt;-----(3)---------------
-   (4)----(5)----->+
-                  ----(5B)->
-                  &lt;---(5C)--
-                  ~~~~~~~~~~~~~(5D)~~~>
-                  &lt;~~~~~~~~~~~~(5E1)~~~
-                  ~~~~~~~~~~~~~(5E2)~~>
-                  &lt;~~~~~~~~~~~~(5E3)~~~
-                  #############(5E4)##>
-                  &lt;############(5E5)###
-                           &lt;----(5F1)--
-                           -----(5F2)->
-                  #############(5G1)##>
-                           &lt;----(5H1)--
-                           -----(5H2)->
-                  &lt;############(5G2)###
-                  #############(5G3)##>
-                   ============(6)====>
-		                       ------(7)----->
-                                      &lt;------(8)------
-                  &lt;==========(9)======
-    &lt;-----(10)----
-   (11)----------->
-                   ==========(12)=====>
-                                       -------------->
-                                      &lt;---------------
-                   &lt;===================
-    &lt;-------------
-          </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Timing of opportunistic encryption transaction&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
-
-<blockquote class="text"><dl>
-<dt>(1)</dt>
-<dd>Human or application clicks with a name.
-</dd>
-<dt>(2)</dt>
-<dd>Application initiates DNS mapping.
-</dd>
-<dt>(3)</dt>
-<dd>Resolver returns A record to application.
-</dd>
-<dt>(4)</dt>
-<dd>Application starts a TCP session or UDP.
-</dd>
-<dt>(5)</dt>
-<dd>SG-A (host or SG) sees datagram to target, and buffers it.
-</dd>
-<dt>(5B)</dt>
-<dd>SG-A asks DNS for TXT record.
-</dd>
-<dt>(5C)</dt>
-<dd>DNS returns TXT record(s).
-</dd>
-<dt>(5D)</dt>
-<dd>Initial IKE Main Mode Packet goes out.
-</dd>
-<dt>(5E)</dt>
-<dd>IKE ISAKMP phase 1 succeeds.
-</dd>
-<dt>(5F)</dt>
-<dd>SG-B asks DNS for TXT record to prove SG-A is an agent for Alice.
-</dd>
-<dt>(5G)</dt>
-<dd>IKE phase 2 negotiation.
-</dd>
-<dt>(5H)</dt>
-<dd>DNS lookup by responder (SG-B).
-</dd>
-<dt>(6)</dt>
-<dd>Buffered datagram is sent by SG-A.
-</dd>
-<dt>(7)</dt>
-<dd>Datagram is received by SG-B, decrypted, and sent to Bob.
-</dd>
-<dt>(8)</dt>
-<dd>Bob replies, and datagram is seen by SG-B.
-</dd>
-<dt>(9)</dt>
-<dd>SG-B already has tunnel up with SG-A, and uses it.
-</dd>
-<dt>(10)</dt>
-<dd>SG-A decrypts datagram and gives it to Alice.
-</dd>
-<dt>(11)</dt>
-<dd>Alice receives datagram. Sends new packet to Bob.
-</dd>
-<dt>(12)</dt>
-<dd>SG-A gets second datagram, sees that tunnel is up, and uses it.
-</dd>
-</dl></blockquote><p>
-</p>
-<p>
-  For the purposes of this section, we will describe only the changes that
-  occur between <a href="#regulartiming">Timing of regular transaction</a> and
-  <a href="#opportunistictiming">Timing of opportunistic encryption transaction</a>. This corresponds to time points 5, 6, 7, 9 and 10 on the list above. 
-  
-</p>
-<a name="rfc.section.11.2.1"></a><h4><a name="anchor57">11.2.1</a>&nbsp;(5) IPsec datagram interception</h4>
-
-<p>
-    At point (5), SG-A intercepts the datagram because this source/destination pair lacks a policy 
-(the non-existent policy state). SG-A creates a hold policy, and buffers the datagram. SG-A requests keys from the keying daemon. 
-    
-</p>
-<a name="rfc.section.11.2.2"></a><h4><a name="anchor58">11.2.2</a>&nbsp;(5B) DNS lookup for TXT record</h4>
-
-<p>
-    SG-A's IKE daemon, having looked up the source/destination pair in the connection
-    class list, creates a new Potential OE connection instance. SG-A starts DNS
-    queries.
-    
-</p>
-<a name="rfc.section.11.2.3"></a><h4><a name="anchor59">11.2.3</a>&nbsp;(5C) DNS returns TXT record(s)</h4>
-
-<p>
-  DNS returns properly formed TXT delegation records, and SG-A's IKE daemon
-  causes this instance to make a transition from Potential OE connection to Pending OE
-  connection.
-  
-</p>
-<p>
-      Using the example above, the returned record might contain:
-
-    <br><hr size="1" shade="0">
-<a name="txtexample"></a>
-</p>
-</font><pre>
-X-IPsec-Server(10)=192.1.1.5 AQMM...3s1Q==
-          </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Example of reverse delegation record for Bob&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
-
-    with SG-B's IP address and public key listed.
-    
-</p>
-<a name="rfc.section.11.2.4"></a><h4><a name="anchor60">11.2.4</a>&nbsp;(5D) Initial IKE main mode packet goes out</h4>
-
-<p>Upon entering Pending OE connection, SG-A sends the initial ISAKMP
-  message with proposals. See <a href="#phase1id">Phase 1 parameters</a>.
-  
-</p>
-<a name="rfc.section.11.2.5"></a><h4><a name="anchor61">11.2.5</a>&nbsp;(5E1) Message 2 of phase 1 exchange</h4>
-
-<p>
-  SG-B receives the message. A new connection instance is created in the
-  unauthenticated OE peer state.
-  
-</p>
-<a name="rfc.section.11.2.6"></a><h4><a name="anchor62">11.2.6</a>&nbsp;(5E2) Message 3 of phase 1 exchange</h4>
-
-<p>
-  SG-A sends a Diffie-Hellman exponent. This is an internal state of the
-  keying daemon.
-  
-</p>
-<a name="rfc.section.11.2.7"></a><h4><a name="anchor63">11.2.7</a>&nbsp;(5E3) Message 4 of phase 1 exchange</h4>
-
-<p>
-  SG-B responds with a Diffie-Hellman exponent. This is an internal state of the
-  keying protocol.
-  
-</p>
-<a name="rfc.section.11.2.8"></a><h4><a name="anchor64">11.2.8</a>&nbsp;(5E4) Message 5 of phase 1 exchange</h4>
-
-<p>
-  SG-A uses the phase 1 SA to send its identity under encryption. 
-  The choice of identity is discussed in <a href="#phase1id">Phase 1 parameters</a>.
-  This is an internal state of the keying protocol.
-  
-</p>
-<a name="rfc.section.11.2.9"></a><h4><a name="anchor65">11.2.9</a>&nbsp;(5F1) Responder lookup of initiator key</h4>
-
-<p>
-  SG-B asks DNS for the public key of the initiator. 
-  DNS looks for a KEY record by IP address in the reverse-map.
-  That is, a KEY resource record is queried for 4.1.1.192.in-addr.arpa
-  (recall that SG-A's external address is 192.1.1.4).
-  SG-B uses the resulting public key to authenticate the initiator. See <a href="#KEY">Use of KEY record</a> for further details. 
-  
-</p>
-<a name="rfc.section.11.2.10"></a><h4><a name="anchor66">11.2.10</a>&nbsp;(5F2) DNS replies with public key of initiator</h4>
-
-<p>
-Upon successfully authenticating the peer, the connection instance makes a
-transition to authenticated OE peer on SG-B.
-
-</p>
-<p>
-The format of the TXT record returned is described in
-<a href="#TXT">Use of TXT delegation record</a>. 
-
-</p>
-<a name="rfc.section.11.2.11"></a><h4><a name="anchor67">11.2.11</a>&nbsp;(5E5) Responder replies with ID and authentication</h4>
-
-<p>
-    SG-B sends its ID along with authentication material. This is an internal
-    state for the keying protocol.
-  
-</p>
-<a name="rfc.section.11.2.12"></a><h4><a name="anchor68">11.2.12</a>&nbsp;(5G) IKE phase 2</h4>
-
-<a name="rfc.section.11.2.12.1"></a><h4><a name="anchor69">11.2.12.1</a>&nbsp;(5G1) Initiator proposes tunnel</h4>
-
-<p>
-    Having established mutually agreeable authentications (via KEY) and
-    authorizations (via TXT), SG-A proposes to create an IPsec tunnel for
-    datagrams transiting from Alice to Bob. This tunnel is established only for 
-    the Alice/Bob combination, not for any subnets that may be behind SG-A and SG-B.
-    
-</p>
-<a name="rfc.section.11.2.12.2"></a><h4><a name="anchor70">11.2.12.2</a>&nbsp;(5H1) Responder determines initiator's authority</h4>
-
-<p>
-    While the identity of SG-A has been established, its authority to
-    speak for Alice has not yet been confirmed. SG-B does a reverse
-    lookup on Alice's address for a TXT record. 
-    
-</p>
-<p>Upon receiving this specific proposal, SG-B's connection instance
-    makes a transition into the potential OE connection state. SG-B may already have an
-    instance, and the check is made as described above.
-</p>
-<a name="rfc.section.11.2.12.3"></a><h4><a name="anchor71">11.2.12.3</a>&nbsp;(5H2) DNS replies with TXT record(s)</h4>
-
-<p>
-      The returned key and IP address should match that of SG-A.
-    
-</p>
-<a name="rfc.section.11.2.12.4"></a><h4><a name="anchor72">11.2.12.4</a>&nbsp;(5G2) Responder agrees to proposal</h4>
-
-<p>
-    Should additional communication occur between, for instance, Dave and Bob using
-    SG-A and SG-B, a new tunnel (phase 2 SA) would be established. The phase 1 SA
-    may be reusable.
-    
-</p>
-<p>SG-A, having successfully keyed the tunnel, now makes a transition from
-    Pending OE connection to Keyed OE connection.
-    
-</p>
-<p>The responder MUST setup the inbound IPsec SAs before sending its reply.
-</p>
-<a name="rfc.section.11.2.12.5"></a><h4><a name="anchor73">11.2.12.5</a>&nbsp;(5G3) Final acknowledgment from initiator</h4>
-
-<p>
-    The initiator agrees with the responder's choice and sets up the tunnel.
-    The initiator sets up the inbound and outbound IPsec SAs.
-    
-</p>
-<p>
-    The proper authorization returned with keys prompts SG-B to make a transition
-    to the keyed OE connection state. 
-    
-</p>
-<p>Upon receipt of this message, the responder may now setup the outbound
-    IPsec SAs.
-</p>
-<a name="rfc.section.11.2.13"></a><h4><a name="anchor74">11.2.13</a>&nbsp;(6) IPsec succeeds, and sets up tunnel for communication between Alice and Bob</h4>
-
-<p>
-  SG-A sends the datagram saved at step (5) through the newly created
-  tunnel to SG-B, where it gets decrypted and forwarded. 
-  Bob receives it at (7) and replies at (8). 
-  
-</p>
-<a name="rfc.section.11.2.14"></a><h4><a name="anchor75">11.2.14</a>&nbsp;(9) SG-B already has tunnel up with G1 and uses it</h4>
-
-<p>
-  At (9), SG-B has already established an SPD entry mapping Bob->Alice via a
-  tunnel, so this tunnel is simply applied. The datagram is encrypted to SG-A,
-  decrypted by SG-A and passed to Alice at (10).
-  
-</p>
-<a name="securityconsiderations"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.12"></a><h3>12.&nbsp;Security considerations</h3>
-
-<a name="rfc.section.12.1"></a><h4><a name="anchor76">12.1</a>&nbsp;Configured vs opportunistic tunnels</h4>
-
-<p>
-    Configured tunnels are those which are setup using bilateral mechanisms: exchanging 
-public keys (raw RSA, DSA, PKIX), pre-shared secrets, or by referencing keys that
-are in known places (distinguished name from LDAP, DNS). These keys are then used to
-configure a specific tunnel. 
-
-</p>
-<p>
-A pre-configured tunnel may be on all the time, or may be keyed only when needed. 
-The end points of the tunnel are not necessarily static: many mobile
-applications (road warrior) are considered to be configured tunnels. 
-
-</p>
-<p>
-The primary characteristic is that configured tunnels are assigned specific
-security properties. They may be trusted in different ways relating to exceptions to 
-firewall rules, exceptions to NAT processing, and to bandwidth or other quality of service restrictions. 
-
-</p>
-<p>
-Opportunistic tunnels are not inherently trusted in any strong way. They are
-created without prior arrangement. As the two parties are strangers, there
-MUST be no confusion of datagrams that arrive from opportunistic peers and
-those that arrive from configured tunnels. A security gateway MUST take care
-that an opportunistic peer can not impersonate a configured peer.
-
-</p>
-<p>
-Ingress filtering MUST be used to make sure that only datagrams authorized by
-negotiation (and the concomitant authentication and authorization) are
-accepted from a tunnel. This is to prevent one peer from impersonating another. 
-
-</p>
-<p>
-An implementation suggestion is to treat opportunistic tunnel
-datagrams as if they arrive on a logical interface distinct from other
-configured tunnels. As the number of opportunistic tunnels that may be
-created automatically on a system is potentially very high, careful attention 
-to scaling should be taken into account.
-
-</p>
-<p>
-As with any IKE negotiation, opportunistic encryption cannot be secure
-without authentication. Opportunistic encryption relies on DNS for its
-authentication information and, therefore, cannot be fully secure without
-a secure DNS. Without secure DNS, opportunistic encryption can protect against passive
-eavesdropping but not against active man-in-the-middle attacks.
-
-</p>
-<a name="rfc.section.12.2"></a><h4><a name="anchor77">12.2</a>&nbsp;Firewalls versus Opportunistic Tunnels</h4>
-
-<p>
-  Typical usage of per datagram access control lists is to implement various
-kinds of security gateways. These are typically called "firewalls". 
-
-</p>
-<p>
-  Typical usage of a virtual private network (VPN) within a firewall is to
-bypass all or part of the access controls between two networks. Additional
-trust (as outlined in the previous section) is given to datagrams that arrive
-in the VPN.
-
-</p>
-<p> 
-  Datagrams that arrive via opportunistically configured tunnels MUST not be
-trusted. Any security policy that would apply to a datagram arriving in the
-clear SHOULD also be applied to datagrams arriving opportunistically.
-
-</p>
-<a name="rfc.section.12.3"></a><h4><a name="anchor78">12.3</a>&nbsp;Denial of service</h4>
-
-<p>
-  There are several different forms of denial of service that an implementor 
-  should concern themselves with. Most of these problems are shared with
-  security gateways that have large numbers of mobile peers (road warriors). 
-
-</p>
-<p>
-  The design of ISAKMP/IKE, and its use of cookies, defend against many kinds
-  of denial of service. Opportunism changes the assumption that if the phase 1 (ISAKMP) 
-  SA is authenticated, that it was worthwhile creating. Because the gateway will communicate with any machine, it is
-  possible to form phase 1 SAs with any machine on the Internet. 
-
-</p>
-<a name="anchor79"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.13"></a><h3>13.&nbsp;IANA Considerations</h3>
-
-<p>
-    There are no known numbers which IANA will need to manage.
-
-</p>
-<a name="anchor80"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.14"></a><h3>14.&nbsp;Acknowledgments</h3>
-
-<p>
-        Substantive portions of this document are based upon previous work by
-        Henry Spencer.
-
-</p>
-<p>
-	Thanks to Tero Kivinen, Sandy Harris, Wes Hardarker, Robert Moskowitz,
-	Jakob Schlyter, Bill Sommerfeld, John Gilmore and John Denker for their
-	comments and constructive criticism.
-
-</p>
-<p>
-	Sandra Hoffman and Bill Dickie did the detailed proof reading and editing.
-
-</p>
-<a name="rfc.references1"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<h3>Normative references</h3>
-<table width="99%" border="0">
-<tr><td class="author-text" valign="top"><b><a name="OEspec">[1]</a></b></td>
-<td class="author-text"><a href="mailto:hugh@mimosa.com">Redelmeier, D.</a> and <a href="mailto:henry@spsystems.net">H. Spencer</a>, "Opportunistic Encryption", paper http://www.freeswan.org/freeswan_trees/freeswan-1.91/doc/opportunism.spec, May 2001.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC0791">[2]</a></b></td>
-<td class="author-text">Defense Advanced Research Projects Agency (DARPA), Information Processing Techniques Office and University of Southern California (USC)/Information Sciences Institute, "<a href="ftp://ftp.isi.edu/in-notes/rfc791.txt">Internet Protocol</a>", STD 5, RFC 791, September 1981.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC1009">[3]</a></b></td>
-<td class="author-text"><a href="mailto:">Braden, R.</a> and <a href="mailto:">J. Postel</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1009.txt">Requirements for Internet gateways</a>", RFC 1009, June 1987.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC1984">[4]</a></b></td>
-<td class="author-text">IAB, IESG, <a href="mailto:brian@dxcoms.cern.ch">Carpenter, B.</a> and <a href="mailto:fred@cisco.com">F. Baker</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1984.txt">IAB and IESG Statement on Cryptographic Technology and the Internet</a>", RFC 1984, August 1996.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2119">[5]</a></b></td>
-<td class="author-text"><a href="mailto:-">Bradner, S.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2119.txt">Key words for use in RFCs to Indicate Requirement Levels</a>", BCP 14, RFC 2119, March 1997.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2367">[6]</a></b></td>
-<td class="author-text"><a href="mailto:danmcd@eng.sun.com">McDonald, D.</a>, <a href="mailto:cmetz@inner.net">Metz, C.</a> and <a href="mailto:phan@itd.nrl.navy.mil">B. Phan</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2367.txt">PF_KEY Key Management API, Version 2</a>", RFC 2367, July 1998.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2401">[7]</a></b></td>
-<td class="author-text"><a href="mailto:kent@bbn.com">Kent, S.</a> and <a href="mailto:rja@corp.home.net">R. Atkinson</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2401.txt">Security Architecture for the Internet Protocol</a>", RFC 2401, November 1998.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2407">[8]</a></b></td>
-<td class="author-text"><a href="mailto:ddp@network-alchemy.com">Piper, D.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2407.txt">The Internet IP Security Domain of Interpretation for ISAKMP</a>", RFC 2407, November 1998.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2408">[9]</a></b></td>
-<td class="author-text"><a href="mailto:wdm@tycho.ncsc.mil">Maughan, D.</a>, <a href="mailto:mss@tycho.ncsc.mil">Schneider, M.</a> and <a href="er@raba.com">M. Schertler</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2408.txt">Internet Security Association and Key Management Protocol (ISAKMP)</a>", RFC 2408, November 1998.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2409">[10]</a></b></td>
-<td class="author-text"><a href="mailto:dharkins@cisco.com">Harkins, D.</a> and <a href="mailto:carrel@ipsec.org">D. Carrel</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2409.txt">The Internet Key Exchange (IKE)</a>", RFC 2409, November 1998.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC3526">[11]</a></b></td>
-<td class="author-text"><a href="mailto:kivinen@ssh.fi">Kivinen, T.</a> and <a href="mailto:mrskojo@cc.helsinki.fi">M. Kojo</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc3526.txt">More MODP Diffie-Hellman groups for IKE</a>", RFC 3526, March 2003.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC1034">[12]</a></b></td>
-<td class="author-text">Mockapetris, P., "<a href="ftp://ftp.isi.edu/in-notes/rfc1034.txt">Domain names - concepts and facilities</a>", STD 13, RFC 1034, November 1987.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC1035">[13]</a></b></td>
-<td class="author-text"><a href="mailto:">Mockapetris, P.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1035.txt">Domain names - implementation and specification</a>", STD 13, RFC 1035, November 1987.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2671">[14]</a></b></td>
-<td class="author-text"><a href="mailto:vixie@isc.org">Vixie, P.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2671.txt">Extension Mechanisms for DNS (EDNS0)</a>", RFC 2671, August 1999.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC1464">[15]</a></b></td>
-<td class="author-text"><a href="mailto:rosenbaum@lkg.dec.com">Rosenbaum, R.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1464.txt">Using the Domain Name System To Store Arbitrary String Attributes</a>", RFC 1464, May 1993.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2535">[16]</a></b></td>
-<td class="author-text"><a href="mailto:dee3@us.ibm.com">Eastlake, D.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2535.txt">Domain Name System Security Extensions</a>", RFC 2535, March 1999.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC3110">[17]</a></b></td>
-<td class="author-text">Eastlake, D., "<a href="ftp://ftp.isi.edu/in-notes/rfc3110.txt">RSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)</a>", RFC 3110, May 2001.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2538">[18]</a></b></td>
-<td class="author-text"><a href="mailto:dee3@us.ibm.com">Eastlake, D.</a> and <a href="mailto:ogud@tislabs.com">O. Gudmundsson</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2538.txt">Storing Certificates in the Domain Name System (DNS)</a>", RFC 2538, March 1999.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2748">[19]</a></b></td>
-<td class="author-text"><a href="mailto:David.Durham@intel.com">Durham, D.</a>, <a href="mailto:jboyle@Level3.net">Boyle, J.</a>, <a href="mailto:ronc@cisco.com">Cohen, R.</a>, <a href="mailto:herzog@iphighway.com">Herzog, S.</a>, <a href="mailto:rajan@research.att.com">Rajan, R.</a> and <a href="mailto:asastry@cisco.com">A. Sastry</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2748.txt">The COPS (Common Open Policy Service) Protocol</a>", RFC 2748, January 2000.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2663">[20]</a></b></td>
-<td class="author-text"><a href="mailto:srisuresh@lucent.com">Srisuresh, P.</a> and <a href="mailto:holdrege@lucent.com">M. Holdrege</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2663.txt">IP Network Address Translator (NAT) Terminology and Considerations</a>", RFC 2663, August 1999.</td></tr>
-</table>
-
-<a name="rfc.authors"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<h3>Authors' Addresses</h3>
-<table width="99%" border="0" cellpadding="0" cellspacing="0">
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">Michael C. Richardson</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">Sandelman Software Works</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">470 Dawson Avenue</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">Ottawa, ON  K1Z 5V7</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">CA</td></tr>
-<tr><td class="author" align="right">EMail:&nbsp;</td>
-<td class="author-text"><a href="mailto:mcr@sandelman.ottawa.on.ca">mcr@sandelman.ottawa.on.ca</a></td></tr>
-<tr><td class="author" align="right">URI:&nbsp;</td>
-<td class="author-text"><a href="http://www.sandelman.ottawa.on.ca/">http://www.sandelman.ottawa.on.ca/</a></td></tr>
-<tr cellpadding="3"><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">D. Hugh Redelmeier</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">Mimosa</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">Toronto, ON</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">CA</td></tr>
-<tr><td class="author" align="right">EMail:&nbsp;</td>
-<td class="author-text"><a href="mailto:hugh@mimosa.com">hugh@mimosa.com</a></td></tr>
-</table>
-<a name="rfc.copyright"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<h3>Full Copyright Statement</h3>
-<p class='copyright'>
-Copyright (C) The Internet Society (2003). All Rights Reserved.</p>
-<p class='copyright'>
-This document and translations of it may be copied and furnished to
-others, and derivative works that comment on or otherwise explain it
-or assist in its implementation may be prepared, copied, published and
-distributed, in whole or in part, without restriction of any kind,
-provided that the above copyright notice and this paragraph are
-included on all such copies and derivative works. However, this
-document itself may not be modified in any way, such as by removing
-the copyright notice or references to the Internet Society or other
-Internet organizations, except as needed for the purpose of
-developing Internet standards in which case the procedures for
-copyrights defined in the Internet Standards process must be
-followed, or as required to translate it into languages other than
-English.</p>
-<p class='copyright'>
-The limited permissions granted above are perpetual and will not be
-revoked by the Internet Society or its successors or assigns.</p>
-<p class='copyright'>
-This document and the information contained herein is provided on an
-&quot;AS IS&quot; basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
-TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
-BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
-HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
-MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.</p>
-<h3>Acknowledgement</h3>
-<p class='copyright'>
-Funding for the RFC Editor function is currently provided by the
-Internet Society.</p>
-</font></body></html>
diff --git a/doc/src/draft-richardson-ipsec-opportunistic.xml b/doc/src/draft-richardson-ipsec-opportunistic.xml
deleted file mode 100644
index d587df693..000000000
--- a/doc/src/draft-richardson-ipsec-opportunistic.xml
+++ /dev/null
@@ -1,2519 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
-<?rfc toc="yes"?>
-<?rfc tocdepth='2' ?>
-
-<rfc ipr="full2026" docName="draft-richardson-ipsec-opportunistic-12.txt">
-
-<front>
-  <area>Security</area>
-  <workgroup>Independent submission</workgroup>
-  <title abbrev="opportunistic">
-     Opportunistic Encryption using The Internet Key Exchange (IKE)
-  </title>
-
-  <author initials="M." surname="Richardson" fullname="Michael C. Richardson">
-    <organization abbrev="SSW">Sandelman Software Works</organization>
-    <address>
-      <postal>   
-        <street>470 Dawson Avenue</street>
-        <city>Ottawa</city>
-        <region>ON</region>
-        <code>K1Z 5V7</code>
-        <country>CA</country>
-      </postal>
-      <email>mcr@sandelman.ottawa.on.ca</email>
-      <uri>http://www.sandelman.ottawa.on.ca/</uri>
-    </address>
-  </author>
-
-  <author initials="D.H." surname="Redelmeier"
-          fullname="D. Hugh Redelmeier">
-    <organization abbrev="Mimosa">Mimosa</organization>
-    <address>
-      <postal>   
-        <city>Toronto</city>
-        <region>ON</region>
-        <country>CA</country>
-      </postal>
-      <email>hugh@mimosa.com</email>
-    </address>
-  </author>
-
-  <date month="June" year="2003"></date>
-
-<abstract>
-  <t>
-This document describes opportunistic encryption (OE) using the Internet Key
-Exchange (IKE) and IPsec.  
-Each system administrator adds new
-resource records to his or her Domain Name System (DNS) to support
-opportunistic encryption. The objective is to allow encryption for secure communication without
-any pre-arrangement specific to the pair of systems involved.
-  </t>
-  <t>
-DNS is used to distribute the public keys of each
-system involved. This is resistant to passive attacks. The use of DNS
-Security (DNSSEC) secures this system against active attackers as well. 
-  </t>
-  <t>
-As a result, the administrative overhead is reduced
-from the square of the number of systems to a linear dependence, and it becomes  
-possible to make secure communication the default even
-when the partner is not known in advance.
-  </t>
-  <t>
-This document is offered up as an Informational RFC.
-  </t>
-</abstract>
-
-</front>
-
-<middle>
-
-<section title="Introduction">
-
-<section title="Motivation">
-
-<t>
-The objective of opportunistic encryption is to allow encryption without
-any pre-arrangement specific to the pair of systems involved. Each
-system administrator adds
-public key information to DNS records to support opportunistic
-encryption and then enables this feature in the nodes' IPsec stack. 
-Once this is done, any two such nodes can communicate securely.
-</t>
-
-<t>
-This document describes opportunistic encryption as designed and
-implemented by the Linux FreeS/WAN project in revisions up and including 2.00.
-Note that 2.01 and beyond implements RFC3445, in a backward compatible way.
-For project information, see http://www.freeswan.org.
-</t>
-
-  <t>
-The Internet Architecture Board (IAB) and Internet Engineering
-Steering Group (IESG) have taken a strong stand that the Internet
-should use powerful encryption to provide security and
-privacy <xref target="RFC1984" />.
-The Linux FreeS/WAN project attempts to provide a practical means to implement this policy. 
-  </t>
-
-  <t>
-The project uses the IPsec, ISAKMP/IKE, DNS and DNSSEC
-protocols because they are
-standardized, widely available and can often be deployed very easily
-without changing hardware or software or retraining users. 
-  </t>
-
-  <t>
-The extensions to support opportunistic encryption are simple.  No
-changes to any on-the-wire formats are needed.  The only changes are to 
-the policy decision making system.  This means that opportunistic
-encryption can be implemented with very minimal changes to an existing 
-IPsec implementation.
-  </t>
-
-  <t>
-Opportunistic encryption creates a "fax effect". The proliferation
-of the fax machine was possible because it did not require that everyone
-buy one overnight. Instead, as each person installed one, the value
-of having one increased - as there were more people that could receive faxes.
-Once opportunistic encryption is installed it
-automatically recognizes 
-other boxes using opportunistic encryption, without any further configuration
-by the network 
-administrator. So, as opportunistic encryption software is installed on more
-boxes, its value 
-as a tool increases.
-</t>
-
-  <t>
-This document describes the infrastructure to permit deployment of
-Opportunistic Encryption.
-</t>
- 
-  <t>
-The term S/WAN is a trademark of RSA Data Systems, and is used with permission
-by this project.
-  </t>
-
-</section>
-
-<section title="Types of network traffic">
-  <t>
-    To aid in understanding the relationship between security processing and IPsec
-    we divide network traffic into four categories:
-    <list style="hanging">
-      <t hangText="* Deny:"> networks to which traffic is always forbidden.</t>
-      <t hangText="* Permit:"> networks to which traffic in the clear is permitted.</t>
-      <t hangText="* Opportunistic tunnel:"> networks to which traffic is encrypted if possible, but otherwise is in the clear  
-	    or fails depending on the default policy in place.	
-      </t>
-      <t hangText="* Configured tunnel:"> networks to which traffic
-must be encrypted, and traffic in the clear is never permitted.
-A Virtual Private Network (VPN) is a form of configured tunnel.
-</t>
-    </list>      
-  </t>
-
-<t>
-Traditional firewall devices handle the first two categories.
-No authentication is required.  
-The permit policy is currently the default on the Internet. 
-</t>
-
-<t>
-This document describes the third category - opportunistic tunnel, which is
-proposed as the new default for the Internet.
-</t>
-
-<t>
-  Category four, encrypt traffic or drop it, requires authentication of the
-  end points. As the number of end points is typically bounded and is typically
-  under a single authority, arranging for distribution of
-  authentication material, while difficult, does not require any new
-  technology. The mechanism described here provides an additional way to
-  distribute the authentication materials, that of a public key method that does not
-  require deployment of an X.509 based infrastructure.  
-</t>
-<t>
-Current Virtual Private Networks can often be replaced by an "OE paranoid"
-policy as described herein. 
-</t>
-</section>	
-
-<section title="Peer authentication in opportunistic encryption">
-
-  <t>
-  Opportunistic encryption creates tunnels between nodes that
-  are essentially strangers. This is done without any prior bilateral
-  arrangement. 
-  There is, therefore, the difficult question of how one knows to whom one is
-  talking.
-  </t>
-
-  <t>
-  One possible answer is that since no useful
-  authentication can be done, none should be tried. This mode of operation is
-  named "anonymous encryption".  An active man-in-the-middle attack can be
-  used to thwart the privacy of this type of communication. 
-  Without peer authentication, there is no way to prevent this kind of attack.
-  </t>
-
-  <t>
-Although a useful mode, anonymous encryption is not the goal of this
-project. Simpler methods are available that can achieve anonymous
-encryption only, but authentication of the peer is a desireable goal.
-The latter is achieved through key distribution in DNS, leveraging upon
-the authentication of the DNS in DNSSEC.
-</t>
-
-  <t>
-  Peers are, therefore, authenticated with DNSSEC when available. Local policy 
-determines how much trust to extend when DNSSEC is not available.
-  </t>
-
-  <t>
-  However, an essential premise of building private connections with
-  strangers is that datagrams received through opportunistic tunnels
-  are no more special than datagrams that arrive in the clear.
-  Unlike in a VPN, these datagrams should not be given any special
-  exceptions when it comes to auditing, further authentication or
-  firewalling.
-  </t>
-  
-  <t>
-  When initiating outbound opportunistic encryption, local 
-  configuration determines what happens if tunnel setup fails. It may be that
-  the packet goes out in the clear, or it may be dropped.
-  </t>
-
-  </section>
-
-<section title="Use of RFC2119 terms">
-<t>
-   The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD,
-   SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this
-   document, are to be interpreted as described in <xref target="RFC2119" />
-</t>
-</section>
-
-</section>
-
-<section title="Overview">
-
-  <section title="Reference diagram">
-
-    <figure anchor="networkdiagram" title="Reference Network Diagram">
-	   <preamble>The following network diagram is used in the rest of
-		this document as the canonical diagram:</preamble>
-           <artwork>
-                          [Q]  [R]          
-                           .    .              AS2                 
-  [A]----+----[SG-A].......+....+.......[SG-B]-------[B]
-         |                 ......
-     AS1 |                 ..PI..
-         |                 ......
-  [D]----+----[SG-D].......+....+.......[C] AS3
-             
-
-           </artwork>
-           <postamble></postamble>
-
-       </figure>
-
-    <t>
-    In this diagram, there are four end-nodes: A, B, C and D. 
-    There are three security gateways, SG-A, SG-B, SG-D. A, D, SG-A and
-    SG-D are part 
-    of the same administrative authority, AS1. SG-A and SG-D are on two
-    different exit
-    paths from organization 1. SG-B/B is an independent organization, AS2.
-    Nodes Q and R are nodes on the Internet. PI is the Public
-    Internet ("The Wild").
-    </t>
-
-  </section>
-
-  <section title="Terminology">
-
-  <t>
-  The following terminology is used in this document:
-  </t>
-
-  <list style="hanging">
-    <t hangText="Security gateway (or simply gateway):"> a system that performs IPsec tunnel
-    mode encapsulation/decapsulation. [SG-x] in the diagram.</t>
-    <t hangText="Alice:"> node [A] in the diagram. When an IP address is needed, this is 192.1.0.65.</t>
-    <t hangText="Bob:"> node [B] in the diagram. When an IP address is needed, this is 192.2.0.66.</t>
-    <t hangText="Carol:"> node [C] in the diagram. When an IP address is needed, this is 192.1.1.67.</t>
-    <t hangText="Dave:"> node [D] in the diagram. When an IP address is needed, this is 192.3.0.68.</t>
-    <t hangText="SG-A:"> Alice's security gateway. Internally it is 192.1.0.1, externally it is 192.1.1.4.</t>
-    <t hangText="SG-B:"> Bob's security gateway. Internally it is 192.2.0.1, externally it is 192.1.1.5.</t>
-    <t hangText="SG-D:"> Dave's security gateway. Also Alice's backup security gateway. Internally it is 192.3.0.1, externally it is 192.1.1.6.</t>
-    <t hangText="."> A period represents an untrusted network of unknown
-        type.</t> 
-    <t hangText="Configured tunnel:"> a tunnel that
-		  is directly and deliberately hand configured on participating gateways.
-		  Configured tunnels are typically given a higher level of
-		  trust than opportunistic tunnels.</t> 
-
-    <t hangText="Road warrior tunnel:"> a configured tunnel connecting one
-		  node with a fixed IP address and one node with a variable IP address.
-		  A road warrior (RW) connection must be initiated by the
-		  variable node, since the fixed node cannot know the
-		  current address for the road warrior. </t>
-
-    <t hangText="Anonymous encryption:">
-	the process of encrypting a session without any knowledge of who the
-	other parties are. No authentication of identities is done.</t>
-
-    <t hangText="Opportunistic encryption:">
-	the process of encrypting a session with authenticated knowledge of
-	who the other party is.</t>
-
-    <t hangText="Lifetime:">
-        the period in seconds (bytes or datagrams) for which a security
-	association will remain alive before needing to be re-keyed.</t>
-
-    <t hangText="Lifespan:">
-        the effective time for which a security association remains useful. A
-	security association with a lifespan shorter than its lifetime would
-	be removed when no longer needed. A security association with a
-	lifespan longer than its lifetime would need to be re-keyed one or
-	more times.</t>
-    
-    <t hangText="Phase 1 SA:"> an ISAKMP/IKE security association sometimes
-      referred to as a keying channel.</t>
-
-    <t hangText="Phase 2 SA:"> an IPsec security association.</t>
-
-    <t hangText="Tunnel:"> another term for a set of phase 2 SA (one in each direction).</t>
-
-    <t hangText="NAT:"> Network Address Translation
-    (see <xref target="RFC2663" />).</t>
-
-    <t hangText="NAPT:"> Network Address and Port Translation
-    (see <xref target="RFC2663" />).</t>
-
-    <t hangText="AS:"> an autonomous system </t>
-
-    <t hangText="FQDN:"> Fully-Qualified Domain Name </t>
-
-    <t hangText="Default-free zone:"> 
-    a set of routers that maintain a complete set of routes to
-    all currently reachable destinations. Having such a list, these routers
-    never make use of a default route. A datagram with a destination address
-    not matching any route will be dropped by such a router.
-    </t>
-
-  </list>
-  </section>
-
-<section title="Model of operation">
-
-<t>
-The opportunistic encryption security gateway (OE gateway) is a regular
-gateway node as described in <xref target="RFC0791" /> section 2.4 and  
-<xref target="RFC1009" /> with the additional capabilities described here and
-in <xref target="RFC2401" />.  
-The algorithm described here provides a way to determine, for each datagram,
-whether or not to encrypt and tunnel the datagram. Two important things
-that must be determined are whether or not to encrypt and tunnel and, if
-so, the destination address or name of the tunnel end point which should be used. 
-</t>
-
-<section title="Tunnel authorization">
-<t>
-The OE gateway determines whether or not to create a tunnel based on 
-the destination address of each packet. Upon receiving a packet with a destination
-address not recently seen, the OE gateway performs a lookup in DNS for an
-authorization resource record (see <xref target="TXT"/>). The record is located using
-the IP address to perform a search in the in-addr.arpa (IPv4) or ip6.arpa
-(IPv6) maps. If an authorization record is found, the OE gateway 
-interprets this as a request for a tunnel to be formed.
-</t>
-</section> 
-
-<section title="Tunnel end-point discovery">
-
-<t>
-The authorization resource record also provides the address or name of the tunnel
-end point which should be used.
-</t>
-<t>
-The record may also provide the public RSA key of the tunnel end point
-itself. This is provided for efficiency only. If the public RSA key is not 
-present, the OE gateway performs a second lookup to find a KEY 
-resource record for the end point address or name.
-</t>
-<t>
-Origin and integrity protection of the resource records is provided by 
-DNSSEC (<xref target="RFC2535"/>). <xref target="nodnssec"/>
-documents an optional restriction on the tunnel end point if DNSSEC signatures
-are not available for the relevant records. 
-</t>
-
-</section>
-
-<section title="Caching of authorization results">
-<t>
-The OE gateway maintains a cache, in the forwarding plane, of
-source/destination pairs for which opportunistic encryption has been
-attempted. This cache maintains a record of whether or not OE was
-successful so that subsequent datagrams can be forwarded properly
-without additional delay. 
-</t>
-
-<t>
-Successful negotiation of OE instantiates a new security association. 
-Failure to negotiate OE results in creation of a 
-forwarding policy entry either to drop or transmit in the clear future
-datagrams. This negative cache is necessary to avoid the possibly lengthy process of repeatedly looking 
-up the same information.
-</t>
-
-<t>
-The cache is timed out periodically, as described in <xref target="teardown" />.
-This removes entries that are no longer
-being used and permits the discovery of changes in authorization policy.
-</t>
-</section>
-
-</section> <!-- "Model of operation" -->
-
-</section> <!-- "Overview" -->
-
-<section title="Protocol Specification">
-
-<t>
-The OE gateway is modeled to have a forwarding plane and a control
-plane. A control channel, such as PF_KEY, connects the two planes. 
-(See <xref target="RFC2367" />.)
-The forwarding plane performs per datagram operations. The control plane
-contains a keying daemon, such as ISAKMP/IKE, and performs all
-authorization, peer authentication and key derivation functions.   
-</t>
-
-<section title="Forwarding plane state machine">
-
-<t>
-Let the OE gateway maintain a collection of objects -- a superset of the
-security policy database (SPD) specified in <xref target="RFC2401" />. For
-each combination of source and destination address, an SPD
-object exists in one of five following states.
-Prior to forwarding each datagram, the responder uses the source and
-destination addresses to pick an entry from the SPD. 
-The SPD then determines if and how the packet is forwarded.
-</t>
-
-<!-- from file forwardingstate.txt -->
-<artwork><![CDATA[
-      .--------------. 	 
-      | non-existant |
-      |    policy    |
-      `--------------'
-             |        
-             | PF_ACQUIRE
-             |           
-             |<---------.
-             V          | new packet
-      .--------------.  | (maybe resend PF_ACQUIRE)
-      |  hold policy |--'                          
-      |              |--.                          
-      `--------------'   \  pass                   
-         |        |       \ msg    .---------.     
-         |        |        \       V         | forward
-         |        |         .-------------.  | packet 
-  create |        |         | pass policy |--'       
-  IPsec  |        |         `-------------'          
-  SA     |        |                                  
-         |         \                                 
-         |          \                                
-         V           \ 	deny                         
-   .---------.        \ msg                          
-   | encrypt |         \                             
-   | policy  |          \         ,---------.        
-   `---------'           \        |         | discard
-                          \       V         | packet 
-                           .-------------.  |        
-                           | deny policy |--'        
-                           '-------------'          
-]]></artwork>
-
-
-<section title="Non-existent policy">
-<t>
-If the gateway does not find an entry, then this policy applies.
-The gateway creates an entry with an initial state of "hold policy" and requests 
-keying material from the keying daemon. The gateway does not forward the datagram,
-rather it SHOULD attach the datagram to the SPD entry as the  "first" datagram and retain it 
-for eventual transmission in a new state. 
-
-</t>
-</section>
-
-<section title="Hold policy">
-<t>
-The gateway requests keying material. If the interface to the keying
-system is lossy (PF_KEY, for instance, can be), the implementation 
-SHOULD include a mechanism to retransmit the
-keying request at a rate limited to less than 1 request per second.
-The gateway does not forward the datagram. The gateway SHOULD attach the 
-datagram to the SPD entry as the "last" datagram where it is retained 
-for eventual transmission.
-If there is a datagram already so stored, then that already stored datagram is discarded.
-</t>
-<t>
-The rational behind saving the the "first" and "last" datagrams are as follows:
-The "first" datagram is probably a TCP SYN packet. Once there is keying
-established, the gateway will release this datagram, avoiding the need to 
-for the end-point to retransmit the datagram. In the case where the connection
-was not a TCP connection, buyt was instead a streaming protocol or a DNS request,
-the "last" datagram that was retained is likely the most recent data. The difference
-between "first" and "last" may also help the end-points determine
-which data awas dropped while negotiation took place.  
-</t>
-</section>
-
-<section title="Pass-through policy">
-<t>
-The gateway forwards the datagram using the normal forwarding table. 
-The gateway enters this state only by command from the keying daemon, 
-and upon entering this state, also forwards the "first" and "last" datagrams.
-</t>
-</section>
-
-<section title="Deny policy">
-<t>
-The gateway discards the datagram. The gateway enters this state only by
-command  
-from the keying daemon, and upon entering this state, discards the "first"
-and "last" datagrams.
-An implementation MAY provide the administator with a control to determine
-if further datagrams cause ICMP messages
-to be generated (i.e. ICMP Destination Unreachable, Communication
-Administratively Prohibited. type=3, code=13). 
-</t>
-</section>
-
-<section title="Encrypt policy">
-<t>
-The gateway encrypts the datagram using the indicated security association database
-(SAD) entry.  The gateway enters this state only by command from the keying daemon, and upon entering
-this state, releases and forwards the "first" and "last" datagrams using the
-new encrypt policy.  
-</t>
-<t>
-If the associated SAD entry expires because of byte, packet or time limits, then
-the entry returns to the Hold policy, and an expire message is sent to the keying daemon.
-</t>
-</section>
-
-<t>
-All states may be created directly by the keying daemon while acting as a
-gateway. 
-</t>
-
-</section> <!-- "Datagram state machine" -->
-
-
-<section anchor="initclasses" title="Keying Daemon -- initiator">
-<t>
-Let the keying daemon maintain a collection of objects. Let them be
-called "connections" or "conn"s. There are two categories of
-connection objects: classes and instances. A class represents an
-abstract policy - what could be. An instance represents an actual connection -  
-what is implemented at the time.
-</t>
-
-<t>
-Let there be two further subtypes of connections: keying channels (Phase
-1 SAs) and data channels (Phase 2 SAs). Each data channel object may have 
-a corresponding SPD and SAD entry maintained by the datagram state machine.
-</t>
-
-<t>
-For the purposes of opportunistic encryption, there MUST, at least, be
-connection classes known as "deny", "always-clear-text", "OE-permissive", and 
-"OE-paranoid".  
-The latter two connection classes define a set of source and/or destination
-addresses for which opportunistic encryption will be attempted.
-The administrator MAY set policy options in a number of additional places.
-An implementation MAY create additional connection classes to further refine
-these policies.
-</t>
-
-<t>
-The simplest system may need only the "OE-permissive" connection, and would
-list its own (single) IP address as the source address of this policy and
-the wild-card address 0.0.0.0/0 as the destination IPv4 address. That is, the
-simplest policy is to try opportunistic encryption with all destinations. 
-</t>
-
-<t>
-The distinction between permissive and paranoid OE use will become clear 
-in the state transition differences. In general a permissive OE will, on
-failure, install a pass-through policy, while a paranoid OE will, on failure, 
-install a drop policy.
-</t>
-
-<t>
-In this description of the keying machine's state transitions, the states
-associated with the keying system itself are omitted because they are best documented in the keying system 
-(<xref target="RFC2407" />, 
-<xref target="RFC2408" /> and <xref target="RFC2409" /> for ISAKMP/IKE),
-and the details are keying system specific. Opportunistic encryption is not
-dependent upon any specific keying protocol, but this document does provide
-requirements for those using ISAKMP/IKE to assure that implementations inter-operate.
-</t>
-<t>
-The state transitions that may be involved in communicating with the
-forwarding plane are omitted. PF_KEY and similar protocols have their own
-set of states required for message sends and completion notifications.
-</t>
-<t>
-Finally, the retransmits and recursive lookups that are normal for DNS are 
-not included in this description of the state machine.
-</t>
-
-<!-- from file initiatorstate.txt -->
-<artwork><![CDATA[
-
-                       |
-	               | PF_ACQUIRE
-		       |     
-                       V
-                .---------------.       
-                |  non-existant |
-                |  connection   |
-                `---------------'
-                 |      |      |
-          send   ,      |      \
-expired   pass  /       |       \ send
-conn.     msg  /        |        \ deny
-  ^           /         |         \ msg
-  |          V          | do       \ 		 
-.---------------.       | DNS       \   .---------------.  
-|  clear-text   |	| lookup     `->|     deny      |---> expired
-|  connection   |	| for 	        |  connection   |     connection
-`---------------'	| destination   `---------------'
-   ^ ^                  |                   ^
-   | | no record        |                   |
-   | | OE-permissive    V                   | no record
-   | |            .---------------.         | OE-paranoid
-   | `------------|  potential OE |---------'
-   |              |  connection   |         ^
-   |              `---------------'         |
-   |                    |                   |
-   |                    | got TXT record    | DNSSEC failure
-   |                    | reply             |
-   |                    V                   | wrong 
-   |              .---------------.         | failure
-   |              |  authenticate |---------'
-   |              | & parse TXT RR|         ^
-   | repeated     `---------------'         |
-   | ICMP               |                   |
-   | failures           | initiate IKE to   |                         
-   | (short-timeout)    | responder         |                         
-   |                    V                   |                          
-   | phase-2      .---------------.         | failure                       
-   | failure      |   pending     |---------'                          
-   | (normal      |     OE        |         ^                          
-   |  timeout)    |               |invalid  | phase-2 failure (short-timeout)
-   |              |               |<--.SPI  | ICMP failures (normal timeout)
-   |              |               |   |     |                          
-   |              | +=======+     |---'     |                          
-   |              | |  IKE  |     |   ^     |                          
-   `--------------| | states|---------------'                          
-                  | +=======+     |   |                                
-                  `---------------'   |                                
-                        | IPsec SA    | invalid SPI                    
-                        | established |                                
-	                V             | rekey time                     
-                  .--------------.    |                                
-                  |   keyed      |<---|-------------------------------.
-                  |  connection  |----'                               |
-                  `--------------'                                    |
-                        | timer                                       |
-                        |                                             |
-                        V                                             |
-                  .--------------.     connection still active        |
-  clear-text----->|   expired    |------------------------------------'
-        deny----->|  connection  |
-                  `--------------'
-                        | dead connected - deleted
-                        V
-]]></artwork>
-
-
-<section title="Nonexistent connection">
-<t>
-There is no connection instance for a given source/destination address pair.
-Upon receipt of a request for keying material for this
-source/destination pair, the initiator searches through the connection classes to
-determine the most appropriate policy. Upon determining an appropriate
-connection class, an instance object is created of that type. 
-Both of the OE types result in a potential OE connection.
-</t>
-<t>Failure to find an appropriate connection class results in an
-administrator defined default. 
-</t>
-<t>
-In each case, when the initiator finds an appropriate class for the new flow, 
-an instance connection is made of the class which matched.
-</t>
-</section>
-
-<section title="Clear-text connection">
-<t>
-The non-existent connection makes a transition to this state when an
-always-clear-text class is instantiated, or when an OE-permissive 
-connection fails. During the transition, the initiator creates a pass-through
-policy object in the forwarding plane for the appropriate flow.
-</t>
-<t>
-Timing out is the only way to leave this state
-(see <xref target="expiring" />).
-</t>
-</section>
-
-<section title="Deny connection">
-<t>
-The empty connection makes a transition to this state when a
-deny class is instantiated, or when an OE-paranoid connection fails. 
-During the transition, the initiator creates a deny policy object in the forwarding plane 
-for the appropriate flow.  
-</t>
-<t>
-Timing out is the only way to leave this state 
-(see <xref target="expiring" />).
-</t>
-</section>
-
-<section title="Potential OE connection">
-<t>
-The empty connection makes a transition to this state when one of either OE class is instantiated.
-During the transition to this state, the initiator creates a hold policy object in the 
-forwarding plane for the appropriate flow.  
-</t>
-<t>
-In addition, when making a transition into this state, DNS lookup is done in
-the reverse-map for a TXT delegation resource record (see <xref target="TXT" />).
-The lookup key is the destination address of the flow.
-</t>
-<t>
-There are three ways to exit this state: 
-<list style="numbers">
-<t>DNS lookup finds a TXT delegation resource record.</t>
-<t>DNS lookup does not find a TXT delegation resource record.</t>
-<t>DNS lookup times out.</t>
-</list>
-</t>
-
-<t>
-Based upon the results of the DNS lookup, the potential OE connection makes a
-transition to the pending OE connection state.  The conditions for a
-successful DNS look are:
-<list style="numbers">
-<t>DNS finds an appropriate resource record</t>
-<t>It is properly formatted according to <xref target="TXT" /></t>
-<t> if DNSSEC is enabled, then the signature has been vouched for.</t>
-</list>
-
-Note that if the initiator does not find the public key 
-present in the TXT delegation record, then the public key must 
-be looked up as a sub-state. Only successful completion of all the 
-DNS lookups is considered a success.
-</t>
-<t>
-If DNS lookup does not find a resource record or DNS times out, then the 
-initiator considers the receiver not OE capable. If this is an OE-paranoid instance, 
-then the potential OE connection makes a transition to the deny connection state.
-If this is an OE-permissive instance, then the potential OE connection makes a transition to the
-clear-text connection state.
-</t>
-<t>
-If the initiator finds a resource record but it is not properly formatted, or
-if DNSSEC is 
-enabled and reports a failure to authenticate, then the potential OE
-connection makes a 
-transition to the deny connection state. This action SHOULD be logged. If the
-administrator wishes to override this transition between states, then an
-always-clear class can be installed for this flow. An implementation MAY make
-this situation a new class.
-</t>
-
-<section anchor="nodnssec" title="Restriction on unauthenticated TXT delegation records">
-<t>
-An implementation SHOULD also provide an additional administrative control
-on delegation records and DNSSEC. This control would apply to delegation
-records (the TXT records in the reverse-map) that are not protected by
-DNSSEC.
-Records of this type are only permitted to delegate to their own address as
-a gateway. When this option is enabled, an active attack on DNS will be
-unable to redirect packets to other than the original destination.
-<!-- This was asked for by Bill Sommerfeld -->
-</t>
-</section>
-</section>
-
-<section title="Pending OE connection">
-<t>
-The potential OE connection makes a transition to this state when 
-the initiator determines that all the information required from the DNS lookup is present.
-Upon entering this state, the initiator attempts to initiate keying to the gateway
-provided.  
-</t>
-<t>
-Exit from this state occurs either with a successfully created IPsec SA, or
-with a failure of some kind.  Successful SA creation results in a transition
-to the key connection state.
-</t>
-<t>
-Three failures have caused significant problems. They are clearly not the
-only possible failures from keying.
-</t>
-<t>
-Note that if there are multiple gateways available in the TXT delegation
-records, then a failure can only be declared after all have been
-tried. Further, creation of a phase 1 SA does not constitute success. A set
-of phase 2 SAs (a tunnel) is considered success.
-</t>
-<t>
-The first failure occurs when an ICMP port unreachable is consistently received
-without any other communication, or when there is silence from the remote
-end. This usually means that either the gateway is not alive, or the
-keying daemon is not functional. For an OE-permissive connection, the initiator makes a transition
-to the clear-text connection but with a low lifespan. For an OE-pessimistic connection,
-the initiator makes a transition to the deny connection again with a low lifespan. The
-lifespan in both 
-cases is kept low because the remote gateway may
-be in the process of rebooting or be otherwise temporarily unavailable. 
-</t>
-<t>
-The length of time to wait for the remote keying daemon to wake up is
-a matter of some debate. If there is a routing failure, 5 minutes is usually long
-enough for the network to
-re-converge. Many systems can reboot in that amount of
-time as well. However, 5 minutes is far too long for most users to wait to
-hear that they can not connect using OE. Implementations SHOULD make this a
-tunable parameter.
-</t>
-<t>
-The second failure occurs after a phase 1 SA has been created, but there is 
-either no response to the phase 2 proposal, or the initiator receives a 
-negative notify (the notify must be 
-authenticated). The remote gateway is not prepared to do OE at this time. 
-As before, the initiator makes a transition to the clear-text or the deny 
-connection based upon connection class, but this
-time with a normal lifespan. 
-</t>
-<t>
-The third failure occurs when there is signature failure while authenticating
-the remote gateway. This can occur when there has been a 
-key roll-over, but DNS has not caught up. In this case again, the initiator makes a 
-transition to the clear-text or the deny connection based
-upon the connection class. However, the lifespan depends upon the remaining
-time to live in the DNS. (Note that DNSSEC signed resource records have a different
-expiry time than non-signed records.) 
-<!-- dig @gateway would also work here -->
-</t>
-
-</section>
-
-<section anchor="keyed" title="Keyed connection">
-<t>
-The pending OE connection makes a transition to this state when 
-session keying material (the phase 2 SAs) is derived. The initiator creates an encrypt
-policy in the forwarding plane for this flow.
-</t>
-<t>
-There are three ways to exit this state. The first is by receipt of an
-authenticated delete message (via the keying channel) from the peer. This is
-normal teardown and results in a transition to the expired connection state.
-</t>
-<t>
-The second exit is by expiry of the forwarding plane keying material. This
-starts a re-key operation with a transition back to pending OE
-connection. In general, the soft expiry occurs with sufficient time left
-to continue to use the keys. A re-key can fail, which may
-result in the connection failing to clear-text or deny as
-appropriate. In the event of a failure, the forwarding plane
-policy does not change until the phase 2 SA (IPsec SA) reaches its
-hard expiry.
-</t>
-<t>
-The third exit is in response to a negotiation from a remote
-gateway. If the forwarding plane signals the control plane that it has received an
-unknown SPI from the remote gateway, or an ICMP is received from the remote gateway
-indicating an unknown SPI, the initiator should consider that 
-the remote gateway has rebooted or restarted. Since these 
-indications are easily forged, the implementation must 
-exercise care.  The initiator should make a cautious 
-(rate-limited) attempt to re-key the connection. 
-</t>
-</section>
-
-<section anchor="expiring" title="Expiring connection">
-<t>
-The initiator will periodically place each of the deny, clear-text, and keyed
-connections into this  
-sub-state. See <xref target="teardown" /> for more details of how often this
-occurs. 
-The initiator queries the forwarding plane for last use time of the
-appropriate 
-policy. If the last use time is relatively recent, then the connection
-returns to the 
-previous deny, clear-text or keyed connection state. If not, then the
-connection enters 
-the expired connection state. 
-</t>
-<t>
-The DNS query and answer that lead to the expiring connection state are also
-examined. The DNS query may become stale. (A negative, i.e. no such record, answer
-is valid for the period of time given by the MINIMUM field in an attached SOA 
-record. See <xref target="RFC1034" /> section 4.3.4.)
-If the DNS query is stale, then a new query is made. If the results change, then the connection 
-makes a transition to a new state as described in potential OE connection state.
-</t>
-<t> 
-Note that when considering how stale a connection is, both outgoing SPD and
-incoming SAD must be queried as some flows may be unidirectional for some time.
-</t>
-<t>
-Also note that the policy at the forwarding plane is not updated unless there
-is a conclusion that there should be a change.
-</t>
-
-</section>
-<section title="Expired connection">
-<t>
-Entry to this state occurs when no datagrams have been forwarded recently via the
-appropriate SPD and SAD objects. The objects in the forwarding plane are
-removed (logging any final byte and packet counts if appropriate) and the
-connection instance in the keying plane is deleted. 
-</t>
-<t>
-The initiator sends an ISAKMP/IKE delete to clean up the phase 2 SAs as described in
-<xref target="teardown" />. 
-</t>
-<t>
-Whether or not to delete the phase 1 SAs
-at this time is left as a local implementation issue. Implementations
-that do delete the phase 1 SAs MUST send authenticated delete messages to
-indicate that they are doing so.  There is an advantage to keeping
-the phase 1 SAs until they expire - they may prove useful again in the 
-near future.
-</t>
-</section>
-
-</section> <!-- "Keying state machine - initiator" -->
-
-<section title="Keying Daemon - responder">
-<t>
-The responder has a set of objects identical to those of the initiator.
-</t>
-<t>
-The responder receives an invitation to create a keying channel from an initiator. 
-</t>
-
-<!-- from file responderstate.txt -->
-<artwork><![CDATA[
-                |
-                | IKE main mode 
-                |  phase 1
-                V
-        .-----------------.  
-        | unauthenticated | 
-        |     OE peer     |
-        `-----------------'
-                |
-                | lookup KEY RR in in-addr.arpa 
-                |             (if ID_IPV4_ADDR)
-                | lookup KEY RR in forward
-                |             (if ID_FQDN)
-                V
-        .-----------------.  RR not found
-        |   received DNS  |---------------> log failure
-        |     reply       | 
-        `----+--------+---'
-     phase 2 |        \      misformatted 
-    proposal |         `------------------> log failure
-             V
-    .----------------.
-    |  authenticated |  identical initiator 
-    |     OE peer    |--------------------> initiator 
-    `----------------'  connection found    state machine
-         |
-         | look for TXT record for initiator
-	 |
-         V  
-   .---------------.
-   |  authorized   |---------------------> log failure
-   |    OE peer    |
-   `---------------'
-         |
-         |
-         V
-    potential OE
-    connection in
-    initiator state
-	machine
-
-
-$Id: draft-richardson-ipsec-opportunistic.xml,v 1.1 2004/03/15 20:35:24 as Exp $
-]]></artwork>
-
-
-<section title="Unauthenticated OE peer">
-<t>
-Upon entering this state, the responder starts a DNS lookup for a KEY record for the
-initiator. 
-The responder looks in the reverse-map for a KEY record for the initiator if the
-initiator has offered an ID_IPV4_ADDR, and in the forward map if the
-initiator has offered an ID_FQDN type. (See <xref target="RFC2407" /> section 
-4.6.2.1.)
-</t>
-<t>
-The responder exits this state upon successful receipt of a KEY from DNS, and use of the key 
-to verify the signature of the initiator.
-</t>
-
-<!--
-<t>
-The public key that is retrieved should be stored in stable storage for an
-administratively defined period of time, (typically several months if
-possible). If a key has previously been stored on disk, then the returned key
-should be compared to what has been received, and the key considered valid
-only if they match.  
-</t>
--->
-
-<t>
-Successful authentication of the peer results in a transition to the
-authenticated OE Peer state.
-</t>
-<t>
-Note that the unauthenticated OE peer state generally occurs in the middle of the key negotiation
-protocol. It is really a form of pseudo-state.
-</t>
-</section>
-
-<section title="Authenticated OE Peer">
-<t>
-The peer will eventually propose one or more phase 2 SAs. The responder uses the source and
-destination address in the proposal to 
-finish instantiating the connection state
-using the connection class table.
-The responder MUST search for an identical connection object at this point. 
-</t>
-<t> 
-If an identical connection is found, then the responder deletes the old instance, 
-and the new object makes a transition to the pending OE connection state. This means
-that new ISAKMP connections with a given peer will always use the latest
-instance, which is the correct one if the peer has rebooted in the interim.
-</t>
-<t> 
-If an identical connection is not found, then the responder makes the transition according to the 
-rules given for the initiator.
-</t>
-<t> 
-Note that if the initiator is in OE-paranoid mode and the responder is in 
-either always-clear-text or deny, then no communication is possible according
-to policy. An implementation is permitted to create new types of policies 
-such as "accept OE but do not initiate it". This is a local matter.
- </t>
-</section>
-
-</section> <!-- "Keying state machine - responder" -->
-
-<section anchor="teardown" title="Renewal and teardown">
-  <section title="Aging">
-<t>
-A potentially unlimited number of tunnels may exist. In practice, only a few
-tunnels are used during a period of time. Unused tunnels MUST, therefore, be
-torn down. Detecting when tunnels are no longer in use is the subject of this section.
-</t>
-
-<t>
-There are two methods for removing tunnels: explicit deletion or expiry. 
-</t>
-
-<t>
-Explicit deletion requires an IKE delete message. As the deletes
-MUST be authenticated, both ends of the tunnel must maintain the 
-key channel (phase 1 ISAKMP SA). An implementation which refuses to either maintain or
-recreate the keying channel SA will be unable to use this method.
-</t>
-
-<t>
-The tunnel expiry method simply allows the IKE daemon to
-expire normally without attempting to re-key it.
-</t>
-
-<t>
-Regardless of which method is used to remove tunnels, the implementation MUST
-a method to determine if the tunnel is still in use.  The specifics are a
-local matter, but  the FreeS/WAN project uses the following criteria. These
-criteria are currently implemented in the key management daemon, but could
-also be implemented at the SPD layer using an idle timer.
-</t>
-
-<t>
-Set a short initial (soft) lifespan of 1 minute since many net flows last
-only a few seconds.
-</t>
-
-<t>
-At the end of the lifespan, check to see if the tunnel was used by
-traffic in either direction during the last 30 seconds. If so, assign a
-longer tentative lifespan of 20 minutes after which, look again. If the
-tunnel is not in use, then close the tunnel.
-</t>
-
-<t>
-The expiring state in the key management
-system (see <xref target="expiring" />) implements these timeouts.
-The timer above may be in the forwarding plane, 
-but then it must be re-settable. 
-</t>
-
-<t>
-The tentative lifespan is independent of re-keying; it is just the time when
-the tunnel's future is next considered. 
-(The term lifespan is used here rather than lifetime for this reason.) 
-Unlike re-keying, this tunnel use check is not costly and should happen
-reasonably frequently.
-</t> 
-
-<t>
-A multi-step back-off algorithm is not considered worth the effort here.
-</t>
-
-<t>
-If the security gateway and the client host are the
-same and not a Bump-in-the-Stack or Bump-in-the-Wire implementation, tunnel
-teardown decisions MAY pay attention to TCP connection status as reported
-by the local TCP layer.  A still-open TCP connection is almost a guarantee that more traffic is
-expected. Closing of the only TCP connection through a tunnel is a
-strong hint that no more traffic is expected.
-</t>
-
-</section> <!-- "Aging" -->
-
-<section title="Teardown and cleanup">
-
-<t>
-Teardown should always be coordinated between the two ends of the tunnel by 
-interpreting and sending delete notifications. There is a
-detailed sub-state in the expired connection state of the key manager that
-relates to retransmits of the delete notifications, but this is considered to 
-be a keying system detail.
-</t>
-
-<t>
-On receiving a delete for the outbound SAs of a tunnel (or some subset of
-them), tear down the inbound ones also and notify the remote end with a
-delete. If the local system receives a delete for a tunnel which is no longer in
-existence, then two delete messages have crossed paths. Ignore the delete.
-The operation has already been completed. Do not generate any messages in this
-situation. 
-</t>
-<t>
-Tunnels are to be considered as bidirectional entities, even though the
-low-level protocols don't treat them this way. 
-</t>
-
-<t>
-When the deletion is initiated locally, rather than as a
-response to a received delete, send a delete for (all) the
-inbound SAs of a tunnel.  If the local system does not receive a responding delete 
-for the outbound SAs, try re-sending the original
-delete. Three tries spaced 10 seconds apart seems a reasonable
-level of effort. A failure of the other end to respond after 3 attempts, 
-indicates that the possibility of further communication is unlikely. Remove the outgoing SAs.
-(The remote system may be a mobile node that is no longer present or powered on.)
-</t>
-
-<t>
-After re-keying, transmission should switch to using the new
-outgoing SAs (ISAKMP or IPsec) immediately, and the old leftover
-outgoing SAs should be cleared out promptly (delete should be sent
-for the outgoing SAs) rather than waiting for them to expire. This
-reduces clutter and minimizes confusion for the operator doing diagnostics.
-</t>
-
-</section>
-
-</section>
-
-</section> <!-- "Specification" -->
-
-<section title="Impacts on IKE">
-
-  <section title="ISAKMP/IKE protocol">
-    <t>
-    The IKE wire protocol needs no modifications. The major changes are
-    implementation issues relating to how the proposals are interpreted, and from
-    whom they may come.
-    </t>
-    <t>
-    As opportunistic encryption is designed to be useful between peers without
-    prior operator configuration, an IKE daemon must be prepared to negotiate
-    phase 1 SAs with any node. This may require a large amount of resources to 
-    maintain cookie state, as well as large amounts of entropy for nonces,
-    cookies and so on. 
-    </t>
-    <t>
-    The major changes to support opportunistic encryption are at the IKE daemon
-    level. These changes relate to handling of key acquisition requests, lookup
-    of public keys and TXT records, and interactions with firewalls and other
-    security facilities that may be co-resident on the same gateway.
-    </t>
-  </section>
-
-  <section title="Gateway discovery process">
-  <t>
-  In a typical configured tunnel, the address of SG-B is provided
-  via configuration. Furthermore, the mapping of an SPD entry to a gateway is
-  typically a 1:1 mapping. When the 0.0.0.0/0 SPD entry technique is used, then
-  the mapping to a gateway is determined by the reverse DNS records.
-  </t>
-  <t>
-  The need to do a DNS lookup and wait for a reply will typically introduce a
-  new state and a new event source (DNS replies) to IKE. Although a
-synchronous DNS request can be implemented for proof of concept, experience
-is that it can cause very high latencies when a queue of queries must
-all timeout in series. 
-  </t>
-  <t> 
-  Use of an asynchronous DNS lookup will also permit overlap of DNS lookups with
-  some of the protocol steps.
-  </t>
-  </section>
-
-  <section title="Self identification">
-  <t>
-     SG-A will have to establish its identity. Use an
-     IPv4 ID in phase 1. 
-  </t>
-  <t> There are many situations where the administrator of SG-A may not be
-      able to control the reverse DNS records for SG-A's public IP address.
-      Typical situations include dialup connections and most residential-type broadband Internet access 
-      (ADSL, cable-modem) connections. In these situations, a fully qualified domain
-      name that is under the control of SG-A's administrator may be used
-      when acting as an initiator only.
-      The FQDN ID should be used in phase 1. See <xref target="fqdn" />
-      for more details and restrictions.
-  </t>
-  </section>
-
-  <section title="Public key retrieval process">
-  <t>
-     Upon receipt of a phase 1 SA proposal with either an IPv4 (IPv6) ID or
-     an FQDN ID, an IKE daemon needs to examine local caches and
-     configuration files to determine if this is part of a configured tunnel.
-     If no configured tunnels are found, then the implementation should attempt to retrieve
-     a KEY record from the reverse DNS in the case of an IPv4/IPv6 ID, or 
-     from the forward DNS in the case of FQDN ID.
-  </t>
-  <t> 
-     It is reasonable that if other non-local sources of policy are used
-     (COPS, LDAP), they be consulted concurrently but some
-     clear ordering of policy be provided. Note that due to variances in
-     latency, implementations must wait for positive or negative replies from all sources
-     of policy before making any decisions.
-  </t>
-  </section>
-  
-  <section title="Interactions with DNSSEC">
-  <t>
-     The implementation described (1.98) neither uses DNSSEC directly to
-     explicitly verify the authenticity of zone information, nor uses the NXT
-     records to provide authentication of the absence of a TXT or KEY
-     record. Rather, this implementation uses a trusted path to a DNSSEC
-     capable caching resolver. 
-  </t>
-  <t> 
-     To distinguish between an authenticated and an unauthenticated DNS
-     resource record, a stub resolver capable of returning DNSSEC
-     information MUST be used.
-  </t>
-     
-  </section>
-
-<!--
-  <section title="Interactions with COPS">
-  <t>
-     At this time there is no experience with implementations that interact
-     with COPS Policy Decision Points (PDP) <xref target="RFC2748" />. It is
-     suggested that it may be 
-     appropriate for many of 
-     the policy and discovery mechanisms outlined here to be done by a PDP.
-     In this context, the IKE daemon present in the Policy Enforcement Point
-     (PEP) may not need any modifications.
-  </t>
-  </section>
--->
-
-  <section title="Required proposal types">
-
-    <section anchor="phase1id" title="Phase 1 parameters">
-      <t>
-        Main mode MUST be used.
-      </t>
-      <t>
-	The initiator MUST offer at least one proposal using some combination
-	of: 3DES, HMAC-MD5 or HMAC-SHA1, DH group 2 or 5. Group 5 SHOULD be
-	proposed first.
-	<xref target="RFC3526" />
-      </t>
-      <t>
-	The initiator MAY offer additional proposals, but the cipher MUST not
-	be weaker than 3DES. The initiator SHOULD limit the number of proposals
-	such that the IKE datagrams do not need to be fragmented.
-      </t>
-      <t>
-	The responder MUST accept one of the proposals. If any configuration
-	of the responder is required then the responder is not acting in an
-	opportunistic way. 
-      </t>
-      <t>
-        The initiator SHOULD use an ID_IPV4_ADDR (ID_IPV6_ADDR for IPv6) of the external
-        interface of the initiator for phase 1. (There is an exception, see <xref
-        target="fqdn" />.) The authentication method MUST be RSA public key signatures. 
-        The RSA key for the initiator SHOULD be placed into a DNS KEY record in
-	the reverse space of the initiator (i.e. using in-addr.arpa or
-        ip6.arpa).
-      </t>
-    </section>
-
-    <section anchor="phase2id" title="Phase 2 parameters">
-      <t>
-        The initiator MUST propose a tunnel between the ultimate
-        sender ("Alice" or "A") and ultimate recipient ("Bob" or "B")
-        using 3DES-CBC
-        mode, MD5 or SHA1 authentication. Perfect Forward Secrecy MUST be specified.
-      </t>
-      <t>
-        Tunnel mode MUST be used.
-      </t>
-      <t>
-        Identities MUST be ID_IPV4_ADDR_SUBNET with the mask being /32.
-      </t>
-      <t>
-        Authorization for the initiator to act on Alice's behalf is determined by
-        looking for a TXT record in the reverse-map at Alice's IP address.
-      </t>
-      <t>
-        Compression SHOULD NOT be mandatory. It MAY be offered as an option.
-      </t>
-    </section>
-  </section>
-
-</section>
-
-<section title="DNS issues">
-  <section anchor="KEY" title="Use of KEY record">
-  <t>
-    In order to establish their own identities, security gateways SHOULD publish
-    their public keys in their reverse DNS via 
-    DNSSEC's KEY record.
-    See section 3 of <xref target="RFC2535">RFC 2535</xref>.
-  </t>	
-  <t>
-    <preamble>For example:</preamble>
-    <artwork><![CDATA[
-KEY 0x4200 4 1 AQNJjkKlIk9...nYyUkKK8
-]]></artwork>
-
-  <list style="hanging">
-  <t hangText="0x4200:"> The flag bits, indicating that this key is prohibited
-    for confidentiality use (it authenticates the peer only, a separate
-    Diffie-Hellman exchange is used for
-    confidentiality), and that this key is associated with the non-zone entity
-    whose name is the RR owner name. No other flags are set.</t>
-  <t hangText="4:">This indicates that this key is for use by IPsec.</t>
-  <t hangText="1:">An RSA key is present.</t>
-  <t hangText="AQNJjkKlIk9...nYyUkKK8:">The public key of the host as described in <xref target="RFC3110" />.</t> 
-  </list>
-  </t>
-  <t>Use of several KEY records allows for key rollover. The SIG Payload in
-  IKE phase 1 SHOULD be accepted if the public key given by any KEY RR
-  validates it.
-  </t>
-  </section>
-
-  <section anchor="TXT" title="Use of TXT delegation record">
-    <t>
-If, for example, machine Alice wishes SG-A to act on her behalf, then
-she publishes a TXT record to provide authorization for SG-A to act on
-Alice's behalf. Similarly for Bob and SG-B.
-</t>
-
-<t>
-These records are located in the reverse DNS (in-addr.arpa or ip6.arpa) for their
-respective IP addresses.  The reverse DNS SHOULD be secured by DNSSEC.
-DNSSEC is required to defend against active attacks.
-    </t>
-    <t>
-      If Alice's address is P.Q.R.S, then she can authorize another node to
-      act on her behalf by publishing records at:
-           <artwork><![CDATA[
-S.R.Q.P.in-addr.arpa
-          ]]></artwork>
-    </t>
-
-    <t>
-    The contents of the resource record are expected to be a string that
-    uses the following syntax, as suggested in <xref target="RFC1464">RFC1464</xref>.
-    (Note that the reply to query may include other TXT resource
-    records used by other applications.)
-
-    <figure anchor="txtformat" title="Format of reverse delegation record">
-           <artwork><![CDATA[
-X-IPsec-Server(P)=A.B.C.D KEY
-          ]]></artwork>
-    </figure>
-    </t>
-
-    where the record is formed by the following fields:
-
-    <list style="hanging"> 
-      <t hangText="P:"> Specifies a precedence for this record.  This is
-      similar to MX record preferences.  Lower numbers have stronger
-      preference. 
-      </t>  
-
-      <t hangText="A.B.C.D:"> Specifies the IP address of the Security Gateway
-      for this client machine.
-      </t>
-
-      <t hangText="KEY:"> Is the encoded RSA Public key of the Security
-      Gateway. The key is provided here to avoid a second DNS lookup. If this
-      field is absent, then a KEY resource record should be looked up in the
-      reverse-map of A.B.C.D. The key is transmitted in base64 format.
-      </t> 
-    </list>
-
-    <t>
-  	The fields of the record MUST be separated by whitespace. This
-        MAY be: space, tab, newline, or carriage return. A space is preferred.
-    </t>
-
-    <t>
-	In the case where Alice is located at a public address behind a 
-	security gateway that has no fixed address (or no control over its
-	reverse-map), then Alice may delegate to a public key by domain name.
-
-    <figure anchor="txtfqdnformat"
-            title="Format of reverse delegation record (FQDN version)">
-           <artwork><![CDATA[
-X-IPsec-Server(P)=@FQDN KEY
-          ]]></artwork>
-    </figure>
-    </t>
-
-    <list style="hanging"> 
-      <t hangText="P:"> Is as above.
-      </t>  
-
-      <t hangText="FQDN:"> Specifies the FQDN that the Security Gateway
-      will identify itself with. 
-      </t>
-
-      <t hangText="KEY:"> Is the encoded RSA Public key of the Security
-      Gateway. </t> 
-    </list>
-
-    <t>
-	If there is more than one such TXT record with strongest (lowest
-	numbered) precedence, one Security Gateway is picked arbitrarily from
-	those specified in the strongest-preference records. 
-    </t>
- 
-  <section title="Long TXT records">
-  <t>
-  When packed into transport format, TXT records which are longer than 255
-  characters are divided into smaller &lt;character-strings&gt;.
-  (See <xref target="RFC1035" /> section 3.3 and 3.3.14.) These MUST
-  be reassembled into a single string for processing.
-  Whitespace characters in the base64 encoding are to be ignored.
-  </t>
-  </section>
-
-  <section title="Choice of TXT record">
-  <t>
-	It has been suggested to use the KEY, OPT, CERT, or KX records
-	instead of a TXT record. None is satisfactory.
-  </t>
-  <t> The KEY RR has a protocol field which could be used to indicate a new protocol, 
-and an algorithm field which could be used to
-        indicate different contents in the key data. However, the KEY record
-	is clearly not intended for storing what are really authorizations,
-	it is just for identities. Other uses have been discouraged.
-  </t>
-  <t> OPT resource records, as defined in <xref target="RFC2671" /> are not 
-  intended to be used for storage of information. They are not to be loaded, 
-	cached or forwarded.  They are, therefore, inappropriate for use here.
-  </t>
-  <t>
-    CERT records <xref target="RFC2538" /> can encode almost any set of
-    information. A custom type code could be used permitting any suitable
-    encoding to be stored, not just X.509.  According to
-    the RFC, the certificate RRs are to be signed internally which may add undesirable 
-and unnecessary bulk. Larger DNS records may require TCP instead of UDP transfers.
-  </t>
-  <t>
-    At the time of protocol design, the CERT RR was not widely deployed and
-    could not be counted upon. Use of CERT records will be investigated,
-    and may be proposed in a future revision of this document.
-  </t>
-  <t>
-    KX records are ideally suited for use instead of TXT records, but had not been deployed at
-    the time of implementation.
-<!-- Jakob Schlyter <j@crt.se> confirmed -->
-  </t>	
-  </section>
-  </section>
-
-  <section anchor="fqdn" title="Use of FQDN IDs">
-    <t>
-      Unfortunately, not every administrator has control over the contents
-      of the reverse-map.  Where the initiator (SG-A) has no suitable reverse-map, the
-      authorization record present in the reverse-map of Alice may refer to a
-      FQDN instead of an IP address.
-    </t>
-    <t>
-      In this case, the client's TXT record gives the fully qualified domain
-      name (FQDN) in place of its security gateway's IP address. 
-      The initiator should use the ID_FQDN ID-payload in phase 1.
-      A forward lookup for a KEY record on the FQDN must yield the
-      initiator's public key. 
-    </t>
-    <t>
-      This method can also be used when the external address of SG-A is
-      dynamic. 
-    </t>
-    <t>
-      If SG-A is acting on behalf of Alice, then Alice must still delegate
-      authority for SG-A to do so in her reverse-map. When Alice and SG-A
-      are one and the same (i.e. Alice is acting as an end-node) then there
-      is no need for this when initiating only. </t>
-    <t>However, Alice must still delegate to  herself if she wishes others to
-       initiate OE to her.  See <xref target="txtfqdnformat" />.
-    </t>
-    <
-  </section> 
-
-<section title="Key roll-over">
-<t>
-Good cryptographic hygiene says that one should replace public/private key pairs
-periodically. Some administrators may wish to do this as often as daily. Typical DNS
-propagation delays are determined by the SOA Resource Record MINIMUM
-parameter, which controls how long DNS replies may be cached. For reasonable
-operation of DNS servers, administrators usually want this value to be at least several 
-hours, sometimes as a long as a day. This presents a problem - a new key MUST
-not be used prior to it propagating through DNS.
-</t>
-<t>
-This problem is dealt with by having the Security Gateway generate a new
-public/private key pair at least MINIMUM seconds in advance of using it. It
-then adds this key to the DNS (both as a second KEY record and in additional TXT
-delegation records) at key generation time. Note: only one key is allowed in
-each TXT record.
-</t>
-<t>
-When authenticating, all gateways MUST have available all public keys 
-that are found in DNS for this entity. This permits the authenticating end
-to check both the key for "today" and the key for "tomorrow". Note that it is 
-the end which is creating the signature (possesses the private key) that
-determines which key is to be used.
-</t>
-
-  </section>
-</section>
-
-
-<section title="Network address translation interaction">
-  <t>
-     There are no fundamentally new issues for implementing opportunistic encryption
-     in the presence of network address translation. Rather there are 
-     only the regular IPsec issues with NAT traversal.
-  </t>
-  <t>
-     There are several situations to consider for NAT.
-  </t>
-  <section title="Co-located NAT/NAPT">
-    <t>
-       If a security gateway is also performing network address translation on
-       behalf of an end-system, then the packet should be translated prior to
-       being subjected to opportunistic encryption. This is in contrast to
-       typically configured tunnels which often exist to bridge islands of 
-       private network address space. The security gateway will use the translated source
-       address for phase 2, and so the responding security gateway will look up that address to
-       confirm SG-A's authorization. 
-    </t>
-    <t> In the case of NAT (1:1), the address space into which the
-        translation is done MUST be globally unique, and control over the
-	reverse-map is assumed.
-        Placing of TXT records is possible.
-    </t>
-    <t> In the case of NAPT (m:1), the address will be the security
-        gateway itself. The ability to get
-        KEY and TXT records in place will again depend upon whether or not
-	there is administrative control over the reverse-map. This is
-	identical to situations involving a single host acting on behalf of
-	itself. 
-
-	FQDN style can be used to get around a lack of a reverse-map for
-	initiators only.
-    </t>
-  </section>
-
-  <section title="Security Gateway behind NAT/NAPT">
-    <t>
-       If there is a NAT or NAPT between the security gateways, then normal IPsec
-       NAT traversal problems occur. In addition to the transport problem
-       which may be solved by other mechanisms, there is the issue of
-       what phase 1 and phase 2 IDs to use. While FQDN could
-       be used during phase 1 for the security gateway, there is no appropriate ID for phase 2.
-       Due to the NAT, the end systems live in different IP address spaces.
-    </t>
-  </section>
-
-  <section title="End System is behind a NAT/NAPT">
-    <t>
-       If the end system is behind a NAT (perhaps SG-B), then there is, in fact, no way for
-       another end system to address a packet to this end system.
-       Not only is opportunistic encryption
-       impossible, but it is also impossible for any communication to
-       be initiate to the end system. It may be possible for this end
-       system to initiate in such communication. This creates an asymmetry, but this is common for 
-       NAPT.
-    </t>
-  </section>
-</section>
-
-<section title="Host implementations">
-<t>
-  When Alice and SG-A are components of the same system, they are
-  considered to be a host implementation. The packet sequence scenario remains unchanged.
-</t>
-<t>
-  Components marked Alice are the upper layers (TCP, UDP, the
-  application), and SG-A is the IP layer.
-</t>
-<t>
-  Note that tunnel mode is still required. 
-</t>
-<t>
-  As Alice and SG-A are acting on behalf of themselves, no TXT based delegation
-  record is necessary for Alice to initiate. She can rely on FQDN in a
-  forward map. This is particularly attractive to mobile nodes such as 
-  notebook computers at conferences.
-  To respond, Alice/SG-A will still need an entry in Alice's reverse-map.
-</t>
-</section>
-
-<section title="Multi-homing">
-<t> 
-If there are multiple paths between Alice and Bob (as illustrated in
-the diagram with SG-D), then additional DNS records are required to establish
-authorization. 
-</t>
-<t>
-In <xref target="networkdiagram" />, Alice has two ways to
-exit her network: SG-A and SG-D. Previously SG-D has been ignored. Postulate
-that there are routers between Alice and her set of security gateways
-(denoted by the + signs and the marking of an autonomous system number for
-Alice's network). Datagrams may, therefore, travel to either SG-A or SG-D en
-route to Bob.
-</t>
-<t>
-As long as all network connections are in good order, it does not matter how
-datagrams exit Alice's network. When they reach either security gateway, the
-security gateway will find the TXT delegation record in Bob's reverse-map,
-and establish an SA with SG-B. 
-</t>
-<t>
-SG-B has no problem establishing that either of SG-A or SG-D may speak for
-Alice, because Alice has published two equally weighted TXT delegation records:
-    <figure anchor="txtmultiexample"
-    title="Multiple gateway delegation example for Alice">
-           <artwork><![CDATA[
-X-IPsec-Server(10)=192.1.1.5 AQMM...3s1Q==
-X-IPsec-Server(10)=192.1.1.6 AAJN...j8r9==
-          ]]></artwork>
-    </figure>
-</t>
-<t>
-Alice's routers can now do any kind of load sharing needed. Both SG-A and SG-D send datagrams addressed to Bob through
-their tunnel to SG-B. 
-</t>
-<t>
-Alice's use of non-equal weight delegation records to show preference of one gateway over another, has relevance only when SG-B 
-is initiating to Alice. 
-</t>
-<t>
-If the precedences are the same, then SG-B has a more difficult time. It
-must decide which of the two tunnels to use. SG-B has no information about
-which link is less loaded, nor which security gateway has more cryptographic
-resources available. SG-B, in fact, has no knowledge of whether both gateways
-are even reachable.  
-</t>
-<t>
-The Public Internet's default-free zone may well know a good route to Alice,
-but the datagrams that SG-B creates must be addressed to either SG-A or SG-D;
-they can not be addressed to Alice directly.
-</t>
-<t>
-SG-B may make a number of choices:
-<list style="numbers">
-<t>It can ignore the problem and round robin among the tunnels. This
-      causes losses during times when one or the other security gateway is
-      unreachable. If this worries Alice, she can change the weights in her
-      TXT delegation records.</t>
-
-<t>It can send to the gateway from which it most recently received datagrams. 
-      This assumes that routing and reachability are symmetrical.</t>
-
-<t>It can listen to BGP information from the Internet to decide which
-      system is currently up. This is clearly much more complicated, but if SG-B is already participating
-      in the BGP peering system to announce Bob, the results data may already
-      be available to it. </t>
-
-<t>It can refuse to negotiate the second tunnel. (It is unclear whether or
-not this is even an option.)</t>
-
-<t>It can silently replace the outgoing portion of the first tunnel with the
-second one while still retaining the incoming portions of both. SG-B can,
-thus, accept datagrams from either SG-A or SG-D, but
-send only to the gateway that most recently re-keyed with it.</t> 
-</list>
-</t>
-
-<t>
-Local policy determines which choice SG-B makes. Note that even if SG-B has perfect
-knowledge about the reachability of SG-A and SG-D, Alice may not be reachable
-from either of these security gateways because of internal reachability
-issues. 
-</t>
-
-<t>
-FreeS/WAN implements option 5.  Implementing a different option is
-being considered. The multi-homing aspects of OE are not well developed and may
-be the subject of a future document.
-</t>
-	
-</section>
-
-<section title="Failure modes">
-  <section title="DNS failures">
-  <t>
-  If a DNS server fails to respond, local policy decides
-  whether or not to permit communication in the clear as embodied in
-  the connection classes in <xref target="initclasses" />.
-  It is easy to mount a denial of service attack on the DNS server
-  responsible for a particular network's reverse-map.
-  Such an attack may cause all communication with that network to go in
-  the clear if the policy is permissive, or fail completely 
-  if the policy is paranoid. Please note that this is an active attack.
-  </t>
-  <t>
-  There are still many networks
-  that do not have properly configured reverse-maps. Further, if the policy is not to communicate,
-  the above denial of service attack isolates the target network. Therefore, the decision of whether 
-or not to permit communication in the clear MUST be a matter of local policy.
-  </t>
-  </section>
-
-  <section title="DNS configured, IKE failures">
-  <t>
-  DNS records claim that opportunistic encryption should
-  occur, but the target gateway either does not respond on port 500, or
-  refuses the proposal. This may be because of a crash or reboot, a
-  faulty configuration, or a firewall filtering port 500.  
-  </t>
-  <t>
-  The receipt of ICMP port, host or network unreachable
-  messages indicates a potential problem, but MUST NOT cause communication
-  to fail 
-  immediately. ICMP messages are easily forged by attackers. If such a
-  forgery caused immediate failure, then an active attacker could easily
-  prevent any 
-  encryption from ever occurring, possibly preventing all communication.
-  </t>
-  <t>
-  In these situations a clear log should be produced
-  and local policy should dictate if communication is then
-  permitted in the clear.
-  </t>
-  </section>
-
-  <section title="System reboots">
-<t>
-Tunnels sometimes go down because the remote end crashes,
-disconnects, or has a network link break.  In general there is no
-notification of this.  Even in the event of a crash and successful reboot, 
-other SGs don't hear about it unless the rebooted SG has specific 
-reason to talk to them immediately.  Over-quick response to temporary 
-network outages is undesirable.  Note that a tunnel can be torn
-down and then re-established without any effect visible to the user
-except a pause in traffic. On the other hand, if one end reboots,
-the other end can't get datagrams to it at all (except via
-IKE) until the situation is noticed.  So a bias toward quick
-response is appropriate even at the cost of occasional
-false alarms.
-</t>
-
-<t>
-A mechanism for recovery after reboot is a topic of current research and is not specified in this
-document.
-</t>
-
-<t>
-A deliberate shutdown should include an attempt, using deletes, to notify all other SGs
-currently connected by phase 1 SAs that communication is
-about to fail.  Again, a remote SG will assume this is a teardown.  Attempts by the
-remote SGs to negotiate new tunnels as replacements should be ignored. When possible, 
-SGs should attempt to preserve information about currently-connected SGs in non-volatile storage, so
-that after a crash, an Initial-Contact can be sent to previous partners to
-indicate loss of all previously established connections.
-</t>
-
-  </section>
-</section>
-
-<!--
-<section title="Performance experiences">
-
-    Claudia> Is it useful to point out (or to clarify for our own discussion) any of the
-    Claudia> following:
-
-    Claudia> *  how much time this is likely to take on typical current hardware?
-    Claudia> *  what steps are likely to be time consuming
-    Claudia> *  how any added time could affect a typical transaction, such as hitting 
-    Claudia>    a web site
-    Claudia> *  any ways to minimize such time delays
-
-  <section title="Introduced latency">
-  </section>
-
-  <section title="Cryptographic performance">
-  </section>
-
-  <section title="Phase 1 SA performance">
-  </section>
-
-</section>
--->
-
-<section title="Unresolved issues">
-  <section title="Control of reverse DNS">
-  <t>
-  The method of obtaining information by reverse DNS lookup causes
-  problems for people who cannot control their reverse DNS
-  bindings. This is an unresolved problem in this version, and is out
-  of scope.
-  </t>
-  </section>
-</section>
-
-<section title="Examples">
-
-<section title="Clear-text usage (permit policy)">
-
-<t>
-Two example scenarios follow. In the first example GW-A
-(Gateway A) and GW-B (Gateway B) have always-clear-text policies, and in the second example they have an OE
-policy. The clear-text policy serves as a reference for what occurs in
-TCP/IP in the absence of Opportunistic Encryption.
-
-<t>
-Alice wants to communicate with Bob. Perhaps she wants to retrieve a
-web page from Bob's web server. In the absence of opportunistic
-encryptors, the following events occur: 
-</t>
-
-       <figure anchor="regulartiming" title="Timing of regular transaction">
-           <artwork><![CDATA[
-  Alice         SG-A       DNS       SG-B           Bob
-   Human or application
-   'clicks' with a name.
-   (1)
-
-    ------(2)-------------->
-    Application looks up
-    name in DNS to get
-    IP address.
-
-    <-----(3)---------------
-    Resolver returns "A" RR
-    to application with IP 
-    address.
-
-   (4)
-   Application starts a TCP session
-   or UDP session and OS sends
-   first datagram
-
-       ----(5)----->
-       Datagram is seen at first gateway
-       from Alice (SG-A). 
-
-                   ----------(6)------>
-                   Datagram traverses
-                   network.
-
-                                       ------(7)----->
-                                       Datagram arrives
-                                       at Bob, is provided
-                                       to TCP.
-
-                                      <------(8)------
-                                       A reply is sent.
-
-                   <----------(9)------
-                   Datagram traverses
-                   network.
-    <----(10)-----
-    Alice receives
-    answer.
-
-   (11)----------->
-    A second exchange
-    occurs.
-                   ----------(12)----->
-                                       -------------->
-                                      <---------------
-                   <-------------------
-    <-------------
-          ]]></artwork>
-</figure>
-
-</t>
-</section>
-
-<section title="Opportunistic encryption">
-
-<t>
-In the presence of properly configured opportunistic encryptors, the
-event list is extended. Only changes are annotated.
-</t>
-
-<t>The following symbols are used in the time-sequence diagram</t>
-
-<t>
-<list style="hanging">
-    <t hangText="-"> A single dash represents clear-text datagrams.</t>
-    <t hangText="="> An equals sign represents phase 2 (IPsec) cipher-text
-        datagrams.</t> 
-    <t hangText="~"> A single tilde represents clear-text phase 1 datagrams.</t>
-    <t hangText="#"> A hash sign represents phase 1 (IKE) cipher-text
-        datagrams.</t> 
-</list>
-</t>
-
-<t>
-<figure anchor="opportunistictiming" title="Timing of opportunistic encryption transaction">
-           <artwork><![CDATA[
-  Alice          SG-A      DNS       SG-B           Bob
-   (1)
-    ------(2)-------------->
-    <-----(3)---------------
-   (4)----(5)----->+
-      SG-A sees datagram 
-      to new target and
-      saves it as "first"
-
-                  ----(5B)->
-                  SG-A asks DNS 
-                  for TXT RR.
-
-                  <---(5C)--
-                  DNS returns TXT RR.
-
-                  ~~~~~~~~~~~~~(5D)~~~>
-                  initial IKE main mode 
-                  packet is sent.       
-
-                  <~~~~~~~~~~~~(5E1)~~~
-                  ~~~~~~~~~~~~~(5E2)~~>
-                  <~~~~~~~~~~~~(5E3)~~~
-                  IKE phase 1 - privacy.
-
-                  #############(5E4)##>
-                  SG-A sends ID to SG-B
-                           <----(5F1)--
-                            SG-B asks DNS
-                            for SG-A's public 
-                            KEY
-                           -----(5F2)->
-                            DNS provides KEY RR.
-                            SG-B authenticates SG-A
-
-                  <############(5E5)###
-                  IKE phase 1 - complete
-                           
-                  #############(5G1)##>
-                  IKE phase 2 - Alice<->Bob
-                  tunnel is proposed.
-
-                           <----(5H1)--
-                            SG-B asks DNS for
-                            Alice's TXT record.
-                           -----(5H2)->
-                            DNS replies with TXT
-                            record. SG-B checks
-                            SG-A's authorization.
-
-                  <############(5G2)###
-                   SG-B accepts proposal.
-
-                  #############(5G3)##>
-                   SG-A confirms.
-
-                   ============(6)====>
-                    SG-A sends "first"
-                    packet in new IPsec
-                    SA.
-                                       ------(7)----->
-                                        packet is decrypted
-                                        and forward to Bob.
-                                      <------(8)------
-                  <==========(9)======
-                    return packet also
-                    encrypted.
-    <-----(10)----
-
-   (11)----------->
-     a second packet
-     is sent by Alice
-                   ==========(12)=====>
-                    existing tunnel is used
-                                       -------------->
-                                      <---------------
-                   <===================
-    <-------------
-          ]]></artwork>
-</figure>
-
-</t>
-
-  <t>
-  For the purposes of this section, we will describe only the changes that
-  occur between <xref target="regulartiming" /> and
-  <xref target="opportunistictiming" />. This corresponds to time points 5, 6, 7, 9 and 10 on the list above. 
-  </t>
-
-<list style="symbols">
-  <t>
-    At point (5), SG-A intercepts the datagram because this source/destination pair lacks a policy 
-(the non-existent policy state). SG-A creates a hold policy, and buffers the datagram. SG-A requests keys from the keying daemon. 
-    </t>
-
-    <t>
-    SG-A's IKE daemon, having looked up the source/destination pair in the connection
-    class list, creates a new Potential OE connection instance. SG-A starts DNS
-    queries.
-    </t>
-  </section>
-
-  <section title="(5C) DNS returns TXT record(s)">
-
-  <t>
-  DNS returns properly formed TXT delegation records, and SG-A's IKE daemon
-  causes this instance to make a transition from Potential OE connection to Pending OE
-  connection.
-  </t>
-
-    <t>
-      Using the example above, the returned record might contain:
-
-    <figure anchor="txtexample"
-    title="Example of reverse delegation record for Bob">
-           <artwork><![CDATA[
-X-IPsec-Server(10)=192.1.1.5 AQMM...3s1Q==
-          ]]></artwork>
-    </figure>
-    with SG-B's IP address and public key listed.
-    </t>
-
-  </section>
-
-  <section title="(5D) Initial IKE main mode packet goes out">
-  <t>Upon entering Pending OE connection, SG-A sends the initial ISAKMP
-  message with proposals. See <xref target="phase1id" />.
-  </t>
-  </section>
-
-  <section title="(5E1) Message 2 of phase 1 exchange">
-  <t>
-  SG-B receives the message. A new connection instance is created in the
-  unauthenticated OE peer state.
-  </t>
-  </section>
-
-  <section title="(5E2) Message 3 of phase 1 exchange">
-  <t>
-  SG-A sends a Diffie-Hellman exponent. This is an internal state of the
-  keying daemon.
-  </t>
-  </section>
-
-  <section title="(5E3) Message 4 of phase 1 exchange">
-  <t>
-  SG-B responds with a Diffie-Hellman exponent. This is an internal state of the
-  keying protocol.
-  </t>
-  </section>
-
-  <section title="(5E4) Message 5 of phase 1 exchange">
-  <t>
-  SG-A uses the phase 1 SA to send its identity under encryption. 
-  The choice of identity is discussed in <xref target="phase1id" />.
-  This is an internal state of the keying protocol.
-  </t>
-  </section>
-
-  <section title="(5F1) Responder lookup of initiator key">
-  <t>
-  SG-B asks DNS for the public key of the initiator. 
-  DNS looks for a KEY record by IP address in the reverse-map.
-  That is, a KEY resource record is queried for 4.1.1.192.in-addr.arpa
-  (recall that SG-A's external address is 192.1.1.4).
-  SG-B uses the resulting public key to authenticate the initiator. See <xref
-  target="KEY" /> for further details. 
-  </t>
-  </section>
-
-<section title="(5F2) DNS replies with public key of initiator">
-<t>
-Upon successfully authenticating the peer, the connection instance makes a
-transition to authenticated OE peer on SG-B.
-</t>
-<t>
-The format of the TXT record returned is described in
-<xref target="TXT" />. 
-</t>
-</section>
-
-  <section title="(5E5) Responder replies with ID and authentication">
-  <t>
-    SG-B sends its ID along with authentication material. This is an internal
-    state for the keying protocol.
-  </t>
-  </section>
-
-  <section title="(5G) IKE phase 2">
-    <section title="(5G1) Initiator proposes tunnel">
-    <t>
-    Having established mutually agreeable authentications (via KEY) and
-    authorizations (via TXT), SG-A proposes to create an IPsec tunnel for
-    datagrams transiting from Alice to Bob. This tunnel is established only for 
-    the Alice/Bob combination, not for any subnets that may be behind SG-A and SG-B.
-    </t>
-    </section>
-
-    <section title="(5H1) Responder determines initiator's authority">
-    <t>
-    While the identity of SG-A has been established, its authority to
-    speak for Alice has not yet been confirmed. SG-B does a reverse
-    lookup on Alice's address for a TXT record. 
-    </t>
-    <t>Upon receiving this specific proposal, SG-B's connection instance
-    makes a transition into the potential OE connection state. SG-B may already have an
-    instance, and the check is made as described above.</t>
-    </section>
-  
-    <section title="(5H2) DNS replies with TXT record(s)">
-    <t>
-      The returned key and IP address should match that of SG-A.
-    </t>	
-    </section>
-    
-    <section title="(5G2) Responder agrees to proposal">
-    <t>
-    Should additional communication occur between, for instance, Dave and Bob using
-    SG-A and SG-B, a new tunnel (phase 2 SA) would be established. The phase 1 SA
-    may be reusable.
-    </t>
-    <t>SG-A, having successfully keyed the tunnel, now makes a transition from
-    Pending OE connection to Keyed OE connection.
-    </t>
-    <t>The responder MUST setup the inbound IPsec SAs before sending its reply.</t>
-    </section>
-
-    <section title="(5G3) Final acknowledgment from initiator">
-    <t>
-    The initiator agrees with the responder's choice and sets up the tunnel.
-    The initiator sets up the inbound and outbound IPsec SAs.
-    </t>
-    <t>
-    The proper authorization returned with keys prompts SG-B to make a transition
-    to the keyed OE connection state. 
-    </t>
-    <t>Upon receipt of this message, the responder may now setup the outbound
-    IPsec SAs.</t> 
-    </section>
-  </section>
-
-  <section title="(6) IPsec succeeds, and sets up tunnel for communication between Alice and Bob">
-  <t>
-  SG-A sends the datagram saved at step (5) through the newly created
-  tunnel to SG-B, where it gets decrypted and forwarded. 
-  Bob receives it at (7) and replies at (8). 
-  </t>
-  </section>
-
-  <section title="(9) SG-B already has tunnel up with G1 and uses it">
-  <t>
-  At (9), SG-B has already established an SPD entry mapping Bob->Alice via a
-  tunnel, so this tunnel is simply applied. The datagram is encrypted to SG-A,
-  decrypted by SG-A and passed to Alice at (10).
-  </t>
-
-  </section>
-</section> <!-- OE example -->
-
-</section> <!-- Examples -->
-
-<section anchor="securityconsiderations" title="Security considerations">
-
-  <section title="Configured vs opportunistic tunnels">
-<t>
-    Configured tunnels are those which are setup using bilateral mechanisms: exchanging 
-public keys (raw RSA, DSA, PKIX), pre-shared secrets, or by referencing keys that
-are in known places (distinguished name from LDAP, DNS). These keys are then used to
-configure a specific tunnel. 
-</t>
-<t>
-A pre-configured tunnel may be on all the time, or may be keyed only when needed. 
-The end points of the tunnel are not necessarily static: many mobile
-applications (road warrior) are considered to be configured tunnels. 
-</t>
-<t>
-The primary characteristic is that configured tunnels are assigned specific
-security properties. They may be trusted in different ways relating to exceptions to 
-firewall rules, exceptions to NAT processing, and to bandwidth or other quality of service restrictions. 
-</t>
-<t>
-Opportunistic tunnels are not inherently trusted in any strong way. They are
-created without prior arrangement. As the two parties are strangers, there
-MUST be no confusion of datagrams that arrive from opportunistic peers and
-those that arrive from configured tunnels. A security gateway MUST take care
-that an opportunistic peer can not impersonate a configured peer.
-</t>
-<t>
-Ingress filtering MUST be used to make sure that only datagrams authorized by
-negotiation (and the concomitant authentication and authorization) are
-accepted from a tunnel. This is to prevent one peer from impersonating another. 
-</t>
-<t>
-An implementation suggestion is to treat opportunistic tunnel
-datagrams as if they arrive on a logical interface distinct from other
-configured tunnels. As the number of opportunistic tunnels that may be
-created automatically on a system is potentially very high, careful attention 
-to scaling should be taken into account.
-</t>
-<t>
-As with any IKE negotiation, opportunistic encryption cannot be secure
-without authentication. Opportunistic encryption relies on DNS for its
-authentication information and, therefore, cannot be fully secure without
-a secure DNS. Without secure DNS, opportunistic encryption can protect against passive
-eavesdropping but not against active man-in-the-middle attacks.
-</t>
-  </section>
-
-  <section title="Firewalls versus Opportunistic Tunnels">
-<t>
-  Typical usage of per datagram access control lists is to implement various
-kinds of security gateways. These are typically called "firewalls". 
-</t>
-<t>
-  Typical usage of a virtual private network (VPN) within a firewall is to
-bypass all or part of the access controls between two networks. Additional
-trust (as outlined in the previous section) is given to datagrams that arrive
-in the VPN.
-</t>
-<t> 
-  Datagrams that arrive via opportunistically configured tunnels MUST not be
-trusted. Any security policy that would apply to a datagram arriving in the
-clear SHOULD also be applied to datagrams arriving opportunistically.
-</t>
-  </section>
-
-  <section title="Denial of service">
-<t>
-  There are several different forms of denial of service that an implementor 
-  should concern themselves with. Most of these problems are shared with
-  security gateways that have large numbers of mobile peers (road warriors). 
-</t>
-<t>
-  The design of ISAKMP/IKE, and its use of cookies, defend against many kinds
-  of denial of service. Opportunism changes the assumption that if the phase 1 (ISAKMP) 
-  SA is authenticated, that it was worthwhile creating. Because the gateway will communicate with any machine, it is
-  possible to form phase 1 SAs with any machine on the Internet. 
-</t>
-
-</section>
-</section>
-
-<section title="IANA Considerations">
-<t>
-    There are no known numbers which IANA will need to manage.
-</t>
-</section>
-
-<section title="Acknowledgments">
-<t>
-        Substantive portions of this document are based upon previous work by
-        Henry Spencer.
-</t>
-<t>
-	Thanks to Tero Kivinen, Sandy Harris, Wes Hardarker, Robert Moskowitz,
-	Jakob Schlyter, Bill Sommerfeld, John Gilmore and John Denker for their
-	comments and constructive criticism.
-</t>
-<t>
-	Sandra Hoffman and Bill Dickie did the detailed proof reading and editing.
-</t>
-</section>
-
-</middle>
-
-<back>
-<references title="Normative references">
-<?rfc include="reference.OEspec" ?>
-<!-- renumber according to reference order -->
-<?rfc include="reference.RFC.0791" ?>
-<?rfc include="reference.RFC.1009" ?>
-<?rfc include="reference.RFC.1984" ?>
-<?rfc include="reference.RFC.2119" ?>
-<!-- IPsec -->
-<?rfc include="reference.RFC.2367" ?>
-<?rfc include="reference.RFC.2401" ?>
-<?rfc include="reference.RFC.2407" ?>
-<?rfc include="reference.RFC.2408" ?>
-<?rfc include="reference.RFC.2409" ?>
-<!-- MODPGROUPS -->
-<?rfc include="reference.RFC.3526" ?>
-<!-- DNSSEC -->
-<?rfc include="reference.RFC.1034" ?>
-<?rfc include="reference.RFC.1035" ?>
-<?rfc include="reference.RFC.2671" ?>
-<?rfc include="reference.RFC.1464" ?>
-<?rfc include="reference.RFC.2535" ?>
-<?rfc include="reference.RFC.3110" ?>
-<?rfc include="reference.RFC.2538" ?>
-<!-- COPS -->
-<?rfc include="reference.RFC.2748" ?>
-<!-- NAT -->
-<?rfc include="reference.RFC.2663" ?>
-</references>
-<!-- <references title="Non-normative references"> -->
-<!-- ESPUDP -->
-<!-- <?rfc include="reference.ESPUDP" ?> -->
-<!-- </references> -->
-</back>
-</rfc>
-<!--
-  $Id: draft-richardson-ipsec-opportunistic.xml,v 1.1 2004/03/15 20:35:24 as Exp $
-
-  $Log: draft-richardson-ipsec-opportunistic.xml,v $
-  Revision 1.1  2004/03/15 20:35:24  as
-  added files from freeswan-2.04-x509-1.5.3
-
-  Revision 1.33  2003/06/30 03:19:59  mcr
-  	timing-diagram with inline explanation.
-
-  Revision 1.32  2003/06/30 01:57:44  mcr
-  	initial edits per-Bob Braden.
-
-  Revision 1.31  2003/05/26 19:31:23  mcr
-  	updates to drafts - IPSEC RR - SC versions, and RFC3526
-  	reference in OE draft.
-
-  Revision 1.30  2003/05/21 15:42:34  mcr
-  	updates due to publication of RFC 3526.
-
-  Revision 1.29  2003/01/17 16:22:55  mcr
-  	rev 11 of OE draft.
-
-  Revision 1.28  2002/07/25 19:27:31  mcr
-  	added DHR's minor edits.
-
-  Revision 1.27  2002/07/21 16:26:26  mcr
-  	slides from presentation at OLS
-  	draft-10 of OE draft.
-
-  Revision 1.26  2002/07/16 03:46:53  mcr
-  	second edits from Sandra.
-
-  Revision 1.25  2002/07/16 03:36:14  mcr
-  	removed HS from authors list
-  	updated reference inclusion to use <?rfc-include directive.
-  Revision 1.24  2002/07/11 02:08:21  mcr
-  	updated XML file from Sandra
-
-  Revision 1.23  2002/06/06 17:18:53  mcr
-  	spellcheck.
-
-  Revision 1.22  2002/06/06 17:14:19  mcr
-  	results of hand-editing session from May 28th.
-  	This is FINAL OE draft.
-
-  Revision 1.21  2002/06/06 02:25:44  mcr
-  	results of hand-editing session from May 28th.
-  	This is FINAL OE draft.
-
-  Revision 1.20  2002/05/24 03:28:37  mcr
-  	changes as requested by RFC editor.
-
-  Revision 1.19  2002/04/09 16:01:05  mcr
-  	comments from PHB.
-
-  Revision 1.18  2002/04/08 02:14:34  mcr
-  	RGBs changes to rev6.
-
-  Revision 1.17  2002/03/12 21:23:55  mcr
-  	adjusted definition of default-free zone.
-  	moved text on key rollover from format description to new
-  	section.
-
-  Revision 1.16  2002/02/22 01:23:21  mcr
-  	revisions from MCR (2002/2/18) and net.
-
-  Revision 1.15  2002/02/21 20:44:12  mcr
-  	extensive from DHR.
-
-  Revision 1.14  2002/02/10 16:20:39  mcr
-  	-05 draft. Many revisions to do "OE system in world of OE systems"
-  	view of the universe.
-
-  Revision 1.13  2001/12/20 04:35:22  mcr
-  	fixed reference to rfc1984.
-
-  Revision 1.12  2001/12/20 03:35:19  mcr
-  	comments from Henry, Tero, and Sandy.
-
-  Revision 1.11  2001/12/19 07:26:22  mcr
-  	added comment about KX records.
-
-  Revision 1.10  2001/11/09 04:28:10  mcr
-  	fixed some typos with XML, and one s/SG-B/SG-D/.
-
-  Revision 1.9  2001/11/09 04:07:13  mcr
-  	expanded section 10: multihoming, with an example.
-
-  Revision 1.8  2001/11/09 02:16:51  mcr
-  	added lifetime/lifespan definitions.
-  	moved example from 5B to 5C.
-  	added reference to phase 1 IDs to 5D.
-  	cleared up text in aging section.
-  	added text about delegation of DNSSEC activity to a DNS server.
-  	spelt out DH group names.
-  	added text about ignoring TXT records unless DNSSEC is deployed (somerfeld)
-  	added example of TXT delegation using FQDN.
-  	clarified some text in NAT interaction section.
-  	clarified absense of TXT record need for host implementation
-
-  Revision 1.7  2001/11/08 23:09:37  mcr
-  	changed revision of draft to 03.
-
-  Revision 1.6  2001/11/08 19:37:14  mcr
-  	fixed some formatting of Aging section.
-
-  Revision 1.5  2001/11/08 19:19:30  mcr
-  	fixed address for DHR, updated address for MCR,
-  	added reference to original HS/DHR OE specification paper.
-
-  Revision 1.4  2001/11/08 19:08:24  mcr
-  	section 10, "Renewal and Teardown" added moved between 4/5, and
-  	slightly rewritten.
-
-  Revision 1.3  2001/11/08 18:56:34  mcr
-  	sections 4.2, 5.6, 5.7.1 and 6.2 edited as per HS.
-  	section 10, "Renewal and Teardown" added.
-  	section 11, "Failure modes" completed.
-
-  Revision 1.2  2001/11/05 20:31:31  mcr
-  	added section from OE spec on aging and teardown.
-
-  Revision 1.1  2001/11/05 04:27:58  mcr
-  	OE draft added to documentation.
-
-  Revision 1.12  2001/10/10 01:12:31  mcr
-  	removed impact on DNS servers section.
-  	removed nested comments.
-  	adjusted data of issue
-
-  Revision 1.11  2001/09/17 02:55:50  mcr
-  	outline is now stable.
-
-  Revision 1.5  2001/08/19 02:53:32  mcr
-  	version 00d formatted.
-
-  Revision 1.10  2001/08/19 02:34:04  mcr
-  	version 00d formatted.
-
-  Revision 1.9  2001/08/19 02:21:54  mcr
-  	version 00d
-
-  Revision 1.8  2001/07/20 19:07:06  mcr
-    commented out section 1.1
-
-  Revision 1.7  2001/07/20 14:14:22  mcr
-  	HS and HD comments.
-
-  Revision 1.6  2001/07/19 00:56:50  mcr
-  	version 00b.
-
-  Revision 1.5  2001/07/12 23:57:07  mcr
-  	OE ID, 00.
-
-
-!>
diff --git a/doc/src/draft-richardson-ipsec-rr.html b/doc/src/draft-richardson-ipsec-rr.html
deleted file mode 100644
index 08473104f..000000000
--- a/doc/src/draft-richardson-ipsec-rr.html
+++ /dev/null
@@ -1,659 +0,0 @@
-<html><head><title>A method for storing IPsec keying material in DNS.</title>
-<STYLE type='text/css'>
-    .title { color: #990000; font-size: 22px; line-height: 22px; font-weight: bold; text-align: right;
-             font-family: helvetica, arial, sans-serif }
-    .filename { color: #666666; font-size: 18px; line-height: 28px; font-weight: bold; text-align: right;
-                  font-family: helvetica, arial, sans-serif }
-    p.copyright { color: #000000; font-size: 10px;
-                  font-family: verdana, charcoal, helvetica, arial, sans-serif }
-    p { margin-left: 2em; margin-right: 2em; }
-    li { margin-left: 3em;  }
-    ol { margin-left: 2em; margin-right: 2em; }
-    ul.text { margin-left: 2em; margin-right: 2em; }
-    pre { margin-left: 3em; color: #333333 }
-    ul.toc { color: #000000; line-height: 16px;
-             font-family: verdana, charcoal, helvetica, arial, sans-serif }
-    H3 { color: #333333; font-size: 16px; line-height: 16px; font-family: helvetica, arial, sans-serif }
-    H4 { color: #000000; font-size: 14px; font-family: helvetica, arial, sans-serif }
-    TD.header { color: #ffffff; font-size: 10px; font-family: arial, helvetica, san-serif; valign: top }
-    TD.author-text { color: #000000; font-size: 10px;
-                     font-family: verdana, charcoal, helvetica, arial, sans-serif }
-    TD.author { color: #000000; font-weight: bold; margin-left: 4em; font-size: 10px; font-family: verdana, charcoal, helvetica, arial, sans-serif }
-     A:link { color: #990000; font-weight: bold;
-              font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
-     A:visited { color: #333333; font-weight: bold;
-                 font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
-     A:name { color: #333333; font-weight: bold;
-              font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
-    .link2 { color:#ffffff; font-weight: bold; text-decoration: none;
-             font-family: monaco, charcoal, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
-             font-size: 9px }
-    .RFC { color:#666666; font-weight: bold; text-decoration: none;
-           font-family: monaco, charcoal, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
-           font-size: 9px }
-    .hotText { color:#ffffff; font-weight: normal; text-decoration: none;
-               font-family: charcoal, monaco, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
-               font-size: 9px }
-</style>
-</head>
-<body bgcolor="#ffffff" text="#000000" alink="#000000" vlink="#666666" link="#990000">
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<table width="66%" border="0" cellpadding="0" cellspacing="0"><tr><td><table width="100%" border="0" cellpadding="2" cellspacing="1">
-<tr valign="top"><td width="33%" bgcolor="#666666" class="header">IPSECKEY WG</td><td width="33%" bgcolor="#666666" class="header">M. Richardson</td></tr>
-<tr valign="top"><td width="33%" bgcolor="#666666" class="header">Internet-Draft</td><td width="33%" bgcolor="#666666" class="header">SSW</td></tr>
-<tr valign="top"><td width="33%" bgcolor="#666666" class="header">Expires: March 4, 2004</td><td width="33%" bgcolor="#666666" class="header">September 4, 2003</td></tr>
-</table></td></tr></table>
-<div align="right"><font face="monaco, MS Sans Serif" color="#990000" size="+3"><b><br><span class="title">A method for storing IPsec keying material in DNS.</span></b></font></div>
-<div align="right"><font face="monaco, MS Sans Serif" color="#666666" size="+2"><b><span class="filename">draft-ietf-ipseckey-rr-07.txt</span></b></font></div>
-<font face="verdana, helvetica, arial, sans-serif" size="2">
-
-<h3>Status of this Memo</h3>
-<p>
-This document is an Internet-Draft and is in full conformance with all provisions of Section 10 of RFC2026.</p>
-<p>
-Internet-Drafts are working documents of the Internet Engineering
-Task Force (IETF), its areas, and its working groups.
-Note that other groups may also distribute working documents as
-Internet-Drafts.</p>
-<p>
-Internet-Drafts are draft documents valid for a maximum of six months
-and may be updated, replaced, or obsoleted by other documents at any time.
-It is inappropriate to use Internet-Drafts as reference material or to cite
-them other than as "work in progress."</p>
-<p>
-The list of current Internet-Drafts can be accessed at
-<a href='http://www.ietf.org/ietf/1id-abstracts.txt'>http://www.ietf.org/ietf/1id-abstracts.txt</a>.</p>
-<p>
-The list of Internet-Draft Shadow Directories can be accessed at
-<a href='http://www.ietf.org/shadow.html'>http://www.ietf.org/shadow.html</a>.</p>
-<p>
-This Internet-Draft will expire on March 4, 2004.</p>
-
-<h3>Copyright Notice</h3>
-<p>
-Copyright (C) The Internet Society (2003). All Rights Reserved.</p>
-
-<h3>Abstract</h3>
-
-<p>
-This document describes a new resource record for DNS. This record may be
-used to store public keys for use in IPsec systems. 
-
-</p>
-<p>
-This record replaces the functionality of the sub-type #1 of the KEY Resource
-Record, which has been obsoleted by RFC3445.
-
-</p><a name="toc"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<h3>Table of Contents</h3>
-<ul compact class="toc">
-<b><a href="#anchor1">1.</a>&nbsp;
-Introduction<br></b>
-<b><a href="#anchor2">1.1</a>&nbsp;
-Overview<br></b>
-<b><a href="#anchor3">1.2</a>&nbsp;
-Usage Criteria<br></b>
-<b><a href="#anchor4">2.</a>&nbsp;
-Storage formats<br></b>
-<b><a href="#anchor5">2.1</a>&nbsp;
-IPSECKEY RDATA format<br></b>
-<b><a href="#anchor6">2.2</a>&nbsp;
-RDATA format - precedence<br></b>
-<b><a href="#algotype">2.3</a>&nbsp;
-RDATA format - algorithm type<br></b>
-<b><a href="#gatewaytype">2.4</a>&nbsp;
-RDATA format - gateway type<br></b>
-<b><a href="#anchor7">2.5</a>&nbsp;
-RDATA format - gateway<br></b>
-<b><a href="#anchor8">2.6</a>&nbsp;
-RDATA format - public keys<br></b>
-<b><a href="#anchor9">3.</a>&nbsp;
-Presentation formats<br></b>
-<b><a href="#anchor10">3.1</a>&nbsp;
-Representation of IPSECKEY RRs<br></b>
-<b><a href="#anchor11">3.2</a>&nbsp;
-Examples<br></b>
-<b><a href="#anchor12">4.</a>&nbsp;
-Security Considerations<br></b>
-<b><a href="#anchor13">4.1</a>&nbsp;
-Active attacks against unsecured IPSECKEY resource records<br></b>
-<b><a href="#anchor14">5.</a>&nbsp;
-IANA Considerations<br></b>
-<b><a href="#anchor15">6.</a>&nbsp;
-Acknowledgments<br></b>
-<b><a href="#rfc.references1">&#167;</a>&nbsp;
-Normative references<br></b>
-<b><a href="#rfc.references2">&#167;</a>&nbsp;
-Non-normative references<br></b>
-<b><a href="#rfc.authors">&#167;</a>&nbsp;
-Author's Address<br></b>
-<b><a href="#rfc.copyright">&#167;</a>&nbsp;
-Full Copyright Statement<br></b>
-</ul>
-<br clear="all">
-
-<a name="anchor1"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.1"></a><h3>1.&nbsp;Introduction</h3>
-
-<p>
-   The type number for the IPSECKEY RR is TBD.
-
-</p>
-<a name="rfc.section.1.1"></a><h4><a name="anchor2">1.1</a>&nbsp;Overview</h4>
-
-<p>
-   The IPSECKEY resource record (RR) is used to publish a public key that is
-   to be associated with a Domain Name System (DNS) name for use with the
-   IPsec protocol suite.  This can be the  public key of a host,
-   network, or application (in the case of per-port keying).
-
-</p>
-<p>
-      The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
-      NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and
-      "OPTIONAL" in this document are to be interpreted as described in
-      RFC2119 <a href="#RFC2119">[8]</a>.
-
-</p>
-<a name="rfc.section.1.2"></a><h4><a name="anchor3">1.2</a>&nbsp;Usage Criteria</h4>
-
-<p>
-   An IPSECKEY resource record SHOULD be used in combination with DNSSEC
-unless some other means of authenticating the IPSECKEY resource record
-is available.
-
-</p>
-<p>  
-   It is expected that there will often be multiple IPSECKEY resource
-   records at the same name. This will be due to the presence
-   of multiple gateways and the need to rollover keys.
-
-
-</p>
-<p>
-   This resource record is class independent.
-
-</p>
-<a name="anchor4"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.2"></a><h3>2.&nbsp;Storage formats</h3>
-
-<a name="rfc.section.2.1"></a><h4><a name="anchor5">2.1</a>&nbsp;IPSECKEY RDATA format</h4>
-
-<p>
-   The RDATA for an IPSECKEY RR consists of a precedence value, a public key,
-   algorithm type, and an optional gateway address.
-
-</p></font><pre>
-    0                   1                   2                   3  
-    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-   |  precedence   | gateway type  |  algorithm  |     gateway     |
-   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------+                 +
-   ~                            gateway                            ~
-   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-   |                                                               /
-   /                          public key                           /
-   /                                                               /
-   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
-</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-
-<a name="rfc.section.2.2"></a><h4><a name="anchor6">2.2</a>&nbsp;RDATA format - precedence</h4>
-
-<p>
-This is an 8-bit precedence for this record. This is interpreted in
-the same way as the PREFERENCE field described in section
-3.3.9 of RFC1035 <a href="#RFC1035">[2]</a>. 
-
-</p>
-<p>
-Gateways listed in IPSECKEY records with  lower precedence are
-to be attempted first. Where there is a tie in precedence, the order
-should be non-deterministic.
-
-</p>
-<a name="rfc.section.2.3"></a><h4><a name="algotype">2.3</a>&nbsp;RDATA format - algorithm type</h4>
-
-<p>
-The algorithm type field identifies the public key's cryptographic
-algorithm and determines the format of the public key field.  
-
-</p>
-<p>
-A value of 0 indicates that no key is present.
-
-</p>
-<p>
-The following values are defined:
-  
-<blockquote class="text"><dl>
-<dt>1</dt>
-<dd>A DSA key is present, in the format defined in RFC2536 <a href="#RFC2536">[11]</a>
-</dd>
-<dt>2</dt>
-<dd>A RSA key is present, in the format defined in RFC3110 <a href="#RFC3110">[12]</a>
-</dd>
-</dl></blockquote><p>
-</p>
-<a name="rfc.section.2.4"></a><h4><a name="gatewaytype">2.4</a>&nbsp;RDATA format - gateway type</h4>
-
-<p>
-The gateway type field indicates the format of the information that
-is stored in the gateway field.
-
-</p>
-<p>
-The following values are defined:
-  
-<blockquote class="text"><dl>
-<dt>0</dt>
-<dd>No gateway is present
-</dd>
-<dt>1</dt>
-<dd>A 4-byte IPv4 address is present
-</dd>
-<dt>2</dt>
-<dd>A 16-byte IPv6 address is present
-</dd>
-<dt>3</dt>
-<dd>A wire-encoded domain name is present. The wire-encoded
-format is self-describing, so the length is implicit. The domain name
-MUST NOT be compressed.
-</dd>
-</dl></blockquote><p>
-</p>
-<a name="rfc.section.2.5"></a><h4><a name="anchor7">2.5</a>&nbsp;RDATA format - gateway</h4>
-
-<p>
-The gateway field indicates a gateway to which an IPsec tunnel may be
-created in order to reach the entity named by this resource record.
-
-</p>
-<p>
-There are three formats:
-
-</p>
-<p>
-A 32-bit IPv4 address is present in the gateway field. The data
-portion is an IPv4 address as described in section 3.4.1 of
-<a href="#RFC1035">RFC1035</a>[2].  This is a 32-bit number in network byte order.
-
-</p>
-<p>A 128-bit IPv6 address is present in the gateway field.
-The data portion is an IPv6 address as described in section 2.2 of
-<a href="#RFC1886">RFC1886</a>[7]. This is a 128-bit number in network byte order.
-
-</p>
-<p>
-The gateway field is a normal wire-encoded domain name, as described
-in section 3.3 of RFC1035 <a href="#RFC1035">[2]</a>. Compression MUST NOT be used. 
-
-</p>
-<a name="rfc.section.2.6"></a><h4><a name="anchor8">2.6</a>&nbsp;RDATA format - public keys</h4>
-
-<p>
-Both of the public key types defined in this document (RSA and DSA)
-inherit their public key formats from the corresponding KEY RR formats. 
-Specifically, the public key field contains the algorithm-specific
-portion of the KEY RR RDATA, which is all of the KEY RR DATA after the
-first four octets.  This is the same portion of the KEY RR that must be
-specified by documents that define a DNSSEC algorithm.  
-Those documents also specify a message digest to be used for generation
-of SIG RRs; that specification is not relevant for IPSECKEY RR.
-
-</p>
-<p>
-Future algorithms, if they are to be used by both DNSSEC (in the KEY
-RR) and IPSECKEY, are likely to use the same public key encodings in
-both records.  Unless otherwise specified, the IPSECKEY public key
-field will contain the algorithm-specific portion of the KEY RR RDATA
-for the corresponding algorithm.  The algorithm must still be
-designated for use by IPSECKEY, and an IPSECKEY algorithm type number
-(which might be different than the DNSSEC algorithm number) must be
-assigned to it.
-
-</p>
-<p>The DSA key format is defined in RFC2536 <a href="#RFC2536">[11]</a>
-</p>
-<p>The RSA key format is defined in RFC3110 <a href="#RFC3110">[12]</a>,
-with the following changes:
-</p>
-<p>
-The earlier definition of RSA/MD5 in RFC2065 limited the exponent and
-modulus to 2552 bits in length.  RFC3110 extended that limit to 4096
-bits for RSA/SHA1 keys.  The IPSECKEY RR imposes no length limit on
-RSA public keys, other than the 65535 octet limit imposed by the
-two-octet length encoding.  This length extension is applicable only
-to IPSECKEY and not to KEY RRs. 
-
-</p>
-<a name="anchor9"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.3"></a><h3>3.&nbsp;Presentation formats</h3>
-
-<a name="rfc.section.3.1"></a><h4><a name="anchor10">3.1</a>&nbsp;Representation of IPSECKEY RRs</h4>
-
-<p>
-   IPSECKEY RRs may appear in a zone data master file.
-   The precedence, gateway type and algorithm and gateway fields are REQUIRED.
-   The base64 encoded public key block is OPTIONAL; if not present,
-   then the public key field of the resource record MUST be construed
-   as being zero octets in length.
-
-</p>
-<p>
-   The algorithm field is an unsigned integer. No mnemonics are defined.
-
-</p>
-<p>
-   If no gateway is to be indicated, then the gateway type field MUST
-   be zero, and the gateway field MUST be "."
-
-</p>
-<p>
-   The Public Key field is represented as a Base64 encoding of the
-   Public Key.  Whitespace is allowed within the Base64 text.  For a
-   definition of Base64 encoding, see
-<a href="#RFC1521">RFC1521</a>[3] Section 5.2.
-
-</p>
-<p>
-   The general presentation for the record as as follows:
-</p>
-</font><pre>
-IN     IPSECKEY ( precedence gateway-type algorithm
-                  gateway base64-encoded-public-key )
-</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-
-</p>
-<a name="rfc.section.3.2"></a><h4><a name="anchor11">3.2</a>&nbsp;Examples</h4>
-
-<p> 
-An example of a node 192.0.2.38 that will accept IPsec tunnels on its
-own behalf.
-</p>
-</font><pre>
-38.2.0.192.in-addr.arpa. 7200 IN     IPSECKEY ( 10 1 2 
-                 192.0.2.38
-                 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
-</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-
-</p>
-<p> 
-An example of a node, 192.0.2.38 that has published its key only.
-</p>
-</font><pre>
-38.2.0.192.in-addr.arpa. 7200 IN     IPSECKEY ( 10 0 2
-                 .
-                 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
-</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-
-</p>
-<p> 
-An example of a node, 192.0.2.38 that has delegated authority to the node
-192.0.2.3.
-</p>
-</font><pre>
-38.2.0.192.in-addr.arpa. 7200 IN     IPSECKEY ( 10 1 2
-                 192.0.2.3
-                 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
-</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-
-</p>
-<p> 
-An example of a node, 192.0.1.38 that has delegated authority to the node
-with the identity "mygateway.example.com".
-</p>
-</font><pre>
-38.1.0.192.in-addr.arpa. 7200 IN     IPSECKEY ( 10 3 2
-                 mygateway.example.com.
-                 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
-</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-
-</p>
-<p> 
-An example of a node, 2001:0DB8:0200:1:210:f3ff:fe03:4d0 that has
-delegated authority to the node 2001:0DB8:c000:0200:2::1
-</p>
-</font><pre>
-$ORIGIN 1.0.0.0.0.0.2.8.B.D.0.1.0.0.2.ip6.int.
-0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN     IPSECKEY ( 10 2 2
-                 2001:0DB8:0:8002::2000:1
-                 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
-</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
-<p>
-
-</p>
-<a name="anchor12"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.4"></a><h3>4.&nbsp;Security Considerations</h3>
-
-<p>
-   This entire memo pertains to the provision of public keying material
-   for use by key management protocols such as ISAKMP/IKE (RFC2407)
-   <a href="#RFC2407">[9]</a>.
-
-</p>
-<p>
-The IPSECKEY resource record contains information that SHOULD be
-communicated to the end client in an integral fashion - i.e. free from
-modification. The form of this channel is up to the consumer of the
-data - there must be a trust relationship between the end consumer of this
-resource record and the server. This relationship may be end-to-end
-DNSSEC validation, a TSIG or SIG(0) channel to another secure source,
-a secure local channel on the host, or some combination of the above.
-
-</p>
-<p>
-The keying material provided by the IPSECKEY resource record is not
-sensitive to passive attacks. The keying material may be freely
-disclosed to any party without any impact on the security properties
-of the resulting IPsec session: IPsec and IKE provide for defense
-against both active and passive attacks.
-
-</p>
-<p>
-   Any user of this resource record MUST carefully document their trust
-   model, and why the trust model of DNSSEC is appropriate, if that is
-   the secure channel used.
-
-</p>
-<a name="rfc.section.4.1"></a><h4><a name="anchor13">4.1</a>&nbsp;Active attacks against unsecured IPSECKEY resource records</h4>
-
-<p>
-This section deals with active attacks against the DNS. These attacks
-require that DNS requests and responses be intercepted and changed.
-DNSSEC is designed to defend against attacks of this kind.
-
-</p>
-<p>
-The first kind of active attack is when the attacker replaces the
-keying material with either a key under its control or with garbage.
-
-</p>
-<p>
-If the attacker is not able to mount a subsequent 
-man-in-the-middle attack on the IKE negotiation after replacing the
-public key, then this will result in a denial of service, as the
-authenticator used by IKE would fail.  
-
-</p>
-<p>
-If the attacker is able to both to mount active attacks against DNS
-and is also in a position to perform a man-in-the-middle attack on IKE and
-IPsec negotiations, then the attacker will be in a position to compromise
-the resulting IPsec channel. Note that an attacker must be able to
-perform active DNS attacks on both sides of the IKE negotiation in
-order for this to succeed. 
-
-</p>
-<p>
-The second kind of active attack is one in which the attacker replaces
-the the gateway address to point to a node under the attacker's
-control. The attacker can then either replace the public key or remove
-it, thus providing an IPSECKEY record of its own to match the
-gateway address. 
-
-</p>
-<p>
-This later form creates a simple man-in-the-middle since the attacker
-can then create a second tunnel to the real destination. Note that, as before,
-this requires that the attacker also mount an active attack against
-the responder. 
-
-</p>
-<p>
-Note that the man-in-the-middle can not just forward cleartext
-packets to the original destination. While the destination may be
-willing to speak in the clear, replying to the original sender,
-the sender will have already created a policy expecting ciphertext.
-Thus, the attacker will need to intercept traffic from both sides. In some
-cases, the attacker may be able to accomplish the full intercept by use
-of Network Addresss/Port Translation (NAT/NAPT) technology.
-
-</p>
-<p>
-Note that the danger here only applies to cases where the gateway
-field of the IPSECKEY RR indicates a different entity than the owner
-name of the IPSECKEY RR.  In cases where the end-to-end integrity of
-the IPSECKEY RR is suspect, the end client MUST restrict its use
-of the IPSECKEY RR to cases where the RR owner name matches the
-content of the gateway field.
-
-</p>
-<a name="anchor14"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.5"></a><h3>5.&nbsp;IANA Considerations</h3>
-
-<p>
-This document updates the IANA Registry for DNS Resource Record Types
-by assigning type X to the IPSECKEY record.  
-
-</p>
-<p>
-This document creates an IANA registry for the algorithm type field.
-
-</p>
-<p>
-Values 0, 1 and 2 are defined in <a href="#algotype">RDATA format - algorithm type</a>. Algorithm numbers
-3 through 255 can be assigned by IETF Consensus (<a href="#RFC2434">see RFC2434</a>[6]).
-
-</p>
-<p>
-This document creates an IANA registry for the gateway type field.
-
-</p>
-<p>
-Values 0, 1, 2 and 3 are defined in <a href="#gatewaytype">RDATA format - gateway type</a>.
-Algorithm numbers 4 through 255 can be assigned by
-Standards Action (<a href="#RFC2434">see RFC2434</a>[6]).
-
-</p>
-<a name="anchor15"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<a name="rfc.section.6"></a><h3>6.&nbsp;Acknowledgments</h3>
-
-<p>
-My thanks to Paul Hoffman, Sam Weiler, Jean-Jacques Puig, Rob Austein,
-and Olafur Gurmundsson who reviewed this document carefully.
-Additional thanks to Olafur Gurmundsson for a reference implementation.
-
-</p>
-<a name="rfc.references1"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<h3>Normative references</h3>
-<table width="99%" border="0">
-<tr><td class="author-text" valign="top"><b><a name="RFC1034">[1]</a></b></td>
-<td class="author-text">Mockapetris, P., "<a href="ftp://ftp.isi.edu/in-notes/rfc1034.txt">Domain names - concepts and facilities</a>", STD 13, RFC 1034, November 1987.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC1035">[2]</a></b></td>
-<td class="author-text"><a href="mailto:">Mockapetris, P.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1035.txt">Domain names - implementation and specification</a>", STD 13, RFC 1035, November 1987.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC1521">[3]</a></b></td>
-<td class="author-text"><a href="mailto:nsb@bellcore.com">Borenstein, N.</a> and <a href="mailto:">N. Freed</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1521.txt">MIME (Multipurpose Internet Mail Extensions) Part One: Mechanisms for Specifying and Describing the Format of Internet Message Bodies</a>", RFC 1521, September 1993.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2026">[4]</a></b></td>
-<td class="author-text"><a href="mailto:sob@harvard.edu">Bradner, S.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2026.txt">The Internet Standards Process -- Revision 3</a>", BCP 9, RFC 2026, October 1996.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2065">[5]</a></b></td>
-<td class="author-text"><a href="mailto:dee@cybercash.com">Eastlake, D.</a> and <a href="mailto:charlie_kaufman@iris.com">C. Kaufman</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2065.txt">Domain Name System Security Extensions</a>", RFC 2065, January 1997.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2434">[6]</a></b></td>
-<td class="author-text"><a href="mailto:narten@raleigh.ibm.com">Narten, T.</a> and <a href="mailto:Harald@Alvestrand.no">H. Alvestrand</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2434.txt">Guidelines for Writing an IANA Considerations Section in RFCs</a>", BCP 26, RFC 2434, October 1998.</td></tr>
-</table>
-
-<a name="rfc.references2"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<h3>Non-normative references</h3>
-<table width="99%" border="0">
-<tr><td class="author-text" valign="top"><b><a name="RFC1886">[7]</a></b></td>
-<td class="author-text"><a href="mailto:set@thumper.bellcore.com">Thomson, S.</a> and <a href="mailto:Christian.Huitema@MIRSA.INRIA.FR">C. Huitema</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1886.txt">DNS Extensions to support IP version 6</a>", RFC 1886, December 1995.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2119">[8]</a></b></td>
-<td class="author-text"><a href="mailto:-">Bradner, S.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2119.txt">Key words for use in RFCs to Indicate Requirement Levels</a>", BCP 14, RFC 2119, March 1997.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2407">[9]</a></b></td>
-<td class="author-text"><a href="mailto:ddp@network-alchemy.com">Piper, D.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2407.txt">The Internet IP Security Domain of Interpretation for ISAKMP</a>", RFC 2407, November 1998.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2535">[10]</a></b></td>
-<td class="author-text"><a href="mailto:dee3@us.ibm.com">Eastlake, D.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2535.txt">Domain Name System Security Extensions</a>", RFC 2535, March 1999.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC2536">[11]</a></b></td>
-<td class="author-text"><a href="mailto:dee3@us.ibm.com">Eastlake, D.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2536.txt">DSA KEYs and SIGs in the Domain Name System (DNS)</a>", RFC 2536, March 1999.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC3110">[12]</a></b></td>
-<td class="author-text">Eastlake, D., "<a href="ftp://ftp.isi.edu/in-notes/rfc3110.txt">RSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)</a>", RFC 3110, May 2001.</td></tr>
-<tr><td class="author-text" valign="top"><b><a name="RFC3445">[13]</a></b></td>
-<td class="author-text">Massey, D. and S. Rose, "<a href="ftp://ftp.isi.edu/in-notes/rfc3445.txt">Limiting the Scope of the KEY Resource Record (RR)</a>", RFC 3445, December 2002.</td></tr>
-</table>
-
-<a name="rfc.authors"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<h3>Author's Address</h3>
-<table width="99%" border="0" cellpadding="0" cellspacing="0">
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">Michael C. Richardson</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">Sandelman Software Works</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">470 Dawson Avenue</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">Ottawa, ON  K1Z 5V7</td></tr>
-<tr><td class="author-text">&nbsp;</td>
-<td class="author-text">CA</td></tr>
-<tr><td class="author" align="right">EMail:&nbsp;</td>
-<td class="author-text"><a href="mailto:mcr@sandelman.ottawa.on.ca">mcr@sandelman.ottawa.on.ca</a></td></tr>
-<tr><td class="author" align="right">URI:&nbsp;</td>
-<td class="author-text"><a href="http://www.sandelman.ottawa.on.ca/">http://www.sandelman.ottawa.on.ca/</a></td></tr>
-</table>
-<a name="rfc.copyright"><br><hr size="1" shade="0"></a>
-<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
-<h3>Full Copyright Statement</h3>
-<p class='copyright'>
-Copyright (C) The Internet Society (2003). All Rights Reserved.</p>
-<p class='copyright'>
-This document and translations of it may be copied and furnished to
-others, and derivative works that comment on or otherwise explain it
-or assist in its implementation may be prepared, copied, published and
-distributed, in whole or in part, without restriction of any kind,
-provided that the above copyright notice and this paragraph are
-included on all such copies and derivative works. However, this
-document itself may not be modified in any way, such as by removing
-the copyright notice or references to the Internet Society or other
-Internet organizations, except as needed for the purpose of
-developing Internet standards in which case the procedures for
-copyrights defined in the Internet Standards process must be
-followed, or as required to translate it into languages other than
-English.</p>
-<p class='copyright'>
-The limited permissions granted above are perpetual and will not be
-revoked by the Internet Society or its successors or assigns.</p>
-<p class='copyright'>
-This document and the information contained herein is provided on an
-&quot;AS IS&quot; basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
-TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
-BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
-HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
-MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.</p>
-<h3>Acknowledgement</h3>
-<p class='copyright'>
-Funding for the RFC Editor function is currently provided by the
-Internet Society.</p>
-</font></body></html>
diff --git a/doc/src/draft-richardson-ipsec-rr.xml b/doc/src/draft-richardson-ipsec-rr.xml
deleted file mode 100644
index e51b32615..000000000
--- a/doc/src/draft-richardson-ipsec-rr.xml
+++ /dev/null
@@ -1,560 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
-<?rfc toc="yes"?>
-
-<rfc ipr="full2026" docName="draft-ietf-ipseckey-rr-07.txt">
-
-<front>
-  <area>Security</area>
-  <workgroup>IPSECKEY WG</workgroup>
-  <title abbrev="ipsecrr">
-     A method for storing IPsec keying material in DNS.
-  </title>
-
-  <author initials="M." surname="Richardson" fullname="Michael C. Richardson">
-    <organization abbrev="SSW">Sandelman Software Works</organization>
-    <address>
-      <postal>   
-        <street>470 Dawson Avenue</street>
-        <city>Ottawa</city>
-        <region>ON</region>
-        <code>K1Z 5V7</code>
-        <country>CA</country>
-      </postal>
-      <email>mcr@sandelman.ottawa.on.ca</email>
-      <uri>http://www.sandelman.ottawa.on.ca/</uri>
-    </address>
-  </author>
-
-  <date month="September" year="2003" />
-
-<abstract>
-  <t>
-This document describes a new resource record for DNS. This record may be
-used to store public keys for use in IPsec systems. 
-</t>
-
-<t>
-This record replaces the functionality of the sub-type #1 of the KEY Resource
-Record, which has been obsoleted by RFC3445.
-</t>
-</abstract>
-
-</front>
-
-<middle>
-
-<section title="Introduction">
-<t>
-   The type number for the IPSECKEY RR is TBD.
-</t>
-
-<section title="Overview">
-<t>
-   The IPSECKEY resource record (RR) is used to publish a public key that is
-   to be associated with a Domain Name System (DNS) name for use with the
-   IPsec protocol suite.  This can be the  public key of a host,
-   network, or application (in the case of per-port keying).
-</t>
-
-<t>
-      The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
-      NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and
-      "OPTIONAL" in this document are to be interpreted as described in
-      RFC2119 <xref target="RFC2119" />.
-</t>
-</section>
-
-<section title="Usage Criteria">
-<t>
-   An IPSECKEY resource record SHOULD be used in combination with DNSSEC
-unless some other means of authenticating the IPSECKEY resource record
-is available.
-</t>
-
-<t>  
-   It is expected that there will often be multiple IPSECKEY resource
-   records at the same name. This will be due to the presence
-   of multiple gateways and the need to rollover keys.
-
-</t>
-
-<t>
-   This resource record is class independent.
-</t>
-</section>
-</section>
-
-<section title="Storage formats">
-
-<section title="IPSECKEY RDATA format">
-
-<t>
-   The RDATA for an IPSECKEY RR consists of a precedence value, a public key,
-   algorithm type, and an optional gateway address.
-</t>
-
-<artwork><![CDATA[
-    0                   1                   2                   3  
-    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-   |  precedence   | gateway type  |  algorithm  |     gateway     |
-   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------+                 +
-   ~                            gateway                            ~
-   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-   |                                                               /
-   /                          public key                           /
-   /                                                               /
-   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
-]]></artwork>
-</section>
-
-<section title="RDATA format - precedence">
-<t>
-This is an 8-bit precedence for this record. This is interpreted in
-the same way as the PREFERENCE field described in section
-3.3.9 of RFC1035 <xref target="RFC1035" />. 
-</t>
-<t>
-Gateways listed in IPSECKEY records with  lower precedence are
-to be attempted first. Where there is a tie in precedence, the order
-should be non-deterministic.
-</t>
-</section>
-
-<section anchor="algotype" title="RDATA format - algorithm type">
-<t>
-The algorithm type field identifies the public key's cryptographic
-algorithm and determines the format of the public key field.  
-</t>
-
-<t>
-A value of 0 indicates that no key is present.
-</t>
-
-<t>
-The following values are defined:
-  <list style="hanging">
-  <t hangText="1">A DSA key is present, in the format defined in RFC2536 <xref target="RFC2536" /></t>
-  <t hangText="2">A RSA key is present, in the format defined in RFC3110 <xref target="RFC3110" /></t>
-  </list>
-</t>
-
-</section>
-
-<section anchor="gatewaytype" title="RDATA format - gateway type">
-<t>
-The gateway type field indicates the format of the information that
-is stored in the gateway field.
-</t>
-
-<t>
-The following values are defined:
-  <list style="hanging">
-  <t hangText="0">No gateway is present</t>
-  <t hangText="1">A 4-byte IPv4 address is present</t>
-  <t hangText="2">A 16-byte IPv6 address is present</t>
-  <t hangText="3">A wire-encoded domain name is present. The wire-encoded
-format is self-describing, so the length is implicit. The domain name
-MUST NOT be compressed.</t>
-  </list>
-</t>
-
-</section>
-
-<section title="RDATA format - gateway">
-<t>
-The gateway field indicates a gateway to which an IPsec tunnel may be
-created in order to reach the entity named by this resource record.
-</t>
-<t>
-There are three formats:
-</t>
-
-<t>
-A 32-bit IPv4 address is present in the gateway field. The data
-portion is an IPv4 address as described in section 3.4.1 of
-<xref target="RFC1035">RFC1035</xref>.  This is a 32-bit number in network byte order.
-</t>
-
-<t>A 128-bit IPv6 address is present in the gateway field.
-The data portion is an IPv6 address as described in section 2.2 of
-<xref target="RFC1886">RFC1886</xref>. This is a 128-bit number in network byte order.
-</t>
-
-<t>
-The gateway field is a normal wire-encoded domain name, as described
-in section 3.3 of RFC1035 <xref target="RFC1035" />. Compression MUST NOT be used. 
-</t>
-
-</section>
-
-<section title="RDATA format - public keys">
-<t>
-Both of the public key types defined in this document (RSA and DSA)
-inherit their public key formats from the corresponding KEY RR formats. 
-Specifically, the public key field contains the algorithm-specific
-portion of the KEY RR RDATA, which is all of the KEY RR DATA after the
-first four octets.  This is the same portion of the KEY RR that must be
-specified by documents that define a DNSSEC algorithm.  
-Those documents also specify a message digest to be used for generation
-of SIG RRs; that specification is not relevant for IPSECKEY RR.
-</t>
-
-<t>
-Future algorithms, if they are to be used by both DNSSEC (in the KEY
-RR) and IPSECKEY, are likely to use the same public key encodings in
-both records.  Unless otherwise specified, the IPSECKEY public key
-field will contain the algorithm-specific portion of the KEY RR RDATA
-for the corresponding algorithm.  The algorithm must still be
-designated for use by IPSECKEY, and an IPSECKEY algorithm type number
-(which might be different than the DNSSEC algorithm number) must be
-assigned to it.
-</t>
-
-<t>The DSA key format is defined in RFC2536 <xref target="RFC2536" /></t>.
-
-<t>The RSA key format is defined in RFC3110 <xref target="RFC3110" />,
-with the following changes:</t>
-
-<t>
-The earlier definition of RSA/MD5 in RFC2065 limited the exponent and
-modulus to 2552 bits in length.  RFC3110 extended that limit to 4096
-bits for RSA/SHA1 keys.  The IPSECKEY RR imposes no length limit on
-RSA public keys, other than the 65535 octet limit imposed by the
-two-octet length encoding.  This length extension is applicable only
-to IPSECKEY and not to KEY RRs. 
-</t>
-
-</section>
-
-</section>
-
-
-
-<section title="Presentation formats">
-
-<section title="Representation of IPSECKEY RRs">
-<t>
-   IPSECKEY RRs may appear in a zone data master file.
-   The precedence, gateway type and algorithm and gateway fields are REQUIRED.
-   The base64 encoded public key block is OPTIONAL; if not present,
-   then the public key field of the resource record MUST be construed
-   as being zero octets in length.
-</t>
-<t>
-   The algorithm field is an unsigned integer. No mnemonics are defined.
-</t>
-<t>
-   If no gateway is to be indicated, then the gateway type field MUST
-   be zero, and the gateway field MUST be "."
-</t>
-
-<t>
-   The Public Key field is represented as a Base64 encoding of the
-   Public Key.  Whitespace is allowed within the Base64 text.  For a
-   definition of Base64 encoding, see
-<xref target="RFC1521">RFC1521</xref> Section 5.2.
-</t>
-
-   
-<t>
-   The general presentation for the record as as follows:
-<artwork><![CDATA[
-IN     IPSECKEY ( precedence gateway-type algorithm
-                  gateway base64-encoded-public-key )
-]]></artwork>
-</t>
-</section>
-
-
-<section title="Examples">
-<t> 
-An example of a node 192.0.2.38 that will accept IPsec tunnels on its
-own behalf.
-<artwork><![CDATA[
-38.2.0.192.in-addr.arpa. 7200 IN     IPSECKEY ( 10 1 2 
-                 192.0.2.38
-                 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
-]]></artwork>
-</t>
-
-<t> 
-An example of a node, 192.0.2.38 that has published its key only.
-<artwork><![CDATA[
-38.2.0.192.in-addr.arpa. 7200 IN     IPSECKEY ( 10 0 2
-                 .
-                 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
-]]></artwork>
-</t>
-
-<t> 
-An example of a node, 192.0.2.38 that has delegated authority to the node
-192.0.2.3.
-<artwork><![CDATA[
-38.2.0.192.in-addr.arpa. 7200 IN     IPSECKEY ( 10 1 2
-                 192.0.2.3
-                 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
-]]></artwork>
-</t>
-
-<t> 
-An example of a node, 192.0.1.38 that has delegated authority to the node
-with the identity "mygateway.example.com".
-<artwork><![CDATA[
-38.1.0.192.in-addr.arpa. 7200 IN     IPSECKEY ( 10 3 2
-                 mygateway.example.com.
-                 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
-]]></artwork>
-</t>
-
-<t> 
-An example of a node, 2001:0DB8:0200:1:210:f3ff:fe03:4d0 that has
-delegated authority to the node 2001:0DB8:c000:0200:2::1
-<artwork><![CDATA[
-$ORIGIN 1.0.0.0.0.0.2.8.B.D.0.1.0.0.2.ip6.int.
-0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN     IPSECKEY ( 10 2 2
-                 2001:0DB8:0:8002::2000:1
-                 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
-]]></artwork>
-</t>
-
-</section>
-</section>
-
-<section title="Security Considerations">
-<t>
-   This entire memo pertains to the provision of public keying material
-   for use by key management protocols such as ISAKMP/IKE (RFC2407)
-   <xref target="RFC2407" />.
-</t>
-
-<t>
-The IPSECKEY resource record contains information that SHOULD be
-communicated to the end client in an integral fashion - i.e. free from
-modification. The form of this channel is up to the consumer of the
-data - there must be a trust relationship between the end consumer of this
-resource record and the server. This relationship may be end-to-end
-DNSSEC validation, a TSIG or SIG(0) channel to another secure source,
-a secure local channel on the host, or some combination of the above.
-</t>
-
-<t>
-The keying material provided by the IPSECKEY resource record is not
-sensitive to passive attacks. The keying material may be freely
-disclosed to any party without any impact on the security properties
-of the resulting IPsec session: IPsec and IKE provide for defense
-against both active and passive attacks.
-</t>
-
-<t>
-   Any user of this resource record MUST carefully document their trust
-   model, and why the trust model of DNSSEC is appropriate, if that is
-   the secure channel used.
-</t>
-
-<section title="Active attacks against unsecured IPSECKEY resource records">
-<t>
-This section deals with active attacks against the DNS. These attacks
-require that DNS requests and responses be intercepted and changed.
-DNSSEC is designed to defend against attacks of this kind.
-</t>
-
-<t>
-The first kind of active attack is when the attacker replaces the
-keying material with either a key under its control or with garbage.
-</t>
-
-<t>
-If the attacker is not able to mount a subsequent 
-man-in-the-middle attack on the IKE negotiation after replacing the
-public key, then this will result in a denial of service, as the
-authenticator used by IKE would fail.  
-</t>
-
-<t>
-If the attacker is able to both to mount active attacks against DNS
-and is also in a position to perform a man-in-the-middle attack on IKE and
-IPsec negotiations, then the attacker will be in a position to compromise
-the resulting IPsec channel. Note that an attacker must be able to
-perform active DNS attacks on both sides of the IKE negotiation in
-order for this to succeed. 
-</t>
-
-<t>
-The second kind of active attack is one in which the attacker replaces
-the the gateway address to point to a node under the attacker's
-control. The attacker can then either replace the public key or remove
-it, thus providing an IPSECKEY record of its own to match the
-gateway address. 
-</t>
-
-<t>
-This later form creates a simple man-in-the-middle since the attacker
-can then create a second tunnel to the real destination. Note that, as before,
-this requires that the attacker also mount an active attack against
-the responder. 
-</t>
-
-<t>
-Note that the man-in-the-middle can not just forward cleartext
-packets to the original destination. While the destination may be
-willing to speak in the clear, replying to the original sender,
-the sender will have already created a policy expecting ciphertext.
-Thus, the attacker will need to intercept traffic from both sides. In some
-cases, the attacker may be able to accomplish the full intercept by use
-of Network Addresss/Port Translation (NAT/NAPT) technology.
-</t>
-
-<t>
-Note that the danger here only applies to cases where the gateway
-field of the IPSECKEY RR indicates a different entity than the owner
-name of the IPSECKEY RR.  In cases where the end-to-end integrity of
-the IPSECKEY RR is suspect, the end client MUST restrict its use
-of the IPSECKEY RR to cases where the RR owner name matches the
-content of the gateway field.
-</t>
-</section>
-
-</section>
-
-<section title="IANA Considerations">
-<t>
-This document updates the IANA Registry for DNS Resource Record Types
-by assigning type X to the IPSECKEY record.  
-</t>
-
-<t>
-This document creates an IANA registry for the algorithm type field.
-</t>
-<t>
-Values 0, 1 and 2 are defined in <xref target="algotype" />. Algorithm numbers
-3 through 255 can be assigned by IETF Consensus (<xref target="RFC2434">see RFC2434</xref>).
-</t>
-
-<t>
-This document creates an IANA registry for the gateway type field.
-</t>
-<t>
-Values 0, 1, 2 and 3 are defined in <xref target="gatewaytype" />.
-Algorithm numbers 4 through 255 can be assigned by
-Standards Action (<xref target="RFC2434">see RFC2434</xref>).
-</t>
-
-
-
-</section>
-
-<section title="Acknowledgments">
-<t>
-My thanks to Paul Hoffman, Sam Weiler, Jean-Jacques Puig, Rob Austein,
-and Olafur Gurmundsson who reviewed this document carefully.
-Additional thanks to Olafur Gurmundsson for a reference implementation.
-</t>
-</section>
-
-</middle>
-
-<back>
-<references title="Normative references">
-<!-- DNSSEC -->
-<?rfc include="reference.RFC.1034" ?>
-<?rfc include="reference.RFC.1035" ?>
-<?rfc include="reference.RFC.1521" ?>
-<?rfc include="reference.RFC.2026" ?>
-<?rfc include="reference.RFC.2065" ?>
-<?rfc include="reference.RFC.2434" ?>
-</references>
-
-<references title="Non-normative references">
-<?rfc include="reference.RFC.1886" ?>
-<?rfc include="reference.RFC.2119" ?>
-<?rfc include="reference.RFC.2407" ?>
-<?rfc include="reference.RFC.2535" ?>
-<?rfc include="reference.RFC.2536" ?>
-<?rfc include="reference.RFC.3110" ?>
-<?rfc include="reference.RFC.3445" ?>
-</references>
-</back>
-</rfc>
-<!--
-  $Id: draft-richardson-ipsec-rr.xml,v 1.1 2004/03/15 20:35:24 as Exp $
-
-  $Log: draft-richardson-ipsec-rr.xml,v $
-  Revision 1.1  2004/03/15 20:35:24  as
-  added files from freeswan-2.04-x509-1.5.3
-
-  Revision 1.23  2003/09/04 23:26:09  mcr
-  	more nits.
-
-  Revision 1.22  2003/08/16 15:55:35  mcr
-  	fixed version to -06.
-
-  Revision 1.21  2003/08/16 15:52:32  mcr
-  	Sam's comments on IANA considerations.
-
-  Revision 1.20  2003/07/27 22:57:54  mcr
-  	updated document with new text about a seperate registry
-  	for the algorithm type.
-
-  Revision 1.19  2003/06/30 01:51:50  mcr
-  	minor typo fixes.
-
-  Revision 1.18  2003/06/16 17:45:00  mcr
-  	adjusted date on rev-04.
-
-  Revision 1.17  2003/06/16 17:41:30  mcr
-  	revision -04
-
-  Revision 1.16  2003/06/16 17:39:20  mcr
-  	adjusted typos, and adjusted IANA considerations.
-
-  Revision 1.15  2003/05/26 19:31:23  mcr
-  	updates to drafts - IPSEC RR - SC versions, and RFC3526
-  	reference in OE draft.
-
-  Revision 1.14  2003/05/23 13:57:40  mcr
-  	updated draft ##.
-
-  Revision 1.13  2003/05/23 13:54:45  mcr
-  	updated month on draft.
-
-  Revision 1.12  2003/05/21 15:42:49  mcr
-  	new SC section with comments from Rob Austein.
-
-  Revision 1.11  2003/05/20 20:52:22  mcr
-  	new security considerations section.
-
-  Revision 1.10  2003/05/20 19:07:47  mcr
-  	rewrote Security Considerations.
-
-  Revision 1.9  2003/05/20 18:17:09  mcr
-  	nits from Rob Austein.
-
-  Revision 1.8  2003/04/29 00:44:59  mcr
-  	updates according to WG consensus: restored three-way
-  	gateway field type.
-
-  Revision 1.7  2003/03/30 17:00:29  mcr
-  	updates according to community feedback.
-
-  Revision 1.6  2003/03/19 02:20:24  mcr
-  	updated draft based upon comments from working group
-
-  Revision 1.5  2003/02/23 22:39:22  mcr
-  	updates to IPSECKEY draft.
-
-  Revision 1.4  2003/02/21 04:39:04  mcr
-  	updated drafts, and added crosscompile.html
-
-  Revision 1.3  2003/01/17 16:26:34  mcr
-  	updated IPSEC KEY draft with restrictions.
-
-  Revision 1.2  2002/08/26 18:20:54  mcr
-  	updated documents
-
-  Revision 1.1  2002/08/10 20:05:33  mcr
-  	document proposing IPSECKEY Resource Record
-
-
-!>
diff --git a/doc/utils/rfc_pg.c b/doc/utils/rfc_pg.c
index 448cc1a36..e2484959e 100644
--- a/doc/utils/rfc_pg.c
+++ b/doc/utils/rfc_pg.c
@@ -1,5 +1,5 @@
 /*
- *  $Header: /var/cvsroot/strongswan/doc/utils/rfc_pg.c,v 1.1 2004/03/15 20:35:24 as Exp $
+ *  $Header: /root/strongswan/doc/utils/rfc_pg.c,v 1.1 2004/03/15 20:35:24 as Exp $
  *
  * from 2-nroff.template file.
  *
diff --git a/lib/Makefile b/lib/Makefile
index fa2b27bef..8f0b6ec24 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -12,7 +12,7 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 #
-# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:24 as Exp $
+# RCSID $Id: Makefile,v 1.2 2006/10/19 18:12:45 as Exp $
 
 FREESWANSRCDIR=..
 include ${FREESWANSRCDIR}/Makefile.inc
@@ -37,5 +37,4 @@ cleanall distclean mostlyclean realclean install programs checkprograms check cl
 	@for d in $(SUBDIRS) ; \
 	do \
 		(cd $$d && $(MAKE) FREESWANSRCDIR=$(FREESWANSRCDIR)/.. $@ ) || exit 1; \
-	done; \
-
+	done; 
diff --git a/programs/Makefile b/programs/Makefile
index 03c9d582a..dbc03f416 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -12,7 +12,7 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 #
-# RCSID $Id: Makefile,v 1.8 2006/04/17 11:04:45 as Exp $
+# RCSID $Id: Makefile,v 1.9 2006/08/28 11:12:36 as Exp $
 
 FREESWANSRCDIR=..
 include ${FREESWANSRCDIR}/Makefile.inc
@@ -42,5 +42,5 @@ cleanall distclean mostlyclean realclean install programs checkprograms check cl
 	@for d in $(SUBDIRS) ; \
 	do \
 		(cd $$d && $(MAKE) FREESWANSRCDIR=$(FREESWANSRCDIR)/.. $@ ) || exit 1;\
-	done; \
+	done; 
 
diff --git a/programs/pluto/connections.c b/programs/pluto/connections.c
index 8bd3ed49b..1ea6ac5fa 100644
--- a/programs/pluto/connections.c
+++ b/programs/pluto/connections.c
@@ -11,7 +11,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: connections.c,v 1.44 2006/07/06 19:20:09 as Exp $
+ * RCSID $Id: connections.c,v 1.46 2006/10/19 15:40:52 as Exp $
  */
 
 #include <string.h>
@@ -862,6 +862,7 @@ extract_end(struct end *dst, const whack_end_t *src, const char *which)
     dst->host_addr = src->host_addr;
     dst->host_nexthop = src->host_nexthop;
     dst->host_srcip = src->host_srcip;
+    dst->has_natip = src->has_natip;
     dst->client = src->client;
     dst->protocol = src->protocol;
     dst->port = src->port;
@@ -880,6 +881,7 @@ extract_end(struct end *dst, const whack_end_t *src, const char *which)
      */
     if (addrbytesptr(&dst->host_srcip, NULL)
     && !isanyaddr(&dst->host_srcip)
+    && !dst->has_natip
     && !dst->has_client)
     {
 	err_t ugh = addrtosubnet(&dst->host_srcip, &dst->client);
@@ -2024,7 +2026,8 @@ cannot_oppo(struct connection *c
 	    char state_buf2[LOG_WIDTH];
 	    time_t n = now();
 
-	    fmt_state(st, n, state_buf, sizeof(state_buf)
+	    fmt_state(FALSE, st, n
+		      , state_buf, sizeof(state_buf)
 		      , state_buf2, sizeof(state_buf2));
 	    DBG_log("cannot_oppo, failure SA1: %s", state_buf);
 	    DBG_log("cannot_oppo, failure SA2: %s", state_buf2);
@@ -3065,7 +3068,7 @@ ISAKMP_SA_established(struct connection *c, so_serial_t serial)
     /* the connection is now oriented so that we are able to determine
      * whether we are a mode config server with a virtual IP to send.
      */
-    if (!isanyaddr(&c->spd.that.host_srcip))
+    if (!isanyaddr(&c->spd.that.host_srcip) && !c->spd.that.has_natip)
 	c->spd.that.modecfg = TRUE;
 	
     if (uniqueIDs)
diff --git a/programs/pluto/connections.h b/programs/pluto/connections.h
index 6dfddbe22..33fbc3fea 100644
--- a/programs/pluto/connections.h
+++ b/programs/pluto/connections.h
@@ -11,7 +11,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: connections.h,v 1.18 2006/04/22 21:59:20 as Exp $
+ * RCSID $Id: connections.h,v 1.19 2006/10/19 15:38:27 as Exp $
  */
 
 #ifndef _CONNECTIONS_H
@@ -143,6 +143,7 @@ struct end {
     bool has_client_wildcard;
     bool has_port_wildcard;
     bool has_id_wildcards;
+    bool has_natip;
     char *updown;
     u_int16_t host_port;	/* host order */
     u_int16_t port;		/* host order */
diff --git a/programs/pluto/constants.c b/programs/pluto/constants.c
index 27e4db1e0..5ca7b65ce 100644
--- a/programs/pluto/constants.c
+++ b/programs/pluto/constants.c
@@ -11,7 +11,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: constants.c,v 1.21 2006/03/27 07:38:59 as Exp $
+ * RCSID $Id: constants.c,v 1.22 2006/10/19 21:07:40 as Exp $
  */
 
 /*
@@ -188,6 +188,7 @@ static const char *const state_name[] = {
 	"STATE_MODE_CFG_R2",
 	"STATE_MODE_CFG_I1",
 	"STATE_MODE_CFG_I2",
+	"STATE_MODE_CFG_I3",
 
 	"STATE_IKE_ROOF"
     };
@@ -218,9 +219,10 @@ const char *const state_story[] = {
 	
 	"sent ModeCfg reply",			 /* STATE_MODE_CFG_R0 */
 	"sent ModeCfg reply",			 /* STATE_MODE_CFG_R1 */
-	"ModeCfg R2",				 /* STATE_MODE_CFG_R2 */
+	"received ModeCfg ack",			 /* STATE_MODE_CFG_R2 */
 	"sent ModeCfg request, expecting reply", /* STATE_MODE_CFG_I1 */
 	"received ModeCfg reply",		 /* STATE_MODE_CFG_I2 */
+	"received ModeCfg set, sent ack",	 /* STATE_MODE_CFG_I3 */
     };
 
 /* kind of struct connection */
@@ -484,6 +486,7 @@ const char *const sa_policy_bit_names[] = {
 	"GROUP",
 	"GROUTED",
 	"UP",
+	"MODECFGPUSH",
 	NULL
     };
 
diff --git a/programs/pluto/constants.h b/programs/pluto/constants.h
index b66d002ee..bad162898 100644
--- a/programs/pluto/constants.h
+++ b/programs/pluto/constants.h
@@ -12,7 +12,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: constants.h,v 1.20 2006/02/28 19:13:33 as Exp $
+ * RCSID $Id: constants.h,v 1.22 2006/10/19 21:07:40 as Exp $
  */
 
 #ifndef _CONSTANTS_H
@@ -510,6 +510,7 @@ enum state_kind {
 
     STATE_MODE_CFG_I1,           /* this is used on the initiator */
     STATE_MODE_CFG_I2,
+    STATE_MODE_CFG_I3,
 
     STATE_IKE_ROOF
 };
@@ -519,17 +520,21 @@ enum state_kind {
 #define PHASE1_INITIATOR_STATES	 (LELEM(STATE_MAIN_I1) | LELEM(STATE_MAIN_I2) \
     | LELEM(STATE_MAIN_I3) | LELEM(STATE_MAIN_I4))
 #define ISAKMP_SA_ESTABLISHED_STATES  (LELEM(STATE_MAIN_R3) | LELEM(STATE_MAIN_I4) \
-    | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_I2))
+    | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_R2) \
+    | LELEM(STATE_MODE_CFG_I2) | LELEM(STATE_MODE_CFG_I3))
 
 #define IS_PHASE1(s) ((STATE_MAIN_R0 <= (s) && (s) <= STATE_MAIN_I4) \
-		   || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_I2))
+		   || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_I3))
 #define IS_QUICK(s) (STATE_QUICK_R0 <= (s) && (s) <= STATE_QUICK_R2)
 #define IS_ISAKMP_ENCRYPTED(s) (STATE_MAIN_I2 <= (s))
-#define IS_ISAKMP_SA_ESTABLISHED(s) ((s) == STATE_MAIN_R3 \
-				  || (s) == STATE_MAIN_I4 \
+#define IS_ISAKMP_SA_ESTABLISHED(s) (         \
+					 (s) == STATE_MAIN_R3     \
+				  || (s) == STATE_MAIN_I4     \
 				  || (s) == STATE_MODE_CFG_R0 \
 				  || (s) == STATE_MODE_CFG_R1 \
-				  || (s) == STATE_MODE_CFG_I2)
+				  || (s) == STATE_MODE_CFG_R2 \
+				  || (s) == STATE_MODE_CFG_I2 \
+				  || (s) == STATE_MODE_CFG_I3)
 #define IS_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_I2 || (s) == STATE_QUICK_R2)
 #define IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_R1)
 
@@ -783,11 +788,12 @@ extern const char *prettypolicy(lset_t policy);
 /* connection policy
  * Other policies could vary per state object.  These live in connection.
  */
-#define POLICY_DONT_REKEY     LELEM(12)	/* don't rekey state either Phase */
-#define POLICY_OPPO     LELEM(13)	/* is this opportunistic? */
-#define POLICY_GROUP	LELEM(14)	/* is this a group template? */
-#define POLICY_GROUTED	LELEM(15)	/* do we want this group routed? */
-#define POLICY_UP	LELEM(16)	/* do we want this up? */
+#define POLICY_DONT_REKEY	LELEM(12)	/* don't rekey state either Phase */
+#define POLICY_OPPO		LELEM(13)	/* is this opportunistic? */
+#define POLICY_GROUP		LELEM(14)	/* is this a group template? */
+#define POLICY_GROUTED		LELEM(15)	/* do we want this group routed? */
+#define POLICY_UP		LELEM(16)	/* do we want this up? */
+#define POLICY_MODECFG_PUSH	LELEM(17)	/* is modecfg pushed by server? */
 
 
 /* Any IPsec policy?  If not, a connection description
diff --git a/programs/pluto/demux.c b/programs/pluto/demux.c
index db7f1c4a6..3146b3d40 100644
--- a/programs/pluto/demux.c
+++ b/programs/pluto/demux.c
@@ -12,7 +12,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: demux.c,v 1.14 2006/06/22 11:58:25 as Exp $
+ * RCSID $Id: demux.c,v 1.16 2006/10/19 21:07:40 as Exp $
  */
 
 /* Ordering Constraints on Payloads
@@ -481,7 +481,17 @@ static const struct state_microcode state_microcode_table[] = {
     { STATE_MODE_CFG_I1, STATE_MODE_CFG_I2
     , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
     , P(ATTR) | P(HASH), P(VID), PT(HASH)
-    , EVENT_SA_REPLACE, modecfg_inR1 },
+    , EVENT_SA_REPLACE, modecfg_inI1 },
+
+    { STATE_MODE_CFG_I2, STATE_MODE_CFG_I3
+    , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2
+    , P(ATTR) | P(HASH), P(VID), PT(HASH)
+    , EVENT_SA_REPLACE, modecfg_inI2 },
+
+    { STATE_MODE_CFG_I3, STATE_UNDEFINED
+    , SMF_ALL_AUTH | SMF_ENCRYPTED
+    , LEMPTY, LEMPTY, PT(NONE)
+    , EVENT_NULL, unexpected },
 
 #undef P
 #undef PT
@@ -1441,7 +1451,7 @@ process_packet(struct msg_digest **mdp)
 	    {
 		st->st_state = STATE_MAIN_R3;	    /* ISAKMP is up... */
 	    }
-	    
+
 	    set_cur_state(st);
 
 	    if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
@@ -1471,7 +1481,7 @@ process_packet(struct msg_digest **mdp)
 	}
 	else
 	{
-	    set_cur_state(st);
+	    set_cur_state(st);  
 	    from_state = st->st_state;
 	}
 
@@ -1563,7 +1573,7 @@ process_packet(struct msg_digest **mdp)
 	    else if (st->st_connection->spd.this.modecfg
 	    && IS_PHASE1(st->st_state))
 	    {
-		from_state = STATE_MODE_CFG_R1;
+		from_state = STATE_MODE_CFG_I2;
 	    }
 	    else
 	    {
@@ -2323,38 +2333,39 @@ complete_state_transition(struct msg_digest **mdp, stf_status result)
 		    , story, sadetails);
 	    }
 
-	    /* Should we start Mode Config as a client */
+	    /* Should we start ModeConfig as a client? */
 	    if (st->st_connection->spd.this.modecfg
 	    && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+	    && !(st->st_connection->policy & POLICY_MODECFG_PUSH)
 	    && !st->st_modecfg.started)
 	    {
 		DBG(DBG_CONTROL,
-		    DBG_log("modecfg client is starting")
+		    DBG_log("starting ModeCfg client in pull mode")
 		)
 		modecfg_send_request(st);
 		break;
 	    }
 
-	    /* Should we set the peer's IP address regardless? */
-/*	    if (st->st_connection->spd.that.modecfg
+	    /* Should we start ModeConfig as a server? */
+	    if (st->st_connection->spd.that.modecfg
 	    && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
-	    && !st->st_modecfg.vars_set
-	    && !(st->st_connection->policy & POLICY_MODECFG_PULL))
+	    && !st->st_modecfg.started
+	    && (st->st_connection->policy & POLICY_MODECFG_PUSH))
 	    {
-		st->st_state = STATE_MODE_CFG_R1;
-		set_cur_state(st);
-		plog("Sending MODE CONFIG set");
-		modecfg_start_set(st);
+		DBG(DBG_CONTROL,
+		    DBG_log("starting ModeCfg server in push mode")
+		)
+		modecfg_send_set(st);
 		break;
 	    }
-*/
-	    /* wait for modecfg_set */
+
+	    /* Wait for ModeConfig set from server */
 	    if (st->st_connection->spd.this.modecfg
 	    && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
 	    && !st->st_modecfg.vars_set)
 	    {
 		DBG(DBG_CONTROL,
-		    DBG_log("waiting for modecfg set from server")
+		    DBG_log("waiting for ModeCfg set from server")
 		)
 		break;
 	    }
diff --git a/programs/pluto/log.c b/programs/pluto/log.c
index 73ffceccd..aef93ff3c 100644
--- a/programs/pluto/log.c
+++ b/programs/pluto/log.c
@@ -12,7 +12,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: log.c,v 1.8 2006/04/29 18:16:02 as Exp $
+ * RCSID $Id: log.c,v 1.9 2006/10/17 10:30:54 as Exp $
  */
 
 #include <stdio.h>
@@ -773,7 +773,7 @@ show_status(bool all, const char *name)
 	whack_log(RC_COMMENT, BLANK_FORMAT);	/* spacer */
     }
     show_connections_status(all, name);
-    show_states_status(name);
+    show_states_status(all, name);
 #ifdef KLIPS
     show_shunt_status();
 #endif
diff --git a/programs/pluto/modecfg.c b/programs/pluto/modecfg.c
index 1c22845a5..ec334aaf5 100644
--- a/programs/pluto/modecfg.c
+++ b/programs/pluto/modecfg.c
@@ -2,6 +2,7 @@
  * Copyright (C) 2001-2002 Colubris Networks
  * Copyright (C) 2003 Sean Mathews - Nu Tech Software Solutions, inc.
  * Copyright (C) 2003-2004 Xelerance Corporation
+ * Copyright (C) 2006 Andreas Steffen - Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -13,7 +14,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: modecfg.c,v 1.6 2006/04/24 20:44:57 as Exp $
+ * RCSID $Id: modecfg.c,v 1.9 2006/10/21 17:11:13 as Exp $
  *
  * This code originally written by Colubris Networks, Inc.
  * Extraction of patch and porting to 1.99 codebases by Xelerance Corporation
@@ -39,23 +40,46 @@
 #include "modecfg.h"
 #include "whack.h"
 
+#define SUPPORTED_ATTR_SET   ( LELEM(INTERNAL_IP4_ADDRESS) \
+                             | LELEM(INTERNAL_IP4_NETMASK) \
+                             | LELEM(INTERNAL_IP4_DNS)     \
+                             | LELEM(INTERNAL_IP4_NBNS)    \
+                             )
+
 /*
- * Addresses assigned (usually via MODE_CONFIG) to the Initiator
+ * Addresses assigned (usually via ModeCfg) to the Initiator
  */
+typedef struct internal_addr internal_addr_t;
+
 struct internal_addr
 {
+    lset_t        attr_set;
     ip_address    ipaddr;
     ip_address    dns[2];
-    ip_address    wins[2];  
+    ip_address    wins[2];
 };
 
 /*
- * Get inside IP address for a connection
+ * Initialize an internal_addr struct
  */
 static void
-get_internal_addresses(struct connection *c, struct internal_addr *ia)
+init_internal_addr(internal_addr_t *ia)
 {
-    zero(ia);
+    ia->attr_set = LEMPTY;
+    anyaddr(AF_INET, &ia->ipaddr);
+    anyaddr(AF_INET, &ia->dns[0]);
+    anyaddr(AF_INET, &ia->dns[1]);
+    anyaddr(AF_INET, &ia->wins[0]);
+    anyaddr(AF_INET, &ia->wins[1]);
+}
+
+/*
+ * get internal IP address for a connection
+ */
+static void
+get_internal_addr(struct connection *c, internal_addr_t *ia)
+{
+    init_internal_addr(ia);
 
     if (isanyaddr(&c->spd.that.host_srcip))
     {
@@ -63,16 +87,78 @@ get_internal_addresses(struct connection *c, struct internal_addr *ia)
     }
     else
     {
+	char srcip[ADDRTOT_BUF];
+
 	ia->ipaddr = c->spd.that.host_srcip;
+
+	addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip));
+	plog("assigning virtual IP source address %s", srcip);
+    }
+
+    if (!isanyaddr(&ia->ipaddr))	/* We got an IP address, send it */
+    {
+	c->spd.that.client.addr     = ia->ipaddr;
+	c->spd.that.client.maskbits = 32;
+	c->spd.that.has_client      = TRUE;
+	
+	ia->attr_set |= LELEM(INTERNAL_IP4_ADDRESS) | LELEM(INTERNAL_IP4_NETMASK);
+    }
+
+
+    if (!isanyaddr(&ia->dns[0]))	/* We got DNS addresses, send them */
+	ia->attr_set |= LELEM(INTERNAL_IP4_DNS);
+
+    if (!isanyaddr(&ia->wins[0]))	/* We got WINS addresses, send them */
+	ia->attr_set |= LELEM(INTERNAL_IP4_NBNS);
+}
+
+/*
+ * Set srcip and client subnet to internal IP address
+ */
+static bool
+set_internal_addr(struct connection *c, internal_addr_t *ia)
+{
+    if (ia->attr_set & LELEM(INTERNAL_IP4_ADDRESS)
+    && !isanyaddr(&ia->ipaddr))
+    {
+	if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
+	|| isanyaddr(&c->spd.this.host_srcip)
+	|| sameaddr(&c->spd.this.host_srcip, &ia->ipaddr))
+	{
+	    char srcip[ADDRTOT_BUF];
+
+	    addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip));
+	    plog("setting virtual IP source address to %s", srcip);
+	}
+	else
+	{
+	    char old_srcip[ADDRTOT_BUF];
+	    char new_srcip[ADDRTOT_BUF];
+
+	    addrtot(&c->spd.this.host_srcip, 0, old_srcip, sizeof(old_srcip));
+	    addrtot(&ia->ipaddr, 0, new_srcip, sizeof(new_srcip));
+	    plog("replacing virtual IP source address %s by %s"
+		, old_srcip, new_srcip);
+	}
+	
+	/* setting srcip */
+	c->spd.this.host_srcip = ia->ipaddr;
+
+	/* setting client subnet to srcip/32 */
+	addrtosubnet(&ia->ipaddr, &c->spd.this.client);
+	setportof(0, &c->spd.this.client.addr);
+	c->spd.this.has_client = TRUE;
+	return TRUE;
     }
+    return FALSE;
 }
 
 /*
  * Compute HASH of Mode Config.
  */
 static size_t
-mode_cfg_hash(u_char *dest, const u_char *start, const u_char *roof
-	     , const struct state *st)
+modecfg_hash(u_char *dest, const u_char *start, const u_char *roof
+	    , const struct state *st)
 {
     struct hmac_ctx ctx;
 
@@ -82,92 +168,51 @@ mode_cfg_hash(u_char *dest, const u_char *start, const u_char *roof
     hmac_final(dest, &ctx);
 
     DBG(DBG_CRYPT,
-	DBG_log("MODE CFG: HASH computed:");
+	DBG_log("ModeCfg HASH computed:");
  	DBG_dump("", dest, ctx.hmac_digest_size)
     ) 
     return ctx.hmac_digest_size;
 }
 
 
-/* Mode Config Reply
- * Generates a reply stream containing Mode Config information (eg: IP, DNS, WINS)
+/* 
+ * Generate an IKE message containing ModeCfg information (eg: IP, DNS, WINS)
  */
-stf_status modecfg_resp(struct state *st
-			, u_int resp
-			, pb_stream *rbody
-			, u_int16_t replytype
-			, bool hackthat
-			, u_int16_t ap_id)
+static stf_status
+modecfg_build_msg(struct state *st, pb_stream *rbody
+				  , u_int16_t msg_type
+				  , internal_addr_t *ia
+				  , u_int16_t ap_id)
 {
-    u_char *r_hash_start,*r_hashval;
-
-    /* START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_ATTR); */
+    u_char *r_hash_start, *r_hashval;
 
-    {
-	pb_stream hash_pbs;
-	int np = ISAKMP_NEXT_ATTR;
-
-	if (!out_generic(np, &isakmp_hash_desc, rbody, &hash_pbs))
-	    return STF_INTERNAL_ERROR;
-	r_hashval = hash_pbs.cur;	/* remember where to plant value */
-	if (!out_zero(st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH"))
-	    return STF_INTERNAL_ERROR;
-	close_output_pbs(&hash_pbs);
-	r_hash_start = (rbody)->cur;	/* hash from after HASH payload */
-    }
+    START_HASH_PAYLOAD(*rbody, ISAKMP_NEXT_ATTR);
 
     /* ATTR out */
     {
-	struct  isakmp_mode_attr attrh;
+	struct isakmp_mode_attr attrh;
 	struct isakmp_attribute attr;
 	pb_stream strattr,attrval;
 	int attr_type;
-	struct internal_addr ia;
 	int dns_idx, wins_idx;
 	bool dont_advance;
+	lset_t attr_set = ia->attr_set;
 
-	attrh.isama_np = ISAKMP_NEXT_NONE;
-	attrh.isama_type = replytype;
-
+	attrh.isama_np         = ISAKMP_NEXT_NONE;
+	attrh.isama_type       = msg_type;
 	attrh.isama_identifier = ap_id;
+
 	if (!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr))
 	    return STF_INTERNAL_ERROR;
 
-	get_internal_addresses(st->st_connection, &ia);
-
-	if (!isanyaddr(&ia.dns[0]))	/* We got DNS addresses, answer with those */
-	    resp |= LELEM(INTERNAL_IP4_DNS);
-	else
-	    resp &= ~LELEM(INTERNAL_IP4_DNS);
-
-	if (!isanyaddr(&ia.wins[0]))	/* We got WINS addresses, answer with those */
-	    resp |= LELEM(INTERNAL_IP4_NBNS);
-	else
-	    resp &= ~LELEM(INTERNAL_IP4_NBNS);
-
-	if (hackthat)
-	{
-	    if (memcmp(&st->st_connection->spd.that.client.addr
-		      ,&ia.ipaddr
-		      ,sizeof(ia.ipaddr)) != 0)
-	    {
-		/* Make the Internal IP address and Netmask 
-		 * as that client address
-		 */
-		st->st_connection->spd.that.client.addr = ia.ipaddr;
-		st->st_connection->spd.that.client.maskbits = 32;
-		st->st_connection->spd.that.has_client = TRUE;
-	    }
-	}
-
 	attr_type = 0;
 	dns_idx = 0;
 	wins_idx = 0;
 
-	while (resp != 0)
+	while (attr_set != 0)
 	{
 	    dont_advance = FALSE;
-	    if (resp & 1)
+	    if (attr_set & 1)
 	    {
 		const u_char *byte_ptr;
 		u_int len;
@@ -179,14 +224,11 @@ stf_status modecfg_resp(struct state *st
 		switch (attr_type)
 		{
 		case INTERNAL_IP4_ADDRESS:
+		    if (!isanyaddr(&ia->ipaddr))
 		    {
-			char srcip[ADDRTOT_BUF];
-
-			addrtot(&ia.ipaddr, 0, srcip, sizeof(srcip));
-			plog("assigning virtual IP source address %s", srcip);
-			len = addrbytesptr(&ia.ipaddr, &byte_ptr);
- 			out_raw(byte_ptr,len,&attrval,"IP4_addr");
-		     }
+			len = addrbytesptr(&ia->ipaddr, &byte_ptr);
+ 			out_raw(byte_ptr, len, &attrval, "IP4_addr");
+		    }
  		    break;
 		case INTERNAL_IP4_NETMASK:
 		    {
@@ -207,7 +249,7 @@ stf_status modecfg_resp(struct state *st
  			    mask = 0;
  			else
  			    mask = 0xffffffff * 1;
-			    out_raw(&mask,4,&attrval,"IP4_mask");
+			    out_raw(&mask, 4, &attrval, "IP4_mask");
 		    }
 		    break;
 		case INTERNAL_IP4_SUBNET:
@@ -228,22 +270,28 @@ stf_status modecfg_resp(struct state *st
 			        m = 0;
 			}
 			len = addrbytesptr(&st->st_connection->spd.this.client.addr, &byte_ptr);
-			out_raw(byte_ptr,len,&attrval,"IP4_subnet");
-			out_raw(mask,sizeof(mask),&attrval,"IP4_submsk");
+			out_raw(byte_ptr, len, &attrval, "IP4_subnet");
+			out_raw(mask, sizeof(mask), &attrval, "IP4_submsk");
 		    }
 		    break;
 		case INTERNAL_IP4_DNS:
- 		    len = addrbytesptr(&ia.dns[dns_idx++], &byte_ptr);
- 		    out_raw(byte_ptr,len,&attrval,"IP4_dns");
-		    if (dns_idx < 2 && !isanyaddr(&ia.dns[dns_idx]))
+		    if (!isanyaddr(&ia->dns[dns_idx]))
+		    {
+ 		    	len = addrbytesptr(&ia->dns[dns_idx++], &byte_ptr);
+ 		        out_raw(byte_ptr, len, &attrval, "IP4_dns");
+		    }
+		    if (dns_idx < 2 && !isanyaddr(&ia->dns[dns_idx]))
 		    {
 			dont_advance = TRUE;
 		    }
  		    break;
 		case INTERNAL_IP4_NBNS:
- 		    len = addrbytesptr(&ia.wins[wins_idx++], &byte_ptr);
- 		    out_raw(byte_ptr,len,&attrval,"IP4_wins");
-		    if (wins_idx < 2 && !isanyaddr(&ia.wins[wins_idx]))
+		    if (!isanyaddr(&ia->wins[wins_idx]))
+		    {
+ 			len = addrbytesptr(&ia->wins[wins_idx++], &byte_ptr);
+ 			out_raw(byte_ptr, len, &attrval, "IP4_wins");
+		    }
+		    if (wins_idx < 2 && !isanyaddr(&ia->wins[wins_idx]))
 		    {
 			dont_advance = TRUE;
 		    }
@@ -254,35 +302,39 @@ stf_status modecfg_resp(struct state *st
 		    break;
 		}
 		close_output_pbs(&attrval);
-
 	    }
 	    if (!dont_advance)
 	    {
 		attr_type++;
-		resp >>= 1;
+		attr_set >>= 1;
 	    }
 	}
 	close_message(&strattr);
     }
 
-    mode_cfg_hash(r_hashval,r_hash_start,rbody->cur,st);
+    modecfg_hash(r_hashval, r_hash_start, rbody->cur,st);
     close_message(rbody);
     encrypt_message(rbody, st);
     return STF_OK;
 }
 
-/* Set MODE_CONFIG data to client.
- * Pack IP Addresses, DNS, etc... and ship
+/*
+ * Send ModeCfg message
  */
-stf_status modecfg_send_set(struct state *st)
+static stf_status
+modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia)
 {
-    pb_stream reply,rbody;
-    char buf[256];
+    pb_stream msg;
+    pb_stream rbody;
+    char buf[BUF_LEN];
 
-    /* set up reply */
-    init_pbs(&reply, buf, sizeof(buf), "ModecfgR1");
+    /* set up attr */
+    init_pbs(&msg, buf, sizeof(buf), "ModeCfg msg buffer");
+
+    /* this is the beginning of a new exchange */
+    st->st_msgid = generate_msgid(st);
+    init_phase2_iv(st, &st->st_msgid);
 
-    st->st_state = STATE_MODE_CFG_R1;
     /* HDR out */
     {
 	struct isakmp_hdr hdr;
@@ -296,503 +348,280 @@ stf_status modecfg_send_set(struct state *st)
 	memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
 	hdr.isa_msgid = st->st_msgid;
 
-	if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
+	if (!out_struct(&hdr, &isakmp_hdr_desc, &msg, &rbody))
 	{
 	    return STF_INTERNAL_ERROR;
 	}
     }
 
-#define MODECFG_SET_ITEM ( LELEM(INTERNAL_IP4_ADDRESS) | LELEM(INTERNAL_IP4_SUBNET) | LELEM(INTERNAL_IP4_NBNS) | LELEM(INTERNAL_IP4_DNS) )
-
-    modecfg_resp(st, MODECFG_SET_ITEM
-		   , &rbody
-		   , ISAKMP_CFG_SET
-		   , TRUE
-		   , 0/* XXX ID */);
-#undef MODECFG_SET_ITEM
+    /* ATTR out */
+    modecfg_build_msg(st, &rbody
+			, isama_type
+			, ia
+			, 0 /* XXX isama_id */
+		     );
 
-    clonetochunk(st->st_tpacket, reply.start
-		, pbs_offset(&reply), "ModeCfg set");
+    clonetochunk(st->st_tpacket, msg.start, pbs_offset(&msg), "ModeCfg msg");
 
     /* Transmit */
-    send_packet(st, "ModeCfg set");
+    send_packet(st, "ModeCfg msg");
 
-    /* RETRANSMIT if Main, SA_REPLACE if Aggressive */
-    if (st->st_event->ev_type != EVENT_RETRANSMIT
-    && st->st_event->ev_type != EVENT_NULL)
+    if (st->st_event->ev_type != EVENT_RETRANSMIT)
     {
 	delete_event(st);
 	event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
     }
-
+    st->st_modecfg.started = TRUE;
     return STF_OK;
 }
 
-/* Set MODE_CONFIG data to client.
- * Pack IP Addresses, DNS, etc... and ship
- */
-stf_status
-modecfg_start_set(struct state *st)
-{
-    if (st->st_msgid == 0)
-    {
-	/* pick a new message id */
-	st->st_msgid = generate_msgid(st);
-    }
-    st->st_modecfg.vars_set = TRUE;
-
-    return modecfg_send_set(st);
-}
-
 /*
- * Send modecfg IP address request (IP4 address)
+ * Send ModeCfg request message from client to server in pull mode
  */
 stf_status
 modecfg_send_request(struct state *st)
 {
-    pb_stream reply;
-    pb_stream rbody;
-    char buf[256];
-    u_char *r_hash_start,*r_hashval;
+    internal_addr_t ia;
 
-    /* set up reply */
-    init_pbs(&reply, buf, sizeof(buf), "modecfg_buf");
+    init_internal_addr(&ia);
+    ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS)
+	        | LELEM(INTERNAL_IP4_NETMASK);
 
     plog("sending ModeCfg request");
-
-    /* this is the beginning of a new exchange */
-    st->st_msgid = generate_msgid(st);
     st->st_state = STATE_MODE_CFG_I1;
+    return modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia);
+}
 
-    /* HDR out */
-    {
-	struct isakmp_hdr hdr;
-
-	zero(&hdr);	/* default to 0 */
-	hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
-	hdr.isa_np = ISAKMP_NEXT_HASH;
-	hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG;
-	hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
-	memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
-	memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
-	hdr.isa_msgid = st->st_msgid;
-
-	if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
-	{
-	    return STF_INTERNAL_ERROR;
-	}
-    }
-
-    START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_ATTR);
-
-    /* ATTR out */
-    {
-	struct  isakmp_mode_attr attrh;
-	struct isakmp_attribute attr;
-	pb_stream strattr;
-
-	attrh.isama_np = ISAKMP_NEXT_NONE;
-	attrh.isama_type = ISAKMP_CFG_REQUEST;
-	attrh.isama_identifier = 0;
-	if (!out_struct(&attrh, &isakmp_attr_desc, &rbody, &strattr))
-	    return STF_INTERNAL_ERROR;
-	/* ISAKMP attr out (ipv4) */
-	attr.isaat_af_type = INTERNAL_IP4_ADDRESS;
-	attr.isaat_lv = 0;
-	out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, NULL);
-	
-	/* ISAKMP attr out (netmask) */
-	attr.isaat_af_type = INTERNAL_IP4_NETMASK;
-	attr.isaat_lv = 0;
-	out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, NULL);
-
-	close_message(&strattr);
-    }
-
-    mode_cfg_hash(r_hashval,r_hash_start,rbody.cur,st);
-
-    close_message(&rbody);
-    close_output_pbs(&reply);
-
-    init_phase2_iv(st, &st->st_msgid);
-    encrypt_message(&rbody, st);
-
-    clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply)
-	, "modecfg: req");
-
-    /* Transmit */
-    send_packet(st, "modecfg: req");
+/*
+ * Send ModeCfg set message from server to client in push mode
+ */
+stf_status
+modecfg_send_set(struct state *st)
+{
+    internal_addr_t ia;
 
-    /* RETRANSMIT if Main, SA_REPLACE if Aggressive */
-    if (st->st_event->ev_type != EVENT_RETRANSMIT)
-    {	
-	delete_event(st);
-	event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0 * 3, st);
-    }
-    st->st_modecfg.started = TRUE;
+    get_internal_addr(st->st_connection, &ia);
 
-    return STF_OK;
+    plog("sending ModeCfg set");
+    st->st_state = STATE_MODE_CFG_R1;
+    return modecfg_send_msg(st, ISAKMP_CFG_SET, &ia);
 }
 
 /*
- * parse a modecfg attribute payload
+ * Parse a ModeCfg attribute payload
  */
 static stf_status
-modecfg_parse_attributes(pb_stream *attrs, u_int *set)
+modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia)
 {
     struct isakmp_attribute attr;
     pb_stream strattr;
 
-    while (pbs_left(attrs) > sizeof(struct isakmp_attribute))
+    while (pbs_left(attrs) >= sizeof(struct isakmp_attribute))
     {
+	u_int16_t attr_type;
+	u_int16_t attr_len;
+
 	if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr))
 	{
-	    int len = (attr.isaat_af_type & 0x8000)? 4 : attr.isaat_lv;
-
-	    if (len < 4)
-	    {
-		plog("Attribute was too short: %d", len);
-		return STF_FAIL;
-	    }
-
-	    attrs->cur += len;
+	    return STF_FAIL;
 	}
+	attr_type = attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK;
+	attr_len  = attr.isaat_lv;
 
-	switch (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )
+	switch (attr_type)
 	{
 	case INTERNAL_IP4_ADDRESS:
+	    if (attr_len == 4)
+	    {
+		initaddr((char *)(strattr.cur), 4, AF_INET, &ia->ipaddr);
+	    }
+	    /* fall through to set attribute flags */
 	case INTERNAL_IP4_NETMASK:
 	case INTERNAL_IP4_DNS:
 	case INTERNAL_IP4_SUBNET:
 	case INTERNAL_IP4_NBNS:
-	    *set |= LELEM(attr.isaat_af_type);
+	    ia->attr_set |= LELEM(attr_type);
 	    break;
 	default:
-	    plog("unsupported mode cfg attribute %s received."
-		, enum_show(&modecfg_attr_names
-		    , attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK ));
+	    plog("unsupported ModeCfg attribute %s received."
+		, enum_show(&modecfg_attr_names, attr_type));
 	    break;
 	}
     }
     return STF_OK;
 }
 
-/* STATE_MODE_CFG_R0:
- * HDR*, HASH, ATTR(REQ=IP) --> HDR*, HASH, ATTR(REPLY=IP)
- *
- * This state occurs both in the responder and in the initiator.
- *
- * In the responding server, it occurs when the client *asks* for an IP
- * address or other information.
- *
- * Otherwise, it occurs in the initiator when the server sends a challenge
- * a set, or has a reply to our request.
+/* 
+ * Parse a ModeCfg message
  */
-stf_status
-modecfg_inR0(struct msg_digest *md)
+static stf_status
+modecfg_parse_msg(struct msg_digest *md, int isama_type, u_int16_t *isama_id
+		, internal_addr_t *ia)
 {
     struct state *const st = md->st;
     struct payload_digest *p;
     stf_status stat;
 
-    plog("received ModeCfg request");
-
     st->st_msgid = md->hdr.isa_msgid;
-    CHECK_QUICK_HASH(md, mode_cfg_hash(hash_val
-				      ,hash_pbs->roof
-				      , md->message_pbs.roof, st)
-		     , "MODECFG-HASH", "MODE R0");
 
-    /* process the MODECFG payloads therein */
+    CHECK_QUICK_HASH(md, modecfg_hash(hash_val
+				    , hash_pbs->roof
+				    , md->message_pbs.roof, st)
+		       , "MODECFG-HASH", "ISAKMP_CFG_MSG");
+
+    /* process the ModeCfg payloads received */
     for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
     {
-	u_int set_modecfg_attrs = LEMPTY;
-
-	switch (p->payload.attribute.isama_type)
-	{
-	default:
-	    plog("Expecting ISAKMP_CFG_REQUEST, got %s instead (ignored)."
-		, enum_name(&attr_msg_type_names
-			, p->payload.attribute.isama_type));
-
-	    stat = modecfg_parse_attributes(&p->pbs, &set_modecfg_attrs);
-	    if (stat != STF_OK)
-		return stat;
-	    break;
+	internal_addr_t ia_candidate;
 
-	case ISAKMP_CFG_REQUEST:
-	    stat = modecfg_parse_attributes(&p->pbs, &set_modecfg_attrs);
-	    if (stat != STF_OK)
-		return stat;
+	init_internal_addr(&ia_candidate);
 
-	    stat = modecfg_resp(st, set_modecfg_attrs
-				,&md->rbody
-				,ISAKMP_CFG_REPLY
-				,TRUE
-				,p->payload.attribute.isama_identifier);
+	if (p->payload.attribute.isama_type == isama_type)
+	{
+	    *isama_id = p->payload.attribute.isama_identifier;
 
-	    if (stat != STF_OK)
+	    stat = modecfg_parse_attributes(&p->pbs, &ia_candidate);
+	    if (stat == STF_OK)
 	    {
-		/* notification payload - not exactly the right choice, but okay */
-		md->note = CERTIFICATE_UNAVAILABLE;
-		return stat;
+		/* retrun with a valid set of attributes */
+		*ia = ia_candidate;
+		return STF_OK;
 	    }
+	}
+	else
+	{
+	    plog("expected %s, got %s instead (ignored)"
+		, enum_name(&attr_msg_type_names, isama_type)
+		, enum_name(&attr_msg_type_names, p->payload.attribute.isama_type));
 
-	    /* they asked us, we responded, msgid is done */
-	    st->st_msgid = 0;
+	    stat = modecfg_parse_attributes(&p->pbs, &ia_candidate);
 	}
+	if (stat != STF_OK)
+	    return stat;
     }
-    return STF_OK;
+    return STF_IGNORE;
 }
 
-/* STATE_MODE_CFG_R2:
- *  HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK)
+/* STATE_MODE_CFG_R0:
+ * HDR*, HASH, ATTR(REQ=IP) --> HDR*, HASH, ATTR(REPLY=IP)
  *
- * used in server push mode, on the client (initiator).
+ * used in ModeCfg pull mode, on the server (responder)
  */
-static stf_status
-modecfg_inI2(struct msg_digest *md)
+stf_status
+modecfg_inR0(struct msg_digest *md)
 {
     struct state *const st = md->st;
-    pb_stream *attrs = &md->chain[ISAKMP_NEXT_ATTR]->pbs;
-    int resp = LEMPTY;
+    u_int16_t isama_id;
+    internal_addr_t ia;
     stf_status stat;
-    struct payload_digest *p;
-    u_int16_t isama_id = 0;
-
-    st->st_msgid = md->hdr.isa_msgid;
-    CHECK_QUICK_HASH(md
-		     , mode_cfg_hash(hash_val
-				    ,hash_pbs->roof
-				    , md->message_pbs.roof
-				    , st)
-		     , "MODECFG-HASH", "MODE R1");
-
-    for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
-    {
-        struct isakmp_attribute attr;
-        pb_stream strattr;
 
-	isama_id = p->payload.attribute.isama_identifier;
-
-	if (p->payload.attribute.isama_type != ISAKMP_CFG_SET)
-	{
-	    plog("Expecting MODE_CFG_SET, got %x instead."
-			 ,md->chain[ISAKMP_NEXT_ATTR]->payload.attribute.isama_type);
-	    return STF_IGNORE;
-	}
-
-	/* CHECK that SET has been received. */
-
-	while (pbs_left(attrs) > sizeof(struct isakmp_attribute))
-	{
-            if (!in_struct(&attr, &isakmp_modecfg_attribute_desc
-			   , attrs, &strattr))
-	    {
-		int len;
-
-		/* Skip unknown */
-		if (attr.isaat_af_type & 0x8000)
-		    len = 4;
-		else
-		    len = attr.isaat_lv;
-
-		if (len < 4)
-		{
-		    plog("Attribute was too short: %d", len);
-		    return STF_FAIL;
-		}
-
-		attrs->cur += len;
-	    }
-
-	    switch (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )
-	    {
-	    case INTERNAL_IP4_ADDRESS:
-		{
-		    struct connection *c = st->st_connection;
-		    ip_address a;
-		    u_int32_t *ap = (u_int32_t *)(strattr.cur);
-		    a.u.v4.sin_family = AF_INET;
-
-		    memcpy(&a.u.v4.sin_addr.s_addr, ap
-			       , sizeof(a.u.v4.sin_addr.s_addr));
-
-		    if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
-		    || isanyaddr(&c->spd.this.host_srcip))
-		    {
-			char srcip[ADDRTOT_BUF];
-
-			c->spd.this.host_srcip = a;
-			addrtot(&a, 0, srcip, sizeof(srcip));
-			plog("setting virtual IP source address to %s", srcip);
-		    }
-
-		    /* setting client subnet as srcip/32 */
-		    addrtosubnet(&a, &c->spd.this.client);
-		    c->spd.this.has_client = TRUE;
-		}
-		resp |= LELEM(attr.isaat_af_type);
-		break;
-	    case INTERNAL_IP4_NETMASK:
-	    case INTERNAL_IP4_DNS:
-	    case INTERNAL_IP4_SUBNET:
-	    case INTERNAL_IP4_NBNS:
-		resp |= LELEM(attr.isaat_af_type);
-		break;
-	    default:
-		plog("unsupported mode cfg attribute %s received."
-			, enum_show(&modecfg_attr_names, (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )));
-		break;
-	    }
-	}
-    }
+    stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia);
+    if (stat != STF_OK)
+	return stat;
 
-    /* ack things */
-    stat = modecfg_resp(st, resp
-			,&md->rbody
-			,ISAKMP_CFG_ACK
-			,FALSE
-			,isama_id);
+    get_internal_addr(st->st_connection, &ia);
 
+    /* build ISAKMP_CFG_REPLY */ 
+    stat = modecfg_build_msg(st, &md->rbody
+			       , ISAKMP_CFG_REPLY
+			       , &ia
+			       , isama_id);
     if (stat != STF_OK)
     {
 	/* notification payload - not exactly the right choice, but okay */
-	md->note = CERTIFICATE_UNAVAILABLE;
+	md->note = ATTRIBUTES_NOT_SUPPORTED;
 	return stat;
     }
 
-    /*
-     * we are done with this exchange, clear things so
-     * that we can start phase 2 properly
-     */
     st->st_msgid = 0;
-
-    if (resp)
-    {
-	st->st_modecfg.vars_set = TRUE;
-    }
     return STF_OK;
 }
 
 /* STATE_MODE_CFG_R1:
- * HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK)
+ * HDR*, HASH, ATTR(ACK,OK)
+ *
+ * used in ModeCfg push mode, on the server (responder)
  */
 stf_status
 modecfg_inR1(struct msg_digest *md)
 {
     struct state *const st = md->st;
-    pb_stream *attrs = &md->chain[ISAKMP_NEXT_ATTR]->pbs;
-    int set_modecfg_attrs = LEMPTY;
+    u_int16_t isama_id;
+    internal_addr_t ia;
     stf_status stat;
-    struct payload_digest *p;
 
-    plog("parsing ModeCfg reply");
-
-    st->st_msgid = md->hdr.isa_msgid;
-    CHECK_QUICK_HASH(md, mode_cfg_hash(hash_val,hash_pbs->roof, md->message_pbs.roof, st)
-	, "MODECFG-HASH", "MODE R1");
+    plog("parsing ModeCfg ack");
 
+    stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia);
+    if (stat != STF_OK)
+	return stat;
 
-    /* process the MODECFG payloads therein */
-    for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
-    {
-        struct isakmp_attribute attr;
-        pb_stream strattr;
-	
-	attrs = &p->pbs;
-	
-	switch (p->payload.attribute.isama_type)
-	{
-	default:
-	{
-	    plog("Expecting MODE_CFG_ACK, got %x instead."
-		,md->chain[ISAKMP_NEXT_ATTR]->payload.attribute.isama_type);
-	    return STF_IGNORE;
-	}
-	break;
-	
-	case ISAKMP_CFG_ACK:
-	    /* CHECK that ACK has been received. */
-	    stat = modecfg_parse_attributes(attrs, &set_modecfg_attrs);
-	    if (stat != STF_OK)
-		return stat;
-	    break;
+    st->st_msgid = 0;
+    return STF_OK;
+}
 
-	case ISAKMP_CFG_REPLY:
-	    while (pbs_left(attrs) > sizeof(struct isakmp_attribute))
-	    {
-		if (!in_struct(&attr, &isakmp_modecfg_attribute_desc
-			       , attrs, &strattr))
-		{
-		    /* Skip unknown */
-		    int len;
-		    if (attr.isaat_af_type & 0x8000)
-			len = 4;
-		    else
-			len = attr.isaat_lv;
-		    
-		    if (len < 4)
-		    {
-			plog("Attribute was too short: %d", len);
-			return STF_FAIL;
-		    }
+/* STATE_MODE_CFG_I1:
+ * HDR*, HASH, ATTR(REPLY=IP)
+ *
+ * used in ModeCfg pull mode, on the client (initiator) 
+ */
+stf_status
+modecfg_inI1(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+    u_int16_t isama_id;
+    internal_addr_t ia;
+    stf_status stat;
 
-		    attrs->cur += len;
-		}
+    plog("parsing ModeCfg reply");
 
-		switch (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )
-		{
-		case INTERNAL_IP4_ADDRESS:
-		   {
-			struct connection *c = st->st_connection;
-			ip_address a;
-			u_int32_t *ap = (u_int32_t *)(strattr.cur);
-			a.u.v4.sin_family = AF_INET;
+    stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia);
+    if (stat != STF_OK)
+	return stat;
 
-			memcpy(&a.u.v4.sin_addr.s_addr, ap
-			   , sizeof(a.u.v4.sin_addr.s_addr));
+    st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia);
+    st->st_msgid = 0;
+    return STF_OK;
+}
 
-			if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
-			|| isanyaddr(&c->spd.this.host_srcip))
-			{
-			    char srcip[ADDRTOT_BUF];
+/* STATE_MODE_CFG_I2:
+ *  HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK)
+ *
+ * used in ModeCfg push mode, on the client (initiator).
+ */
+stf_status
+modecfg_inI2(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+    u_int16_t isama_id;
+    internal_addr_t ia;
+    lset_t attr_set;
+    stf_status stat;
 
-			    c->spd.this.host_srcip = a;
-			    addrtot(&a, 0, srcip, sizeof(srcip));
-			    plog("setting virtual IP source address to %s", srcip);
-			}
+    plog("parsing ModeCfg set");
 
-			/* setting client subnet as srcip/32 */
-			addrtosubnet(&a, &c->spd.this.client);
-			setportof(0, &c->spd.this.client.addr);
-			c->spd.this.has_client = TRUE;
-		    }
-		    /* fall through to set attribute flage */
+    stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia);
+    if (stat != STF_OK)
+	return stat;
 
-		case INTERNAL_IP4_NETMASK:
-		case INTERNAL_IP4_DNS:
-		case INTERNAL_IP4_SUBNET:
-		case INTERNAL_IP4_NBNS:
-		    set_modecfg_attrs |= LELEM(attr.isaat_af_type);
-		    break;
-		default:
-		    plog("unsupported mode cfg attribute %s received."
-			    , enum_show(&modecfg_attr_names
-				, (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )));
-		    break;
-		}
-	    }
-	    break;
-	}
-    }
+    st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia);
 
-    /* we are done with this exchange, clear things so that we can start phase 2 properly */
-    st->st_msgid = 0;
+    /* prepare ModeCfg ack which sends zero length attributes */
+    attr_set = ia.attr_set;
+    init_internal_addr(&ia);
+    ia.attr_set = attr_set & SUPPORTED_ATTR_SET;
 
-    if (set_modecfg_attrs)
+    stat = modecfg_build_msg(st, &md->rbody
+			       , ISAKMP_CFG_ACK
+			       , &ia
+			       , isama_id);
+    if (stat != STF_OK)
     {
-	st->st_modecfg.vars_set = TRUE;
+	/* notification payload - not exactly the right choice, but okay */
+	md->note = ATTRIBUTES_NOT_SUPPORTED;
+	return stat;
     }
+
+    st->st_msgid = 0;
     return STF_OK;
 }
diff --git a/programs/pluto/modecfg.h b/programs/pluto/modecfg.h
index f6856d263..1f8259ca8 100644
--- a/programs/pluto/modecfg.h
+++ b/programs/pluto/modecfg.h
@@ -12,22 +12,17 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: modecfg.h,v 1.1 2005/01/06 22:10:15 as Exp $
+ * RCSID $Id: modecfg.h,v 1.3 2006/10/19 21:07:40 as Exp $
  */
 
 struct state;
 
-stf_status modecfg_resp(struct state *st
-			, u_int resp
-			, pb_stream *s, u_int16_t cmd
-			, bool hackthat, u_int16_t id);
-
-stf_status modecfg_send_set(struct state *st);
-
-extern stf_status modecfg_start_set(struct state *st);
-
-/* Mode Config States */
+/* ModeConfig starting functions */
+extern stf_status modecfg_send_request(struct state *st);
+extern stf_status modecfg_send_set(struct state *st);
 
+/* ModeConfig state transition functions */
 extern stf_status modecfg_inR0(struct msg_digest *md);
 extern stf_status modecfg_inR1(struct msg_digest *md);
-extern stf_status modecfg_send_request(struct state *st);
+extern stf_status modecfg_inI1(struct msg_digest *md);
+extern stf_status modecfg_inI2(struct msg_digest *md);
diff --git a/programs/pluto/state.c b/programs/pluto/state.c
index 0781d2eb3..8181c34b4 100644
--- a/programs/pluto/state.c
+++ b/programs/pluto/state.c
@@ -12,7 +12,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: state.c,v 1.13 2006/04/29 18:16:02 as Exp $
+ * RCSID $Id: state.c,v 1.15 2006/10/20 15:02:23 as Exp $
  */
 
 #include <stdio.h>
@@ -716,7 +716,7 @@ state_eroute_usage(ip_subnet *ours, ip_subnet *his
 	});
 }
 
-void fmt_state(struct state *st, time_t n
+void fmt_state(bool all, struct state *st, time_t n
 , char *state_buf, size_t state_buf_len
 , char *state_buf2, size_t state_buf2_len)
 {
@@ -735,20 +735,22 @@ void fmt_state(struct state *st, time_t n
     /* XXX spd-enum */
     const char *eo = c->spd.eroute_owner == st->st_serialno
 	? "; eroute owner" : "";
-
+    const char *dpd = (all && st->st_dpd && c->dpd_action != DPD_ACTION_NONE)
+		      ? "; DPD active" : "";
+    
     passert(st->st_event != 0);
 
     fmt_conn_instance(c, inst);
 
     snprintf(state_buf, state_buf_len
-	, "#%lu: \"%s\"%s %s (%s); %s in %lds%s%s%s"
+	, "#%lu: \"%s\"%s %s (%s); %s in %lds%s%s%s%s"
 	, st->st_serialno
 	, c->name, inst
 	, enum_name(&state_names, st->st_state)
 	, state_story[st->st_state - STATE_MAIN_R0]
 	, enum_name(&timer_event_names, st->st_event->ev_type)
 	, delta
-	, np1, np2, eo);
+	, np1, np2, eo, dpd);
 
     /* print out SPIs if SAs are established */
     if (state_buf2_len != 0)
@@ -846,7 +848,7 @@ state_compare(const void *a, const void *b)
 }
 
 void
-show_states_status(const char *name)
+show_states_status(bool all, const char *name)
 {
     time_t n = now();
     int i;
@@ -892,7 +894,8 @@ show_states_status(const char *name)
 
 	st = array[i];
 
-	fmt_state(st, n, state_buf, sizeof(state_buf)
+	fmt_state(all, st, n
+		  , state_buf, sizeof(state_buf)
 		  , state_buf2, sizeof(state_buf2));
 	whack_log(RC_COMMENT, state_buf);
 	if (state_buf2[0] != '\0')
diff --git a/programs/pluto/state.h b/programs/pluto/state.h
index 2f30d77f1..c7212fd1a 100644
--- a/programs/pluto/state.h
+++ b/programs/pluto/state.h
@@ -12,7 +12,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: state.h,v 1.11 2006/03/08 22:12:37 as Exp $
+ * RCSID $Id: state.h,v 1.12 2006/10/17 10:30:54 as Exp $
  */
 
 #include <sys/types.h>
@@ -259,11 +259,11 @@ extern struct state
     *find_phase1_state(const struct connection *c, lset_t ok_states),
     *find_sender(size_t packet_len, u_char *packet);
 
-extern void show_states_status(const char *name);
+extern void show_states_status(bool all, const char *name);
 extern void for_each_state(void *(f)(struct state *, void *data), void *data);
 extern void find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi);
 extern ipsec_spi_t uniquify_his_cpi(ipsec_spi_t cpi, struct state *st);
-extern void fmt_state(struct state *st, time_t n
+extern void fmt_state(bool all, struct state *st, time_t n
 		     , char *state_buf, size_t state_buf_len
 		     , char *state_buf2, size_t state_buf_len2);
 extern void delete_states_by_peer(ip_address *peer);
diff --git a/programs/pluto/vendor.c b/programs/pluto/vendor.c
index a51971cde..cbb26a5ef 100644
--- a/programs/pluto/vendor.c
+++ b/programs/pluto/vendor.c
@@ -11,7 +11,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: vendor.c,v 1.39 2006/07/06 12:32:41 as Exp $
+ * RCSID $Id: vendor.c,v 1.41 2006/10/19 15:21:08 as Exp $
  */
 
 #include <stdlib.h>
@@ -200,9 +200,13 @@ static struct vid_struct _vid_tab[] = {
 	 */
 	DEC_MD5_VID(STRONGSWAN_4_0_0, "strongSwan 4.0.0")
 	DEC_MD5_VID(STRONGSWAN_4_0_1, "strongSwan 4.0.1")
-	DEC_MD5_VID(STRONGSWAN_4_0_1, "strongSwan 4.0.2")
+	DEC_MD5_VID(STRONGSWAN_4_0_2, "strongSwan 4.0.2")
+	DEC_MD5_VID(STRONGSWAN_4_0_3, "strongSwan 4.0.3")
+	DEC_MD5_VID(STRONGSWAN_4_0_4, "strongSwan 4.0.4")
+	DEC_MD5_VID(STRONGSWAN_4_0_5, "strongSwan 4.0.5")
 
-	DEC_MD5_VID(STRONGSWAN,       "strongSwan 2.7.3")
+	DEC_MD5_VID(STRONGSWAN,       "strongSwan 2.8.0")
+	DEC_MD5_VID(STRONGSWAN_2_7_3, "strongSwan 2.7.3")
 	DEC_MD5_VID(STRONGSWAN_2_7_2, "strongSwan 2.7.2")
 	DEC_MD5_VID(STRONGSWAN_2_7_1, "strongSwan 2.7.1")
 	DEC_MD5_VID(STRONGSWAN_2_7_0, "strongSwan 2.7.0")
diff --git a/programs/pluto/vendor.h b/programs/pluto/vendor.h
index c4ed6d294..c7f70a480 100644
--- a/programs/pluto/vendor.h
+++ b/programs/pluto/vendor.h
@@ -11,7 +11,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: vendor.h,v 1.34 2006/07/06 12:32:41 as Exp $
+ * RCSID $Id: vendor.h,v 1.36 2006/10/19 15:21:08 as Exp $
  */
 
 #ifndef _VENDOR_H_
@@ -79,10 +79,14 @@ enum known_vendorid {
   VID_STRONGSWAN_2_7_0		= 58,
   VID_STRONGSWAN_2_7_1		= 59,
   VID_STRONGSWAN_2_7_2		= 60,
+  VID_STRONGSWAN_2_7_3		= 61,
 
   VID_STRONGSWAN_4_0_0		= 70,
   VID_STRONGSWAN_4_0_1		= 71,
   VID_STRONGSWAN_4_0_2		= 72,
+  VID_STRONGSWAN_4_0_3		= 73,
+  VID_STRONGSWAN_4_0_4		= 74,
+  VID_STRONGSWAN_4_0_5		= 75,
 
   /* 101 - 200 : NAT-Traversal */
   VID_NATT_STENBERG_01		=101,
diff --git a/programs/pluto/whack.h b/programs/pluto/whack.h
index 3086f1543..755918a2c 100644
--- a/programs/pluto/whack.h
+++ b/programs/pluto/whack.h
@@ -11,7 +11,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: whack.h,v 1.16 2006/04/17 10:39:14 as Exp $
+ * RCSID $Id: whack.h,v 1.17 2006/10/19 15:18:43 as Exp $
  */
 
 #ifndef _WHACK_H
@@ -62,6 +62,7 @@ struct whack_end {
     bool has_client_wildcard;
     bool has_port_wildcard;
     bool has_srcip;
+    bool has_natip;
     bool modecfg;
     bool hostaccess;
     certpolicy_t sendcert;
diff --git a/programs/starter/args.c b/programs/starter/args.c
index 6f3da63eb..2b2853a20 100644
--- a/programs/starter/args.c
+++ b/programs/starter/args.c
@@ -12,7 +12,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: args.c,v 1.9 2006/04/17 10:32:36 as Exp $
+ * RCSID $Id: args.c,v 1.10 2006/10/19 14:58:30 as Exp $
  */
 
 #include <stddef.h>
@@ -191,6 +191,7 @@ static const token_info_t token_info[] =
     { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL                          },
     { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL                        },
     { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action               },
+    { ARG_MISC, 0, NULL  /* KW_MODECONFIG */                                       },
 
     /* ca section keywords */
     { ARG_STR,  offsetof(starter_ca_t, name), NULL                                 },
@@ -209,6 +210,7 @@ static const token_info_t token_info[] =
     { ARG_MISC, 0, NULL  /* KW_SUBNETWITHIN */                                     },
     { ARG_MISC, 0, NULL  /* KW_PROTOPORT */                                        },
     { ARG_MISC, 0, NULL  /* KW_SOURCEIP */                                         },
+    { ARG_MISC, 0, NULL  /* KW_NATIP */                                            },
     { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool                        },
     { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool                      },
     { ARG_STR,  offsetof(starter_end_t, updown), NULL                              },
diff --git a/programs/starter/confread.c b/programs/starter/confread.c
index af0f00877..edd041ab4 100644
--- a/programs/starter/confread.c
+++ b/programs/starter/confread.c
@@ -11,7 +11,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: confread.c,v 1.38 2006/06/20 21:52:53 as Exp $
+ * RCSID $Id: confread.c,v 1.39 2006/10/19 14:58:30 as Exp $
  */
 
 #include <stddef.h>
@@ -255,6 +255,11 @@ kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token
 	end->has_port_wildcard = has_port_wildcard;
 	break;
     case KW_SOURCEIP:
+	if (end->has_natip)
+	{
+	    plog("# natip and sourceip cannot be defined at the same time");
+	    goto err;
+	}
 	if (streq(value, "%modeconfig") || streq(value, "%modecfg"))
 	{
 	    end->modecfg = TRUE;
@@ -272,6 +277,22 @@ kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token
 	}
 	conn->policy |= POLICY_TUNNEL;
 	break;
+    case KW_NATIP:
+	if (end->has_srcip)
+	{
+	    plog("# natip and sourceip cannot be defined at the same time");
+	    goto err;
+	}
+	conn->tunnel_addr_family = ip_version(value);
+	ugh = ttoaddr(value, 0, conn->tunnel_addr_family, &end->srcip);
+	if (ugh != NULL)
+	{
+	    plog("# bad addr: %s=%s [%s]", name, value, ugh);
+	    goto err;
+	}
+	end->has_natip = TRUE;
+	conn->policy |= POLICY_TUNNEL;
+	break;
     default:
 	break;
     }
@@ -430,6 +451,9 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg)
 	case KW_REKEY:
 	    KW_POLICY_FLAG("no", "yes", POLICY_DONT_REKEY)
 	    break;
+	case KW_MODECONFIG:
+	    KW_POLICY_FLAG("push", "pull", POLICY_MODECFG_PUSH)
+	    break;
 	default:
 	    break;
 	}
diff --git a/programs/starter/confread.h b/programs/starter/confread.h
index a3b1b7379..052f5d527 100644
--- a/programs/starter/confread.h
+++ b/programs/starter/confread.h
@@ -11,7 +11,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: confread.h,v 1.23 2006/04/17 10:32:36 as Exp $
+ * RCSID $Id: confread.h,v 1.24 2006/10/19 15:01:05 as Exp $
  */
 
 #ifndef _IPSEC_CONFREAD_H_
@@ -49,15 +49,16 @@ struct starter_end {
 	char		*cert;
 	char		*ca;
 	char		*groups;
-	char            *iface;
+	char		*iface;
 	ip_address	addr;
 	ip_address	nexthop;
 	ip_address	srcip;
-	ip_subnet       subnet;
+	ip_subnet	subnet;
 	bool		has_client;
 	bool		has_client_wildcard;
-        bool		has_port_wildcard;
+	bool		has_port_wildcard;
 	bool		has_srcip;
+	bool		has_natip;
 	bool		modecfg;
 	certpolicy_t	sendcert;
 	bool		firewall;
diff --git a/programs/starter/keywords.c b/programs/starter/keywords.c
index 4cc5c03e8..75be0a542 100644
--- a/programs/starter/keywords.c
+++ b/programs/starter/keywords.c
@@ -44,7 +44,7 @@ error "gperf generated tables don't work with this execution character set. Plea
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: keywords.c,v 1.7 2006/04/17 10:32:48 as Exp $
+ * RCSID $Id: keywords.c,v 1.8 2006/10/19 14:58:30 as Exp $
  */
 
 #include <string.h>
@@ -56,12 +56,12 @@ struct kw_entry {
     kw_token_t token;
 };
 
-#define TOTAL_KEYWORDS 77
+#define TOTAL_KEYWORDS 80
 #define MIN_WORD_LENGTH 3
 #define MAX_WORD_LENGTH 17
 #define MIN_HASH_VALUE 9
-#define MAX_HASH_VALUE 146
-/* maximum key range = 138, duplicates = 0 */
+#define MAX_HASH_VALUE 156
+/* maximum key range = 148, duplicates = 0 */
 
 #ifdef __GNUC__
 __inline
@@ -77,32 +77,32 @@ hash (str, len)
 {
   static const unsigned char asso_values[] =
     {
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-       15, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147,  85, 147,  40,
-       25,  25,   0,  10,   5,  80, 147,  35,  60,  35,
-       60,  55,  10, 147,  15,  20,   5,  65, 147, 147,
-      147,  35,   0, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
-      147, 147, 147, 147, 147, 147
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+       25, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157,  90, 157,  60,
+       50,  25,   0,  10,   5,  65, 157,  65,  70,   5,
+        0,  75,  35, 157,  10,  20,   5,  70, 157, 157,
+      157,  55,   0, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157, 157, 157, 157, 157,
+      157, 157, 157, 157, 157, 157
     };
   return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[len - 1]];
 }
@@ -111,104 +111,113 @@ static const struct kw_entry wordlist[] =
   {
     {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
     {"left",              KW_LEFT},
-    {""}, {""}, {""},
+    {"leftupdown",        KW_LEFTUPDOWN},
+    {""}, {""},
     {"leftcert",          KW_LEFTCERT,},
     {"auth",              KW_AUTH},
     {"leftsubnet",        KW_LEFTSUBNET},
-    {""},
+    {"leftsubnetwithin",  KW_LEFTSUBNETWITHIN},
     {"leftsendcert",      KW_LEFTSENDCERT},
     {"leftprotoport",     KW_LEFTPROTOPORT},
     {""},
     {"right",             KW_RIGHT},
-    {"leftnexthop",       KW_LEFTNEXTHOP},
-    {"leftsourceip",      KW_LEFTSOURCEIP},
-    {"esp",               KW_ESP},
+    {"rightupdown",       KW_RIGHTUPDOWN},
+    {"dumpdir",           KW_DUMPDIR},
+    {""},
     {"rightcert",         KW_RIGHTCERT},
     {""},
     {"rightsubnet",       KW_RIGHTSUBNET},
-    {""},
+    {"rightsubnetwithin", KW_RIGHTSUBNETWITHIN},
     {"rightsendcert",     KW_RIGHTSENDCERT},
     {"rightprotoport",    KW_RIGHTPROTOPORT},
     {"leftgroups",        KW_LEFTGROUPS},
-    {"leftid",            KW_LEFTID},
-    {"rightnexthop",      KW_RIGHTNEXTHOP},
-    {"rightsourceip",     KW_RIGHTSOURCEIP},
+    {""}, {""},
+    {"compress",          KW_COMPRESS},
     {"lefthostaccess",    KW_LEFTHOSTACCESS},
     {"interfaces",        KW_INTERFACES},
+    {""}, {""}, {""}, {""}, {""},
+    {"rightgroups",       KW_RIGHTGROUPS},
+    {""},
+    {"pfs",               KW_PFS},
+    {"leftnatip",         KW_LEFTNATIP},
+    {"righthostaccess",   KW_RIGHTHOSTACCESS},
+    {"leftnexthop",       KW_LEFTNEXTHOP},
+    {"leftsourceip",      KW_LEFTSOURCEIP},
     {""}, {""},
+    {"virtual_private",   KW_VIRTUAL_PRIVATE},
+    {""}, {""},
+    {"ike",               KW_IKE},
+    {""},
+    {"rightnatip",        KW_RIGHTNATIP},
+    {"leftid",            KW_LEFTID},
+    {"rightnexthop",      KW_RIGHTNEXTHOP},
+    {"rightsourceip",     KW_RIGHTSOURCEIP},
+    {"dpdaction",         KW_DPDACTION},
+    {"keep_alive",        KW_KEEP_ALIVE},
+    {"ikelifetime",       KW_IKELIFETIME},
+    {""},
     {"pfsgroup",          KW_PFSGROUP},
     {"type",              KW_TYPE},
     {"dpdtimeout",        KW_DPDTIMEOUT},
-    {"rightgroups",       KW_RIGHTGROUPS},
-    {"rightid",           KW_RIGHTID},
-    {"pfs",               KW_PFS},
-    {"rekeyfuzz",         KW_REKEYFUZZ},
-    {"righthostaccess",   KW_RIGHTHOSTACCESS},
     {"authby",            KW_AUTHBY},
-    {""},
+    {"rightid",           KW_RIGHTID},
     {"leftrsasigkey",     KW_LEFTRSASIGKEY},
-    {""}, {""},
+    {""},
+    {"modeconfig",        KW_MODECONFIG},
     {"cacert",            KW_CACERT},
-    {"hidetos",           KW_HIDETOS},
-    {"ike",               KW_IKE},
     {""},
-    {"virtual_private",   KW_VIRTUAL_PRIVATE},
+    {"esp",               KW_ESP},
+    {"rekeyfuzz",         KW_REKEYFUZZ},
     {""},
-    {"dumpdir",           KW_DUMPDIR},
+    {"rekeymargin",       KW_REKEYMARGIN},
+    {"hidetos",           KW_HIDETOS},
     {"packetdefault",     KW_PACKETDEFAULT},
     {"rightrsasigkey",    KW_RIGHTRSASIGKEY},
-    {"keep_alive",        KW_KEEP_ALIVE},
-    {"ikelifetime",       KW_IKELIFETIME},
+    {"strictcrlpolicy",   KW_STRICTCRLPOLICY},
+    {""},
+    {"leftfirewall",      KW_LEFTFIREWALL},
     {""},
-    {"compress",          KW_COMPRESS},
     {"auto",              KW_AUTO},
-    {"strictcrlpolicy",   KW_STRICTCRLPOLICY},
+    {"klipsdebug",        KW_KLIPSDEBUG},
     {"keyingtries",       KW_KEYINGTRIES},
     {"keylife",           KW_KEYLIFE},
-    {"dpddelay",          KW_DPDDELAY},
+    {"nat_traversal",     KW_NAT_TRAVERSAL},
     {"cachecrls",         KW_CACHECRLS},
-    {"leftupdown",        KW_LEFTUPDOWN},
+    {"plutodebug",        KW_PLUTODEBUG},
     {"keyexchange",       KW_KEYEXCHANGE},
-    {"leftfirewall",      KW_LEFTFIREWALL},
-    {"nocrsend",          KW_NOCRSEND},
+    {"ocspuri",           KW_OCSPURI},
+    {"rightfirewall",     KW_RIGHTFIREWALL},
+    {"uniqueids",         KW_UNIQUEIDS},
     {""},
-    {"rekey",             KW_REKEY},
-    {"leftsubnetwithin",  KW_LEFTSUBNETWITHIN},
+    {"leftca",            KW_LEFTCA},
     {"pkcs11module",      KW_PKCS11MODULE},
-    {"nat_traversal",     KW_NAT_TRAVERSAL},
+    {""},
     {"also",              KW_ALSO},
     {"pkcs11keepstate",   KW_PKCS11KEEPSTATE},
-    {"rightupdown",       KW_RIGHTUPDOWN},
+    {""},
     {"crluri2",           KW_CRLURI2},
-    {"rightfirewall",     KW_RIGHTFIREWALL},
-    {"postpluto",         KW_POSTPLUTO},
-    {"plutodebug",        KW_PLUTODEBUG},
-    {"pkcs11proxy",       KW_PKCS11PROXY},
-    {"rightsubnetwithin", KW_RIGHTSUBNETWITHIN},
-    {"prepluto",          KW_PREPLUTO},
-    {""}, {""},
-    {"leftca",            KW_LEFTCA},
-    {""}, {""},
-    {"dpdaction",         KW_DPDACTION},
-    {""}, {""}, {""},
     {"ldaphost",          KW_LDAPHOST},
+    {"postpluto",         KW_POSTPLUTO},
     {""},
-    {"klipsdebug",        KW_KLIPSDEBUG},
     {"overridemtu",       KW_OVERRIDEMTU},
     {"rightca",           KW_RIGHTCA},
-    {"fragicmp",          KW_FRAGICMP},
-    {""}, {""},
-    {"rekeymargin",       KW_REKEYMARGIN},
-    {"ocspuri",           KW_OCSPURI},
-    {""},
-    {"uniqueids",         KW_UNIQUEIDS},
-    {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+    {"prepluto",          KW_PREPLUTO},
+    {""}, {""}, {""}, {""},
+    {"dpddelay",          KW_DPDDELAY},
+    {""}, {""}, {""}, {""},
+    {"nocrsend",          KW_NOCRSEND},
+    {""}, {""}, {""}, {""},
     {"ldapbase",          KW_LDAPBASE},
+    {""},
+    {"rekey",             KW_REKEY},
+    {"pkcs11proxy",       KW_PKCS11PROXY},
+    {""}, {""}, {""}, {""}, {""}, {""},
+    {"fragicmp",          KW_FRAGICMP},
+    {""}, {""}, {""}, {""}, {""}, {""}, {""},
+    {"crluri",            KW_CRLURI},
     {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-    {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-    {"crlcheckinterval",  KW_CRLCHECKINTERVAL},
-    {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-    {"crluri",            KW_CRLURI}
+    {""}, {""}, {""}, {""}, {""},
+    {"crlcheckinterval",  KW_CRLCHECKINTERVAL}
   };
 
 #ifdef __GNUC__
diff --git a/programs/starter/keywords.h b/programs/starter/keywords.h
index 6542ae1be..be3aabf3b 100644
--- a/programs/starter/keywords.h
+++ b/programs/starter/keywords.h
@@ -12,7 +12,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: keywords.h,v 1.8 2006/04/17 10:30:27 as Exp $
+ * RCSID $Id: keywords.h,v 1.9 2006/10/19 14:57:56 as Exp $
  */
 
 #ifndef _KEYWORDS_H_
@@ -76,9 +76,10 @@ typedef enum {
     KW_DPDDELAY,
     KW_DPDTIMEOUT,
     KW_DPDACTION,
+    KW_MODECONFIG,
 
 #define KW_CONN_FIRST	KW_CONN_SETUP
-#define KW_CONN_LAST	KW_DPDACTION
+#define KW_CONN_LAST	KW_MODECONFIG
 
    /* ca section keywords */
     KW_CA_NAME,
@@ -100,6 +101,7 @@ typedef enum {
     KW_SUBNETWITHIN,
     KW_PROTOPORT,
     KW_SOURCEIP,
+    KW_NATIP,
     KW_FIREWALL,
     KW_HOSTACCESS,
     KW_UPDOWN,
@@ -121,6 +123,7 @@ typedef enum {
     KW_LEFTSUBNETWITHIN,
     KW_LEFTPROTOPORT,
     KW_LEFTSOURCEIP,
+    KW_LEFTNATIP,
     KW_LEFTFIREWALL,
     KW_LEFTHOSTACCESS,
     KW_LEFTUPDOWN,
@@ -141,6 +144,7 @@ typedef enum {
     KW_RIGHTSUBNETWITHIN,
     KW_RIGHTPROTOPORT,
     KW_RIGHTSOURCEIP,
+    KW_RIGHTNATIP,
     KW_RIGHTFIREWALL,
     KW_RIGHTHOSTACCESS,
     KW_RIGHTUPDOWN,
diff --git a/programs/starter/keywords.txt b/programs/starter/keywords.txt
index dcfdafc98..fc9e49e47 100644
--- a/programs/starter/keywords.txt
+++ b/programs/starter/keywords.txt
@@ -13,7 +13,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: keywords.txt,v 1.6 2006/04/17 10:30:27 as Exp $
+ * RCSID $Id: keywords.txt,v 1.7 2006/10/19 14:57:56 as Exp $
  */
 
 #include <string.h>
@@ -65,6 +65,7 @@ pfsgroup,          KW_PFSGROUP
 dpddelay,          KW_DPDDELAY
 dpdtimeout,        KW_DPDTIMEOUT
 dpdaction,         KW_DPDACTION
+modeconfig,        KW_MODECONFIG
 cacert,            KW_CACERT
 ldaphost,          KW_LDAPHOST
 ldapbase,          KW_LDAPBASE
@@ -77,6 +78,7 @@ leftsubnet,        KW_LEFTSUBNET
 leftsubnetwithin,  KW_LEFTSUBNETWITHIN
 leftprotoport,     KW_LEFTPROTOPORT
 leftsourceip,      KW_LEFTSOURCEIP
+leftnatip,         KW_LEFTNATIP
 leftfirewall,      KW_LEFTFIREWALL
 lefthostaccess,    KW_LEFTHOSTACCESS
 leftupdown,        KW_LEFTUPDOWN
@@ -92,6 +94,7 @@ rightsubnet,       KW_RIGHTSUBNET
 rightsubnetwithin, KW_RIGHTSUBNETWITHIN
 rightprotoport,    KW_RIGHTPROTOPORT
 rightsourceip,     KW_RIGHTSOURCEIP
+rightnatip,        KW_RIGHTNATIP
 rightfirewall,     KW_RIGHTFIREWALL
 righthostaccess,   KW_RIGHTHOSTACCESS
 rightupdown,       KW_RIGHTUPDOWN
diff --git a/programs/starter/starterwhack.c b/programs/starter/starterwhack.c
index 0d7a3715e..b4bf2fb9d 100644
--- a/programs/starter/starterwhack.c
+++ b/programs/starter/starterwhack.c
@@ -11,7 +11,7 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
- * RCSID $Id: starterwhack.c,v 1.18 2006/06/20 21:52:53 as Exp $
+ * RCSID $Id: starterwhack.c,v 1.19 2006/10/19 15:02:46 as Exp $
  */
 
 #include <sys/types.h>
@@ -171,6 +171,7 @@ set_whack_end(whack_end_t *w, starter_end_t *end)
     w->has_client_wildcard = end->has_client_wildcard;
     w->has_port_wildcard   = end->has_port_wildcard;
     w->has_srcip           = end->has_srcip;
+    w->has_natip           = end->has_natip;
     w->modecfg             = end->modecfg;
     w->hostaccess          = end->hostaccess;
     w->sendcert            = end->sendcert;
diff --git a/testing/INSTALL b/testing/INSTALL
index 055219ae6..cfb9f1806 100644
--- a/testing/INSTALL
+++ b/testing/INSTALL
@@ -53,7 +53,7 @@ are required for the strongSwan testing environment:
     * A vanilla Linux kernel on which the UML kernel will be based on.
       We recommend the use of
 
-      http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.17.7.tar.bz2
+      http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.1.tar.bz2
 
     * Starting with Linux kernel 2.6.9 no patch must be applied any more in order
       to make the vanilla kernel UML-capable. For older kernels you'll find
@@ -63,15 +63,15 @@ are required for the strongSwan testing environment:
 
     * The matching .config file required to compile the UML kernel:
 
-      http://download.strongswan.org/uml/.config-2.6.17
+      http://download.strongswan.org/uml/.config-2.6.18
 
     * A gentoo-based UML file system (compressed size 130 MBytes) found at
 
-      http://download.strongswan.org/uml/gentoo-fs-20060330.tar.bz2
+      http://download.strongswan.org/uml/gentoo-fs-20061006.tar.bz2
 
     * The latest strongSwan distribution
 
-      http://download.strongswan.org/strongswan-2.7.3.tar.gz
+      http://download.strongswan.org/strongswan-2.8.0.tar.gz
 
 
 3. Creating the environment
@@ -146,5 +146,5 @@ README document.
 
 -----------------------------------------------------------------------------
 
-This file is RCSID $Id: INSTALL,v 1.43 2006/08/03 10:20:54 as Exp $
+This file is RCSID $Id: INSTALL,v 1.43 2006/10/19 15:36:10 as Exp $
 
diff --git a/testing/do-tests b/testing/do-tests
index ceddd72d8..6119d37d4 100755
--- a/testing/do-tests
+++ b/testing/do-tests
@@ -14,7 +14,7 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 #
-# RCSID $Id: do-tests,v 1.20 2006/02/08 21:27:59 as Exp $
+# RCSID $Id: do-tests,v 1.21 2006/10/19 21:12:43 as Exp $
 
 DIR=`dirname $0`
 
@@ -68,15 +68,16 @@ cp -rfp $DEFAULTTESTSDIR/* $TESTSDIR
 
 for host in $STRONGSWANHOSTS
 do
-    eval ip_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+    eval ip_${host}="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $1 }' | awk '{ print $1 }'`"
+
     case $host in
     moon)
-        eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+        eval ip1_${host}="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
         searchandreplace PH_IP_MOON $ip_moon $TESTSDIR
         searchandreplace PH_IP1_MOON $ip1_moon $TESTSDIR
         ;;
     sun)
-        eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+        eval ip1_${host}="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
         searchandreplace PH_IP_SUN $ip_sun $TESTSDIR
         searchandreplace PH_IP1_SUN $ip1_sun $TESTSDIR
         ;;
@@ -90,12 +91,12 @@ do
         searchandreplace PH_IP_BOB $ip_bob $TESTSDIR
         ;;
     carol)
-        eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+        eval ip1_${host}="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
         searchandreplace PH_IP_CAROL $ip_carol $TESTSDIR
         searchandreplace PH_IP1_CAROL $ip1_carol $TESTSDIR
         ;;
     dave)
-        eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+        eval ip1_${host}="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
         searchandreplace PH_IP_DAVE $ip_dave $TESTSDIR
         searchandreplace PH_IP1_DAVE $ip1_dave $TESTSDIR
         ;;
@@ -105,7 +106,6 @@ do
     esac
 done
 
-
 ##############################################################################
 # create header for the results html file
 #
diff --git a/testing/hosts/alice/etc/conf.d/net b/testing/hosts/alice/etc/conf.d/net
index 3070a46b1..02494db97 100644
--- a/testing/hosts/alice/etc/conf.d/net
+++ b/testing/hosts/alice/etc/conf.d/net
@@ -2,10 +2,9 @@
 
 # This is basically the ifconfig argument without the ifconfig $iface
 #
-iface_lo="127.0.0.1 netmask 255.0.0.0"
-iface_eth0="PH_IP_ALICE broadcast 10.1.255.255 netmask 255.255.0.0"
+config_eth0=( "PH_IP_ALICE broadcast 10.1.255.255 netmask 255.255.0.0"
+              "PH_IP6_ALICE/16" )
 
 # For setting the default gateway
 #
-gateway="eth0/PH_IP1_MOON"
-
+routes_eth0=( "default via PH_IP_MOON1" )
diff --git a/testing/hosts/alice/etc/init.d/net.eth0 b/testing/hosts/alice/etc/init.d/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/alice/etc/init.d/net.eth0
+++ b/testing/hosts/alice/etc/init.d/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/alice/etc/ipsec.conf b/testing/hosts/alice/etc/ipsec.conf
index d6cdbba7b..4e525d929 100755
--- a/testing/hosts/alice/etc/ipsec.conf
+++ b/testing/hosts/alice/etc/ipsec.conf
@@ -1,7 +1,5 @@
 # /etc/ipsec.conf - strongSwan IPsec configuration file
 
-version	2.0	# conforms to second version of ipsec.conf specification
-
 config setup
 	plutodebug=control
 	crlcheckinterval=180
diff --git a/testing/hosts/alice/etc/runlevels/default/net.eth0 b/testing/hosts/alice/etc/runlevels/default/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/alice/etc/runlevels/default/net.eth0
+++ b/testing/hosts/alice/etc/runlevels/default/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/bob/etc/conf.d/net b/testing/hosts/bob/etc/conf.d/net
index 09133acad..bd0b3a5ce 100644
--- a/testing/hosts/bob/etc/conf.d/net
+++ b/testing/hosts/bob/etc/conf.d/net
@@ -2,9 +2,9 @@
 
 # This is basically the ifconfig argument without the ifconfig $iface
 #
-iface_lo="127.0.0.1 netmask 255.0.0.0"
-iface_eth0="PH_IP_BOB broadcast 10.2.255.255 netmask 255.255.0.0"
+config_eth0=( "PH_IP_BOB broadcast 10.2.255.255 netmask 255.255.0.0"
+              "PH_IP6_BOB/16" )
 
 # For setting the default gateway
 #
-gateway="eth0/PH_IP1_SUN"
+routes_eth0=( "default via PH_IP_SUN1" )
diff --git a/testing/hosts/bob/etc/init.d/net.eth0 b/testing/hosts/bob/etc/init.d/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/bob/etc/init.d/net.eth0
+++ b/testing/hosts/bob/etc/init.d/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/bob/etc/ipsec.conf b/testing/hosts/bob/etc/ipsec.conf
index cdef4e042..9040fc25d 100755
--- a/testing/hosts/bob/etc/ipsec.conf
+++ b/testing/hosts/bob/etc/ipsec.conf
@@ -1,7 +1,5 @@
 # /etc/ipsec.conf - strongSwan IPsec configuration file
 
-version	2.0	# conforms to second version of ipsec.conf specification
-
 config setup
 	plutodebug=control
 	crlcheckinterval=180
diff --git a/testing/hosts/bob/etc/runlevels/default/net.eth0 b/testing/hosts/bob/etc/runlevels/default/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/bob/etc/runlevels/default/net.eth0
+++ b/testing/hosts/bob/etc/runlevels/default/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/carol/etc/conf.d/net b/testing/hosts/carol/etc/conf.d/net
index 39470ad14..f7f685942 100644
--- a/testing/hosts/carol/etc/conf.d/net
+++ b/testing/hosts/carol/etc/conf.d/net
@@ -2,9 +2,9 @@
 
 # This is basically the ifconfig argument without the ifconfig $iface
 #
-iface_lo="127.0.0.1 netmask 255.0.0.0"
-iface_eth0="PH_IP_CAROL broadcast 192.168.0.255 netmask 255.255.255.0"
+config_eth0=( "PH_IP_CAROL broadcast 192.168.0.255 netmask 255.255.255.0"
+              "PH_IP6_CAROL/16" )
 
 # For setting the default gateway
 #
-gateway="eth0/192.168.0.254"
+routes_eth0=( "default via 192.168.0.254" )
diff --git a/testing/hosts/carol/etc/init.d/net.eth0 b/testing/hosts/carol/etc/init.d/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/carol/etc/init.d/net.eth0
+++ b/testing/hosts/carol/etc/init.d/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/carol/etc/ipsec.conf b/testing/hosts/carol/etc/ipsec.conf
index 3228f4e16..43deae00f 100755
--- a/testing/hosts/carol/etc/ipsec.conf
+++ b/testing/hosts/carol/etc/ipsec.conf
@@ -1,7 +1,5 @@
 # /etc/ipsec.conf - strongSwan IPsec configuration file
 
-version	2.0	# conforms to second version of ipsec.conf specification
-
 config setup
 	plutodebug=control
 	crlcheckinterval=180
diff --git a/testing/hosts/carol/etc/ipsec.d/private/carolKey.pem b/testing/hosts/carol/etc/ipsec.d/private/carolKey.pem
index 0522355ce..5a41744f6 100644
--- a/testing/hosts/carol/etc/ipsec.d/private/carolKey.pem
+++ b/testing/hosts/carol/etc/ipsec.d/private/carolKey.pem
@@ -1,27 +1,30 @@
 -----BEGIN RSA PRIVATE KEY-----
-MIIEowIBAAKCAQEAuBuEkgQI4IbI0njTrS6f/AG4noxCO2ErkIAQ+BdP+W9nKehL
-GF+5bmB4MILFB6zp1k95vrAlLgXl8feomgsz5nifXetmUITLIwGRwWW8rRo0Vj4B
-GzSbtqtRfwHs9+L03pYdNiA7hel4EcsmtlDP0BTRXdLStx79ZW5WOKJL9wmGuBKL
-uuXztCjWNg4D0/ToFlAuPR0U1xZasakqn+Fe8EXU5I/1vXmOyAyUIJYsmpeYtUoO
-0qAM8sllHX2YguGBwe9rHEPtytov0ZHhCZYtvSbzigAgjBrD7SelkkxgMwx5h461
-x6kJYKZHL5eaypxa7iu00K7TlbVGxeNhkQoGNwIDAQABAoIBAQCnhwq8H4XAYYWN
-17quJPYZR6uqQfDmvYX5yD8osXXpgNC8Fo92z2wZnxje86+8S0DA7bLXrMs4NM/H
-vVcjTTxd5LcHrHN+o0eBRCVQeXYVgfnL3EH/coCa2Qugaa0q589wV+Ke5Pek5AyJ
-DHXegmyHaNoW6Qcq8L0dtigpAq3jTLG5w/3QCo8DMDKOGNR3AJrFpDlS/gW3JXuL
-Tn+PUojoWO9W6joDGYDTi4eeYyfZSajzwZvzecEpez3vwKN0pupvHA6BJCR8Mzkq
-5EYIH0hvWLtBy8uiWRXTfu/ggoQI9/Z5hBWIQk71m23uMIBbkm+oDn/1fLSBcWfK
-cr9RyM+RAoGBANpWewy7xCbkRV/90bgBNkTZ9HeFsFsWOgFVyB1XwM2E/nOqdRJc
-rxFt5Qt63DaXB+2REn231EIrsIz/Xd+R9KDl+yZOCY/m/mL4oquTPurEGJPzZdgW
-X3kUOFW1pbfcMcmzSp1FPufI17JPiePtUb/q3C4RAjCKlnskHftEyK1pAoGBANfd
-eEN8UzoV/R3WsGNDNOecMdIVAX9aiGnkLLraP7CRZ1heCH5y+RV1RB98yppkJG31
-fw5F8a6GoomkMHWGqhzDzQacZQV8w7C6rDY0Bk5TF5vemvJTGlrydwodfMvcJj8Y
-KZrS7A0iS3GAAmM6VGr3THyscszfJTq0NwE3v4KfAoGAY7L1wVzENxYpb6nRZ/p1
-s37rGODdJNrDZfSrympVygMexeZiSx4zevv5iQJzKCJTJnIGRY35yLV2iwvY68wU
-LpyV0Gn2B9Xs93idn0c/hahBqN2N9dxRgFJxXwHxSEGuInJScfo6vVCC3hNf3cpy
-d/Zg0FBH9a5zBIv7fM9t63ECgYAosrSt5I68cNDcA1IWJOGgmS47cYJqxGLbtA1K
-3UMMwx08592qGXsktIs3dIuuOBs2MAbYZg9+3Btg3/fS8KS576CEEpBpTHCIrWky
-fvSBZ+EXngyQi2J4qyYOXijdNpBvbNrLOeEPSNv4di39D05DLITbLJgoUBnwy3Fj
-ZWNR+QKBgEKn19f5QWs/O1DPWBXfvCSc01cuSUx20a6Z3B6Lxj+7MuXBjVxPkGge
-kEaZnNzwgm+QQ1C51nIn9gY4LZx7OxMy0idEss76aRq4Lb7I6XakBrCQLQ9IiTkv
-gNOeJYGsQv7tkIWWRlBIXjSBGwT6HzTEfN5cvdHSDzARGFGjwYfK
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,1E1991A43D0778B7
+
+MAsd1YBlHz54KjvBvhpwDBewinBkxBo/NmdsMetLIcV8Ag87YcKtTXYju+fbW21y
+DI12iPDQeS9tk17tS8qE5ubWmx/8n0fa5VCdLZ06JK6eeASXNoomXZh5rGsd42It
+sj0irWAnbIA3nFFWQl+Uz5pGZMse7aDSNyk1zs3xtywFIaditYIBsRhrTVmJ/bCK
+waVr++S2pwUHJ/phKoZQ8pwgF5KtYOZxdNtYIzfOZNMoplESR3+WYBYSuW8BKuOc
+QAign/BL2JVJLD4OpHQ68D8Su2sbh6ZYA5jslZLDgG9O7eiMbkCE+N8DmKO6wNAr
+zB5ILb4u5dIyTqun32tOENEhpZqDdMQtZZ34fRBze4IoMx9LrEOAHdZAQyyERP80
+iJCnH8BNf6FerA+XeDs4LVd1yrCklXKFINatqSRP/tNY3kruKw2Q7cAi2AFf+Rv6
+1lrvwK4MiLSHFtzcgEJuxm2bxeceIwXLJ2AVlfLBJvK/yJlq0MPedFbl6E6UwKfw
+cMLokF3sa1XrfwpJ93enGLqdpJrkR3dTzrsshjIhjQqfc8lqLwRlbMGc9u+V0ZsK
+OJ8e26wc/4l5D7CQ1vmgT/R/tuydBtUskgH96anhNJj1M95odkoh4Zicmm5iLgy2
+kluVYiEk0Fs7hc5Qtv8ZLN7ZoBRvZfJZWhXHDXmh71g1aoVYacIkFwiTMX4NoDy5
+QVq9tFUZ1TW4VrNIzfq++rLoz4XlgVy0Yz8jNWKuB0KRuHPNSsQUY2NHkDX+wOjq
+MP1SfNDxqPoqrmCqbgMw/9DmeOj9gyiTyjZhPZTxFOp67FYEYzYtR6bLQKEhdgf6
+iOVROZyrFHMZdBiUgV8GECds1th6ZYWmNRGdvxYjSjExIYgkDrcWbowTqD0bFC9b
+zClaSqrxR6GHUzbUVOBuCP+RmUx4j6gPvMRLUcIn5RmpbGtPE0ixeB5sFB0IuRRW
+6u2YToCiuq3EG1iJRmxjnBa/zj1aBO6OlsE/aPc0Sx+Jhm+MUbDioxUAriX96bJ+
+DEB4zgDhC0vIvkkUVAzQMkWPX479nPDmiZLpMqUIfqUh75WDpHbCladyGMgSkEo0
+IKq96oAWHJC8WLH0UMxMNuf8Ut+TsSpIO6G0RPl/cx3+hQqSUC5oUB7R3ZAWYx+6
+mawjkNJEx72yeJmQtGiZYEfeMt0Svm10PypMXFu0+2JjiS2eRj2K1yqrUnuL6AnY
+GYYmTmR74dnVAd35bRYJjY1XHGC9MyqBn4jLqKZm1BKO3sFsctGDy6vybnvAgPD7
+LioGQHPiOZmQe9Q5mMLedE9NAUCzlR8BHRbWtlnajQWcC0JcVu/mBQsjOt/KHh/V
+CY4aFXE56lRH2OpqZQxFpBFOSFDcuVX+zcEBGmKfk65n2MFL4McAJUhVRZL561Zx
+r9BvILv1Ld6/hECbodq0sUqvbDYHzv25zxAVKSIk1xy85mP5aNbk8xuGHmm860wg
+YOqdePwBEcDHoio+ov/uFYB7+4gt40vV90EzSiyfdq8x9RFMViJU430IkIBcvByo
+tFFcbN8ucBozxtl4AX495GVSRI7V0XXBtEdOIwJIzPBylZOHxCuTnA==
 -----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/carol/etc/ipsec.secrets b/testing/hosts/carol/etc/ipsec.secrets
index 797f18a01..6a2aea811 100644
--- a/testing/hosts/carol/etc/ipsec.secrets
+++ b/testing/hosts/carol/etc/ipsec.secrets
@@ -1,7 +1,3 @@
 # /etc/ipsec.secrets - strongSwan IPsec secrets file
 
-: RSA carolKey.pem
-
-
-
-
+: RSA carolKey.pem "nH5ZQEWtku0RJEZ6"
diff --git a/testing/hosts/carol/etc/runlevels/default/net.eth0 b/testing/hosts/carol/etc/runlevels/default/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/carol/etc/runlevels/default/net.eth0
+++ b/testing/hosts/carol/etc/runlevels/default/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/dave/etc/conf.d/net b/testing/hosts/dave/etc/conf.d/net
index db3753fb0..2b902525a 100644
--- a/testing/hosts/dave/etc/conf.d/net
+++ b/testing/hosts/dave/etc/conf.d/net
@@ -2,9 +2,9 @@
 
 # This is basically the ifconfig argument without the ifconfig $iface
 #
-iface_lo="127.0.0.1 netmask 255.0.0.0"
-iface_eth0="PH_IP_DAVE broadcast 192.168.0.255 netmask 255.255.255.0"
+config_eth0=( "PH_IP_DAVE broadcast 192.168.0.255 netmask 255.255.255.0"
+              "PH_IP6_DAVE/16" )
 
 # For setting the default gateway
 #
-gateway="eth0/192.168.0.254"
+routes_eth0=( "default via 192.168.0.254" )
diff --git a/testing/hosts/dave/etc/init.d/net.eth0 b/testing/hosts/dave/etc/init.d/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/dave/etc/init.d/net.eth0
+++ b/testing/hosts/dave/etc/init.d/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/dave/etc/ipsec.conf b/testing/hosts/dave/etc/ipsec.conf
index 76623491c..5fc5eef46 100755
--- a/testing/hosts/dave/etc/ipsec.conf
+++ b/testing/hosts/dave/etc/ipsec.conf
@@ -1,7 +1,5 @@
 # /etc/ipsec.conf - strongSwan IPsec configuration file
 
-version	2.0	# conforms to second version of ipsec.conf specification
-
 config setup
 	plutodebug=control
 	crlcheckinterval=180
diff --git a/testing/hosts/dave/etc/runlevels/default/net.eth0 b/testing/hosts/dave/etc/runlevels/default/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/dave/etc/runlevels/default/net.eth0
+++ b/testing/hosts/dave/etc/runlevels/default/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/default/etc/hosts b/testing/hosts/default/etc/hosts
index b8bc8da66..25c18ad5e 100644
--- a/testing/hosts/default/etc/hosts
+++ b/testing/hosts/default/etc/hosts
@@ -12,23 +12,56 @@
 10.1.0.254	uml1.strongswan.org	uml1
 10.2.0.254	uml1.strongswan.org	uml2
 
-PH_IP_ALICE	alice.strongswan.org	alice
-PH_IP_VENUS	venus.strongswan.org	venus
-PH_IP1_MOON	moon1.strongswan.org	moon1
-PH_IP_MOON	moon.strongswan.org	moon
-PH_IP_CAROL	carol.strongswan.org	carol
-PH_IP1_CAROL	carol1.strongswan.org	carol1
-PH_IP_WINNETOU	winnetou.strongswan.org	winnetou crl.strongswan.org ocsp.strongswan.org ldap.strongswan.org
-PH_IP_DAVE	dave.strongswan.org	dave
-PH_IP1_DAVE	dave1.strongswan.org	dave1
-PH_IP_SUN	sun.strongswan.org	sun
-PH_IP1_SUN	sun1.strongswan.org	sun1
-PH_IP_BOB	bob.strongswan.org	bob
+10.1.0.10	alice.strongswan.org	alice
+10.1.0.20	venus.strongswan.org	venus
+10.1.0.1	moon1.strongswan.org	moon1
+192.168.0.1	moon.strongswan.org	moon
+192.168.0.100	carol.strongswan.org	carol
+10.3.0.1	carol1.strongswan.org	carol1
+192.168.0.150	winnetou.strongswan.org	winnetou crl.strongswan.org ocsp.strongswan.org ldap.strongswan.org
+192.168.0.200	dave.strongswan.org	dave
+10.3.0.2	dave1.strongswan.org	dave1
+192.168.0.2	sun.strongswan.org	sun
+10.2.0.1	sun1.strongswan.org	sun1
+10.2.0.10	bob.strongswan.org	bob
 
-# IPV6 versions of localhost and co
+# IPv6 versions of localhost and co
 ::1 ip6-localhost ip6-loopback
 fe00::0 ip6-localnet
 ff00::0 ip6-mcastprefix
 ff02::1 ip6-allnodes
 ff02::2 ip6-allrouters
 ff02::3 ip6-allhosts
+
+# IPv6 solicited-node multicast addresses
+ff02::1:ff00:1	ip6-mcast-1
+ff02::1:ff00:2	ip6-mcast-2
+ff02::1:ff00:10	ip6-mcast-10
+ff02::1:ff00:15	ip6-mcast-15
+ff02::1:ff00:20	ip6-mcast-20
+
+# IPv6 site-local addresses
+fec1::10	ip6-alice.strongswan.org    ip6-alice
+fec1::20	ip6-venus.strongswan.org    ip6-venus
+fec1::1 	ip6-moon1.strongswan.org    ip6-moon1
+fec0::1 	ip6-moon.strongswan.org     ip6-moon
+fec0::10	ip6-carol.strongswan.org    ip6-carol
+fec3::1 	ip6-carol1.strongswan.org   ip6-carol1
+fec0::15	ip6-winnetou.strongswan.org ip6-winnetou 
+fec0::20	ip6-dave.strongswan.org     ip6-dave
+fec3::2 	ip6-dave1.strongswan.org    ip6-dave1
+fec0::2 	ip6-sun.strongswan.org      ip6-sun
+fec2::1 	ip6-sun1.strongswan.org     ip6-sun1
+fec2::10	ip6-bob.strongswan.org      ip6-bob
+
+# IPv6 link-local HW derived addresses
+fe80::fcfd:0aff:fe01:14	ip6-hw-venus.strongswan.org    ip6-hw-venus
+fe80::fcfd:0aff:fe01:0a	ip6-hw-alice.strongswan.org    ip6-hw-alice
+fe80::fcfd:0aff:fe01:01	ip6-hw-moon1.strongswan.org    ip6-hw-moon1
+fe80::fcfd:c0ff:fea8:01 ip6-hw-moon.strongswan.org     ip6-hw-moon
+fe80::fcfd:c0ff:fea8:64	ip6-hw-carol.strongswan.org    ip6-hw-carol
+fe80::fcfd:c0ff:fea8:96 ip6-hw-winnetou.strongswan.org ip6-hw-winnetou
+fe80::fcfd:c0ff:fea8:c8	ip6-hw-dave.strongswan.org     ip6-hw-dave
+fe80::fcfd:c0ff:fea8:02	ip6-hw-sun.strongswan.org      ip6-hw-sun
+fe80::fcfd:0aff:fe02:01	ip6-hw-sun1.strongswan.org     ip6-hw-sun1
+fe80::fcfd:0aff:fe02:0a ip6-hw-bob.strongswan.org      ip6-hw-bob
diff --git a/testing/hosts/moon/etc/conf.d/net b/testing/hosts/moon/etc/conf.d/net
index 7dec60ba5..7f09fd8a5 100644
--- a/testing/hosts/moon/etc/conf.d/net
+++ b/testing/hosts/moon/etc/conf.d/net
@@ -2,10 +2,11 @@
 
 # This is basically the ifconfig argument without the ifconfig $iface
 #
-iface_lo="127.0.0.1 netmask 255.0.0.0"
-iface_eth0="PH_IP_MOON broadcast 192.168.0.255 netmask 255.255.255.0"
-iface_eth1="PH_IP1_MOON broadcast 10.1.255.255 netmask 255.255.0.0"
+config_eth0=( "PH_IP_MOON broadcast 192.168.0.255 netmask 255.255.255.0"
+              "PH_IP6_MOON/16" )
+config_eth1=( "PH_IP_MOON1 broadcast 10.1.255.255 netmask 255.255.0.0"
+              "PH_IP6_MOON1/16" )
 
 # For setting the default gateway
 #
-gateway="eth0/192.168.0.254"
+routes_eth0=( "default via 192.168.0.254" )
diff --git a/testing/hosts/moon/etc/init.d/net.eth0 b/testing/hosts/moon/etc/init.d/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/moon/etc/init.d/net.eth0
+++ b/testing/hosts/moon/etc/init.d/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/moon/etc/init.d/net.eth1 b/testing/hosts/moon/etc/init.d/net.eth1
index fa1200242..92b3851cf 100755
--- a/testing/hosts/moon/etc/init.d/net.eth1
+++ b/testing/hosts/moon/etc/init.d/net.eth1
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/moon/etc/ipsec.conf b/testing/hosts/moon/etc/ipsec.conf
index a0e97e057..c7d7dc2ed 100755
--- a/testing/hosts/moon/etc/ipsec.conf
+++ b/testing/hosts/moon/etc/ipsec.conf
@@ -1,7 +1,5 @@
 # /etc/ipsec.conf - strongSwan IPsec configuration file
 
-version	2.0	# conforms to second version of ipsec.conf specification
-
 config setup
 	plutodebug=control
 	crlcheckinterval=180
@@ -12,7 +10,7 @@ conn %default
 	keylife=20m
 	rekeymargin=3m
 	keyingtries=1
-	left=192.168.0.1
+	left=PH_IP_MOON
 	leftnexthop=%direct
 	leftcert=moonCert.pem
 	leftid=@moon.strongswan.org
@@ -20,13 +18,13 @@ conn %default
 
 conn net-net
 	leftsubnet=10.1.0.0/16
-	right=192.168.0.2
+	right=PH_IP_SUN
 	rightsubnet=10.2.0.0/16
 	rightid=@sun.strongswan.org
 	auto=add
         
 conn host-host
-	right=192.168.0.2
+	right=PH_IP_SUN
 	rightid=@sun.strongswan.org
 	auto=add
 
diff --git a/testing/hosts/moon/etc/runlevels/default/net.eth0 b/testing/hosts/moon/etc/runlevels/default/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/moon/etc/runlevels/default/net.eth0
+++ b/testing/hosts/moon/etc/runlevels/default/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/moon/etc/runlevels/default/net.eth1 b/testing/hosts/moon/etc/runlevels/default/net.eth1
index fa1200242..92b3851cf 100755
--- a/testing/hosts/moon/etc/runlevels/default/net.eth1
+++ b/testing/hosts/moon/etc/runlevels/default/net.eth1
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/sun/etc/conf.d/net b/testing/hosts/sun/etc/conf.d/net
index 0f8dc57b1..4a6370ab7 100644
--- a/testing/hosts/sun/etc/conf.d/net
+++ b/testing/hosts/sun/etc/conf.d/net
@@ -2,12 +2,13 @@
 
 # This is basically the ifconfig argument without the ifconfig $iface
 #
-iface_lo="127.0.0.1 netmask 255.0.0.0"
-iface_eth0="PH_IP_SUN broadcast 192.168.0.255 netmask 255.255.255.0"
-iface_eth1="PH_IP1_SUN broadcast 10.2.255.255 netmask 255.255.0.0"
+config_eth0=( "PH_IP_SUN broadcast 192.168.0.255 netmask 255.255.255.0"
+              "PH_IP6_SUN/16" )
+config_eth1=( "PH_IP_SUN1 broadcast 10.2.255.255 netmask 255.255.0.0"
+              "PH_IP6_SUN1/16" )
 
 # For setting the default gateway
 #
-gateway="eth0/192.168.0.254"
+routes_eth0=( "default via 192.168.0.254" )
 
 
diff --git a/testing/hosts/sun/etc/init.d/net.eth0 b/testing/hosts/sun/etc/init.d/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/sun/etc/init.d/net.eth0
+++ b/testing/hosts/sun/etc/init.d/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/sun/etc/init.d/net.eth1 b/testing/hosts/sun/etc/init.d/net.eth1
index fa1200242..92b3851cf 100755
--- a/testing/hosts/sun/etc/init.d/net.eth1
+++ b/testing/hosts/sun/etc/init.d/net.eth1
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/sun/etc/ipsec.conf b/testing/hosts/sun/etc/ipsec.conf
index 4d0299a08..1106ded6f 100755
--- a/testing/hosts/sun/etc/ipsec.conf
+++ b/testing/hosts/sun/etc/ipsec.conf
@@ -1,7 +1,5 @@
 # /etc/ipsec.conf - strongSwan IPsec configuration file
 
-version	2.0	# conforms to second version of ipsec.conf specification
-
 config setup
 	plutodebug=control
 	crlcheckinterval=180
diff --git a/testing/hosts/sun/etc/runlevels/default/net.eth0 b/testing/hosts/sun/etc/runlevels/default/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/sun/etc/runlevels/default/net.eth0
+++ b/testing/hosts/sun/etc/runlevels/default/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/sun/etc/runlevels/default/net.eth1 b/testing/hosts/sun/etc/runlevels/default/net.eth1
index fa1200242..92b3851cf 100755
--- a/testing/hosts/sun/etc/runlevels/default/net.eth1
+++ b/testing/hosts/sun/etc/runlevels/default/net.eth1
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/venus/etc/conf.d/net b/testing/hosts/venus/etc/conf.d/net
index 2c55c2c20..43ec97807 100644
--- a/testing/hosts/venus/etc/conf.d/net
+++ b/testing/hosts/venus/etc/conf.d/net
@@ -2,10 +2,9 @@
 
 # This is basically the ifconfig argument without the ifconfig $iface
 #
-iface_lo="127.0.0.1 netmask 255.0.0.0"
-iface_eth0="PH_IP_VENUS broadcast 10.1.255.255 netmask 255.255.0.0"
+config_eth0=( "PH_IP_VENUS broadcast 10.1.255.255 netmask 255.255.0.0"
+              "PH_IP6_VENUS/16" )
 
 # For setting the default gateway
 #
-gateway="eth0/PH_IP1_MOON"
-
+routes_eth0=( "default via PH_IP_MOON1" )
diff --git a/testing/hosts/venus/etc/init.d/net.eth0 b/testing/hosts/venus/etc/init.d/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/venus/etc/init.d/net.eth0
+++ b/testing/hosts/venus/etc/init.d/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/venus/etc/ipsec.conf b/testing/hosts/venus/etc/ipsec.conf
index 35f264f82..8e4e47459 100755
--- a/testing/hosts/venus/etc/ipsec.conf
+++ b/testing/hosts/venus/etc/ipsec.conf
@@ -1,7 +1,5 @@
 # /etc/ipsec.conf - strongSwan IPsec configuration file
 
-version	2.0	# conforms to second version of ipsec.conf specification
-
 config setup
 	plutodebug=control
 	crlcheckinterval=180
diff --git a/testing/hosts/venus/etc/runlevels/default/net.eth0 b/testing/hosts/venus/etc/runlevels/default/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/venus/etc/runlevels/default/net.eth0
+++ b/testing/hosts/venus/etc/runlevels/default/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/winnetou/etc/conf.d/apache2 b/testing/hosts/winnetou/etc/conf.d/apache2
index cfb80a7d9..0c96fe77f 100644
--- a/testing/hosts/winnetou/etc/conf.d/apache2
+++ b/testing/hosts/winnetou/etc/conf.d/apache2
@@ -1,6 +1,6 @@
 # Copyright 1999-2004 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/strongswan/testing/hosts/winnetou/etc/conf.d/apache2,v 1.2 2006/01/06 12:21:21 as Exp $
+# $Header: /root/strongswan/testing/hosts/winnetou/etc/conf.d/apache2,v 1.2 2006/01/06 12:21:21 as Exp $
 
 # Config file for /etc/init.d/apache2
 
diff --git a/testing/hosts/winnetou/etc/conf.d/net b/testing/hosts/winnetou/etc/conf.d/net
index 1a32153f3..7fbc37014 100644
--- a/testing/hosts/winnetou/etc/conf.d/net
+++ b/testing/hosts/winnetou/etc/conf.d/net
@@ -2,9 +2,9 @@
 
 # This is basically the ifconfig argument without the ifconfig $iface
 #
-iface_lo="127.0.0.1 netmask 255.0.0.0"
-iface_eth0="PH_IP_WINNETOU broadcast 192.168.0.255 netmask 255.255.255.0"
+config_eth0=( "PH_IP_WINNETOU broadcast 192.168.0.255 netmask 255.255.255.0"
+              "PH_IP6_WINNETOU/16" )
 
 # For setting the default gateway
 #
-gateway="eth0/192.168.0.254"
+routes_eth0=( "default via 192.168.0.254" )
diff --git a/testing/hosts/winnetou/etc/init.d/net.eth0 b/testing/hosts/winnetou/etc/init.d/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/winnetou/etc/init.d/net.eth0
+++ b/testing/hosts/winnetou/etc/init.d/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/hosts/winnetou/etc/init.d/slapd b/testing/hosts/winnetou/etc/init.d/slapd
index d4c070b33..6e3130e90 100755
--- a/testing/hosts/winnetou/etc/init.d/slapd
+++ b/testing/hosts/winnetou/etc/init.d/slapd
@@ -1,7 +1,7 @@
 #!/sbin/runscript
 # Copyright 1999-2004 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/strongswan/testing/hosts/winnetou/etc/init.d/slapd,v 1.2 2005/05/31 14:04:43 as Exp $
+# $Header: /root/strongswan/testing/hosts/winnetou/etc/init.d/slapd,v 1.2 2005/05/31 14:04:43 as Exp $
 
 depend() {
 	need net
diff --git a/testing/hosts/winnetou/etc/openldap/slapd.conf b/testing/hosts/winnetou/etc/openldap/slapd.conf
index 4558ee2e2..5a99f955d 100644
--- a/testing/hosts/winnetou/etc/openldap/slapd.conf
+++ b/testing/hosts/winnetou/etc/openldap/slapd.conf
@@ -53,9 +53,9 @@ argsfile	/var/run/openldap/slapd.args
 #######################################################################
 
 database	bdb
-checkpoint	32	30 # <kbyte> <min>
 suffix		"o=Linux strongSwan,c=CH"
 rootdn		"cn=Manager,o=Linux strongSwan,c=CH"
+checkpoint	32	30 # <kbyte> <min>
 # Cleartext passwords, especially for the rootdn, should
 # be avoid.  See slappasswd(8) and slapd.conf(5) for details.
 # Use of strong authentication encouraged.
diff --git a/testing/hosts/winnetou/etc/openssl/index.txt b/testing/hosts/winnetou/etc/openssl/index.txt
index 4db6c2924..9e744674d 100644
--- a/testing/hosts/winnetou/etc/openssl/index.txt
+++ b/testing/hosts/winnetou/etc/openssl/index.txt
@@ -13,3 +13,6 @@ R	140321062536Z	050621195214Z	0C	unknown	/C=CH/O=Linux strongSwan/OU=Research/CN
 V	140321062916Z		0D	unknown	/C=CH/O=Linux strongSwan/OU=Sales/CN=Sales CA
 V	100607191714Z		0E	unknown	/C=CH/O=Linux strongSwan/CN=winnetou.strongswan.org
 V	100620195806Z		0F	unknown	/C=CH/O=Linux strongSwan/OU=Research/CN=Research CA
+V	111007105811Z		10	unknown	/C=CH/O=Linux strongSwan/OU=SHA-256/CN=moon.strongswan.org
+V	111007121250Z		11	unknown	/C=CH/O=Linux strongSwan/OU=SHA-384/CN=carol@strongswan.org
+V	111007122112Z		12	unknown	/C=CH/O=Linux strongSwan/OU=SHA-512/CN=dave@strongswan.org
diff --git a/testing/hosts/winnetou/etc/openssl/index.txt.attr b/testing/hosts/winnetou/etc/openssl/index.txt.attr
index 8f7e63a34..3a7e39e6e 100644
--- a/testing/hosts/winnetou/etc/openssl/index.txt.attr
+++ b/testing/hosts/winnetou/etc/openssl/index.txt.attr
@@ -1 +1 @@
-unique_subject = yes
+unique_subject = no
diff --git a/testing/hosts/winnetou/etc/openssl/index.txt.attr.old b/testing/hosts/winnetou/etc/openssl/index.txt.attr.old
index 8f7e63a34..3a7e39e6e 100644
--- a/testing/hosts/winnetou/etc/openssl/index.txt.attr.old
+++ b/testing/hosts/winnetou/etc/openssl/index.txt.attr.old
@@ -1 +1 @@
-unique_subject = yes
+unique_subject = no
diff --git a/testing/hosts/winnetou/etc/openssl/index.txt.old b/testing/hosts/winnetou/etc/openssl/index.txt.old
index 669702b0c..4d7201a35 100644
--- a/testing/hosts/winnetou/etc/openssl/index.txt.old
+++ b/testing/hosts/winnetou/etc/openssl/index.txt.old
@@ -12,3 +12,6 @@ V	100216084430Z		0B	unknown	/C=CH/O=Linux strongSwan/OU=Authorization Authority/
 R	140321062536Z	050621195214Z	0C	unknown	/C=CH/O=Linux strongSwan/OU=Research/CN=Research CA
 V	140321062916Z		0D	unknown	/C=CH/O=Linux strongSwan/OU=Sales/CN=Sales CA
 V	100607191714Z		0E	unknown	/C=CH/O=Linux strongSwan/CN=winnetou.strongswan.org
+V	100620195806Z		0F	unknown	/C=CH/O=Linux strongSwan/OU=Research/CN=Research CA
+V	111007105811Z		10	unknown	/C=CH/O=Linux strongSwan/OU=SHA-256/CN=moon.strongswan.org
+V	111007121250Z		11	unknown	/C=CH/O=Linux strongSwan/OU=SHA-384/CN=carol@strongswan.org
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/10.pem b/testing/hosts/winnetou/etc/openssl/newcerts/10.pem
new file mode 100644
index 000000000..307f4953e
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/10.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEHzCCAwegAwIBAgIBEDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA2MTAwODEwNTgxMVoXDTExMTAwNzEwNTgxMVowWDELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xEDAOBgNVBAsTB1NIQS0y
+NTYxHDAaBgNVBAMTE21vb24uc3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDzXHm8D8sY1lmX7o1KK0jt/M+UzAI2Ifpx7nAqoviH
+XQIPe56BOAm4zHhEIlojEMFd1nncplXvDDGjuV/2F0KK1bFxbNtom88Ix1jrRWtk
+FLopYwj3ERC2970OhNO3nuPLrnEAzj6k3XPGMTA3drGnpRf162f7mHAdmYIRXtWm
+mfaecs4wGFs8BFGdeDfo6SPhQXZSBwZqjzQxvk1PA7E1qifgR5IGNZkNQRQ9IZD0
+86xzjmZgg5DaJcQKw45elpiVKQN6OkdWTngR3uUBfseWNeRGP5UxCUbDnPijWUbA
+6ZAdEfFXLgSpSoXHLNttvGg+SWm0kgKTpHYWYhvpflKNAgMBAAGjggEFMIIBATAJ
+BgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQU0gL3aEo/H8c/Ld/GkBTb
+W9Ma+nUwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJ
+BgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJz
+dHJvbmdTd2FuIFJvb3QgQ0GCAQAwHgYDVR0RBBcwFYITbW9vbi5zdHJvbmdzd2Fu
+Lm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3Jn
+L3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQCItzRn3TNWUzczBd8z
+MtdPEsRl5Oi4fV3UecQxhjxAmJDLsEZT5I4uNa1XoLkJm6jVdSL7k+bjzjmpNJ1H
+uL49cqia2yTdGP4IU0K8dTGaflg3ccaLLGGXTWU/NtgdI1o6yuZTwb6a9ZL7wWZT
+x21BAsvyPTzCpUS1yCK4bFeYOxOYDphUGcwb0JTuRxx2/710b+p64BYiCfVkQJxT
+eF1ZtjSW6nJgzMRg5n2zNpdrdXMMCPI6Nl7V6wxbs3Cphmz5qx3lijwi7nZt+jE5
+qK5gphph1MkKIhnA7MF66KEcx5Rknao68yLBBDIA/AISZ3bCIj8R1SGgl/tMYfep
+sbRF
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/11.pem b/testing/hosts/winnetou/etc/openssl/newcerts/11.pem
new file mode 100644
index 000000000..d4b532323
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/11.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEITCCAwmgAwIBAgIBETANBgkqhkiG9w0BAQwFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA2MTAwODEyMTI1MFoXDTExMTAwNzEyMTI1MFowWTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xEDAOBgNVBAsTB1NIQS0z
+ODQxHTAbBgNVBAMUFGNhcm9sQHN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAtCwjB6Yni4jSTbPJ4GX0kM06nr2tDBdU0PH6dZra
+IXNaNiBthBNPNDeCYAQDG/ouwuywAJ6L2Lt0GYEhJSwfXMm87fYSG8qRP+C/nlKz
+3fCfsuZ8yOAo5NAp2kgvbFVdB5cMeOtid21UqUvDxkncjFRDgpERtrjSthalUFYu
+ObIcSMPdlcDho73jzq6zVK5XDJ4l1LHUQLbS4SzyrphCYKekTIoDy3YwRUys6Pdm
+4QlFBIXuBwOYHjclvVu0HQVNSM4nWAJd+204KUm/+8neO0kn1Yakv9yoa47o3KGP
+3XjtmcgY9SqBbuF+8yDcZQ7+5zUBjc0J+d8txdPoIjLi7wIDAQABo4IBBjCCAQIw
+CQYDVR0TBAIwADALBgNVHQ8EBAMCA6gwHQYDVR0OBBYEFIUlEfDm3V0eDmRrpIvj
+4FiPpGlpMG0GA1UdIwRmMGSAFF2n3XAGUTJ+57Zts7Xl4GDqLk3voUmkRzBFMQsw
+CQYDVQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMS
+c3Ryb25nU3dhbiBSb290IENBggEAMB8GA1UdEQQYMBaBFGNhcm9sQHN0cm9uZ3N3
+YW4ub3JnMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwuc3Ryb25nc3dhbi5v
+cmcvc3Ryb25nc3dhbi5jcmwwDQYJKoZIhvcNAQEMBQADggEBAL5ZmFmy8lW4Vdwq
+hWB6qTtLLa1wwCvTXwbV9V+F8dK39AvHj6CHFqTiFhAbGIq/Ryt9cg2XGy1TDjVj
+hQEua7mjp8XH2j2NLY2SiFTMjchbHmMylFk2FrHy2ZnmlRCiH83TAw+EnUWsQKj+
+gL+7Of9SpiaaIblrl+aCiBVktRuXcFSaxjYWTVXOeTCwnxQdF2SNtUKDoCuVPk1J
+XCrs86mj575xL/FGjyN4SVbjTEZ4lm1emxrf/RblZOhCKp7mUic8KyP0kf7o6X8E
+MXXjq9fDQVrSDG/q62uhZu7CyInnBpWnoUKiMImSxRn/cs0r7RUspC5DtJyhE33Y
+DW2BzIc=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/12.pem b/testing/hosts/winnetou/etc/openssl/newcerts/12.pem
new file mode 100644
index 000000000..73088cd1d
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/12.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEHzCCAwegAwIBAgIBEjANBgkqhkiG9w0BAQ0FADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA2MTAwODEyMjExMloXDTExMTAwNzEyMjExMlowWDELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xEDAOBgNVBAsTB1NIQS01
+MTIxHDAaBgNVBAMUE2RhdmVAc3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDL4+PsltDM0QCCS08tkefhll5Q0nb2VEdRZotBIdt6
+XEY1kmDlw0yQOp0XUznnIhcrxXpKeWpLqJdbo56jSxMaUB3Mod1u+aKvVhCgkOT8
+uQa7gIdcNMuXnfnch7yYYS6YxVfzdr/qXBxmVYNbR9sXy48vAD6glZLEVjDITHJO
+a6tEVSrAOMyeuA9XTYJiGw5loj63YbUr6Ikp6W9SncPCtfX6G2Amk38MTuITu93W
+Pd/bGB06ra6gmMQGAhXuGs14n3QZfQz9PWTp9TPsQNqQZdEjQyNdfeAKtPuz5jnO
+cnZuhvVR0q4sxWuy64vkyZ57luTZAXyxdInBeBOp7sC3AgMBAAGjggEFMIIBATAJ
+BgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQU0wvMMeoe59mocM/RiYnD
+iw9NUm0wbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJ
+BgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJz
+dHJvbmdTd2FuIFJvb3QgQ0GCAQAwHgYDVR0RBBcwFYETZGF2ZUBzdHJvbmdzd2Fu
+Lm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3Jn
+L3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBDQUAA4IBAQC/uKe2O9elbSFgpKP5
+7ZjJrCkYu493iH/PDm5G4D76q6WkRvZDqTgGDSIrXrt1xRLIsVJES+HERxfED0DB
+yXNe22p1jR8iZdCesZxmEsKYyLh9XmeixKCfnLvStWCVs0+vqwhJlIkyEAveZ4HR
+Yq121khdmCDDUugpjEl/nU7CLvCRVgFrlhDm1QLs2rYqxwQrJ2SH4/1W0YRdkY2R
+vKZ2ngjLBNjBfXWNXSOpEAG367nVam5lFAepUC0wZTshyCUXt1NzClTnxWABm6M6
+x2Qwg4D6Qt5iXSjR8+DGVh+LaBL/alQi1YYcjkxufdFHnko294c0HsZcTZ3KRghk
+ue1F
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/serial b/testing/hosts/winnetou/etc/openssl/serial
index f599e28b8..b1bd38b62 100644
--- a/testing/hosts/winnetou/etc/openssl/serial
+++ b/testing/hosts/winnetou/etc/openssl/serial
@@ -1 +1 @@
-10
+13
diff --git a/testing/hosts/winnetou/etc/openssl/serial.old b/testing/hosts/winnetou/etc/openssl/serial.old
index 0ced2f35e..48082f72f 100644
--- a/testing/hosts/winnetou/etc/openssl/serial.old
+++ b/testing/hosts/winnetou/etc/openssl/serial.old
@@ -1 +1 @@
-0F
+12
diff --git a/testing/hosts/winnetou/etc/runlevels/default/net.eth0 b/testing/hosts/winnetou/etc/runlevels/default/net.eth0
index fa1200242..92b3851cf 100755
--- a/testing/hosts/winnetou/etc/runlevels/default/net.eth0
+++ b/testing/hosts/winnetou/etc/runlevels/default/net.eth0
@@ -1,314 +1,1124 @@
 #!/sbin/runscript
-# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Copyright (c) 2004-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-#NB: Config is in /etc/conf.d/net
+# Contributed by Roy Marples (uberlord@gentoo.org)
+# Many thanks to Aron Griffis (agriffis@gentoo.org)
+# for help, ideas and patches
 
-if [[ -n $NET_DEBUG ]]; then
-	set -x
-	devnull=/dev/stderr
-else
-	devnull=/dev/null
-fi
+#NB: Config is in /etc/conf.d/net
 
 # For pcmcia users. note that pcmcia must be added to the same
 # runlevel as the net.* script that needs it.
 depend() {
-	use hotplug pcmcia
-}
+	need localmount
+	after bootmisc hostname
+	use isapnp isdn pcmcia usb wlan
 
-checkconfig() {
-	if [[ -z "${ifconfig_IFACE}" ]]; then
-		eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
-		eerror "(or \$iface_$IFACE for old-style configuration)"
-		return 1
+	# Load any custom depend functions for the given interface
+	# For example, br0 may need eth0 and eth1
+	local iface="${SVCNAME#*.}"
+	[[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
+
+	if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
+		after net.lo net.lo0
+
+		# Support new style RC_NEED and RC_USE in one net file
+		local x="RC_NEED_${iface}"
+		[[ -n ${!x} ]] && need ${!x}
+		x="RC_USE_${iface}"
+		[[ -n ${!x} ]] && use ${!x}
 	fi
-	if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
-		eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
-		return 1
+
+	return 0
+}
+
+# Define where our modules are
+MODULES_DIR="${svclib}/net"
+
+# Make some wrappers to fudge after/before/need/use depend flags.
+# These are callbacks so MODULE will be set.
+after() {
+	eval "${MODULE}_after() { echo \"$*\"; }"
+}
+before() {
+	eval "${MODULE}_before() { echo \"$*\"; }"
+}
+need() {
+	eval "${MODULE}_need() { echo \"$*\"; }"
+}
+installed() {
+	# We deliberately misspell this as _installed will probably be used
+	# at some point
+	eval "${MODULE}_instlled() { echo \"$*\"; }"
+}
+provide() {
+	eval "${MODULE}_provide() { echo \"$*\"; }"
+}
+functions() {
+	eval "${MODULE}_functions() { echo \"$*\"; }"
+}
+variables() {
+	eval "${MODULE}_variables() { echo \"$*\"; }"
+}
+
+is_loopback() {
+	[[ $1 == "lo" || $1 == "lo0" ]]
+}
+
+# char* interface_device(char *iface)
+#
+# Gets the base device of the interface
+# Can handle eth0:1 and eth0.1
+# Which returns eth0 in this case
+interface_device() {
+	local dev="${1%%.*}"
+	[[ ${dev} == "$1" ]] && dev="${1%%:*}"
+	echo "${dev}"
+}
+
+# char* interface_type(char* iface)
+#
+# Returns the base type of the interface
+# eth, ippp, etc
+interface_type() {
+	echo "${1%%[0-9]*}"
+}
+
+# int calculate_metric(char *interface, int base)
+#
+# Calculates the best metric for the interface
+# We use this when we add routes so we can prefer interfaces over each other
+calculate_metric() {
+	local iface="$1" metric="$2"
+
+	# Have we already got a metric?
+	local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
+		/proc/net/route)
+	if [[ -n ${m} ]] ; then
+		echo "${m}"
+		return 0
 	fi
+
+	local i= dest= gw= flags= ref= u= m= mtu= metrics=
+	while read i dest gw flags ref u m mtu ; do
+		# Ignore lo
+		is_loopback "${i}" && continue
+		# We work out metrics from default routes only
+		[[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
+		metrics="${metrics}\n${m}"
+	done < /proc/net/route
+
+	# Now, sort our metrics
+	metrics=$(echo -e "${metrics}" | sort -n)
+
+	# Now, find the lowest we can use
+	local gotbase=false
+	for m in ${metrics} ; do
+		[[ ${m} -lt ${metric} ]] && continue
+		[[ ${m} == ${metric} ]] && ((metric++))
+		[[ ${m} -gt ${metric} ]] && break
+	done
+	
+	echo "${metric}"
 }
 
-# Fix bug 50039 (init.d/net.eth0 localization)
-# Some other commands in this script might need to be wrapped, but
-# we'll get them one-by-one.  Note that LC_ALL trumps LC_anything_else
-# according to locale(7)
-ifconfig() {
-	LC_ALL=C /sbin/ifconfig "$@"
+# int netmask2cidr(char *netmask)
+#
+# Returns the CIDR of a given netmask
+netmask2cidr() {
+	local binary= i= bin=
+
+	for i in ${1//./ }; do
+		bin=""
+		while [[ ${i} != "0" ]] ; do
+			bin=$[${i}%2]${bin}
+			(( i=i>>1 ))
+		done
+		binary="${binary}${bin}"
+	done
+	binary="${binary%%0*}"
+	echo "${#binary}"
 }
 
-# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
-# The following variables are set, which should be declared local by
-# the calling routine.
-#	status_IFACE			(up or '')
-#	vlans_IFACE				(space-separated list)
-#	ifconfig_IFACE			(array of ifconfig lines, replaces iface_IFACE)
-#	dhcpcd_IFACE			(command-line args for dhcpcd)
-#	routes_IFACE			(array of route lines)
-#	inet6_IFACE				(array of inet6 lines)
-#	ifconfig_fallback_IFACE	(fallback ifconfig if dhcp fails)
-setup_vars() {
-	local i iface="${1//\./_}"
-
-	status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
-	eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
-	eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
-	eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
-	eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
-	eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
-	eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
-
-	# BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
-	# if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
-	eval local iface_IFACE=\"\$\{iface_$iface\}\"
-	if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
-		# Make sure these get evaluated as arrays
-		local -a aliases broadcasts netmasks
-
-		# Start with the primary interface
-		ifconfig_IFACE=( "${iface_IFACE}" )
-
-		# ..then add aliases
-		eval aliases=( \$\{alias_$iface\} )
-		eval broadcasts=( \$\{broadcast_$iface\} )
-		eval netmasks=( \$\{netmask_$iface\} )
-		for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
-			ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+
+# bool is_function(char* name)
+#
+# Returns 0 if the given name is a shell function, otherwise 1
+is_function() {
+	[[ -z $1 ]] && return 1
+	[[ $(type -t "$1") == "function" ]]
+}
+
+# void function_wrap(char* source, char* target)
+#
+# wraps function calls - for example function_wrap(this, that)
+# maps function names this_* to that_*
+function_wrap() {
+	local i=
+
+	is_function "${2}_depend" && return
+
+	for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
+		eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
+	done
+}
+
+# char[] * expand_parameters(char *cmd)
+#
+# Returns an array after expanding parameters. For example
+# "192.168.{1..3}.{1..3}/24 brd +"
+# will return
+# "192.168.1.1/24 brd +"
+# "192.168.1.2/24 brd +"
+# "192.168.1.3/24 brd +"
+# "192.168.2.1/24 brd +"
+# "192.168.2.2/24 brd +"
+# "192.168.2.3/24 brd +"
+# "192.168.3.1/24 brd +"
+# "192.168.3.2/24 brd +"
+# "192.168.3.3/24 brd +"
+expand_parameters() {
+	local x=$(eval echo ${@// /_})
+	local -a a=( ${x} )
+
+	a=( "${a[@]/#/\"}" )
+	a=( "${a[@]/%/\"}" )
+	echo "${a[*]//_/ }"
+}
+
+# void configure_variables(char *interface, char *option1, [char *option2])
+#
+# Maps configuration options from <variable>_<option> to <variable>_<iface>
+# option2 takes precedence over option1
+configure_variables() {
+	local iface="$1" option1="$2" option2="$3"
+
+	local mod= func= x= i=
+	local -a ivars=() ovars1=() ovars2=()
+	local ifvar=$(bash_variable "${iface}")
+
+	for mod in ${MODULES[@]}; do
+		is_function ${mod}_variables || continue
+		for v in $(${mod}_variables) ; do
+			x=
+			[[ -n ${option2} ]] && x="${v}_${option2}[@]"
+			[[ -z ${!x} ]] && x="${v}_${option1}[@]"
+			[[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
 		done
+	done
+
+	return 0
+}
+# bool module_load_minimum(char *module)
+#
+# Does the minimum checking on a module - even when forcing
+module_load_minimum() {
+	local f="$1.sh" MODULE="${1##*/}"
+
+	if [[ ! -f ${f} ]] ; then
+		eerror "${f} does not exist"
+		return 1
 	fi
 
-	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
-	if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
-		inet6_IFACE=( ${inet6_IFACE} )
+	if ! source "${f}" ; then
+		eerror "${MODULE} failed a sanity check"
+		return 1
 	fi
+
+	for f in depend; do
+		is_function "${MODULE}_${f}" && continue
+		eerror "${MODULE}.sh does not support the required function ${f}"
+		return 1
+	done
+
+	return 0
 }
 
-iface_start() {
-	local IFACE=${1} i x retval
-	checkconfig || return 1
-
-	if [[ ${ifconfig_IFACE} != dhcp ]]; then
-		# Show the address, but catch if this interface will be inet6 only
-		i=${ifconfig_IFACE%% *}
-		if [[ ${i} == *.*.*.* ]]; then
-			ebegin "Bringing ${IFACE} up (${i})"
-		else
-			ebegin "Bringing ${IFACE} up"
+# bool modules_load_auto()
+#
+# Load and check each module for sanity
+# If the module is not installed, the functions are to be removed
+modules_load_auto() {
+	local i j inst
+
+	# Populate the MODULES array
+	# Basically we treat evey file in ${MODULES_DIR} as a module
+	MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
+		[[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
+	done
+	MODULES=( "${MODULES[@]}" )
+
+	# Each of these sources into the global namespace, so it's
+	# important that module functions and variables are prefixed with
+	# the module name, for example iproute2_
+
+	j="${#MODULES[@]}"
+	loaded_interface=false
+	for (( i=0; i<j; i++ )); do
+		MODULES[i]="${MODULES[i]%.sh*}"
+		if [[ ${MODULES[i]##*/} == "interface" ]] ; then
+			eerror "interface is a reserved name - cannot load a module called interface"
+			return 1
 		fi
-		# ifconfig does not always return failure ..
-		ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
-		ifconfig ${IFACE} up &>${devnull}
-		eend $? || return $?
-	else
-		# Check that eth0 was not brought up by the kernel ...
-		if [[ ${status_IFACE} == up ]]; then
-			einfo "Keeping kernel configuration for ${IFACE}"
+		
+		(
+		u=0;
+		module_load_minimum "${MODULES[i]}" || u=1;
+		if [[ ${u} == 0 ]] ; then
+			inst="${MODULES[i]##*/}_check_installed";
+			if is_function "${inst}" ; then
+				${inst} false || u=1;
+			fi
+		fi
+		exit "${u}";
+		)
+
+		if [[ $? == 0 ]] ; then
+			source "${MODULES[i]}.sh"
+			MODULES[i]="${MODULES[i]##*/}"
 		else
-			ebegin "Bringing ${IFACE} up via DHCP"
-			/sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
-			retval=$?
-			eend $retval
-			if [[ $retval == 0 ]]; then
-				# DHCP succeeded, show address retrieved
-				i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' | 
-					cut -d: -f2)
-				[[ -n ${i} ]] && einfo "  ${IFACE} received address ${i}"
-			elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
-				# DHCP failed, try fallback.
-				# Show the address, but catch if this interface will be inet6 only
-				i=${ifconfig_fallback_IFACE%% *}
-				if [[ ${i} == *.*.*.* ]]; then
-					ebegin "Using fallback configuration (${i}) for ${IFACE}"
-				else
-					ebegin "Using fallback configuration for ${IFACE}"
+			unset MODULES[i]
+		fi
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	return 0
+}
+
+# bool modules_check_installed(void)
+#
+# Ensure that all modules have the required modules loaded
+# This enables us to remove modules from the MODULES array
+# Whilst other modules can still explicitly call them
+# One example of this is essidnet which configures network
+# settings for the specific ESSID connected to as the user
+# may be using a daemon to configure wireless instead of our
+# iwconfig module
+modules_check_installed() {
+	local i j missingdeps nmods="${#MODULES[@]}"
+
+	for (( i=0; i<nmods; i++ )); do
+		is_function "${MODULES[i]}_instlled" || continue
+		for j in $( ${MODULES[i]}_instlled ); do
+			missingdeps=true
+			if is_function "${j}_check_installed" ; then
+				${j}_check_installed && missingdeps=false
+			elif is_function "${j}_depend" ; then
+				missingdeps=false
+			fi
+			${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+}
+
+# bool modules_check_user(void)
+modules_check_user() {
+	local iface="$1" ifvar=$(bash_variable "${IFACE}")
+	local i= j= k= l= nmods="${#MODULES[@]}"
+	local -a umods=()
+
+	# Has the interface got any specific modules?
+	umods="modules_${ifvar}[@]"
+	umods=( "${!umods}" )
+
+	# Global setting follows interface-specific setting
+	umods=( "${umods[@]}" "${modules[@]}" )
+
+	# Add our preferred modules
+	local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
+	umods=( "${umods[@]}" "${pmods[@]}" )
+
+	# First we strip any modules that conflict from user settings
+	# So if the user specifies pump then we don't use dhcpcd
+	for (( i=0; i<${#umods[@]}; i++ )); do
+		# Some users will inevitably put "dhcp" in their modules
+		# list.  To keep users from screwing up their system this
+		# way, ignore this setting so that the default dhcp
+		# module will be used.
+		[[ ${umods[i]} == "dhcp" ]] && continue
+
+		# We remove any modules we explicitly don't want
+		if [[ ${umods[i]} == "!"* ]] ; then
+			for (( j=0; j<nmods; j++ )); do
+				[[ -z ${MODULES[j]} ]] && continue
+				if [[ ${umods[i]:1} == "${MODULES[j]}" \
+					|| ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
+					# We may need to setup a class wrapper for it even though
+					# we don't use it directly
+					# However, we put it into an array and wrap later as
+					# another module may provide the same thing
+					${MODULES[j]}_check_installed \
+						&& WRAP_MODULES=(
+							"${WRAP_MODULES[@]}"
+							"${MODULES[j]} ${PROVIDES[j]}"
+						)
+					unset MODULES[j]
+					unset PROVIDES[j]
 				fi
-				ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
-				ifconfig ${IFACE} up &>${devnull}
-				eend $? || return $?
+			done
+			continue
+		fi
+
+		if ! is_function "${umods[i]}_depend" ; then
+			# If the module is one of our preferred modules, then
+			# ignore this error; whatever is available will be
+			# used instead.
+			(( i < ${#umods[@]} - ${#pmods[@]} )) || continue
+
+			# The function may not exist because the modules software is
+			# not installed. Load the module and report its error
+			if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
+				source "${MODULES_DIR}/${umods[i]}.sh"
+				is_function "${umods[i]}_check_installed" \
+					&& ${umods[i]}_check_installed true
 			else
-				return $retval
+				eerror "The module \"${umods[i]}\" does not exist"
 			fi
+			return 1
 		fi
-	fi
 
-	if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
-		einfo "  Adding aliases"
-		for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
-			ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
-			eend $?
+		if is_function "${umods[i]}_provide" ; then
+			mod=$(${umods[i]}_provide)
+		else
+			mod="${umods[i]}"
+		fi
+		for (( j=0; j<nmods; j++ )); do
+			[[ -z ${MODULES[j]} ]] && continue
+			if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
+				# We don't have a match - now ensure that we still provide an
+				# alternative. This is to handle our preferred modules.
+				for (( l=0; l<nmods; l++ )); do
+					[[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
+					if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
+						unset MODULES[j]
+						unset PROVIDES[j]
+						break
+					fi
+				done
+			fi
+		done
+	done
+
+	# Then we strip conflicting modules.
+	# We only need to do this for 3rd party modules that conflict with
+	# our own modules and the preferred list AND the user modules
+	# list doesn't specify a preference.
+	for (( i=0; i<nmods-1; i++ )); do
+		[[ -z ${MODULES[i]} ]] && continue			
+		for (( j=i+1; j<nmods; j++)); do
+			[[ -z ${MODULES[j]} ]] && continue
+			[[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
+			&& unset MODULES[j] && unset PROVIDES[j]
+		done
+	done
+
+	MODULES=( "${MODULES[@]}" )
+	PROVIDES=( "${PROVIDES[@]}" )
+	return 0
+}
+
+# void modules_sort(void)
+#
+# Sort our modules
+modules_sort() {
+	local i= j= nmods=${#MODULES[@]} m=
+	local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
+
+	# Make our provide list
+	for ((i=0; i<nmods; i++)); do
+		dead[i]="false"
+		if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
+			local provided=false
+			for ((j=0; j<${#provide[@]}; j++)); do
+				if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
+					provide_list[j]="${provide_list[j]} ${MODULES[i]}"
+					provided=true
+				fi
+			done
+			if ! ${provided}; then
+				provide[j]="${PROVIDES[i]}"
+				provide_list[j]="${MODULES[i]}"
+			fi
+		fi
+	done
+
+	# Create an after array, which holds which modules the module at
+	# index i must be after
+	for ((i=0; i<nmods; i++)); do
+		if is_function "${MODULES[i]}_after" ; then
+			after[i]=" ${after[i]} $(${MODULES[i]}_after) "
+		fi
+		if is_function "${MODULES[i]}_before" ; then
+			for m in $(${MODULES[i]}_before); do
+				for ((j=0; j<nmods; j++)) ; do
+					if [[ ${PROVIDES[j]} == "${m}" ]] ; then
+						after[j]=" ${after[j]} ${MODULES[i]} "
+						break
+					fi
+				done
+			done
+		fi
+	done
+
+	# Replace the after list modules with real modules
+	for ((i=0; i<nmods; i++)); do
+		if [[ -n ${after[i]} ]] ; then
+			for ((j=0; j<${#provide[@]}; j++)); do
+				after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
+			done
+		fi
+	done
+	
+	# We then use the below code to provide a topologial sort
+    module_after_visit() {
+        local name="$1" i= x=
+
+		for ((i=0; i<nmods; i++)); do
+			[[ ${MODULES[i]} == "$1" ]] && break
 		done
+
+        ${dead[i]} && return
+        dead[i]="true"
+
+        for x in ${after[i]} ; do
+            module_after_visit "${x}"
+        done
+
+        sorted=( "${sorted[@]}" "${MODULES[i]}" )
+		sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
+    }
+
+	for x in ${MODULES[@]}; do
+		module_after_visit "${x}"
+	done
+
+	MODULES=( "${sorted[@]}" )
+	PROVIDES=( "${sortedp[@]}" )
+}
+
+# bool modules_check_depends(bool showprovides)
+modules_check_depends() {
+	local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
+	local missingdeps= p= interface=false
+
+	for (( i=0; i<nmods; i++ )); do
+		if is_function "${MODULES[i]}_need" ; then
+			for needmod in $(${MODULES[i]}_need); do
+				missingdeps=true
+				for (( j=0; j<nmods; j++ )); do
+					if [[ ${needmod} == "${MODULES[j]}" \
+						|| ${needmod} == "${PROVIDES[j]}" ]] ; then
+						missingdeps=false
+						break
+					fi
+				done
+				if ${missingdeps} ; then
+					eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
+					return 1
+				fi
+			done
+		fi
+
+		if is_function "${MODULES[i]}_functions" ; then
+			for f in $(${MODULES[i]}_functions); do
+				if ! is_function "${f}" ; then
+					eerror "${MODULES[i]}: missing required function \"${f}\""
+					return 1
+				fi
+			done
+		fi
+
+		[[ ${PROVIDES[i]} == "interface" ]] && interface=true
+
+		if ${showprovides} ; then
+			[[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
+			&& veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
+		fi
+	done
+
+	if ! ${interface} ; then
+		eerror "no interface module has been loaded"
+		return 1
 	fi
 
-	if [[ -n ${inet6_IFACE} ]]; then
-		einfo "  Adding inet6 addresses"
-		for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${IFACE} inet6 add ${inet6_IFACE[i]}"
-			ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
-			eend $?
+	return 0
+}
+
+# bool modules_load(char *iface, bool starting)
+#
+# Loads the defined handler and modules for the interface
+# Returns 0 on success, otherwise 1
+modules_load()  {
+	local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
+	local -a x=()
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a PROVIDES=() WRAP_MODULES=()
+
+	if ! is_loopback "${iface}" ; then
+		x="modules_force_${iface}[@]"
+		[[ -n ${!x} ]] && modules_force=( "${!x}" )
+		if [[ -n ${modules_force} ]] ; then
+			ewarn "WARNING: You are forcing modules!"
+			ewarn "Do not complain or file bugs if things start breaking"
+			report=true
+		fi
+	fi
+
+	veinfo "Loading networking modules for ${iface}"
+	eindent
+
+	if [[ -z ${modules_force} ]] ; then
+		modules_load_auto || return 1
+	else
+		j="${#modules_force[@]}"
+		for (( i=0; i<j; i++ )); do
+			module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
+			if is_function "${modules_force[i]}_check_installed" ; then
+				${modules_force[i]}_check_installed || unset modules_force[i]
+			fi
 		done
+		MODULES=( "${modules_force[@]}" )
 	fi
 
-	# Set static routes
-	if [[ -n ${routes_IFACE} ]]; then
-		einfo "  Adding routes"
-		for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
-			ebegin "    ${routes_IFACE[i]}"
-			/sbin/route add ${routes_IFACE[i]}
-			eend $?
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		# Now load our dependencies - we need to use the MODULE variable
+		# here as the after/before/need functions use it
+		MODULE="${MODULES[i]}"
+		${MODULE}_depend
+
+		# expose does exactly the same thing as depend
+		# However it is more "correct" as it exposes things to other modules
+		# instead of depending on them ;)
+		is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
+
+		# If no provide is given, assume module name
+		if is_function "${MODULES[i]}_provide" ; then
+			PROVIDES[i]=$(${MODULES[i]}_provide)
+		else
+			PROVIDES[i]="${MODULES[i]}"
+		fi
+	done
+
+	if [[ -n ${modules_force[@]} ]] ; then
+		# Strip any duplicate modules providing the same thing
+		j="${#MODULES[@]}"
+		for (( i=0; i<j-1; i++ )); do
+			[[ -z ${MODULES[i]} ]] && continue
+			for (( k=i+1; k<j; k++ )); do
+				if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
+					unset MODULES[k]
+					unset PROVIDES[k]
+				fi
+			done
 		done
+		MODULES=( "${MODULES[@]}" )
+		PROVIDES=( "${PROVIDES[@]}" )
+	else
+		if ${starting}; then
+			modules_check_user "${iface}" || return 1
+		else
+			# Always prefer iproute2 for taking down interfaces
+			if is_function iproute2_provide ; then
+				function_wrap iproute2 "$(iproute2_provide)"
+			fi
+		fi
 	fi
+	
+	# Wrap our modules
+	j="${#MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
+	done
+	j="${#WRAP_MODULES[@]}"
+	for (( i=0; i<j; i++ )); do
+		function_wrap ${WRAP_MODULES[i]}
+	done
+	
+	if [[ -z ${modules_force[@]} ]] ; then
+		modules_check_installed || return 1
+		modules_sort || return 1
+	fi
+
+	veinfo "modules: ${MODULES[@]}"
+	eindent
+
+	${starting} && p=true
+	modules_check_depends "${p}" || return 1
+	return 0
+}
+
+# bool iface_start(char *interface)
+#
+# iface_start is called from start.  It's expected to start the base
+# interface (for example "eth0"), aliases (for example "eth0:1") and to start
+# VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
+# calling itself recursively.
+iface_start() {
+	local iface="$1" mod config_counter="-1" x config_worked=false
+	local RC_INDENTATION="${RC_INDENTATION}"
+	local -a config=() fallback=() fallback_route=() conf=() a=() b=()
+	local ifvar=$(bash_variable "$1") i= j= metric=0
 
-	# Set default route if applicable to this interface
-	if [[ ${gateway} == ${IFACE}/* ]]; then
-		local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
-		local gw=${gateway#*/}
-		if [[ ${ogw} != ${gw} ]]; then
-			ebegin "  Setting default gateway ($gw)"
-
-			# First delete any existing route if it was setup by kernel...
-			/sbin/route del default dev ${IFACE} &>${devnull}
-
-			# Second delete old gateway if it was set...
-			/sbin/route del default gw ${ogw} &>${devnull}
-
-			# Third add our new default gateway
-			/sbin/route add default gw ${gw} >${devnull}
-			eend $? || {
-				true # need to have some command in here
-				# Note: This originally called stop, which is obviously
-				# wrong since it's calling with a local version of IFACE.
-				# The below code works correctly to abort configuration of
-				# the interface, but is commented because we're assuming
-				# that default route failure should not cause the interface
-				# to be unconfigured.
-				#local error=$?
-				#ewarn "Aborting configuration of ${IFACE}"
-				#iface_stop ${IFACE}
-				#return ${error}
-			}
+	# pre Start any modules with
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_start" ; then
+			${mod}_pre_start "${iface}" || { eend 1; return 1; }
 		fi
+	done
+
+	x="metric_${ifvar}"
+	# If we don't have a metric then calculate one
+	# Our modules will set the metric variable to a suitable base
+	# in their pre starts.
+	if [[ -z ${!x} ]] ; then
+		eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
 	fi
 
-	# Enabling rp_filter causes wacky packets to be auto-dropped by
-	# the kernel.  Note that we only do this if it is not set via
-	# /etc/sysctl.conf ...
-	if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
-			-z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
-		echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+	# We now expand the configuration parameters and pray that the
+	# fallbacks expand to the same number as config or there will be
+	# trouble!
+	a="config_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		config=( "${config[@]}" "${b[@]}" )
+	done
+
+	a="fallback_${ifvar}[@]"
+	a=( "${!a}" )
+	for (( i=0; i<${#a[@]}; i++ )); do 
+		eval b=( $(expand_parameters "${a[i]}") )
+		fallback=( "${fallback[@]}" "${b[@]}" )
+	done
+
+	# We don't expand routes
+	fallback_route="fallback_route_${ifvar}[@]"
+	fallback_route=( "${!fallback_route}" )
+	
+	# We must support old configs
+	if [[ -z ${config} ]] ; then
+		interface_get_old_config "${iface}" || return 1
+		if [[ -n ${config} ]] ; then
+			ewarn "You are using a deprecated configuration syntax for ${iface}"
+			ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
+		fi
+	fi
+
+	# Handle "noop" correctly
+	if [[ ${config[0]} == "noop" ]] ; then
+		if interface_is_up "${iface}" true ; then
+			einfo "Keeping current configuration for ${iface}"
+			eend 0
+			return 0
+		fi
+
+		# Remove noop from the config var
+		config=( "${config[@]:1}" )
+	fi
+
+	# Provide a default of DHCP if no configuration is set and we're auto
+	# Otherwise a default of NULL
+	if [[ -z ${config} ]] ; then
+		ewarn "Configuration not set for ${iface} - assuming DHCP"
+		if is_function "dhcp_start" ; then
+			config=( "dhcp" )
+		else
+			eerror "No DHCP client installed"
+			return 1
+		fi
 	fi
+
+	einfo "Bringing up ${iface}"
+	eindent
+	for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
+		# Handle null and noop correctly
+		if [[ ${config[config_counter]} == "null" \
+			|| ${config[config_counter]} == "noop" ]] ; then
+			eend 0
+			config_worked=true
+			continue
+		fi
+
+		# We convert it to an array - this has the added
+		# bonus of trimming spaces!
+		conf=( ${config[config_counter]} )
+		einfo "${conf[0]}"
+
+		# Do we have a function for our config?
+		if is_function "${conf[0]}_start" ; then
+			eindent
+			${conf[0]}_start "${iface}" ; x=$?
+			eoutdent
+			[[ ${x} == 0 ]] && config_worked=true && continue
+			# We need to test to see if it's an IP address or a function
+			# We do this by testing if the 1st character is a digit
+		elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
+			x="0"
+			if ! is_loopback "${iface}" ; then
+				if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
+					if arping_address_exists "${iface}" "${conf[0]}" ; then
+						eerror "${conf[0]%%/*} already taken on ${iface}"
+						x="1"
+					fi
+				fi
+			fi
+			[[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
+			eend "${x}" && config_worked=true && continue
+		else
+			if [[ ${conf[0]} == "dhcp" ]] ; then
+				eerror "No DHCP client installed"
+			else
+				eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
+			fi
+		fi
+
+		if [[ -n ${fallback[config_counter]} ]] ; then
+			einfo "Trying fallback configuration"
+			config[config_counter]="${fallback[config_counter]}"
+			fallback[config_counter]=""
+
+			# Do we have a fallback route?
+			if [[ -n ${fallback_route[config_counter]} ]] ; then
+				x="fallback_route[config_counter]"
+				eval "routes_${ifvar}=( \"\${!x}\" )"
+				fallback_route[config_counter]=""
+			fi
+
+			(( config_counter-- )) # since the loop will increment it
+			continue
+		fi
+	done
+	eoutdent
+
+	# We return failure if no configuration parameters worked
+	${config_worked} || return 1
+
+	# Start any modules with _post_start
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_post_start" ; then
+			${mod}_post_start "${iface}" || return 1
+		fi
+	done
+
+	return 0
 }
 
+# bool iface_stop(char *interface)
+#
 # iface_stop: bring down an interface.  Don't trust information in
 # /etc/conf.d/net since the configuration might have changed since
 # iface_start ran.  Instead query for current configuration and bring
 # down the interface.
 iface_stop() {
-	local IFACE=${1} i x aliases inet6 count
-
-	# Try to do a simple down (no aliases, no inet6, no dhcp)
-	aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
-	inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
-	if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
-		ebegin "Bringing ${IFACE} down"
-		ifconfig ${IFACE} down &>/dev/null
-		eend 0
-		return 0
-	fi
+	local iface="$1" i= aliases= need_begin=false mod=
+	local RC_INDENTATION="${RC_INDENTATION}"
 
-	einfo "Bringing ${IFACE} down"
+	# pre Stop any modules
+	for mod in ${MODULES[@]}; do
+		if is_function "${mod}_pre_stop" ; then
+			${mod}_pre_stop "${iface}" || return 1
+		fi
+	done
+
+	einfo "Bringing down ${iface}"
+	eindent
+
+	# Collect list of aliases for this interface.
+	# List will be in reverse order.
+	if interface_exists "${iface}" ; then
+		aliases=$(interface_get_aliases_rev "${iface}")
+	fi
 
 	# Stop aliases before primary interface.
 	# Note this must be done in reverse order, since ifconfig eth0:1 
 	# will remove eth0:2, etc.  It might be sufficient to simply remove 
 	# the base interface but we're being safe here.
-	for i in ${aliases} ${IFACE}; do
-
-		# Delete all the inet6 addresses for this interface
-		inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
-		if [[ -n ${inet6} ]]; then
-			einfo "  Removing inet6 addresses"
-			for x in ${inet6}; do 
-				ebegin "    ${IFACE} inet6 del ${x}"
-				ifconfig ${i} inet6 del ${x}
-				eend $?
-			done
+	for i in ${aliases} ${iface}; do
+		# Stop all our modules
+		for mod in ${MODULES[@]}; do
+			if is_function "${mod}_stop" ; then
+				${mod}_stop "${i}" || return 1
+			fi
+		done
+
+		# A module may have removed the interface
+		if ! interface_exists "${iface}" ; then
+			eend 0
+			continue
 		fi
 
-		# Stop DHCP (should be N/A for aliases)
-		# Don't trust current configuration... investigate ourselves
-		if /sbin/dhcpcd -z ${i} &>${devnull}; then
-			ebegin "  Releasing DHCP lease for ${IFACE}"
-			for ((count = 0; count < 9; count = count + 1)); do
-				/sbin/dhcpcd -z ${i} &>${devnull} || break
-				sleep 1
-			done
-			[[ ${count} -lt 9 ]]
-			eend $? "Timed out"
+		# We don't delete ppp assigned addresses
+		if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
+			# Delete all the addresses for this alias
+			interface_del_addresses "${i}"
 		fi
-		ebegin "  Stopping ${i}"
-		ifconfig ${i} down &>${devnull}
-		eend 0
+
+		# Do final shut down of this alias
+		if [[ ${IN_BACKGROUND} != "true" \
+			&& ${RC_DOWN_INTERFACE} == "yes" ]] ; then
+			ebegin "Shutting down ${i}"
+			interface_iface_stop "${i}"
+			eend "$?"
+		fi
+	done
+
+	# post Stop any modules
+	for mod in ${MODULES[@]}; do
+		# We have already taken down the interface, so no need to error
+		is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
 	done
 
 	return 0
 }
 
-start() {
-	# These variables are set by setup_vars
-	local status_IFACE vlans_IFACE dhcpcd_IFACE 
-	local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+# bool run_start(char *iface)
+#
+# Brings up ${IFACE}.  Calls preup, iface_start, then postup.
+# Returns 0 (success) unless preup or iface_start returns 1 (failure).
+# Ignores the return value from postup.
+# We cannot check that the device exists ourselves as modules like
+# tuntap make create it.
+run_start() {
+	local iface="$1" IFVAR=$(bash_variable "$1")
+
+	# We do this so users can specify additional addresses for lo if they
+	# need too - additional routes too
+	# However, no extra modules are loaded as they are just not needed
+	if [[ ${iface} == "lo" ]] ; then
+		metric_lo="0"
+		config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
+	elif [[ ${iface} == "lo0" ]] ; then
+		metric_lo0="0"
+		config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
+		routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
+	fi
+
+	# We may not have a loaded module for ${iface}
+	# Some users may have "alias natsemi eth0" in /etc/modules.d/foo
+	# so we can work with this
+	# However, if they do the same with eth1 and try to start it
+	# but eth0 has not been loaded then the module gets loaded as
+	# eth0.
+	# Not much we can do about this :(
+	# Also, we cannot error here as some modules - such as bridge
+	# create interfaces
+	if ! interface_exists "${iface}" ; then
+		/sbin/modprobe "${iface}" &>/dev/null
+	fi
 
 	# Call user-defined preup function if it exists
-	if [[ $(type -t preup) == function ]]; then
+	if is_function preup ; then
 		einfo "Running preup function"
-		preup ${IFACE} || {
-			eerror "preup ${IFACE} failed"
-			return 1
-		}
+		eindent
+		( preup "${iface}" )
+		eend "$?" "preup ${iface} failed" || return 1
+		eoutdent
 	fi
 
-	# Start the primary interface and aliases
-	setup_vars ${IFACE}
-	iface_start ${IFACE} || return 1
+	# If config is set to noop and the interface is up with an address
+	# then we don't start it
+	local config=
+	config="config_${IFVAR}[@]"
+	config=( "${!config}" )
+	if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
+		einfo "Keeping current configuration for ${iface}"
+		eend 0
+	else
+		# Remove noop from the config var
+		[[ ${config[0]} == "noop" ]] \
+			&& eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
 
-	# Start vlans
-	local vlan
-	for vlan in ${vlans_IFACE}; do
-		/sbin/vconfig add ${IFACE} ${vlan} >${devnull}
-		setup_vars ${IFACE}.${vlan}
-		iface_start ${IFACE}.${vlan}
-	done
+		# There may be existing ip address info - so we strip it
+		if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
+			&& ${IN_BACKGROUND} != "true" ]] ; then
+			interface_del_addresses "${iface}"
+		fi
+
+		# Start the interface
+		if ! iface_start "${iface}" ; then
+			if [[ ${IN_BACKGROUND} != "true" ]] ; then
+				interface_exists "${iface}" && interface_down "${iface}"
+			fi
+			eend 1
+			return 1
+		fi
+	fi
 
 	# Call user-defined postup function if it exists
-	if [[ $(type -t postup) == function ]]; then
+	if is_function postup ; then
+		# We need to mark the service as started incase a
+		# postdown function wants to restart services that depend on us
+		mark_service_started "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postup function"
-		postup ${IFACE}
+		eindent
+		( postup "${iface}" )
+		eoutdent
 	fi
+
+	return 0
 }
 
-stop() {
+# bool run_stop(char *iface) {
+#
+# Brings down ${iface}.  If predown call returns non-zero, then
+# stop returns non-zero to indicate failure bringing down device.
+# In all other cases stop returns 0 to indicate success.
+run_stop() {
+	local iface="$1" IFVAR=$(bash_variable "$1") x
+
+	# Load our ESSID variable so users can use it in predown() instead
+	# of having to write code.
+	local ESSID=$(get_options ESSID) ESSIDVAR=
+	[[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
+
 	# Call user-defined predown function if it exists
-	if [[ $(type -t predown) == function ]]; then
+	if is_function predown ; then
 		einfo "Running predown function"
-		predown ${IFACE}
+		eindent
+		( predown "${iface}" )
+		eend $? "predown ${iface} failed" || return 1
+		eoutdent
+	elif is_net_fs / ; then
+		eerror "root filesystem is network mounted -- can't stop ${iface}"
+		return 1
+	elif is_union_fs / ; then
+		for x in $(unionctl "${dir}" --list \
+		| sed -e 's/^\(.*\) .*/\1/') ; do
+			if is_net_fs "${x}" ; then
+				eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
+				return 1
+			fi
+		done
 	fi
 
-	# Don't depend on setup_vars since configuration might have changed.
-	# Investigate current configuration instead.
-	local vlan
-	for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
-		iface_stop ${vlan}
-		/sbin/vconfig rem ${vlan} >${devnull}
-	done
+	iface_stop "${iface}" || return 1  # always succeeds, btw
 
-	iface_stop ${IFACE} || return 1  # always succeeds, btw
+	# Release resolv.conf information.
+	[[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
+	
+	# Mark us as inactive if called from the background
+	[[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
 
 	# Call user-defined postdown function if it exists
-	if [[ $(type -t postdown) == function ]]; then
+	if is_function postdown ; then
+		# We need to mark the service as stopped incase a
+		# postdown function wants to restart services that depend on us
+		[[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
+		end_service "net.${iface}" 0
 		einfo "Running postdown function"
-		postdown ${IFACE}
+		eindent
+		( postdown "${iface}" )
+		eoutdent
+	fi
+
+
+	return 0
+}
+
+# bool run(char *iface, char *cmd)
+#
+# Main start/stop entry point
+# We load modules here and remove any functions that they
+# added as we may be called inside the same shell scope for another interface
+run() {
+	local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
+	local starting=true
+	local -a MODULES=() mods=()
+	local IN_BACKGROUND="${IN_BACKGROUND}"
+
+	if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
+		IN_BACKGROUND=true
+	else
+		IN_BACKGROUND=false
+	fi
+
+	# We need to override the exit function as runscript.sh now checks
+	# for it. We need it so we can mark the service as inactive ourselves.
+	unset -f exit
+
+	eindent
+	[[ ${cmd} == "stop" ]] && starting=false
+
+	# We force lo to only use these modules for a major speed boost
+	if is_loopback "${iface}" ; then	
+		modules_force=( "iproute2" "ifconfig" "system" )
+	fi
+
+	if modules_load "${iface}" "${starting}" ; then
+		if [[ ${cmd} == "stop" ]] ; then
+			# Reverse the module list for stopping
+			mods=( "${MODULES[@]}" )
+			for ((i = 0; i < ${#mods[@]}; i++)); do
+				MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
+			done
+
+			run_stop "${iface}" && r=0
+		else
+			# Only hotplug on ethernet interfaces
+			if [[ ${IN_HOTPLUG} == 1 ]] ; then
+				if ! interface_is_ethernet "${iface}" ; then
+					eerror "We only hotplug for ethernet interfaces"
+					return 1
+				fi
+			fi
+
+			run_start "${iface}" && r=0
+		fi
+	fi
+
+	if [[ ${r} != "0" ]] ; then
+		if [[ ${cmd} == "start" ]] ; then
+			# Call user-defined failup if it exists
+			if is_function failup ; then
+				einfo "Running failup function"
+				eindent
+				( failup "${iface}" )
+				eoutdent
+			fi
+		else
+			# Call user-defined faildown if it exists
+			if is_function faildown ; then
+				einfo "Running faildown function"
+				eindent
+				( faildown "${iface}" )
+				eoutdent
+			fi
+		fi
+		[[ ${IN_BACKGROUND} == "true" ]] \
+			&& mark_service_inactive "net.${iface}"
 	fi
+
+	return "${r}"
+}
+
+# bool start(void)
+#
+# Start entry point so that we only have one function
+# which localises variables and unsets functions
+start() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Starting ${IFACE}"
+	run "${IFACE}" start
+}
+
+# bool stop(void)
+#
+# Stop entry point so that we only have one function
+# which localises variables and unsets functions
+stop() {
+	declare -r IFACE="${SVCNAME#*.}"
+	einfo "Stopping ${IFACE}"
+	run "${IFACE}" stop
 }
 
 # vim:ts=4
diff --git a/testing/scripts/build-hostconfig b/testing/scripts/build-hostconfig
index 0df8861c8..28b321a70 100755
--- a/testing/scripts/build-hostconfig
+++ b/testing/scripts/build-hostconfig
@@ -14,7 +14,7 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 #
-# RCSID $Id: build-hostconfig,v 1.3 2005/02/08 10:40:48 as Exp $
+# RCSID $Id: build-hostconfig,v 1.4 2006/10/19 21:38:45 as Exp $
 
 DIR=`dirname $0`
 
@@ -58,44 +58,61 @@ HOSTIP=`ifconfig eth0 |grep inet |sed -e "s/.*inet addr://" -e "s/  Bcast.*//"`
 for host in $STRONGSWANHOSTS
 do
     cecho-n "${host}.."
-    eval ip_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+    eval ipv4_${host}="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $1 }' | awk '{ print $1 }'`"
+    eval ipv6_${host}="`echo $HOSTNAMEIPV6 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $1 }' | awk '{ print $1 }'`"
 
-    [ "`eval echo \\\$ip_${host}`" != "$HOSTIP" ] || die "$host has the same IP as eth0 (Host)! Please change that."
+    [ "`eval echo \\\$ipv4_${host}`" != "$HOSTIP" ] || die "$host has the same IP as eth0 (Host)! Please change that."
 
     case $host in
     moon)
-        eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
-        [ "`eval echo \\\$ip1_${host}`" != "$HOSTIP" ] || die "eth1 of $host has the same IP as eth0 (Host)! Please change that."
-        searchandreplace PH_IP_MOON $ip_moon $HOSTCONFIGDIR
-        searchandreplace PH_IP1_MOON $ip1_moon $HOSTCONFIGDIR
+        eval ipv4_moon1="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
+        [ "`eval echo \\\$ipv4_moon1`" != "$HOSTIP" ] || die "eth1 of $host has the same IP as eth0 (Host)! Please change that."
+        searchandreplace PH_IP_MOON1 $ipv4_moon1 $HOSTCONFIGDIR
+        searchandreplace PH_IP_MOON  $ipv4_moon  $HOSTCONFIGDIR
+        eval ipv6_moon1="`echo $HOSTNAMEIPV6 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
+        searchandreplace PH_IP6_MOON1 $ipv6_moon1 $HOSTCONFIGDIR
+        searchandreplace PH_IP6_MOON  $ipv6_moon  $HOSTCONFIGDIR
         ;;
     sun)
-        eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
-        [ "`eval echo \\\$ip1_${host}`" != "$HOSTIP" ] || die "eth1 of $host has the same IP as eth0 (Host)! Please change that."
-        searchandreplace PH_IP_SUN $ip_sun $HOSTCONFIGDIR
-        searchandreplace PH_IP1_SUN $ip1_sun $HOSTCONFIGDIR
+        eval ipv4_sun1="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
+        [ "`eval echo \\\$ipv4_sun1`" != "$HOSTIP" ] || die "eth1 of $host has the same IP as eth0 (Host)! Please change that."
+        searchandreplace PH_IP_SUN1 $ipv4_sun1 $HOSTCONFIGDIR
+        searchandreplace PH_IP_SUN  $ipv4_sun  $HOSTCONFIGDIR
+        eval ipv6_sun1="`echo $HOSTNAMEIPV6 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
+        searchandreplace PH_IP6_SUN1 $ipv6_sun1 $HOSTCONFIGDIR
+        searchandreplace PH_IP6_SUN  $ipv6_sun  $HOSTCONFIGDIR
         ;;
     alice)
-        searchandreplace PH_IP_ALICE $ip_alice $HOSTCONFIGDIR
+        searchandreplace PH_IP_ALICE  $ipv4_alice $HOSTCONFIGDIR
+        searchandreplace PH_IP6_ALICE $ipv6_alice $HOSTCONFIGDIR
         ;;
     venus)
-        searchandreplace PH_IP_VENUS $ip_venus $HOSTCONFIGDIR
+        searchandreplace PH_IP_VENUS  $ipv4_venus $HOSTCONFIGDIR
+        searchandreplace PH_IP6_VENUS $ipv6_venus $HOSTCONFIGDIR
         ;;
     bob)
-        searchandreplace PH_IP_BOB $ip_bob $HOSTCONFIGDIR
+        searchandreplace PH_IP_BOB  $ipv4_bob $HOSTCONFIGDIR
+        searchandreplace PH_IP6_BOB $ipv6_bob $HOSTCONFIGDIR
         ;;
     carol)
-        eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
-        searchandreplace PH_IP_CAROL $ip_carol $HOSTCONFIGDIR
-        searchandreplace PH_IP1_CAROL $ip1_carol $HOSTCONFIGDIR
+        eval ipv4_carol1="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
+        searchandreplace PH_IP_CAROL1 $ipv4_carol1 $HOSTCONFIGDIR
+        searchandreplace PH_IP_CAROL  $ipv4_carol  $HOSTCONFIGDIR
+        eval ipv6_carol1="`echo $HOSTNAMEIPV6 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
+        searchandreplace PH_IP6_CAROL1 $ipv6_carol1 $HOSTCONFIGDIR
+        searchandreplace PH_IP6_CAROL  $ipv6_carol  $HOSTCONFIGDIR
         ;;
     dave)
-        eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
-        searchandreplace PH_IP_DAVE $ip_dave $HOSTCONFIGDIR
-        searchandreplace PH_IP1_DAVE $ip1_dave $HOSTCONFIGDIR
+        eval ipv4_dave1="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
+        searchandreplace PH_IP_DAVE1 $ipv4_dave1 $HOSTCONFIGDIR
+        searchandreplace PH_IP_DAVE  $ipv4_dave  $HOSTCONFIGDIR
+        eval ipv6_dave1="`echo $HOSTNAMEIPV6 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $2 }' | awk '{ print $1 }'`"
+        searchandreplace PH_IP6_DAVE1 $ipv6_dave1 $HOSTCONFIGDIR
+        searchandreplace PH_IP6_DAVE  $ipv6_dave  $HOSTCONFIGDIR
         ;;
     winnetou)
-        searchandreplace PH_IP_WINNETOU $ip_winnetou $HOSTCONFIGDIR
+        searchandreplace PH_IP_WINNETOU  $ipv4_winnetou $HOSTCONFIGDIR
+        searchandreplace PH_IP6_WINNETOU $ipv6_winnetou $HOSTCONFIGDIR
         ;;
     esac
 done
diff --git a/testing/scripts/build-sshkeys b/testing/scripts/build-sshkeys
index f4d584d6b..2faa3963d 100755
--- a/testing/scripts/build-sshkeys
+++ b/testing/scripts/build-sshkeys
@@ -14,7 +14,7 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 #
-# RCSID $Id: build-sshkeys,v 1.2 2005/02/15 14:12:16 as Exp $
+# RCSID $Id: build-sshkeys,v 1.3 2006/10/19 21:38:45 as Exp $
 
 DIR=`dirname $0`
 
@@ -58,10 +58,10 @@ else
     cecho "done"
 fi
 
-for host in $HOSTNAMEIPS
+for host in $HOSTNAMEIPV4
 do
-    HOSTNAME=`echo $host | awk -F : '{ print $1 }'`
-    IP=`echo $host | awk -F : '{ print $2 }'`
+    HOSTNAME=`echo $host | awk -F, '{ print $1 }'`
+    IP=`echo $host | awk -F, '{ print $2 }'`
     if [ `grep "$IP " ~/.ssh/known_hosts | wc -l` != "0" ]
     then
         cecho "!! Warning: An entry exists for the following IP address: $IP"
diff --git a/testing/scripts/build-umlrootfs b/testing/scripts/build-umlrootfs
index ba103838f..1d534c81b 100755
--- a/testing/scripts/build-umlrootfs
+++ b/testing/scripts/build-umlrootfs
@@ -14,7 +14,7 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 #
-# RCSID $Id: build-umlrootfs,v 1.11 2006/01/08 22:29:56 as Exp $
+# RCSID $Id: build-umlrootfs,v 1.12 2006/10/20 14:26:05 as Exp $
 
 DIR=`dirname $0`
 
@@ -90,6 +90,12 @@ tar xjpf $ROOTFS -C $LOOPDIR     >> $LOGFILE 2>&1
 cecho "done"
 
 
+######################################################
+# remove /etc/resolv.conf
+#
+cecho " * Removing /etc/resolv.conf"
+rm -f $LOOPDIR/etc/resolv.conf
+
 ######################################################
 # copying default /etc/hosts to the root filesystem
 #
@@ -153,7 +159,7 @@ cp $LOOPDIR/etc/ssh/ssh_host_rsa_key $LOOPDIR/root/.ssh/id_rsa
 
 for host in $STRONGSWANHOSTS
 do
-    eval ip="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+    eval ip="`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $1 }' | awk '{ print $1 }'`"
     echo "$host,$ip `cat $HOSTCONFIGDIR/ssh_host_rsa_key.pub`" >> $LOOPDIR/root/.ssh/known_hosts
     echo "`cat $HOSTCONFIGDIR/ssh_host_rsa_key.pub` root@$host" >> $LOOPDIR/root/.ssh/authorized_keys
 done
diff --git a/testing/scripts/load-testconfig b/testing/scripts/load-testconfig
index 89da17e72..9c0477e54 100755
--- a/testing/scripts/load-testconfig
+++ b/testing/scripts/load-testconfig
@@ -14,7 +14,7 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 #
-# RCSID $Id: load-testconfig,v 1.2 2004/12/13 21:02:42 as Exp $
+# RCSID $Id: load-testconfig,v 1.3 2006/10/19 21:38:45 as Exp $
 
 DIR=`dirname $0`
 
@@ -46,7 +46,7 @@ if [ -d $TESTSDIR/$testname/hosts ]
 then
     for host in `ls $TESTSDIR/$testname/hosts`
     do
-	eval HOSTLOGIN="root@`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+	eval HOSTLOGIN="root@`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $1 }' | awk '{ print $1 }'`"
 	scp -rp $TESTSDIR/$testname/hosts/$host/etc $HOSTLOGIN:/ > /dev/null 2>&1
     done
 fi
@@ -58,7 +58,7 @@ fi
 
 for host in $IPSECHOSTS
 do
-    eval HOSTLOGIN="root@`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+    eval HOSTLOGIN="root@`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $1 }' | awk '{ print $1 }'`"
     ssh $HOSTLOGIN 'rm -f /var/log/auth.log; \
 		    kill -SIGHUP `cat /var/run/syslogd.pid`' > /dev/null 2>&1
 done
diff --git a/testing/scripts/restore-defaults b/testing/scripts/restore-defaults
index 129e46f56..03f723e82 100755
--- a/testing/scripts/restore-defaults
+++ b/testing/scripts/restore-defaults
@@ -14,7 +14,7 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 #
-# RCSID $Id: restore-defaults,v 1.2 2004/12/20 07:56:33 as Exp $
+# RCSID $Id: restore-defaults,v 1.3 2006/10/19 21:40:27 as Exp $
 
 DIR=`dirname $0`
 
@@ -47,7 +47,7 @@ if [ -d $TESTSDIR/${testname}/hosts ]
 then
     for host in `ls $TESTSDIR/${testname}/hosts`
     do
-	eval HOSTLOGIN="root@`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+	eval HOSTLOGIN="root@`echo $HOSTNAMEIPV4 | sed -n -e "s/^.*${host},//gp" | awk -F, '{ print $1 }' | awk '{ print $1 }'`"
 	scp -rp $HOSTCONFIGDIR/${host}/etc $HOSTLOGIN:/ > /dev/null 2>&1
     done
 fi
diff --git a/testing/testing.conf b/testing/testing.conf
index 4f323d354..6a2db67fd 100755
--- a/testing/testing.conf
+++ b/testing/testing.conf
@@ -14,34 +14,34 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 #
-# RCSID $Id: testing.conf,v 1.56 2006/08/03 10:20:54 as Exp $
+# RCSID $Id: testing.conf,v 1.57 2006/10/19 21:38:44 as Exp $
 
 # Root directory of testing
 UMLTESTDIR=~/strongswan-testing
 
 # Bzipped kernel sources
 # (file extension .tar.bz2 required)
-KERNEL=$UMLTESTDIR/linux-2.6.17.7.tar.bz2
+KERNEL=$UMLTESTDIR/linux-2.6.18.1.tar.bz2
 
 # Extract kernel version
 KERNELVERSION=`basename $KERNEL .tar.bz2 | sed -e 's/linux-//'`
 
 # Kernel configuration file
-KERNELCONFIG=$UMLTESTDIR/.config-2.6.17
+KERNELCONFIG=$UMLTESTDIR/.config-2.6.18
 
 # Bzipped uml patch for kernel
 # (not needed anymore for 2.6.9 kernel or higher)
-UMLPATCH=
+UMLPATCH=$UMLTESTDIR/uml_jmpbuf-2.6.18.patch.bz2
 
 # Bzipped source of strongSwan
-STRONGSWAN=$UMLTESTDIR/strongswan-2.7.3.tar.bz2
+STRONGSWAN=$UMLTESTDIR/strongswan-2.8.0.tar.bz2
 
 # strongSwan compile options (use "yes" or "no")
 USE_LIBCURL="yes"
 USE_LDAP="yes"
 
 # Gentoo linux root filesystem
-ROOTFS=$UMLTESTDIR/gentoo-fs-20060330.tar.bz2
+ROOTFS=$UMLTESTDIR/gentoo-fs-20061006.tar.bz2
 
 # Size of the finished root filesystem in MB
 ROOTFSSIZE=544
@@ -98,20 +98,30 @@ SELECTEDTESTSONLY="no"
 SELECTEDTESTS="net2net-cert"
 
 ##############################################################
-# hostname and according IP(s)
-# You may change the IPs but keep them in the same net,
+# hostname and corresponding IPv4 and IPv6 addresses
+# You may change the IPs but keep them in the same subnet,
 # this means retain the netmasks!
 # Also don't use IPs ending with 254, they are reserved!
 #
-HOSTNAMEIPS="\
-alice:10.1.0.10 \
-venus:10.1.0.20 \
-moon:192.168.0.1:10.1.0.1 \
-carol:192.168.0.100:10.3.0.1 \
-winnetou:192.168.0.150 \
-dave:192.168.0.200:10.3.0.2 \
-sun:192.168.0.2:10.2.0.1 \
-bob:10.2.0.10"
+HOSTNAMEIPV4="\
+alice,10.1.0.10 \
+venus,10.1.0.20 \
+moon,192.168.0.1,10.1.0.1 \
+carol,192.168.0.100,10.3.0.1 \
+winnetou,192.168.0.150 \
+dave,192.168.0.200,10.3.0.2 \
+sun,192.168.0.2,10.2.0.1 \
+bob,10.2.0.10"
+
+HOSTNAMEIPV6="\
+alice,fec1::10 \
+venus,fec1::20 \
+moon,fec0::1,fec1::1 \
+carol,fec0::10,fec3::1 \
+winnetou,fec0::15 \
+dave,fec0::20,fec3::2 \
+sun,fec0::2,fec2::1 \
+bob,fec2::10"
 
 ##############################################################
 # VPN gateways / clients
@@ -138,17 +148,13 @@ IFCONFIG_2="10.2.0.254 netmask 255.255.0.0"
 ##############################################################
 # Network interfaces of the UML instances
 #
-SWITCH_alice="eth0=daemon,,unix,/tmp/umlswitch1"
-SWITCH_venus="eth0=daemon,,unix,/tmp/umlswitch1"
-SWITCH_moon="eth0=daemon,,unix,/tmp/umlswitch0 \
-             eth1=daemon,,unix,/tmp/umlswitch1"
-SWITCH_carol="eth0=daemon,,unix,/tmp/umlswitch0"
-SWITCH_winnetou="eth0=daemon,,unix,/tmp/umlswitch0"
-SWITCH_dave="eth0=daemon,,unix,/tmp/umlswitch0"
-SWITCH_sun="eth0=daemon,,unix,/tmp/umlswitch0 \
-            eth1=daemon,,unix,/tmp/umlswitch2"
-SWITCH_bob="eth0=daemon,,unix,/tmp/umlswitch2"
-
-
-
-
+SWITCH_alice="eth0=daemon,fe:fd:0a:01:00:0a,unix,/tmp/umlswitch1"
+SWITCH_venus="eth0=daemon,fe:fd:0a:01:00:14,unix,/tmp/umlswitch1"
+SWITCH_moon="eth0=daemon,fe:fd:c0:a8:00:01,unix,/tmp/umlswitch0 \
+             eth1=daemon,fe:fd:0a:01:00:01,unix,/tmp/umlswitch1"
+SWITCH_carol="eth0=daemon,fe:fd:c0:a8:00:64,unix,/tmp/umlswitch0"
+SWITCH_winnetou="eth0=daemon,fe:fd:c0:a8:00:96,unix,/tmp/umlswitch0"
+SWITCH_dave="eth0=daemon,fe:fd:c0:a8:00:c8,unix,/tmp/umlswitch0"
+SWITCH_sun="eth0=daemon,fe:fd:c0:a8:00:02,unix,/tmp/umlswitch0 \
+            eth1=daemon,fe:fd:0a:02:00:01,unix,/tmp/umlswitch2"
+SWITCH_bob="eth0=daemon,fe:fd:0a:02:00:0a,unix,/tmp/umlswitch2"
diff --git a/testing/tests/crl-ldap/pretest.dat b/testing/tests/crl-ldap/pretest.dat
index 64fae2a16..0097e78f4 100644
--- a/testing/tests/crl-ldap/pretest.dat
+++ b/testing/tests/crl-ldap/pretest.dat
@@ -5,3 +5,4 @@ moon::ipsec start
 carol::ipsec start
 carol::sleep 2
 carol::ipsec up home
+carol::sleep 2
diff --git a/testing/tests/dpd-clear/evaltest.dat b/testing/tests/dpd-clear/evaltest.dat
index 98d5b146b..da3567d3e 100644
--- a/testing/tests/dpd-clear/evaltest.dat
+++ b/testing/tests/dpd-clear/evaltest.dat
@@ -1,5 +1,6 @@
 carol::ipsec status::STATE_MAIN_I4 (ISAKMP SA established)::YES
 carol::iptables -A INPUT -i eth0 -s PH_IP_MOON -j DROP::no output expected::NO
+moon::ipsec statusall::DPD active::YES
 moon::sleep 50::no output expected::NO
 moon::cat /var/log/auth.log::inserting event EVENT_DPD::YES
 moon::cat /var/log/auth.log::DPD: No response from peer - declaring peer dead::YES
diff --git a/testing/tests/mode-config-push/description.txt b/testing/tests/mode-config-push/description.txt
new file mode 100644
index 000000000..387c3b409
--- /dev/null
+++ b/testing/tests/mode-config-push/description.txt
@@ -0,0 +1,10 @@
+The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each to gateway <b>moon</b>.
+Both <b>carol</b> and <b>dave</b> request a <b>virtual IP</b> via the IKE Mode Config protocol
+by using the <b>leftsourceip=%modeconfig</b> parameter. By setting the option <b>modeconfig=push</b>
+on both the roadwarriors and the gateway, the Mode Config server <b>moon</b> will actively push
+the configuration down to <b>carol</b> and <b>dave</b>.
+<p>
+<b>leftfirewall=yes</b> automatically inserts iptables-based firewall rules that let pass the
+tunneled traffic. In order to test the tunnels, <b>carol</b> and <b>dave</b> then ping the client
+<b>alice</b> behind the gateway <b>moon</b>. The source IP addresses of the two pings will
+be the virtual IPs <b>carol1</b> and <b>dave1</b>, respectively.
diff --git a/testing/tests/mode-config-push/evaltest.dat b/testing/tests/mode-config-push/evaltest.dat
new file mode 100644
index 000000000..7de32d681
--- /dev/null
+++ b/testing/tests/mode-config-push/evaltest.dat
@@ -0,0 +1,16 @@
+carol::cat /var/log/auth.log::setting virtual IP source address to 10.3.0.1::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+dave::cat /var/log/auth.log::setting virtual IP source address to 10.3.0.2::YES
+dave::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+dave::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::ipsec status::rw-carol.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec status::rw-dave.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
+moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: ICMP echo request::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: ICMP echo reply::YES
+alice::tcpdump::IP dave1.strongswan.org > alice.strongswan.org: ICMP echo request::YES
+alice::tcpdump::IP alice.strongswan.org > dave1.strongswan.org: ICMP echo reply::YES
diff --git a/testing/tests/mode-config-push/hosts/carol/etc/ipsec.conf b/testing/tests/mode-config-push/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..d66c4d329
--- /dev/null
+++ b/testing/tests/mode-config-push/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,31 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version	2.0	# conforms to second version of ipsec.conf specification
+
+config setup
+	plutodebug=control
+	crlcheckinterval=180
+	strictcrlpolicy=no
+
+conn %default
+	ikelifetime=60m
+	keylife=20m
+	rekeymargin=3m
+	keyingtries=1
+	modeconfig=push
+
+conn home
+	left=PH_IP_CAROL
+	leftsourceip=%modeconfig
+	leftnexthop=%direct
+	leftcert=carolCert.pem
+	leftid=carol@strongswan.org
+	leftfirewall=yes
+	right=PH_IP_MOON
+	rightsubnet=10.1.0.0/16
+	rightid=@moon.strongswan.org
+	auto=add
+
+
+
+
diff --git a/testing/tests/mode-config-push/hosts/dave/etc/ipsec.conf b/testing/tests/mode-config-push/hosts/dave/etc/ipsec.conf
new file mode 100755
index 000000000..bf2625148
--- /dev/null
+++ b/testing/tests/mode-config-push/hosts/dave/etc/ipsec.conf
@@ -0,0 +1,31 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version	2.0	# conforms to second version of ipsec.conf specification
+
+config setup
+	plutodebug=control
+	crlcheckinterval=180
+	strictcrlpolicy=no
+
+conn %default
+	ikelifetime=60m
+	keylife=20m
+	rekeymargin=3m
+	keyingtries=1
+	modeconfig=push
+
+conn home
+	left=PH_IP_DAVE
+	leftsourceip=%modeconfig
+	leftnexthop=%direct
+	leftcert=daveCert.pem
+	leftid=dave@strongswan.org
+	leftfirewall=yes
+	right=PH_IP_MOON
+	rightsubnet=10.1.0.0/16
+	rightid=@moon.strongswan.org
+	auto=add
+
+
+
+
diff --git a/testing/tests/mode-config-push/hosts/moon/etc/ipsec.conf b/testing/tests/mode-config-push/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..3416c5d68
--- /dev/null
+++ b/testing/tests/mode-config-push/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,34 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version	2.0	# conforms to second version of ipsec.conf specification
+
+config setup
+	plutodebug=control
+	crlcheckinterval=180
+	strictcrlpolicy=no
+
+conn %default
+	ikelifetime=60m
+	keylife=20m
+	rekeymargin=3m
+	keyingtries=1
+	modeconfig=push
+	left=PH_IP_MOON
+	leftsubnet=10.1.0.0/16
+	leftsourceip=PH_IP1_MOON
+	leftnexthop=%direct
+	leftcert=moonCert.pem
+	leftid=@moon.strongswan.org
+	leftfirewall=yes
+
+conn rw-carol
+	right=%any
+	rightid=carol@strongswan.org
+	rightsourceip=PH_IP1_CAROL
+	auto=add
+
+conn rw-dave
+	right=%any
+	rightid=dave@strongswan.org
+	rightsourceip=PH_IP1_DAVE
+	auto=add
diff --git a/testing/tests/mode-config-push/posttest.dat b/testing/tests/mode-config-push/posttest.dat
new file mode 100644
index 000000000..932b319a7
--- /dev/null
+++ b/testing/tests/mode-config-push/posttest.dat
@@ -0,0 +1,11 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+dave::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+dave::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
+dave::/etc/init.d/iptables stop 2> /dev/null
+carol::ip addr del PH_IP1_CAROL/32 dev eth0
+dave::ip addr del PH_IP1_DAVE/32 dev eth0
diff --git a/testing/tests/mode-config-push/pretest.dat b/testing/tests/mode-config-push/pretest.dat
new file mode 100644
index 000000000..1e45f00fd
--- /dev/null
+++ b/testing/tests/mode-config-push/pretest.dat
@@ -0,0 +1,9 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+dave::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+dave::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
+dave::ipsec up home
diff --git a/testing/tests/mode-config-push/test.conf b/testing/tests/mode-config-push/test.conf
new file mode 100644
index 000000000..1a8f2a4e0
--- /dev/null
+++ b/testing/tests/mode-config-push/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou dave"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w-d.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon alice"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol dave"
diff --git a/testing/tests/mode-config-swapped/evaltest.dat b/testing/tests/mode-config-swapped/evaltest.dat
index be8ca6ef5..7de32d681 100644
--- a/testing/tests/mode-config-swapped/evaltest.dat
+++ b/testing/tests/mode-config-swapped/evaltest.dat
@@ -10,7 +10,7 @@ moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
 moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
 moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES
 moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES
-alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: icmp::YES
-alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: icmp::YES
-alice::tcpdump::IP dave1.strongswan.org > alice.strongswan.org: icmp::YES
-alice::tcpdump::IP alice.strongswan.org > dave1.strongswan.org: icmp::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: ICMP echo request::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: ICMP echo reply::YES
+alice::tcpdump::IP dave1.strongswan.org > alice.strongswan.org: ICMP echo request::YES
+alice::tcpdump::IP alice.strongswan.org > dave1.strongswan.org: ICMP echo reply::YES
diff --git a/testing/tests/mode-config/evaltest.dat b/testing/tests/mode-config/evaltest.dat
index be8ca6ef5..7de32d681 100644
--- a/testing/tests/mode-config/evaltest.dat
+++ b/testing/tests/mode-config/evaltest.dat
@@ -10,7 +10,7 @@ moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
 moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
 moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES
 moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES
-alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: icmp::YES
-alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: icmp::YES
-alice::tcpdump::IP dave1.strongswan.org > alice.strongswan.org: icmp::YES
-alice::tcpdump::IP alice.strongswan.org > dave1.strongswan.org: icmp::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: ICMP echo request::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: ICMP echo reply::YES
+alice::tcpdump::IP dave1.strongswan.org > alice.strongswan.org: ICMP echo request::YES
+alice::tcpdump::IP alice.strongswan.org > dave1.strongswan.org: ICMP echo reply::YES
diff --git a/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.secrets b/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..fac55d63b
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA carolKey.pem
diff --git a/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.secrets b/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..fac55d63b
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA carolKey.pem
diff --git a/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.secrets b/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..fac55d63b
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA carolKey.pem
diff --git a/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.secrets b/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..fac55d63b
--- /dev/null
+++ b/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA carolKey.pem
diff --git a/testing/tests/starter-also-loop/pretest.dat b/testing/tests/starter-also-loop/pretest.dat
index aa46124dc..b135b12c3 100644
--- a/testing/tests/starter-also-loop/pretest.dat
+++ b/testing/tests/starter-also-loop/pretest.dat
@@ -1 +1,2 @@
 moon::ipsec start --debug-all
+moon::sleep 1
diff --git a/testing/tests/starter-includes/evaltest.dat b/testing/tests/starter-includes/evaltest.dat
index be8ca6ef5..7de32d681 100644
--- a/testing/tests/starter-includes/evaltest.dat
+++ b/testing/tests/starter-includes/evaltest.dat
@@ -10,7 +10,7 @@ moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
 moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
 moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES
 moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES
-alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: icmp::YES
-alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: icmp::YES
-alice::tcpdump::IP dave1.strongswan.org > alice.strongswan.org: icmp::YES
-alice::tcpdump::IP alice.strongswan.org > dave1.strongswan.org: icmp::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: ICMP echo request::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: ICMP echo reply::YES
+alice::tcpdump::IP dave1.strongswan.org > alice.strongswan.org: ICMP echo request::YES
+alice::tcpdump::IP alice.strongswan.org > dave1.strongswan.org: ICMP echo reply::YES
diff --git a/testing/tests/virtual-ip-swapped/evaltest.dat b/testing/tests/virtual-ip-swapped/evaltest.dat
index 5160a340f..bf3965727 100644
--- a/testing/tests/virtual-ip-swapped/evaltest.dat
+++ b/testing/tests/virtual-ip-swapped/evaltest.dat
@@ -5,5 +5,5 @@ carol::ping -c 1 PH_IP1_MOON::64 bytes from PH_IP1_MOON: icmp_seq=1::YES
 moon::ping -c 1 PH_IP1_CAROL::64 bytes from PH_IP1_CAROL: icmp_seq=1::YES
 moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
 moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
-alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: icmp::YES
-alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: icmp::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: ICMP echo request::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: ICMP echo reply::YES
diff --git a/testing/tests/virtual-ip/evaltest.dat b/testing/tests/virtual-ip/evaltest.dat
index 5160a340f..bf3965727 100644
--- a/testing/tests/virtual-ip/evaltest.dat
+++ b/testing/tests/virtual-ip/evaltest.dat
@@ -5,5 +5,5 @@ carol::ping -c 1 PH_IP1_MOON::64 bytes from PH_IP1_MOON: icmp_seq=1::YES
 moon::ping -c 1 PH_IP1_CAROL::64 bytes from PH_IP1_CAROL: icmp_seq=1::YES
 moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
 moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
-alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: icmp::YES
-alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: icmp::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: ICMP echo request::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: ICMP echo reply::YES
diff --git a/testing/tests/wlan/evaltest.dat b/testing/tests/wlan/evaltest.dat
index ccf5d0c8a..1936c93a3 100644
--- a/testing/tests/wlan/evaltest.dat
+++ b/testing/tests/wlan/evaltest.dat
@@ -8,4 +8,4 @@ alice::ping -c 1 PH_IP_MOON::64 bytes from PH_IP_MOON: icmp_seq=1::YES
 alice::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_seq=1::YES
 venus::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_seq=1::YES
 moon::tcpdump::ESP::YES
-sun::tcpdump::icmp::YES
+sun::tcpdump::ICMP::YES
-- 
cgit v1.2.3