]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/ipv6cp.c
pppd: Fix SIGSEGV in EAP-TLS code when TLS verify method is not specified
[ppp.git] / pppd / ipv6cp.c
index 2d062c52b34b2c18ad6ba11755f8f4804cf323e7..d80ae216814e9017e65e629aaf15d038d61e4c39 100644 (file)
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * $Id: ipv6cp.c,v 1.17 2002/12/04 23:03:32 paulus Exp $ 
  */
 
-#define RCSID  "$Id: ipv6cp.c,v 1.17 2002/12/04 23:03:32 paulus Exp $"
-
 /*
  * TODO: 
  *
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <netdb.h>
 #include "magic.h"
 #include "pathnames.h"
 
-static const char rcsid[] = RCSID;
 
 /* global vars */
 ipv6cp_options ipv6cp_wantoptions[NUM_PPP];     /* Options that we want to request */
@@ -177,21 +173,32 @@ ipv6cp_options ipv6cp_hisoptions[NUM_PPP];        /* Options that we ack'd */
 int no_ifaceid_neg = 0;
 
 /* local vars */
+static int default_route_set[NUM_PPP];         /* Have set up a default route */
 static int ipv6cp_is_up;
 
+/* Hook for a plugin to know when IPv6 protocol has come up */
+void (*ipv6_up_hook)(void) = NULL;
+
+/* Hook for a plugin to know when IPv6 protocol has come down */
+void (*ipv6_down_hook)(void) = NULL;
+
+/* Notifiers for when IPCPv6 goes up and down */
+struct notifier *ipv6_up_notifier = NULL;
+struct notifier *ipv6_down_notifier = NULL;
+
 /*
  * Callbacks for fsm code.  (CI = Configuration Information)
  */
-static void ipv6cp_resetci __P((fsm *));       /* Reset our CI */
-static int  ipv6cp_cilen __P((fsm *));         /* Return length of our CI */
-static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
-static int  ipv6cp_ackci __P((fsm *, u_char *, int));  /* Peer ack'd our CI */
-static int  ipv6cp_nakci __P((fsm *, u_char *, int));  /* Peer nak'd our CI */
-static int  ipv6cp_rejci __P((fsm *, u_char *, int));  /* Peer rej'd our CI */
-static int  ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
-static void ipv6cp_up __P((fsm *));            /* We're UP */
-static void ipv6cp_down __P((fsm *));          /* We're DOWN */
-static void ipv6cp_finished __P((fsm *));      /* Don't need lower layer */
+static void ipv6cp_resetci (fsm *);    /* Reset our CI */
+static int  ipv6cp_cilen (fsm *);              /* Return length of our CI */
+static void ipv6cp_addci (fsm *, u_char *, int *); /* Add our CI */
+static int  ipv6cp_ackci (fsm *, u_char *, int);       /* Peer ack'd our CI */
+static int  ipv6cp_nakci (fsm *, u_char *, int, int);/* Peer nak'd our CI */
+static int  ipv6cp_rejci (fsm *, u_char *, int);       /* Peer rej'd our CI */
+static int  ipv6cp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */
+static void ipv6cp_up (fsm *);         /* We're UP */
+static void ipv6cp_down (fsm *);               /* We're DOWN */
+static void ipv6cp_finished (fsm *);   /* Don't need lower layer */
 
 fsm ipv6cp_fsm[NUM_PPP];               /* IPV6CP fsm structure */
 
@@ -216,9 +223,9 @@ static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
 /*
  * Command-line options.
  */
