2006-11-20 07:16:27 +03:00
|
|
|
/* $NetBSD: in6_ifattach.c,v 1.68 2006/11/20 04:16:27 dyoung Exp $ */
|
2001-07-18 17:12:27 +04:00
|
|
|
/* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */
|
1999-07-04 01:24:45 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
2000-04-10 19:45:24 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* 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. Neither the name of the project nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
2000-04-10 19:45:24 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2001-11-13 03:56:55 +03:00
|
|
|
#include <sys/cdefs.h>
|
2006-11-20 07:16:27 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.68 2006/11/20 04:16:27 dyoung Exp $");
|
2001-11-13 03:56:55 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/sockio.h>
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <sys/kernel.h>
|
2001-02-07 11:59:47 +03:00
|
|
|
#include <sys/syslog.h>
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <sys/md5.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_dl.h>
|
|
|
|
#include <net/if_types.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_var.h>
|
|
|
|
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/ip6.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/in6_ifattach.h>
|
|
|
|
#include <netinet6/ip6_var.h>
|
|
|
|
#include <netinet6/nd6.h>
|
2003-07-08 14:20:45 +04:00
|
|
|
#include <netinet6/ip6_mroute.h>
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
#include <netinet6/scope6_var.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <net/net_osdep.h>
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
unsigned long in6_maxmtu = 0;
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
int ip6_auto_linklocal = 1; /* enable by default */
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
struct callout in6_tmpaddrtimer_ch = CALLOUT_INITIALIZER;
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static int get_hostid_ifid __P((struct ifnet *, struct in6_addr *));
|
|
|
|
#endif
|
2000-04-12 14:36:38 +04:00
|
|
|
static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
|
2006-03-06 02:47:08 +03:00
|
|
|
static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *));
|
2000-04-12 14:36:38 +04:00
|
|
|
static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
|
|
|
|
static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
|
|
|
|
static int in6_ifattach_loopback __P((struct ifnet *));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-04-12 14:36:38 +04:00
|
|
|
#define EUI64_GBIT 0x01
|
|
|
|
#define EUI64_UBIT 0x02
|
2002-11-02 10:30:55 +03:00
|
|
|
#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (/*CONSTCOND*/ 0)
|
2000-04-12 14:36:38 +04:00
|
|
|
#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT)
|
|
|
|
#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6))
|
|
|
|
#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT)
|
|
|
|
#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6))
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-04-12 14:36:38 +04:00
|
|
|
#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6))
|
|
|
|
#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6))
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
#define GEN_TEMPID_RETRY_MAX 5
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* Generate a last-resort interface identifier from hostid.
|
|
|
|
* works only for certain architectures (like sparc).
|
|
|
|
* also, using hostid itself may constitute a privacy threat, much worse
|
|
|
|
* than MAC addresses (hostids are used for software licensing).
|
|
|
|
* maybe we should use MD5(hostid) instead.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
get_hostid_ifid(ifp, in6)
|
|
|
|
struct ifnet *ifp;
|
|
|
|
struct in6_addr *in6; /* upper 64bits are preserved */
|
|
|
|
{
|
|
|
|
int off, len;
|
|
|
|
static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
static const uint8_t allone[8] =
|
|
|
|
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
|
|
|
|
|
|
if (!hostid)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* get up to 8 bytes from the hostid field - should we get */
|
|
|
|
len = (sizeof(hostid) > 8) ? 8 : sizeof(hostid);
|
|
|
|
off = sizeof(*in6) - len;
|
|
|
|
memcpy(&in6->s6_addr[off], &hostid, len);
|
|
|
|
|
|
|
|
/* make sure we do not return anything bogus */
|
|
|
|
if (memcmp(&in6->s6_addr[8], allzero, sizeof(allzero)))
|
|
|
|
return -1;
|
|
|
|
if (memcmp(&in6->s6_addr[8], allone, sizeof(allone)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* make sure to set "u" bit to local, and "g" bit to individual. */
|
|
|
|
in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
|
|
|
|
in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
|
|
|
|
|
|
|
|
/* convert EUI64 into IPv6 interface identifier */
|
|
|
|
EUI64_TO_IFID(in6);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
|
|
|
* Generate a last-resort interface identifier, when the machine has no
|
|
|
|
* IEEE802/EUI64 address sources.
|
2000-04-12 14:36:38 +04:00
|
|
|
* The goal here is to get an interface identifier that is
|
|
|
|
* (1) random enough and (2) does not change across reboot.
|
|
|
|
* We currently use MD5(hostname) for it.
|
1999-12-13 18:17:17 +03:00
|
|
|
*/
|
|
|
|
static int
|
2006-11-16 04:32:37 +03:00
|
|
|
get_rand_ifid(struct ifnet *ifp,
|
2006-10-12 05:30:41 +04:00
|
|
|
struct in6_addr *in6) /* upper 64bits are preserved */
|
1999-12-13 18:17:17 +03:00
|
|
|
{
|
|
|
|
MD5_CTX ctxt;
|
|
|
|
u_int8_t digest[16];
|
|
|
|
|
2000-04-12 14:36:38 +04:00
|
|
|
#if 0
|
|
|
|
/* we need at least several letters as seed for ifid */
|
|
|
|
if (hostnamelen < 3)
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* generate 8 bytes of pseudo-random value. */
|
2006-03-06 02:47:08 +03:00
|
|
|
memset(&ctxt, 0, sizeof(ctxt));
|
1999-12-13 18:17:17 +03:00
|
|
|
MD5Init(&ctxt);
|
2002-09-11 06:41:19 +04:00
|
|
|
MD5Update(&ctxt, (u_char *)hostname, hostnamelen);
|
1999-12-13 18:17:17 +03:00
|
|
|
MD5Final(digest, &ctxt);
|
|
|
|
|
2000-04-12 14:36:38 +04:00
|
|
|
/* assumes sizeof(digest) > sizeof(ifid) */
|
2006-03-06 02:47:08 +03:00
|
|
|
memcpy(&in6->s6_addr[8], digest, 8);
|
1999-12-13 18:17:17 +03:00
|
|
|
|
|
|
|
/* make sure to set "u" bit to local, and "g" bit to individual. */
|
2000-04-12 14:36:38 +04:00
|
|
|
in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
|
|
|
|
in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
|
|
|
|
|
|
|
|
/* convert EUI64 into IPv6 interface identifier */
|
|
|
|
EUI64_TO_IFID(in6);
|
1999-12-13 18:17:17 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
static int
|
|
|
|
generate_tmp_ifid(seed0, seed1, ret)
|
|
|
|
u_int8_t *seed0, *ret;
|
|
|
|
const u_int8_t *seed1;
|
|
|
|
{
|
|
|
|
MD5_CTX ctxt;
|
|
|
|
u_int8_t seed[16], digest[16], nullbuf[8];
|
|
|
|
u_int32_t val32;
|
|
|
|
/*
|
|
|
|
* interface ID for subnet anycast addresses.
|
|
|
|
* XXX: we assume the unicast address range that requires IDs
|
|
|
|
* in EUI-64 format.
|
|
|
|
*/
|
|
|
|
static const uint8_t anycast_id[8] = { 0xfd, 0xff, 0xff, 0xff,
|
|
|
|
0xff, 0xff, 0xff, 0x80 };
|
|
|
|
static const uint8_t isatap_id[4] = { 0x00, 0x00, 0x5e, 0xfe };
|
|
|
|
int badid, retry = 0;
|
|
|
|
|
|
|
|
/* If there's no hisotry, start with a random seed. */
|
|
|
|
memset(nullbuf, 0, sizeof(nullbuf));
|
|
|
|
if (memcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
val32 = arc4random();
|
|
|
|
memcpy(seed + sizeof(val32) * i, &val32, sizeof(val32));
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
memcpy(seed, seed0, 8);
|
|
|
|
|
|
|
|
/* copy the right-most 64-bits of the given address */
|
|
|
|
/* XXX assumption on the size of IFID */
|
|
|
|
memcpy(&seed[8], seed1, 8);
|
|
|
|
|
|
|
|
again:
|
|
|
|
/* for debugging purposes only */
|
|
|
|
#if 0
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printf("generate_tmp_ifid: new randomized ID from: ");
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
printf("%02x", seed[i]);
|
|
|
|
printf(" ");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* generate 16 bytes of pseudo-random value. */
|
|
|
|
memset(&ctxt, 0, sizeof(ctxt));
|
|
|
|
MD5Init(&ctxt);
|
|
|
|
MD5Update(&ctxt, seed, sizeof(seed));
|
|
|
|
MD5Final(digest, &ctxt);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (3)
|
|
|
|
* Take the left-most 64-bits of the MD5 digest and set bit 6 (the
|
|
|
|
* left-most bit is numbered 0) to zero.
|
|
|
|
*/
|
|
|
|
memcpy(ret, digest, 8);
|
|
|
|
ret[0] &= ~EUI64_UBIT;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reject inappropriate identifiers according to
|
|
|
|
* draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (4)
|
|
|
|
* At this moment, we reject following cases:
|
|
|
|
* - all 0 identifier
|
|
|
|
* - identifiers that conflict with reserved subnet anycast addresses,
|
|
|
|
* which are defined in RFC 2526.
|
|
|
|
* - identifiers that conflict with ISATAP addresses
|
|
|
|
* - identifiers used in our own addresses
|
|
|
|
*/
|
|
|
|
badid = 0;
|
|
|
|
if (memcmp(nullbuf, ret, sizeof(nullbuf)) == 0)
|
|
|
|
badid = 1;
|
|
|
|
else if (memcmp(anycast_id, ret, 7) == 0 &&
|
|
|
|
(anycast_id[7] & ret[7]) == anycast_id[7]) {
|
|
|
|
badid = 1;
|
|
|
|
} else if (memcmp(isatap_id, ret, sizeof(isatap_id)) == 0)
|
|
|
|
badid = 1;
|
|
|
|
else {
|
|
|
|
struct in6_ifaddr *ia;
|
|
|
|
|
|
|
|
for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
|
|
|
|
if (!memcmp(&ia->ia_addr.sin6_addr.s6_addr[8],
|
|
|
|
ret, 8)) {
|
|
|
|
badid = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In the event that an unacceptable identifier has been generated,
|
|
|
|
* restart the process, using the right-most 64 bits of the MD5 digest
|
|
|
|
* obtained in place of the history value.
|
|
|
|
*/
|
|
|
|
if (badid) {
|
|
|
|
/* for debugging purposes only */
|
|
|
|
#if 0
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printf("unacceptable random ID: ");
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
printf("%02x", digest[i]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (++retry < GEN_TEMPID_RETRY_MAX) {
|
|
|
|
memcpy(seed, &digest[8], 8);
|
|
|
|
goto again;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We're so unlucky. Give up for now, and return
|
|
|
|
* all 0 IDs to tell the caller not to make a
|
|
|
|
* temporary address.
|
|
|
|
*/
|
|
|
|
nd6log((LOG_NOTICE,
|
|
|
|
"generate_tmp_ifid: never found a good ID\n"));
|
|
|
|
memset(ret, 0, 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (6)
|
|
|
|
* Take the rightmost 64-bits of the MD5 digest and save them in
|
|
|
|
* stable storage as the history value to be used in the next
|
|
|
|
* iteration of the algorithm.
|
|
|
|
*/
|
|
|
|
memcpy(seed0, &digest[8], 8);
|
|
|
|
|
|
|
|
/* for debugging purposes only */
|
|
|
|
#if 0
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printf("to: ");
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
printf("%02x", digest[i]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
2000-04-12 14:36:38 +04:00
|
|
|
* Get interface identifier for the specified interface.
|
|
|
|
* XXX assumes single sockaddr_dl (AF_LINK address) per an interface
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2006-03-06 02:47:08 +03:00
|
|
|
int
|
|
|
|
in6_get_hw_ifid(ifp, in6)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ifnet *ifp;
|
2001-12-18 06:04:02 +03:00
|
|
|
struct in6_addr *in6; /* upper 64bits are preserved */
|
2000-04-12 14:36:38 +04:00
|
|
|
{
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct sockaddr_dl *sdl;
|
2002-09-11 06:41:19 +04:00
|
|
|
char *addr;
|
2000-04-12 14:36:38 +04:00
|
|
|
size_t addrlen;
|
|
|
|
static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
static u_int8_t allone[8] =
|
|
|
|
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
|
|
|
2006-11-20 07:16:27 +03:00
|
|
|
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
|
2000-04-12 14:36:38 +04:00
|
|
|
if (ifa->ifa_addr->sa_family != AF_LINK)
|
|
|
|
continue;
|
|
|
|
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
|
|
|
|
if (sdl == NULL)
|
|
|
|
continue;
|
|
|
|
if (sdl->sdl_alen == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
found:
|
|
|
|
addr = LLADDR(sdl);
|
|
|
|
addrlen = sdl->sdl_alen;
|
|
|
|
|
|
|
|
switch (ifp->if_type) {
|
2000-11-05 20:17:12 +03:00
|
|
|
case IFT_IEEE1394:
|
2002-06-09 01:22:29 +04:00
|
|
|
case IFT_IEEE80211:
|
2000-11-05 20:17:12 +03:00
|
|
|
/* IEEE1394 uses 16byte length address starting with EUI64 */
|
|
|
|
if (addrlen > 8)
|
|
|
|
addrlen = 8;
|
2002-06-09 01:22:29 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* get EUI64 */
|
|
|
|
switch (ifp->if_type) {
|
|
|
|
/* IEEE802/EUI64 cases - what others? */
|
|
|
|
case IFT_ETHER:
|
|
|
|
case IFT_FDDI:
|
|
|
|
case IFT_ATM:
|
|
|
|
case IFT_IEEE1394:
|
|
|
|
case IFT_IEEE80211:
|
2000-04-12 14:36:38 +04:00
|
|
|
/* look at IEEE802/EUI64 only */
|
|
|
|
if (addrlen != 8 && addrlen != 6)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check for invalid MAC address - on bsdi, we see it a lot
|
|
|
|
* since wildboar configures all-zero MAC on pccard before
|
|
|
|
* card insertion.
|
|
|
|
*/
|
2006-03-06 02:47:08 +03:00
|
|
|
if (memcmp(addr, allzero, addrlen) == 0)
|
2000-04-12 14:36:38 +04:00
|
|
|
return -1;
|
2006-03-06 02:47:08 +03:00
|
|
|
if (memcmp(addr, allone, addrlen) == 0)
|
2000-04-12 14:36:38 +04:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* make EUI64 address */
|
|
|
|
if (addrlen == 8)
|
2006-03-06 02:47:08 +03:00
|
|
|
memcpy(&in6->s6_addr[8], addr, 8);
|
2000-04-12 14:36:38 +04:00
|
|
|
else if (addrlen == 6) {
|
|
|
|
in6->s6_addr[8] = addr[0];
|
|
|
|
in6->s6_addr[9] = addr[1];
|
|
|
|
in6->s6_addr[10] = addr[2];
|
|
|
|
in6->s6_addr[11] = 0xff;
|
2000-04-13 20:21:25 +04:00
|
|
|
in6->s6_addr[12] = 0xfe;
|
2000-04-12 14:36:38 +04:00
|
|
|
in6->s6_addr[13] = addr[3];
|
|
|
|
in6->s6_addr[14] = addr[4];
|
|
|
|
in6->s6_addr[15] = addr[5];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IFT_ARCNET:
|
|
|
|
if (addrlen != 1)
|
|
|
|
return -1;
|
|
|
|
if (!addr[0])
|
|
|
|
return -1;
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
memset(&in6->s6_addr[8], 0, 8);
|
2000-04-12 14:36:38 +04:00
|
|
|
in6->s6_addr[15] = addr[0];
|
|
|
|
|
2000-04-16 19:00:56 +04:00
|
|
|
/*
|
|
|
|
* due to insufficient bitwidth, we mark it local.
|
|
|
|
*/
|
2000-04-12 14:36:38 +04:00
|
|
|
in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
|
|
|
|
in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IFT_GIF:
|
|
|
|
#ifdef IFT_STF
|
|
|
|
case IFT_STF:
|
|
|
|
#endif
|
|
|
|
/*
|
2001-02-07 11:59:47 +03:00
|
|
|
* RFC2893 says: "SHOULD use IPv4 address as ifid source".
|
2000-04-16 19:00:56 +04:00
|
|
|
* however, IPv4 address is not very suitable as unique
|
|
|
|
* identifier source (can be renumbered).
|
|
|
|
* we don't do this.
|
2000-04-12 14:36:38 +04:00
|
|
|
*/
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sanity check: g bit must not indicate "group" */
|
|
|
|
if (EUI64_GROUP(in6))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* convert EUI64 into IPv6 interface identifier */
|
|
|
|
EUI64_TO_IFID(in6);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sanity check: ifid must not be all zero, avoid conflict with
|
|
|
|
* subnet router anycast
|
|
|
|
*/
|
|
|
|
if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
|
2006-03-06 02:47:08 +03:00
|
|
|
memcmp(&in6->s6_addr[9], allzero, 7) == 0) {
|
2000-04-12 14:36:38 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get interface identifier for the specified interface. If it is not
|
|
|
|
* available on ifp0, borrow interface identifier from other information
|
|
|
|
* sources.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
get_ifid(ifp0, altifp, in6)
|
|
|
|
struct ifnet *ifp0;
|
|
|
|
struct ifnet *altifp; /*secondary EUI64 source*/
|
|
|
|
struct in6_addr *in6;
|
|
|
|
{
|
|
|
|
struct ifnet *ifp;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-04-12 14:36:38 +04:00
|
|
|
/* first, try to get it from the interface itself */
|
2006-03-06 02:47:08 +03:00
|
|
|
if (in6_get_hw_ifid(ifp0, in6) == 0) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
|
|
|
|
if_name(ifp0)));
|
2000-04-12 14:36:38 +04:00
|
|
|
goto success;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-04-12 14:36:38 +04:00
|
|
|
/* try secondary EUI64 source. this basically is for ATM PVC */
|
2006-03-06 02:47:08 +03:00
|
|
|
if (altifp && in6_get_hw_ifid(altifp, in6) == 0) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
|
|
|
|
if_name(ifp0), if_name(altifp)));
|
2000-04-12 14:36:38 +04:00
|
|
|
goto success;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* next, try to get it from some other hardware interface */
|
2006-11-20 07:16:27 +03:00
|
|
|
TAILQ_FOREACH(ifp, &ifnet, if_list) {
|
2000-04-12 14:36:38 +04:00
|
|
|
if (ifp == ifp0)
|
1999-06-28 10:36:47 +04:00
|
|
|
continue;
|
2006-03-06 02:47:08 +03:00
|
|
|
if (in6_get_hw_ifid(ifp, in6) != 0)
|
2000-04-12 14:36:38 +04:00
|
|
|
continue;
|
2000-04-16 19:00:56 +04:00
|
|
|
|
2000-04-12 14:36:38 +04:00
|
|
|
/*
|
|
|
|
* to borrow ifid from other interface, ifid needs to be
|
|
|
|
* globally unique
|
|
|
|
*/
|
|
|
|
if (IFID_UNIVERSAL(in6)) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_DEBUG,
|
|
|
|
"%s: borrow interface identifier from %s\n",
|
|
|
|
if_name(ifp0), if_name(ifp)));
|
2000-04-12 14:36:38 +04:00
|
|
|
goto success;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
#if 0
|
|
|
|
/* get from hostid - only for certain architectures */
|
|
|
|
if (get_hostid_ifid(ifp, in6) == 0) {
|
|
|
|
nd6log((LOG_DEBUG,
|
|
|
|
"%s: interface identifier generated by hostid\n",
|
|
|
|
if_name(ifp0)));
|
|
|
|
goto success;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-04-12 14:36:38 +04:00
|
|
|
/* last resort: get from random number source */
|
|
|
|
if (get_rand_ifid(ifp, in6) == 0) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_DEBUG,
|
|
|
|
"%s: interface identifier generated by random number\n",
|
|
|
|
if_name(ifp0)));
|
2000-04-12 14:36:38 +04:00
|
|
|
goto success;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-10-01 14:56:02 +04:00
|
|
|
printf("%s: failed to get interface identifier\n", if_name(ifp0));
|
2000-04-12 14:36:38 +04:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
success:
|
2002-06-07 08:30:40 +04:00
|
|
|
nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
|
|
if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
|
|
|
|
in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
|
|
|
|
in6->s6_addr[14], in6->s6_addr[15]));
|
2000-04-12 14:36:38 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2002-06-09 01:22:29 +04:00
|
|
|
in6_ifattach_linklocal(ifp, altifp)
|
2000-04-12 14:36:38 +04:00
|
|
|
struct ifnet *ifp;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct ifnet *altifp; /*secondary EUI64 source*/
|
2000-04-12 14:36:38 +04:00
|
|
|
{
|
2002-06-09 01:22:29 +04:00
|
|
|
struct in6_ifaddr *ia;
|
|
|
|
struct in6_aliasreq ifra;
|
2006-03-06 02:47:08 +03:00
|
|
|
struct nd_prefixctl pr0;
|
2002-06-09 01:22:29 +04:00
|
|
|
int i, error;
|
2000-04-12 14:36:38 +04:00
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* configure link-local address.
|
2000-04-12 14:36:38 +04:00
|
|
|
*/
|
2006-03-06 02:47:08 +03:00
|
|
|
memset(&ifra, 0, sizeof(ifra));
|
2000-04-12 14:36:38 +04:00
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* in6_update_ifa() does not use ifra_name, but we accurately set it
|
|
|
|
* for safety.
|
2000-04-12 14:36:38 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
|
|
|
|
|
|
|
|
ifra.ifra_addr.sin6_family = AF_INET6;
|
|
|
|
ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000);
|
2002-06-09 01:22:29 +04:00
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
|
|
|
|
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
|
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
|
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
|
|
|
|
} else {
|
|
|
|
if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
|
|
|
|
nd6log((LOG_ERR,
|
|
|
|
"%s: no ifid available\n", if_name(ifp)));
|
2002-09-11 06:46:42 +04:00
|
|
|
return (-1);
|
2000-04-12 14:36:38 +04:00
|
|
|
}
|
|
|
|
}
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL))
|
|
|
|
return (-1);
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
ifra.ifra_prefixmask.sin6_family = AF_INET6;
|
|
|
|
ifra.ifra_prefixmask.sin6_addr = in6mask64;
|
|
|
|
/* link-local addresses should NEVER expire. */
|
|
|
|
ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
|
|
|
|
ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* Now call in6_update_ifa() to do a bunch of procedures to configure
|
|
|
|
* a link-local address. We can set NULL to the 3rd argument, because
|
|
|
|
* we know there's no other link-local address on the interface
|
|
|
|
* and therefore we are adding one (instead of updating one).
|
|
|
|
*/
|
2006-03-06 02:47:08 +03:00
|
|
|
if ((error = in6_update_ifa(ifp, &ifra, NULL,
|
|
|
|
IN6_IFAUPDATE_DADDELAY)) != 0) {
|
2000-04-12 14:36:38 +04:00
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* XXX: When the interface does not support IPv6, this call
|
|
|
|
* would fail in the SIOCSIFADDR ioctl. I believe the
|
|
|
|
* notification is rather confusing in this case, so just
|
|
|
|
* suppress it. (jinmei@kame.net 20010130)
|
2000-04-12 14:36:38 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
if (error != EAFNOSUPPORT)
|
2002-06-11 11:28:05 +04:00
|
|
|
nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
|
2002-06-09 01:22:29 +04:00
|
|
|
"configure a link-local address on %s "
|
|
|
|
"(errno=%d)\n",
|
2002-06-11 11:28:05 +04:00
|
|
|
if_name(ifp), error));
|
2002-09-11 06:46:42 +04:00
|
|
|
return (-1);
|
2000-04-12 14:36:38 +04:00
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (!ia) {
|
|
|
|
panic("ia == NULL in in6_ifattach_linklocal");
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
#endif
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* Make the link-local prefix (fe80::/64%link) as on-link.
|
|
|
|
* Since we'd like to manage prefixes separately from addresses,
|
|
|
|
* we make an ND6 prefix structure for the link-local prefix,
|
|
|
|
* and add it to the prefix list as a never-expire prefix.
|
|
|
|
* XXX: this change might affect some existing code base...
|
|
|
|
*/
|
2006-03-06 02:47:08 +03:00
|
|
|
memset(&pr0, 0, sizeof(pr0));
|
2002-06-09 01:22:29 +04:00
|
|
|
pr0.ndpr_ifp = ifp;
|
|
|
|
/* this should be 64 at this moment. */
|
|
|
|
pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
|
|
|
|
pr0.ndpr_prefix = ifra.ifra_addr;
|
|
|
|
/* apply the mask for safety. (nd6_prelist_add will apply it again) */
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
|
|
|
|
in6mask64.s6_addr32[i];
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Initialize parameters. The link-local prefix must always be
|
|
|
|
* on-link, and its lifetimes never expire.
|
|
|
|
*/
|
|
|
|
pr0.ndpr_raf_onlink = 1;
|
|
|
|
pr0.ndpr_raf_auto = 1; /* probably meaningless */
|
|
|
|
pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
|
|
|
|
pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
|
|
|
|
/*
|
|
|
|
* Since there is no other link-local addresses, nd6_prefix_lookup()
|
|
|
|
* probably returns NULL. However, we cannot always expect the result.
|
|
|
|
* For example, if we first remove the (only) existing link-local
|
|
|
|
* address, and then reconfigure another one, the prefix is still
|
|
|
|
* valid with referring to the old link-local address.
|
|
|
|
*/
|
|
|
|
if (nd6_prefix_lookup(&pr0) == NULL) {
|
|
|
|
if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (error);
|
2000-04-12 14:36:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
in6_ifattach_loopback(ifp)
|
|
|
|
struct ifnet *ifp; /* must be IFT_LOOP */
|
|
|
|
{
|
2002-06-09 01:22:29 +04:00
|
|
|
struct in6_aliasreq ifra;
|
|
|
|
int error;
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
memset(&ifra, 0, sizeof(ifra));
|
2000-04-12 14:36:38 +04:00
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* in6_update_ifa() does not use ifra_name, but we accurately set it
|
|
|
|
* for safety.
|
2000-04-12 14:36:38 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
|
|
|
|
|
|
|
|
ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
ifra.ifra_prefixmask.sin6_family = AF_INET6;
|
|
|
|
ifra.ifra_prefixmask.sin6_addr = in6mask128;
|
2000-04-12 14:36:38 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Always initialize ia_dstaddr (= broadcast address) to loopback
|
2002-06-09 01:22:29 +04:00
|
|
|
* address. Follows IPv4 practice - see in_ifinit().
|
2000-04-12 14:36:38 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
ifra.ifra_dstaddr.sin6_family = AF_INET6;
|
|
|
|
ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
|
|
|
|
|
|
|
|
ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
ifra.ifra_addr.sin6_family = AF_INET6;
|
|
|
|
ifra.ifra_addr.sin6_addr = in6addr_loopback;
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* the loopback address should NEVER expire. */
|
|
|
|
ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
|
|
|
|
ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* we don't need to perform DAD on loopback interfaces. */
|
|
|
|
ifra.ifra_flags |= IN6_IFF_NODAD;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We are sure that this is a newly assigned address, so we can set
|
|
|
|
* NULL to the 3rd arg.
|
|
|
|
*/
|
2006-03-06 02:47:08 +03:00
|
|
|
if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) {
|
2002-06-11 11:28:05 +04:00
|
|
|
nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure "
|
2002-06-09 01:22:29 +04:00
|
|
|
"the loopback address on %s (errno=%d)\n",
|
2002-06-11 11:28:05 +04:00
|
|
|
if_name(ifp), error));
|
2002-09-11 06:46:42 +04:00
|
|
|
return (-1);
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* compute NI group address, based on the current hostname setting.
|
|
|
|
* see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
|
|
|
|
*
|
|
|
|
* when ifp == NULL, the caller is responsible for filling scopeid.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
in6_nigroup(ifp, name, namelen, sa6)
|
|
|
|
struct ifnet *ifp;
|
|
|
|
const char *name;
|
|
|
|
int namelen;
|
|
|
|
struct sockaddr_in6 *sa6;
|
|
|
|
{
|
|
|
|
const char *p;
|
2002-09-11 07:23:24 +04:00
|
|
|
u_int8_t *q;
|
2002-06-09 01:22:29 +04:00
|
|
|
MD5_CTX ctxt;
|
|
|
|
u_int8_t digest[16];
|
2002-09-11 06:41:19 +04:00
|
|
|
u_int8_t l;
|
|
|
|
u_int8_t n[64]; /* a single label must not exceed 63 chars */
|
2002-06-09 01:22:29 +04:00
|
|
|
|
|
|
|
if (!namelen || !name)
|
2000-04-12 14:36:38 +04:00
|
|
|
return -1;
|
2002-06-09 01:22:29 +04:00
|
|
|
|
|
|
|
p = name;
|
|
|
|
while (p && *p && *p != '.' && p - name < namelen)
|
|
|
|
p++;
|
|
|
|
if (p - name > sizeof(n) - 1)
|
|
|
|
return -1; /* label too long */
|
|
|
|
l = p - name;
|
2002-09-11 06:41:19 +04:00
|
|
|
strncpy((char *)n, name, l);
|
2002-06-09 01:22:29 +04:00
|
|
|
n[(int)l] = '\0';
|
|
|
|
for (q = n; *q; q++) {
|
|
|
|
if ('A' <= *q && *q <= 'Z')
|
|
|
|
*q = *q - 'A' + 'a';
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* generate 8 bytes of pseudo-random value. */
|
2006-03-06 02:47:08 +03:00
|
|
|
memset(&ctxt, 0, sizeof(ctxt));
|
2002-06-09 01:22:29 +04:00
|
|
|
MD5Init(&ctxt);
|
|
|
|
MD5Update(&ctxt, &l, sizeof(l));
|
|
|
|
MD5Update(&ctxt, n, l);
|
|
|
|
MD5Final(digest, &ctxt);
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
memset(sa6, 0, sizeof(*sa6));
|
2002-06-09 01:22:29 +04:00
|
|
|
sa6->sin6_family = AF_INET6;
|
|
|
|
sa6->sin6_len = sizeof(*sa6);
|
|
|
|
sa6->sin6_addr.s6_addr16[0] = htons(0xff02);
|
|
|
|
sa6->sin6_addr.s6_addr8[11] = 2;
|
2006-03-06 02:47:08 +03:00
|
|
|
memcpy(&sa6->sin6_addr.s6_addr32[3], digest,
|
2002-06-09 01:22:29 +04:00
|
|
|
sizeof(sa6->sin6_addr.s6_addr32[3]));
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (in6_setscope(&sa6->sin6_addr, ifp, NULL))
|
|
|
|
return (-1); /* XXX: should not fail */
|
2002-06-09 01:22:29 +04:00
|
|
|
|
2000-04-12 14:36:38 +04:00
|
|
|
return 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2000-02-02 19:58:10 +03:00
|
|
|
/*
|
|
|
|
* XXX multiple loopback interface needs more care. for instance,
|
|
|
|
* nodelocal address needs to be configured onto only one of them.
|
2000-04-12 14:36:38 +04:00
|
|
|
* XXX multiple link-local address case
|
2000-02-02 19:58:10 +03:00
|
|
|
*/
|
1999-06-28 10:36:47 +04:00
|
|
|
void
|
2000-04-12 14:36:38 +04:00
|
|
|
in6_ifattach(ifp, altifp)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ifnet *ifp;
|
2000-04-12 14:36:38 +04:00
|
|
|
struct ifnet *altifp; /* secondary EUI64 source */
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2000-04-12 14:36:38 +04:00
|
|
|
struct in6_ifaddr *ia;
|
|
|
|
struct in6_addr in6;
|
1999-12-13 18:17:17 +03:00
|
|
|
|
2001-08-23 06:58:24 +04:00
|
|
|
/* some of the interfaces are inherently not IPv6 capable */
|
|
|
|
switch (ifp->if_type) {
|
2002-05-23 10:25:25 +04:00
|
|
|
case IFT_BRIDGE:
|
2004-02-11 20:36:33 +03:00
|
|
|
#ifdef IFT_PFLOG
|
2004-02-11 13:42:24 +03:00
|
|
|
case IFT_PFLOG:
|
2004-02-11 20:36:33 +03:00
|
|
|
#endif
|
|
|
|
#ifdef IFT_PFSYNC
|
2004-02-11 13:42:24 +03:00
|
|
|
case IFT_PFSYNC:
|
2004-02-11 20:36:33 +03:00
|
|
|
#endif
|
2002-05-23 10:25:25 +04:00
|
|
|
return;
|
2001-08-23 06:58:24 +04:00
|
|
|
}
|
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
/*
|
|
|
|
* if link mtu is too small, don't try to configure IPv6.
|
|
|
|
* remember there could be some link-layer that has special
|
|
|
|
* fragmentation logic.
|
|
|
|
*/
|
2002-06-11 11:28:05 +04:00
|
|
|
if (ifp->if_mtu < IPV6_MMTU) {
|
|
|
|
nd6log((LOG_INFO, "in6_ifattach: "
|
|
|
|
"%s has too small MTU, IPv6 not enabled\n",
|
|
|
|
if_name(ifp)));
|
2002-05-29 11:53:39 +04:00
|
|
|
return;
|
2002-06-11 11:28:05 +04:00
|
|
|
}
|
2002-05-29 11:53:39 +04:00
|
|
|
|
2001-07-18 17:12:27 +04:00
|
|
|
/* create a multicast kludge storage (if we have not had one) */
|
|
|
|
in6_createmkludge(ifp);
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
2000-04-12 14:36:38 +04:00
|
|
|
* quirks based on interface type
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2000-04-12 14:36:38 +04:00
|
|
|
switch (ifp->if_type) {
|
|
|
|
#ifdef IFT_STF
|
|
|
|
case IFT_STF:
|
|
|
|
/*
|
2001-08-23 06:58:24 +04:00
|
|
|
* 6to4 interface is a very special kind of beast.
|
|
|
|
* no multicast, no linklocal. RFC2529 specifies how to make
|
|
|
|
* linklocals for 6to4 interface, but there's no use and
|
|
|
|
* it is rather harmful to have one.
|
2000-04-12 14:36:38 +04:00
|
|
|
*/
|
2002-05-29 11:53:39 +04:00
|
|
|
return;
|
2000-04-12 14:36:38 +04:00
|
|
|
#endif
|
2006-05-18 13:05:49 +04:00
|
|
|
case IFT_CARP:
|
|
|
|
return;
|
2000-04-12 14:36:38 +04:00
|
|
|
default:
|
|
|
|
break;
|
1999-09-13 16:15:54 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
2000-04-12 14:36:38 +04:00
|
|
|
* usually, we require multicast capability to the interface
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2000-04-12 14:36:38 +04:00
|
|
|
if ((ifp->if_flags & IFF_MULTICAST) == 0) {
|
2002-06-11 11:28:05 +04:00
|
|
|
nd6log((LOG_INFO, "in6_ifattach: "
|
2001-08-23 06:58:24 +04:00
|
|
|
"%s is not multicast capable, IPv6 not enabled\n",
|
2002-06-11 11:28:05 +04:00
|
|
|
if_name(ifp)));
|
2000-04-12 14:36:38 +04:00
|
|
|
return;
|
|
|
|
}
|
2000-02-02 01:52:04 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* assign loopback address for loopback interface.
|
|
|
|
* XXX multiple loopback interface case.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
|
|
|
|
in6 = in6addr_loopback;
|
2000-04-12 14:36:38 +04:00
|
|
|
if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
|
|
|
|
if (in6_ifattach_loopback(ifp) != 0)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* assign a link-local address, if there's none.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
if (ip6_auto_linklocal) {
|
|
|
|
ia = in6ifa_ifpforlinklocal(ifp, 0);
|
|
|
|
if (ia == NULL) {
|
|
|
|
if (in6_ifattach_linklocal(ifp, altifp) == 0) {
|
|
|
|
/* linklocal address assigned */
|
|
|
|
} else {
|
|
|
|
/* failed to assign linklocal address. bark? */
|
2000-04-12 14:36:38 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-02 19:58:10 +03:00
|
|
|
/*
|
|
|
|
* NOTE: in6_ifdetach() does not support loopback if at this moment.
|
2001-12-21 11:54:52 +03:00
|
|
|
* We don't need this function in bsdi, because interfaces are never removed
|
|
|
|
* from the ifnet list in bsdi.
|
2000-02-02 19:58:10 +03:00
|
|
|
*/
|
1999-06-28 10:36:47 +04:00
|
|
|
void
|
|
|
|
in6_ifdetach(ifp)
|
|
|
|
struct ifnet *ifp;
|
|
|
|
{
|
|
|
|
struct in6_ifaddr *ia, *oia;
|
2000-05-05 12:03:12 +04:00
|
|
|
struct ifaddr *ifa, *next;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct rtentry *rt;
|
|
|
|
short rtflags;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct in6_multi_mship *imm;
|
2000-02-04 17:34:22 +03:00
|
|
|
|
2003-07-08 14:20:45 +04:00
|
|
|
/* remove ip6_mrouter stuff */
|
|
|
|
ip6_mrouter_detach(ifp);
|
|
|
|
|
2000-02-04 17:34:22 +03:00
|
|
|
/* remove neighbor management table */
|
|
|
|
nd6_purge(ifp);
|
|
|
|
|
2000-05-05 12:03:12 +04:00
|
|
|
/* nuke any of IPv6 addresses we have */
|
2006-11-20 07:16:27 +03:00
|
|
|
for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa; ifa = next) {
|
|
|
|
next = TAILQ_NEXT(ifa, ifa_list);
|
2000-05-05 12:03:12 +04:00
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET6)
|
|
|
|
continue;
|
2002-06-09 01:22:29 +04:00
|
|
|
in6_purgeaddr(ifa);
|
2000-05-05 12:03:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* undo everything done by in6_ifattach(), just in case */
|
2006-11-20 07:16:27 +03:00
|
|
|
for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa; ifa = next) {
|
|
|
|
next = TAILQ_NEXT(ifa, ifa_list);
|
2000-05-05 12:03:12 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET6
|
|
|
|
|| !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ia = (struct in6_ifaddr *)ifa;
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* leave from multicast groups we have joined for the interface
|
|
|
|
*/
|
2006-11-20 07:16:27 +03:00
|
|
|
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
|
2002-06-09 01:22:29 +04:00
|
|
|
LIST_REMOVE(imm, i6mm_chain);
|
|
|
|
in6_leavegroup(imm);
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* remove from the routing table */
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((ia->ia_flags & IFA_ROUTE) &&
|
|
|
|
(rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
|
1999-06-28 10:36:47 +04:00
|
|
|
rtflags = rt->rt_flags;
|
|
|
|
rtfree(rt);
|
2002-06-07 08:30:40 +04:00
|
|
|
rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
|
|
|
|
(struct sockaddr *)&ia->ia_addr,
|
|
|
|
(struct sockaddr *)&ia->ia_prefixmask,
|
|
|
|
rtflags, (struct rtentry **)0);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* remove from the linked list */
|
2006-11-20 07:16:27 +03:00
|
|
|
TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
|
2000-05-05 12:03:12 +04:00
|
|
|
IFAFREE(&ia->ia_ifa);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* also remove from the IPv6 address chain(itojun&jinmei) */
|
|
|
|
oia = ia;
|
|
|
|
if (oia == (ia = in6_ifaddr))
|
|
|
|
in6_ifaddr = ia->ia_next;
|
|
|
|
else {
|
|
|
|
while (ia->ia_next && (ia->ia_next != oia))
|
|
|
|
ia = ia->ia_next;
|
|
|
|
if (ia->ia_next)
|
|
|
|
ia->ia_next = oia->ia_next;
|
2001-02-07 11:59:47 +03:00
|
|
|
else {
|
2002-06-09 01:22:29 +04:00
|
|
|
nd6log((LOG_ERR,
|
2002-06-07 08:30:40 +04:00
|
|
|
"%s: didn't unlink in6ifaddr from list\n",
|
|
|
|
if_name(ifp)));
|
2001-02-07 11:59:47 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2000-05-05 12:03:12 +04:00
|
|
|
IFAFREE(&oia->ia_ifa);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2000-02-02 16:44:05 +03:00
|
|
|
|
2000-02-02 19:58:10 +03:00
|
|
|
/* cleanup multicast address kludge table, if there is any */
|
|
|
|
in6_purgemkludge(ifp);
|
2000-02-04 17:34:22 +03:00
|
|
|
|
2001-12-21 11:54:52 +03:00
|
|
|
/*
|
|
|
|
* remove neighbor management table. we call it twice just to make
|
|
|
|
* sure we nuke everything. maybe we need just one call.
|
|
|
|
* XXX: since the first call did not release addresses, some prefixes
|
|
|
|
* might remain. We should call nd6_purge() again to release the
|
|
|
|
* prefixes after removing all addresses above.
|
|
|
|
* (Or can we just delay calling nd6_purge until at this point?)
|
|
|
|
*/
|
2000-05-05 12:03:12 +04:00
|
|
|
nd6_purge(ifp);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2006-03-06 02:47:08 +03:00
|
|
|
|
|
|
|
int
|
|
|
|
in6_get_tmpifid(ifp, retbuf, baseid, generate)
|
|
|
|
struct ifnet *ifp;
|
|
|
|
u_int8_t *retbuf;
|
|
|
|
const u_int8_t *baseid;
|
|
|
|
int generate;
|
|
|
|
{
|
|
|
|
u_int8_t nullbuf[8];
|
|
|
|
struct nd_ifinfo *ndi = ND_IFINFO(ifp);
|
|
|
|
|
|
|
|
memset(nullbuf, 0, sizeof(nullbuf));
|
|
|
|
if (memcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
|
|
|
|
/* we've never created a random ID. Create a new one. */
|
|
|
|
generate = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (generate) {
|
|
|
|
memcpy(ndi->randomseed1, baseid, sizeof(ndi->randomseed1));
|
|
|
|
|
|
|
|
/* generate_tmp_ifid will update seedn and buf */
|
|
|
|
(void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
|
|
|
|
ndi->randomid);
|
|
|
|
}
|
|
|
|
memcpy(retbuf, ndi->randomid, 8);
|
|
|
|
if (generate && memcmp(retbuf, nullbuf, sizeof(nullbuf)) == 0) {
|
|
|
|
/* generate_tmp_ifid could not found a good ID. */
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
in6_tmpaddrtimer(void *ignored_arg)
|
2006-03-06 02:47:08 +03:00
|
|
|
{
|
|
|
|
struct nd_ifinfo *ndi;
|
|
|
|
u_int8_t nullbuf[8];
|
|
|
|
struct ifnet *ifp;
|
|
|
|
int s = splsoftnet();
|
|
|
|
|
|
|
|
callout_reset(&in6_tmpaddrtimer_ch,
|
|
|
|
(ip6_temp_preferred_lifetime - ip6_desync_factor -
|
|
|
|
ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL);
|
|
|
|
|
|
|
|
memset(nullbuf, 0, sizeof(nullbuf));
|
|
|
|
for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
|
|
|
|
ndi = ND_IFINFO(ifp);
|
|
|
|
if (memcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
|
|
|
|
/*
|
|
|
|
* We've been generating a random ID on this interface.
|
|
|
|
* Create a new one.
|
|
|
|
*/
|
|
|
|
(void)generate_tmp_ifid(ndi->randomseed0,
|
|
|
|
ndi->randomseed1, ndi->randomid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
splx(s);
|
|
|
|
}
|