]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/ipv6cp.c
pppd.8: Document netmask option
[ppp.git] / pppd / ipv6cp.c
index decaa6705e6cf335e7271fd55d3a08712bb87736..a36b1d942be4d530215078aebba7699156ebc75a 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <unistd.h>
 #include <netdb.h>
 #include <sys/param.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#include "pppd.h"
+#include "pppd-private.h"
+#include "options.h"
 #include "fsm.h"
+#include "eui64.h"
 #include "ipcp.h"
 #include "ipv6cp.h"
 #include "magic.h"
@@ -181,11 +184,8 @@ static int default_route_set[NUM_PPP];             /* Have set up a default route */
 static int ipv6cp_is_up;
 static bool ipv6cp_noremote;
 
-/* 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;
+ipv6_up_hook_fn *ipv6_up_hook = NULL;
+ipv6_down_hook_fn *ipv6_down_hook = NULL;
 
 /* Notifiers for when IPCPv6 goes up and down */
 struct notifier *ipv6_up_notifier = NULL;
@@ -229,10 +229,10 @@ static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
  * Command-line options.
  */
 static int setifaceid (char **arg);
-static void printifaceid (option_t *,
+static void printifaceid (struct option *,
                          void (*)(void *, char *, ...), void *);
 
-static option_t ipv6cp_option_list[] = {
+static struct option ipv6cp_option_list[] = {
     { "ipv6", o_special, (void *)setifaceid,
       "Set interface identifiers for IPV6",
       OPT_A2PRINTER, (void *)printifaceid },
@@ -259,10 +259,11 @@ static option_t ipv6cp_option_list[] = {
       &ipv6cp_wantoptions[0].default_route },
 
     { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
-      "Use (default) IPv4 address as interface identifier", 1 },
-
+      "Use (default) IPv4 addresses for both local and remote interface identifiers", 1 },
     { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
-      "Use uniquely-available persistent value for link local address", 1 },
+      "Use uniquely-available persistent value for local interface identifier", 1 },
+    { "ipv6cp-use-remotenumber", o_bool, &ipv6cp_wantoptions[0].use_remotenumber,
+      "Use remotenumber value for remote interface identifier", 1 },
 
 #ifdef __linux__
     { "ipv6cp-noremote", o_bool, &ipv6cp_noremote,
@@ -370,7 +371,7 @@ setifaceid(char **argv)
        *comma = '\0';
 
        if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
-           option_error("Illegal interface identifier (local): %s", arg);
+           ppp_option_error("Illegal interface identifier (local): %s", arg);
            return 0;
        }
 
@@ -387,7 +388,7 @@ setifaceid(char **argv)
      */
     if (*comma != 0 && *++comma != '\0') {
        if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
-           option_error("Illegal interface identifier (remote): %s", comma);
+           ppp_option_error("Illegal interface identifier (remote): %s", comma);
            return 0;
        }
        if (option_priority >= prio_remote) {
@@ -405,7 +406,7 @@ setifaceid(char **argv)
 char *llv6_ntoa(eui64_t ifaceid);
 
 static void
-printifaceid(option_t *opt, void (*printer) (void *, char *, ...), void *arg)
+printifaceid(struct option *opt, void (*printer) (void *, char *, ...), void *arg)
 {
        ipv6cp_options *wo = &ipv6cp_wantoptions[0];
 
@@ -1082,6 +1083,23 @@ endswitch:
 }
 
 
+/*
+ * eui48_to_eui64 - Convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
+ */
+static void
+eui48_to_eui64(eui64_t *p_eui64, const u_char addr[6])
+{
+    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];
+}
+
+
 /*
  * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI
  *
@@ -1101,18 +1119,7 @@ ether_to_eui64(eui64_t *p_eui64)
         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];
-
+    eui48_to_eui64(p_eui64, addr);
     return 1;
 }
 
@@ -1149,6 +1156,46 @@ ipv6_check_options(void)
        }
     }
 
+    if (!wo->opt_remote && wo->use_remotenumber && *remote_number) {
+       /* remote number can be either MAC address, IPv4 address, IPv6 address or telephone number */
+       struct in_addr addr;
+       struct in6_addr addr6;
+       unsigned long long tel;
+       unsigned char mac[6];
+       const char *str;
+       char *endptr;
+       if (sscanf(remote_number, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+                  &mac[0], &mac[1], &mac[2],
+                  &mac[3], &mac[4], &mac[5]) == 6) {
+           eui48_to_eui64(&wo->hisid, mac);
+       } else if (inet_pton(AF_INET, remote_number, &addr) == 1) {
+           eui64_setlo32(wo->hisid, ntohl(addr.s_addr));
+       } else if (inet_pton(AF_INET6, remote_number, &addr6) == 1) {
+           /* use low 64 bits of IPv6 address for interface identifier */
+           wo->hisid.e8[0] = addr6.s6_addr[8];
+           wo->hisid.e8[1] = addr6.s6_addr[9];
+           wo->hisid.e8[2] = addr6.s6_addr[10];
+           wo->hisid.e8[3] = addr6.s6_addr[11];
+           wo->hisid.e8[4] = addr6.s6_addr[12];
+           wo->hisid.e8[5] = addr6.s6_addr[13];
+           wo->hisid.e8[6] = addr6.s6_addr[14];
+           wo->hisid.e8[7] = addr6.s6_addr[15];
+       } else {
+           str = remote_number;
+           /* telephone number may start with leading '+' sign, so skip it */
+           if (str[0] == '+')
+               str++;
+           errno = 0;
+           tel = strtoull(str, &endptr, 10);
+           if (!errno && *str && !*endptr && tel) {
+               wo->hisid.e32[0] = htonl(tel >> 32);
+               wo->hisid.e32[1] = htonl(tel & 0xFFFFFFFF);
+           }
+       }
+       if (!eui64_iszero(wo->hisid))
+           wo->opt_remote = 1;
+    }
+
     if (!wo->opt_local) {      /* init interface identifier */
        if (wo->use_ip && eui64_iszero(wo->ourid)) {
            eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
@@ -1253,9 +1300,9 @@ ipv6cp_up(fsm *f)
            return;
        }
     }
-    script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
+    ppp_script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
     if (!eui64_iszero(ho->hisid))
-        script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
+        ppp_script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
 
 #ifdef IPV6CP_COMP
     /* set tcp compression */
@@ -1349,7 +1396,7 @@ static void
 ipv6cp_down(fsm *f)
 {
     IPV6CPDEBUG(("ipv6cp: down"));
-    update_link_stats(f->unit);
+    ppp_get_link_stats(NULL);
     notify(ipv6_down_notifier, 0);
     if (ipv6_down_hook)
        ipv6_down_hook();
@@ -1443,7 +1490,7 @@ ipv6cp_script_done(void *arg)
 static void
 ipv6cp_script(char *script)
 {
-    char strspeed[32], strlocal[32], strremote[32];
+    char strspeed[32], strlocal[64], strremote[64];
     char *argv[8];
 
     sprintf(strspeed, "%d", baud_rate);