/*
* 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 :
+
+ Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt,
+ Alain.Durand@imag.fr, IMAG,
+ Jean-Luc.Richier@imag.fr, IMAG-LSR.
+
+ Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE,
+ Alain.Durand@imag.fr, IMAG,
+ Jean-Luc.Richier@imag.fr, IMAG-LSR.
+
+ Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt
+ Économique ayant pour membres BULL S.A. et l'INRIA).
+
+ Ce logiciel informatique est disponible aux conditions
+ usuelles dans la recherche, c'est-à-dire qu'il peut
+ être utilisé, copié, modifié, distribué à l'unique
+ condition que ce texte soit conservé afin que
+ l'origine de ce logiciel soit reconnue.
+
+ Le nom de l'Institut National de Recherche en Informatique
+ et en Automatique (INRIA), de l'IMAG, ou d'une personne morale
+ ou physique ayant participé à l'élaboration de ce logiciel ne peut
+ être utilisé sans son accord préalable explicite.
+
+ Ce logiciel est fourni tel quel sans aucune garantie,
+ support ou responsabilité d'aucune sorte.
+ Ce logiciel est dérivé de sources d'origine
+ "University of California at Berkeley" et
+ "Digital Equipment Corporation" couvertes par des copyrights.
+
+ L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG)
+ est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National
+ Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant
+ sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR).
+
+ This work has been done in the context of GIE DYADE (joint R & D venture
+ between BULL S.A. and INRIA).
+
+ This software is available with usual "research" terms
+ with the aim of retain credits of the software.
+ Permission to use, copy, modify and distribute this software for any
+ purpose and without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies,
+ and the name of INRIA, IMAG, or any contributor not be used in advertising
+ or publicity pertaining to this material without the prior explicit
+ permission. The software is provided "as is" without any
+ warranties, support or liabilities of any kind.
+ This software is derived from source code from
+ "University of California at Berkeley" and
+ "Digital Equipment Corporation" protected by copyrights.
+
+ Grenoble's Institute of Computer Science and Applied Mathematics (IMAG)
+ is a federation of seven research units funded by the CNRS, National
+ Polytechnic Institute of Grenoble and University Joseph Fourier.
+ The research unit in Software, Systems, Networks (LSR) is member of IMAG.
+*/
+
+/*
* Derived from :
*
*
* 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.1 1999/08/13 01:58:43 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
*
- * Original version by Inria (www.inria.fr)
- * Modified to match RFC2472 by Tommi Komulainen <Tommi.Komulainen@iki.fi>
+ * 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.19 2004/01/13 03:59:37 paulus Exp $
*/
-#ifndef lint
-static char rcsid[]="$Id: ipv6cp.c,v 1.1 1999/08/13 01:58:43 paulus Exp $";
-#endif
+#define RCSID "$Id: ipv6cp.c,v 1.19 2004/01/13 03:59:37 paulus Exp $"
/*
* TODO:
*
+ * Proxy Neighbour Discovery.
+ *
* Better defines for selecting the ordering of
* interface up / set address. (currently checks for __linux__,
* since SVR4 && (SNI || __USLC__) didn't work properly)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include "pppd.h"
#include "fsm.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 */
ipv6cp_options ipv6cp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
/*
* Command-line options.
*/
-static int setifaceid __P((char *arg));
+static int setifaceid __P((char **arg));
+static void printifaceid __P((option_t *,
+ void (*)(void *, char *, ...), void *));
static option_t ipv6cp_option_list[] = {
- { "ipv6", o_special, setifaceid,
- "Set interface identifiers for IPV6" },
+ { "ipv6", o_special, (void *)setifaceid,
+ "Set interface identifiers for IPV6",
+ OPT_A2PRINTER, (void *)printifaceid },
+
+ { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag,
+ "Enable IPv6 and IPv6CP", OPT_PRIO | 1 },
{ "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
- "Disable IPv6 and IPv6CP" },
+ "Disable IPv6 and IPv6CP", OPT_PRIOSUB },
{ "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
- "Disable IPv6 and IPv6CP" },
+ "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS },
{ "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
"Accept peer's interface identifier for us", 1 },
+
{ "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
- "Use (default) IPv4 address as interface identifier", 0 },
+ "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" },
+ "Set timeout for IPv6CP", OPT_PRIO },
{ "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
- "Set max #xmits for term-reqs" },
+ "Set max #xmits for term-reqs", OPT_PRIO },
{ "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
- "Set max #xmits for conf-reqs" },
+ "Set max #xmits for conf-reqs", OPT_PRIO },
{ "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
- "Set max #conf-naks for IPv6CP" },
+ "Set max #conf-naks for IPv6CP", OPT_PRIO },
{ NULL }
};
ipv6_active_pkt
};
-static void ipv6cp_clear_addrs __P((int));
+static void ipv6cp_clear_addrs __P((int, eui64_t, eui64_t));
static void ipv6cp_script __P((char *));
static void ipv6cp_script_done __P((void *));
* setifaceid - set the interface identifiers manually
*/
static int
-setifaceid(arg)
- char *arg;
+setifaceid(argv)
+ char **argv;
{
- char *comma;
+ char *comma, *arg, c;
ipv6cp_options *wo = &ipv6cp_wantoptions[0];
struct in6_addr addr;
+ static int prio_local, prio_remote;
+
+#define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
+ (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
-#define VALIDID(a) ( ((a).s6_addr64[0] == 0) && \
- ((a).s6_addr64[1] != 0) )
-
+ arg = *argv;
if ((comma = strchr(arg, ',')) == NULL)
comma = arg + strlen(arg);
* If comma first character, then no local identifier
*/
if (comma != arg) {
+ c = *comma;
*comma = '\0';
if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
- option_error("Illegal interface identifier: %s", arg);
+ option_error("Illegal interface identifier (local): %s", arg);
return 0;
}
-
- eui64_copy(addr.s6_addr32[2], wo->ourid);
- wo->opt_local = 1;
- *comma = ',';
+
+ if (option_priority >= prio_local) {
+ eui64_copy(addr.s6_addr32[2], wo->ourid);
+ wo->opt_local = 1;
+ prio_local = option_priority;
+ }
+ *comma = c;
}
/*
*/
if (*comma != 0 && *++comma != '\0') {
if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
- option_error("Illegal interface identifier: %s", comma);
+ option_error("Illegal interface identifier (remote): %s", comma);
return 0;
}
- eui64_copy(addr.s6_addr32[2], wo->hisid);
- wo->opt_remote = 1;
+ if (option_priority >= prio_remote) {
+ eui64_copy(addr.s6_addr32[2], wo->hisid);
+ wo->opt_remote = 1;
+ prio_remote = option_priority;
+ }
}
+ if (override_value("+ipv6", option_priority, option_source))
+ ipv6cp_protent.enabled_flag = 1;
return 1;
}
+char *llv6_ntoa(eui64_t ifaceid);
+
+static void
+printifaceid(opt, printer, arg)
+ option_t *opt;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ ipv6cp_options *wo = &ipv6cp_wantoptions[0];
+
+ if (wo->opt_local)
+ printer(arg, "%s", llv6_ntoa(wo->ourid));
+ printer(arg, ",");
+ if (wo->opt_remote)
+ printer(arg, "%s", llv6_ntoa(wo->hisid));
+}
+
/*
* Make a string representation of a network address.
*/
* 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;
orc = CONFREJ;
break;
}
-#else
- orc = CONFREJ;
- break;
-#endif
ho->neg_vj = 1;
ho->vj_protocol = cishort;
break;
+#else
+ orc = CONFREJ;
+ break;
+#endif
default:
orc = CONFREJ;
{
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)) {
+
+ /*
+ * On systems where there are no Ethernet interfaces used, there
+ * may be other ways to obtain a persistent id. Right now, it
+ * will fall back to using magic [see eui64_magic] below when
+ * an EUI-48 from MAC address can't be obtained. Other possibilities
+ * include obtaining EEPROM serial numbers, or some other unique
+ * yet persistent number. On Sparc platforms, this is possible,
+ * but too bad there's no standards yet for x86 machines.
+ */
+ if (ether_to_eui64(&wo->ourid)) {
+ wo->opt_local = 1;
+ }
+ }
+#endif
+
if (!wo->opt_local) { /* init interface identifier */
if (wo->use_ip && eui64_iszero(wo->ourid)) {
eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
{
ipv6cp_options *wo = &ipv6cp_wantoptions[u];
-#if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
- if (!sifup(u, PPP_IPV6))
+#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__)))
- if (!sifup(u, PPP_IPV6))
+ if (!sifup(u))
return 0;
#endif
if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
return;
}
}
- script_setenv("LLLOCAL", llv6_ntoa(go->ourid));
- script_setenv("LLREMOTE", llv6_ntoa(ho->hisid));
+ script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
+ script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
#ifdef IPV6CP_COMP
/* set tcp compression */
if (! eui64_equals(ho->hisid, wo->hisid))
warn("Remote LL address changed to %s",
llv6_ntoa(ho->hisid));
- ipv6cp_clear_addrs(f->unit);
+ ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid);
/* Set the interface to the new addresses */
if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
/*
* Set LL addresses
*/
-#if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+#if !defined(__linux__) && !defined(SOL2) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
if (debug)
warn("sif6addr failed");
#endif
/* bring the interface up for IPv6 */
- if (!sifup(f->unit, PPP_IPV6)) {
+#if defined(SOL2)
+ if (!sif6up(f->unit)) {
if (debug)
- warn("sif6up failed");
+ warn("sifup 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(SVR4) && (defined(SNI) || defined(__USLC__)))
+#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
if (debug)
warn("sif6addr failed");
if (demand) {
sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
} else {
+ sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
#if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
- sifdown(f->unit, PPP_IPV6);
+#if defined(SOL2)
+ sif6down(f->unit);
+#else
+ sifdown(f->unit);
+#endif /* defined(SOL2) */
#endif
- ipv6cp_clear_addrs(f->unit);
+ ipv6cp_clear_addrs(f->unit,
+ ipv6cp_gotoptions[f->unit].ourid,
+ ipv6cp_hisoptions[f->unit].hisid);
#if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
- sifdown(f->unit, PPP_IPV6);
+ sifdown(f->unit);
#endif
}
/*
* ipv6cp_clear_addrs() - clear the interface addresses, routes,
- * proxy arp entries, etc.
+ * proxy neighbour discovery entries, etc.
*/
static void
-ipv6cp_clear_addrs(unit)
+ipv6cp_clear_addrs(unit, ourid, hisid)
int unit;
+ eui64_t ourid;
+ eui64_t hisid;
{
- eui64_t ourid, hisid;
-
- ourid = ipv6cp_gotoptions[unit].ourid;
- hisid = ipv6cp_hisoptions[unit].hisid;
cif6addr(unit, ourid, hisid);
}
case TERMREQ:
if (len > 0 && *p >= ' ' && *p < 0x7f) {
printer(arg, " ");
- print_string(p, len, printer, arg);
+ print_string((char *)p, len, printer, arg);
p += len;
len = 0;
}
*/
#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