* 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.19 2004/01/13 03:59:37 paulus Exp $
+ * $Id: ipv6cp.c,v 1.21 2005/08/25 23:59:34 paulus Exp $
*/
-#define RCSID "$Id: ipv6cp.c,v 1.19 2004/01/13 03:59:37 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>
#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 */
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) __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)
*/
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 */
{ "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
"Accept peer's interface identifier for us", 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 },
wo->vj_protocol = IPV6CP_COMP;
#endif
+ /*
+ * XXX This controls whether the user may use the defaultroute option.
+ */
+ ao->default_route = 1;
}
* 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;
* 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;
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
wo->opt_local = 1;
}
}
-#endif
if (!wo->opt_local) { /* init interface identifier */
if (wo->use_ip && eui64_iszero(wo->ourid)) {
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);
}
}
{
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__)))
#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));
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)");
+ 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);
+ /* 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));
}
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
{
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);
} 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
}
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);
}
/*