-static int setifaceid __P((char **arg));
-static void printifaceid __P((option_t *,
-                             void (*)(void *, char *, ...), void *));
+static int setifaceid (char **arg);
+static void printifaceid (option_t *,
+                         void (*)(void *, char *, ...), void *);
 
 static option_t ipv6cp_option_list[] = {
     { "ipv6", o_special, (void *)setifaceid,
@@ -234,14 +241,23 @@ static option_t ipv6cp_option_list[] = {
 
     { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
       "Accept peer's interface identifier for us", 1 },
+    { "ipv6cp-accept-remote", o_bool, &ipv6cp_allowoptions[0].accept_remote,
+      "Accept peer's interface identifier for itself", 1 },
+
+    { "defaultroute6", o_bool, &ipv6cp_wantoptions[0].default_route,
+      "Add default IPv6 route", OPT_ENABLE|1, &ipv6cp_allowoptions[0].default_route },
+    { "nodefaultroute6", o_bool, &ipv6cp_allowoptions[0].default_route,
+      "disable defaultroute6 option", OPT_A2CLR,
+      &ipv6cp_wantoptions[0].default_route },
+    { "-defaultroute6", o_bool, &ipv6cp_allowoptions[0].default_route,
+      "disable defaultroute6 option", OPT_ALIAS | OPT_A2CLR,
+      &ipv6cp_wantoptions[0].default_route },
 
     { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
       "Use (default) IPv4 address as interface identifier", 1 },
 
-#if defined(SOL2) || defined(__linux__)
     { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
       "Use uniquely-available persistent value for link local address", 1 },
-#endif /* defined(SOL2) */
 
     { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
       "Set timeout for IPv6CP", OPT_PRIO },
@@ -259,18 +275,18 @@ static option_t ipv6cp_option_list[] = {
 /*
  * Protocol entry points from main code.
  */
-static void ipv6cp_init __P((int));
-static void ipv6cp_open __P((int));
-static void ipv6cp_close __P((int, char *));
-static void ipv6cp_lowerup __P((int));
-static void ipv6cp_lowerdown __P((int));
-static void ipv6cp_input __P((int, u_char *, int));
-static void ipv6cp_protrej __P((int));
-static int  ipv6cp_printpkt __P((u_char *, int,
-                              void (*) __P((void *, char *, ...)), void *));
-static void ipv6_check_options __P((void));
-static int  ipv6_demand_conf __P((int));
-static int  ipv6_active_pkt __P((u_char *, int));
+static void ipv6cp_init (int);
+static void ipv6cp_open (int);
+static void ipv6cp_close (int, char *);
+static void ipv6cp_lowerup (int);
+static void ipv6cp_lowerdown (int);
+static void ipv6cp_input (int, u_char *, int);
+static void ipv6cp_protrej (int);
+static int  ipv6cp_printpkt (u_char *, int,
+                            void (*) (void *, char *, ...), void *);
+static void ipv6_check_options (void);
+static int  ipv6_demand_conf (int);
+static int  ipv6_active_pkt (u_char *, int);
 
 struct protent ipv6cp_protent = {
     PPP_IPV6CP,
@@ -283,7 +299,7 @@ struct protent ipv6cp_protent = {
     ipv6cp_close,
     ipv6cp_printpkt,
     NULL,
-    0,
+    1,
     "IPV6CP",
     "IPV6",
     ipv6cp_option_list,
@@ -292,9 +308,9 @@ struct protent ipv6cp_protent = {
     ipv6_active_pkt
 };
 
-static void ipv6cp_clear_addrs __P((int, eui64_t, eui64_t));
-static void ipv6cp_script __P((char *));
-static void ipv6cp_script_done __P((void *));
+static void ipv6cp_clear_addrs (int, eui64_t, eui64_t);
+static void ipv6cp_script (char *);
+static void ipv6cp_script_done (void *);
 
 /*
  * Lengths of configuration options.
@@ -320,8 +336,7 @@ static pid_t ipv6cp_script_pid;
  * setifaceid - set the interface identifiers manually
  */
 static int
-setifaceid(argv)
-    char **argv;
+setifaceid(char **argv)
 {
     char *comma, *arg, c;
     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
@@ -378,10 +393,7 @@ setifaceid(argv)
 char *llv6_ntoa(eui64_t ifaceid);
 
 static void
-printifaceid(opt, printer, arg)
-    option_t *opt;
-    void (*printer) __P((void *, char *, ...));
-    void *arg;
+printifaceid(option_t *opt, void (*printer) (void *, char *, ...), void *arg)
 {
        ipv6cp_options *wo = &ipv6cp_wantoptions[0];
 
@@ -396,8 +408,7 @@ printifaceid(opt, printer, arg)
  * Make a string representation of a network address.
  */
 char *
-llv6_ntoa(ifaceid)
-    eui64_t ifaceid;
+llv6_ntoa(eui64_t ifaceid)
 {
     static char b[64];
 
@@ -410,8 +421,7 @@ llv6_ntoa(ifaceid)
  * ipv6cp_init - Initialize IPV6CP.
  */
 static void
-ipv6cp_init(unit)
-    int unit;
+ipv6cp_init(int unit)
 {
     fsm *f = &ipv6cp_fsm[unit];
     ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
@@ -425,7 +435,8 @@ ipv6cp_init(unit)
     memset(wo, 0, sizeof(*wo));
     memset(ao, 0, sizeof(*ao));
 
-    wo->accept_local = 1;
+    wo->accept_local = 0;
+    wo->accept_remote = 0;
     wo->neg_ifaceid = 1;
     ao->neg_ifaceid = 1;
 
@@ -435,6 +446,10 @@ ipv6cp_init(unit)
     wo->vj_protocol = IPV6CP_COMP;
 #endif
 
+    /*
+     * XXX This controls whether the user may use the defaultroute option.
+     */
+    ao->default_route = 1;
 }
 
 
@@ -442,8 +457,7 @@ ipv6cp_init(unit)
  * ipv6cp_open - IPV6CP is allowed to come up.
  */
 static void
-ipv6cp_open(unit)
-    int unit;
+ipv6cp_open(int unit)
 {
     fsm_open(&ipv6cp_fsm[unit]);
 }
@@ -453,9 +467,7 @@ ipv6cp_open(unit)
  * ipv6cp_close - Take IPV6CP down.
  */
 static void
-ipv6cp_close(unit, reason)
-    int unit;
-    char *reason;
+ipv6cp_close(int unit, char *reason)
 {
     fsm_close(&ipv6cp_fsm[unit], reason);
 }
@@ -465,8 +477,7 @@ ipv6cp_close(unit, reason)
  * ipv6cp_lowerup - The lower layer is up.
  */
 static void
-ipv6cp_lowerup(unit)
-    int unit;
+ipv6cp_lowerup(int unit)
 {
     fsm_lowerup(&ipv6cp_fsm[unit]);
 }
@@ -476,8 +487,7 @@ ipv6cp_lowerup(unit)
  * ipv6cp_lowerdown - The lower layer is down.
  */
 static void
-ipv6cp_lowerdown(unit)
-    int unit;
+ipv6cp_lowerdown(int unit)
 {
     fsm_lowerdown(&ipv6cp_fsm[unit]);
 }
@@ -487,10 +497,7 @@ ipv6cp_lowerdown(unit)
  * ipv6cp_input - Input IPV6CP packet.
  */
 static void
-ipv6cp_input(unit, p, len)
-    int unit;
-    u_char *p;
-    int len;
+ipv6cp_input(int unit, u_char *p, int len)
 {
     fsm_input(&ipv6cp_fsm[unit], p, len);
 }
@@ -502,8 +509,7 @@ ipv6cp_input(unit, p, len)
  * Pretend the lower layer went down, so we shut up.
  */
 static void
-ipv6cp_protrej(unit)
-    int unit;
+ipv6cp_protrej(int unit)
 {
     fsm_lowerdown(&ipv6cp_fsm[unit]);
 }
@@ -513,8 +519,7 @@ ipv6cp_protrej(unit)
  * ipv6cp_resetci - Reset our CI.
  */
 static void
-ipv6cp_resetci(f)
-    fsm *f;
+ipv6cp_resetci(fsm *f)
 {
     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
@@ -522,8 +527,12 @@ ipv6cp_resetci(f)
     wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
     
     if (!wo->opt_local) {
-       eui64_magic_nz(wo->ourid);
+       wo->accept_local = 1;
+       if (!demand)
+           eui64_magic_nz(wo->ourid);
     }
+    if (!wo->opt_remote)
+       wo->accept_remote = 1;
     
     *go = *wo;
     eui64_zero(go->hisid);     /* last proposed interface identifier */
@@ -534,8 +543,7 @@ ipv6cp_resetci(f)
  * ipv6cp_cilen - Return length of our CI.
  */
 static int
-ipv6cp_cilen(f)
-    fsm *f;
+ipv6cp_cilen(fsm *f)
 {
     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
 
@@ -551,10 +559,7 @@ ipv6cp_cilen(f)
  * ipv6cp_addci - Add our desired CIs to a packet.
  */
 static void
-ipv6cp_addci(f, ucp, lenp)
-    fsm *f;
-    u_char *ucp;
-    int *lenp;
+ipv6cp_addci(fsm *f, u_char *ucp, int *lenp)
 {
     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
     int len = *lenp;
@@ -599,10 +604,7 @@ ipv6cp_addci(f, ucp, lenp)
  *     1 - Ack was good.
  */
 static int
-ipv6cp_ackci(f, p, len)
-    fsm *f;
-    u_char *p;
-    int len;
+ipv6cp_ackci(fsm *f, u_char *p, int len)
 {
     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
     u_short cilen, citype, cishort;
@@ -670,10 +672,7 @@ bad:
  *     1 - Nak was good.
  */
 static int
-ipv6cp_nakci(f, p, len)
-    fsm *f;
-    u_char *p;
-    int len;
+ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject)
 {
     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
     u_char citype, cilen, *next;
@@ -719,19 +718,21 @@ ipv6cp_nakci(f, p, len)
      * from our idea, only if the accept_{local,remote} flag is set.
      */
     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
-             if (go->accept_local) {
-                 while (eui64_iszero(ifaceid) || 
-                        eui64_equals(ifaceid, go->hisid)) /* bad luck */
-                     eui64_magic(ifaceid);
-                 try.ourid = ifaceid;
-                 IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
-             }
-             );
+                if (treat_as_reject) {
+                    try.neg_ifaceid = 0;
+                } else if (go->accept_local) {
+                    while (eui64_iszero(ifaceid) || 
+                           eui64_equals(ifaceid, go->hisid)) /* bad luck */
+                        eui64_magic(ifaceid);
+                    try.ourid = ifaceid;
+                    IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
+                }
+                );
 
 #ifdef IPV6CP_COMP
     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
            {
-               if (cishort == IPV6CP_COMP) {
+               if (cishort == IPV6CP_COMP && !treat_as_reject) {
                    try.vj_protocol = cishort;
                } else {
                    try.neg_vj = 0;
@@ -752,10 +753,10 @@ ipv6cp_nakci(f, p, len)
      * If they want to negotiate about interface identifier, we comply.
      * If they want us to ask for compression, we refuse.
      */
-    while (len > CILEN_VOID) {
+    while (len >= CILEN_VOID) {
        GETCHAR(citype, p);
        GETCHAR(cilen, p);
-       if( (len -= cilen) < 0 )
+       if ( cilen < CILEN_VOID || (len -= cilen) < 0 )
            goto bad;
        next = p + cilen - 2;
 
@@ -805,10 +806,7 @@ bad:
  * ipv6cp_rejci - Reject some of our CIs.
  */
 static int
-ipv6cp_rejci(f, p, len)
-    fsm *f;
-    u_char *p;
-    int len;
+ipv6cp_rejci(fsm *f, u_char *p, int len)
 {
     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
     u_char cilen;
@@ -880,11 +878,7 @@ bad:
  * CONFNAK; returns CONFREJ if it can't return CONFACK.
  */
 static int
-ipv6cp_reqci(f, inp, len, reject_if_disagree)
-    fsm *f;
-    u_char *inp;               /* Requested CIs */
-    int *len;                  /* Length of requested CIs */
-    int reject_if_disagree;
+ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree)
 {
     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
@@ -948,7 +942,7 @@ ipv6cp_reqci(f, inp, len, reject_if_disagree)
                orc = CONFREJ;          /* Reject CI */
                break;
            }
-           if (!eui64_iszero(wo->hisid) && 
+           if (!eui64_iszero(wo->hisid) && !wo->accept_remote &&
                !eui64_equals(ifaceid, wo->hisid) && 
                eui64_iszero(go->hisid)) {
                    
@@ -1062,24 +1056,58 @@ endswitch:
 }
 
 
+/*
+ * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI
+ *
+ * walks the list of valid ethernet interfaces, starting with devnam
+ * (for PPPoE it is ethernet interface), and convert the first
+ * found 48-bit MAC address into EUI 64. caller also assumes that
+ * the system has a properly configured Ethernet interface for this
+ * function to return non-zero.
+ */
+static int
+ether_to_eui64(eui64_t *p_eui64)
+{
+    u_char addr[6];
+
+    if (get_if_hwaddr(addr, devnam) < 0 && get_first_ether_hwaddr(addr) < 0) {
+        error("ipv6cp: no persistent id can be found");
+        return 0;
+    }
+
+    /*
+     * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
+     */
+    p_eui64->e8[0] = addr[0] | 0x02;
+    p_eui64->e8[1] = addr[1];
+    p_eui64->e8[2] = addr[2];
+    p_eui64->e8[3] = 0xFF;
+    p_eui64->e8[4] = 0xFE;
+    p_eui64->e8[5] = addr[3];
+    p_eui64->e8[6] = addr[4];
+    p_eui64->e8[7] = addr[5];
+
+    return 1;
+}
+
+
 /*
  * ipv6_check_options - check that any IP-related options are OK,
  * and assign appropriate defaults.
  */
 static void
-ipv6_check_options()
+ipv6_check_options(void)
 {
     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
 
     if (!ipv6cp_protent.enabled_flag)
        return;
 
-#if defined(SOL2) || defined(__linux__)
     /*
      * Persistent link-local id is only used when user has not explicitly
      * configure/hard-code the id
      */
-    if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) {
+    if ((wo->use_persistent) && (!wo->opt_local)) {
 
        /* 
         * On systems where there are no Ethernet interfaces used, there
@@ -1094,7 +1122,6 @@ ipv6_check_options()
            wo->opt_local = 1;
        }
     }
-#endif
 
     if (!wo->opt_local) {      /* init interface identifier */
        if (wo->use_ip && eui64_iszero(wo->ourid)) {
@@ -1114,11 +1141,6 @@ ipv6_check_options()
                wo->opt_remote = 1;
        }
     }
-
-    if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
-       option_error("local/remote LL address required for demand-dialling\n");
-       exit(1);
-    }
 }
 
 
@@ -1127,20 +1149,21 @@ ipv6_check_options()
  * IPV6CP were up, for use with dial-on-demand.
  */
 static int
-ipv6_demand_conf(u)
-    int u;
+ipv6_demand_conf(int u)
 {
     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
 
-#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
-#if defined(SOL2)
+    if (eui64_iszero(wo->hisid)) {
+       /* make up an arbitrary identifier for the peer */
+       eui64_magic_nz(wo->hisid);
+    }
+    if (eui64_iszero(wo->ourid)) {
+       /* make up an arbitrary identifier for us */
+       eui64_magic_nz(wo->ourid);
+    }
+
     if (!sif6up(u))
        return 0;
-#else
-    if (!sifup(u))
-       return 0;
-#endif /* defined(SOL2) */
-#endif    
     if (!sif6addr(u, wo->ourid, wo->hisid))
        return 0;
 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
@@ -1149,8 +1172,10 @@ ipv6_demand_conf(u)
 #endif
     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
        return 0;
+    if (wo->default_route)
+       if (sif6defaultroute(u, wo->ourid, wo->hisid))
+           default_route_set[u] = 1;
 
-    notice("ipv6_demand_conf");
     notice("local  LL address %s", llv6_ntoa(wo->ourid));
     notice("remote LL address %s", llv6_ntoa(wo->hisid));
 
@@ -1164,8 +1189,7 @@ ipv6_demand_conf(u)
  * Configure the IPv6 network interface appropriately and bring it up.
  */
 static void
-ipv6cp_up(f)
-    fsm *f;
+ipv6cp_up(fsm *f)
 {
     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
@@ -1218,7 +1242,7 @@ ipv6cp_up(f)
            if (! eui64_equals(ho->hisid, wo->hisid))
                warn("Remote LL address changed to %s", 
                     llv6_ntoa(ho->hisid));
-           ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid);
+           ipv6cp_clear_addrs(f->unit, wo->ourid, wo->hisid);
 
            /* Set the interface to the new addresses */
            if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
@@ -1228,50 +1252,36 @@ ipv6cp_up(f)
                return;
            }
 
+           /* assign a default route through the interface if required */
+           if (ipv6cp_wantoptions[f->unit].default_route)
+               if (sif6defaultroute(f->unit, go->ourid, ho->hisid))
+                   default_route_set[f->unit] = 1;
        }
        demand_rexmit(PPP_IPV6);
        sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
 
     } else {
-       /*
-        * Set LL addresses
-        */
-#if !defined(__linux__) && !defined(SOL2) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
-       if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
-           if (debug)
-               warn("sif6addr failed");
-           ipv6cp_close(f->unit, "Interface configuration failed");
-           return;
-       }
-#endif
-
        /* bring the interface up for IPv6 */
-#if defined(SOL2)
        if (!sif6up(f->unit)) {
            if (debug)
-               warn("sifup failed (IPV6)");
-           ipv6cp_close(f->unit, "Interface configuration failed");
-           return;
-       }
-#else
-       if (!sifup(f->unit)) {
-           if (debug)
-               warn("sifup failed (IPV6)");
+               warn("sif6up failed (IPV6)");
            ipv6cp_close(f->unit, "Interface configuration failed");
            return;
        }
-#endif /* defined(SOL2) */
 
-#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
        if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
            if (debug)
                warn("sif6addr failed");
            ipv6cp_close(f->unit, "Interface configuration failed");
            return;
        }
-#endif
        sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
 
+       /* assign a default route through the interface if required */
+       if (ipv6cp_wantoptions[f->unit].default_route)
+           if (sif6defaultroute(f->unit, go->ourid, ho->hisid))
+               default_route_set[f->unit] = 1;
+
        notice("local  LL address %s", llv6_ntoa(go->ourid));
        notice("remote LL address %s", llv6_ntoa(ho->hisid));
     }
@@ -1279,6 +1289,10 @@ ipv6cp_up(f)
     np_up(f->unit, PPP_IPV6);
     ipv6cp_is_up = 1;
 
+    notify(ipv6_up_notifier, 0);
+    if (ipv6_up_hook)
+       ipv6_up_hook();
+
     /*
      * Execute the ipv6-up script, like this:
      * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
@@ -1297,11 +1311,13 @@ ipv6cp_up(f)
  * and delete routes through it.
  */
 static void
-ipv6cp_down(f)
-    fsm *f;
+ipv6cp_down(fsm *f)
 {
     IPV6CPDEBUG(("ipv6cp: down"));
     update_link_stats(f->unit);
+    notify(ipv6_down_notifier, 0);
+    if (ipv6_down_hook)
+       ipv6_down_hook();
     if (ipv6cp_is_up) {
        ipv6cp_is_up = 0;
        np_down(f->unit, PPP_IPV6);
@@ -1319,16 +1335,14 @@ ipv6cp_down(f)
     } else {
        sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
-#if defined(SOL2)
        sif6down(f->unit);
-#else
-       sifdown(f->unit);
-#endif /* defined(SOL2) */
 #endif
        ipv6cp_clear_addrs(f->unit, 
                           ipv6cp_gotoptions[f->unit].ourid,
                           ipv6cp_hisoptions[f->unit].hisid);
-#if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
+#if defined(__linux__)
+       sif6down(f->unit);
+#elif defined(SVR4) && (defined(SNI) || defined(__USLC))
        sifdown(f->unit);
 #endif
     }
@@ -1346,10 +1360,7 @@ ipv6cp_down(f)
  * proxy neighbour discovery entries, etc.
  */
 static void
-ipv6cp_clear_addrs(unit, ourid, hisid)
-    int unit;
-    eui64_t ourid;
-    eui64_t hisid;
+ipv6cp_clear_addrs(int unit, eui64_t ourid, eui64_t hisid)
 {
     cif6addr(unit, ourid, hisid);
 }
@@ -1359,8 +1370,7 @@ ipv6cp_clear_addrs(unit, ourid, hisid)
  * ipv6cp_finished - possibly shut down the lower layers.
  */
 static void
-ipv6cp_finished(f)
-    fsm *f;
+ipv6cp_finished(fsm *f)
 {
     np_finished(f->unit, PPP_IPV6);
 }
@@ -1371,8 +1381,7 @@ ipv6cp_finished(f)
  * has finished.
  */
 static void
-ipv6cp_script_done(arg)
-    void *arg;
+ipv6cp_script_done(void *arg)
 {
     ipv6cp_script_pid = 0;
     switch (ipv6cp_script_state) {
@@ -1397,8 +1406,7 @@ ipv6cp_script_done(arg)
  * interface-name tty-name speed local-LL remote-LL.
  */
 static void
-ipv6cp_script(script)
-    char *script;
+ipv6cp_script(char *script)
 {
     char strspeed[32], strlocal[32], strremote[32];
     char *argv[8];
@@ -1416,7 +1424,8 @@ ipv6cp_script(script)
     argv[6] = ipparam;
     argv[7] = NULL;
 
-    ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
+    ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done,
+                                   NULL, 0);
 }
 
 /*
@@ -1428,11 +1437,8 @@ static char *ipv6cp_codenames[] = {
 };
 
 static int
-ipv6cp_printpkt(p, plen, printer, arg)
-    u_char *p;
-    int plen;
-    void (*printer) __P((void *, char *, ...));
-    void *arg;
+ipv6cp_printpkt(u_char *p, int plen,
+               void (*printer) (void *, char *, ...), void *arg)
 {
     int code, id, len, olen;
     u_char *pstart, *optend;
@@ -1522,7 +1528,6 @@ ipv6cp_printpkt(p, plen, printer, arg)
  */
 #define IP6_HDRLEN     40      /* bytes */
 #define IP6_NHDR_FRAG  44      /* fragment IPv6 header */
-#define IPPROTO_TCP    6
 #define TCP_HDRLEN     20
 #define TH_FIN         0x01
 
@@ -1536,9 +1541,7 @@ ipv6cp_printpkt(p, plen, printer, arg)
 #define get_tcpflags(x)        (((unsigned char *)(x))[13])
 
 static int
-ipv6_active_pkt(pkt, len)
-    u_char *pkt;
-    int len;
+ipv6_active_pkt(u_char *pkt, int len)
 {
     u_char *tcp;