summaryrefslogtreecommitdiff
path: root/pppd/ipv6cp.c
diff options
context:
space:
mode:
Diffstat (limited to 'pppd/ipv6cp.c')
-rw-r--r--pppd/ipv6cp.c78
1 files changed, 63 insertions, 15 deletions
diff --git a/pppd/ipv6cp.c b/pppd/ipv6cp.c
index decaa67..130819d 100644
--- a/pppd/ipv6cp.c
+++ b/pppd/ipv6cp.c
@@ -153,6 +153,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/param.h>
@@ -259,10 +260,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,
@@ -1083,6 +1085,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
*
* walks the list of valid ethernet interfaces, starting with devnam
@@ -1101,18 +1120,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 +1157,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));