]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/ipv6cp.c
pppoe-discovery: add options to tune discovery timeout and attempts
[ppp.git] / pppd / ipv6cp.c
index b877625c74f55f7bc4b5384222e9d11d3411553d..356ff84ead4103cb846c31c6e806786b166a33e5 100644 (file)
@@ -1,16 +1,38 @@
 /*
-    ipv6cp.c - PPP IPV6 Control Protocol.
-    Copyright (C) 1999  Tommi Komulainen <Tommi.Komulainen@iki.fi>
-
-    Redistribution and use in source and binary forms are permitted
-    provided that the above copyright notice and this paragraph are
-    duplicated in all such forms.  The name of the author may not be
-    used to endorse or promote products derived from this software
-    without specific prior written permission.
-    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-    IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-    WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-*/
+ * ipv6cp.c - PPP IPV6 Control Protocol.
+ *
+ * Copyright (c) 1999 Tommi Komulainen.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name(s) of the authors of this software must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Tommi Komulainen
+ *     <Tommi.Komulainen@iki.fi>".
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * 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.
+ *
+ */
 
 /*  Original version, based on RFC2023 :
 
  *
  * ipcp.c - PPP IP Control Protocol.
  *
- * Copyright (c) 1989 Carnegie Mellon University.
- * All rights reserved.
+ * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Carnegie Mellon University.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
  *
- * $Id: ipv6cp.c,v 1.13 2001/03/08 05:11:12 paulus Exp $ 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any legal
+ *    details, please contact
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * 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.21 2005/08/25 23:59:34 paulus Exp $ 
  */
 
-#define RCSID  "$Id: ipv6cp.c,v 1.13 2001/03/08 05:11:12 paulus Exp $"
+#define RCSID  "$Id: ipv6cp.c,v 1.21 2005/08/25 23:59:34 paulus Exp $"
 
 /*
  * TODO: 
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <netdb.h>
@@ -134,6 +180,16 @@ int no_ifaceid_neg = 0;
 /* local vars */
 static int ipv6cp_is_up;
 
+/* Hook for a plugin to know when IPv6 protocol has come up */
+void (*ipv6_up_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to know when IPv6 protocol has come down */
+void (*ipv6_down_hook) __P((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)
  */
@@ -141,7 +197,7 @@ 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_nakci __P((fsm *, u_char *, int, 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 */
@@ -193,10 +249,8 @@ static option_t ipv6cp_option_list[] = {
     { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
       "Use (default) IPv4 address as interface identifier", 1 },
 
-#if defined(SOL2)
     { "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 },
@@ -330,8 +384,10 @@ setifaceid(argv)
     return 1;
 }
 
+char *llv6_ntoa(eui64_t ifaceid);
+
 static void
-printipaddr(opt, printer, arg)
+printifaceid(opt, printer, arg)
     option_t *opt;
     void (*printer) __P((void *, char *, ...));
     void *arg;
@@ -623,10 +679,11 @@ bad:
  *     1 - Nak was good.
  */
 static int
-ipv6cp_nakci(f, p, len)
+ipv6cp_nakci(f, p, len, treat_as_reject)
     fsm *f;
     u_char *p;
     int len;
+    int treat_as_reject;
 {
     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
     u_char citype, cilen, *next;
@@ -672,19 +729,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;
@@ -705,10 +764,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;
 
@@ -1024,7 +1083,9 @@ ipv6_check_options()
 {
     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
 
-#if defined(SOL2)
+    if (!ipv6cp_protent.enabled_flag)
+       return;
+
     /*
      * Persistent link-local id is only used when user has not explicitly
      * configure/hard-code the id
@@ -1044,7 +1105,6 @@ ipv6_check_options()
            wo->opt_local = 1;
        }
     }
-#endif
 
     if (!wo->opt_local) {      /* init interface identifier */
        if (wo->use_ip && eui64_iszero(wo->ourid)) {
@@ -1067,7 +1127,7 @@ ipv6_check_options()
 
     if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
        option_error("local/remote LL address required for demand-dialling\n");
-       exit(1);
+       exit(EXIT_OPTION_ERROR);
     }
 }
 
@@ -1082,15 +1142,8 @@ ipv6_demand_conf(u)
 {
     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
 
-#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
-#if defined(SOL2)
     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__)))
@@ -1183,43 +1236,20 @@ ipv6cp_up(f)
        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)");
+               warn("sif6up failed (IPV6)");
            ipv6cp_close(f->unit, "Interface configuration failed");
            return;
        }
-#else
-       if (!sifup(f->unit)) {
-           if (debug)
-               warn("sifup 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);
 
        notice("local  LL address %s", llv6_ntoa(go->ourid));
@@ -1229,6 +1259,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
@@ -1252,6 +1286,9 @@ ipv6cp_down(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);
@@ -1269,16 +1306,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
     }
@@ -1366,7 +1401,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);
 }
 
 /*
@@ -1472,7 +1508,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