2005-01-07 02:30:35 +00:00
|
|
|
/*-
|
1999-11-22 02:45:11 +00:00
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* 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. 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.
|
|
|
|
*
|
|
|
|
* 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.
|
2007-12-10 16:03:40 +00:00
|
|
|
*
|
|
|
|
* $KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $
|
1999-11-22 02:45:11 +00:00
|
|
|
*/
|
|
|
|
|
2007-12-10 16:03:40 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
1999-11-22 02:45:11 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <sys/kernel.h>
|
2001-06-11 12:39:29 +00:00
|
|
|
#include <sys/syslog.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
#include <sys/md5.h>
|
|
|
|
|
|
|
|
#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>
|
|
|
|
#include <netinet/if_ether.h>
|
2001-08-04 17:10:14 +00:00
|
|
|
#include <netinet/in_pcb.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
#include <netinet/ip6.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
#include <netinet6/ip6_var.h>
|
2001-06-11 12:39:29 +00:00
|
|
|
#include <netinet6/in6_var.h>
|
2001-08-04 17:10:14 +00:00
|
|
|
#include <netinet6/in6_pcb.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
#include <netinet6/in6_ifattach.h>
|
|
|
|
#include <netinet6/ip6_var.h>
|
|
|
|
#include <netinet6/nd6.h>
|
2000-07-04 16:35:15 +00:00
|
|
|
#include <netinet6/scope6_var.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
unsigned long in6_maxmtu = 0;
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
#ifdef IP6_AUTO_LINKLOCAL
|
|
|
|
int ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;
|
|
|
|
#else
|
2006-10-13 12:41:36 +00:00
|
|
|
int ip6_auto_linklocal = 1; /* enable by default */
|
2001-06-11 12:39:29 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
struct callout in6_tmpaddrtimer_ch;
|
|
|
|
|
2001-08-04 17:10:14 +00:00
|
|
|
extern struct inpcbinfo udbinfo;
|
|
|
|
extern struct inpcbinfo ripcbinfo;
|
|
|
|
|
2008-01-08 19:08:58 +00:00
|
|
|
static int get_rand_ifid(struct ifnet *, struct in6_addr *);
|
|
|
|
static int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *);
|
|
|
|
static int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
|
|
|
|
static int in6_ifattach_linklocal(struct ifnet *, struct ifnet *);
|
|
|
|
static int in6_ifattach_loopback(struct ifnet *);
|
|
|
|
static void in6_purgemaddrs(struct ifnet *);
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
#define EUI64_GBIT 0x01
|
|
|
|
#define EUI64_UBIT 0x02
|
|
|
|
#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
|
|
|
|
#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))
|
|
|
|
|
|
|
|
#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6))
|
|
|
|
#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6))
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Generate a last-resort interface identifier, when the machine has no
|
|
|
|
* IEEE802/EUI64 address sources.
|
2000-07-04 16:35:15 +00: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.
|
2007-07-05 16:23:49 +00:00
|
|
|
*
|
|
|
|
* in6 - upper 64bits are preserved
|
1999-11-22 02:45:11 +00:00
|
|
|
*/
|
|
|
|
static int
|
2007-07-05 16:23:49 +00:00
|
|
|
get_rand_ifid(struct ifnet *ifp, struct in6_addr *in6)
|
1999-11-22 02:45:11 +00:00
|
|
|
{
|
|
|
|
MD5_CTX ctxt;
|
|
|
|
u_int8_t digest[16];
|
|
|
|
int hostnamelen = strlen(hostname);
|
|
|
|
|
2000-07-04 16:35:15 +00: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. */
|
1999-11-22 02:45:11 +00:00
|
|
|
bzero(&ctxt, sizeof(ctxt));
|
|
|
|
MD5Init(&ctxt);
|
|
|
|
MD5Update(&ctxt, hostname, hostnamelen);
|
|
|
|
MD5Final(digest, &ctxt);
|
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
/* assumes sizeof(digest) > sizeof(ifid) */
|
|
|
|
bcopy(digest, &in6->s6_addr[8], 8);
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
/* make sure to set "u" bit to local, and "g" bit to individual. */
|
2000-07-04 16:35:15 +00: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-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
static int
|
2007-07-05 16:23:49 +00:00
|
|
|
generate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret)
|
2001-06-11 12:39:29 +00:00
|
|
|
{
|
|
|
|
MD5_CTX ctxt;
|
|
|
|
u_int8_t seed[16], digest[16], nullbuf[8];
|
|
|
|
u_int32_t val32;
|
|
|
|
|
2007-07-05 16:23:49 +00:00
|
|
|
/* If there's no history, start with a random seed. */
|
2001-06-11 12:39:29 +00:00
|
|
|
bzero(nullbuf, sizeof(nullbuf));
|
|
|
|
if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
2003-10-31 16:06:05 +00:00
|
|
|
val32 = arc4random();
|
2001-06-11 12:39:29 +00:00
|
|
|
bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));
|
|
|
|
}
|
2003-10-08 18:26:08 +00:00
|
|
|
} else
|
2001-06-11 12:39:29 +00:00
|
|
|
bcopy(seed0, seed, 8);
|
|
|
|
|
|
|
|
/* copy the right-most 64-bits of the given address */
|
|
|
|
/* XXX assumption on the size of IFID */
|
|
|
|
bcopy(seed1, &seed[8], 8);
|
|
|
|
|
|
|
|
if (0) { /* for debugging purposes only */
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printf("generate_tmp_ifid: new randomized ID from: ");
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
printf("%02x", seed[i]);
|
|
|
|
printf(" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate 16 bytes of pseudo-random value. */
|
|
|
|
bzero(&ctxt, sizeof(ctxt));
|
|
|
|
MD5Init(&ctxt);
|
|
|
|
MD5Update(&ctxt, seed, sizeof(seed));
|
|
|
|
MD5Final(digest, &ctxt);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* RFC 3041 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.
|
|
|
|
*/
|
|
|
|
bcopy(digest, ret, 8);
|
|
|
|
ret[0] &= ~EUI64_UBIT;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: we'd like to ensure that the generated value is not zero
|
|
|
|
* for simplicity. If the caclculated digest happens to be zero,
|
|
|
|
* use a random non-zero value as the last resort.
|
|
|
|
*/
|
|
|
|
if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) {
|
2005-10-19 10:09:19 +00:00
|
|
|
nd6log((LOG_INFO,
|
|
|
|
"generate_tmp_ifid: computed MD5 value is zero.\n"));
|
2001-06-11 12:39:29 +00:00
|
|
|
|
2003-10-31 16:06:05 +00:00
|
|
|
val32 = arc4random();
|
2001-06-11 12:39:29 +00:00
|
|
|
val32 = 1 + (val32 % (0xffffffff - 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* RFC 3041 3.2.1. (4)
|
|
|
|
* 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
|
2003-10-08 18:26:08 +00:00
|
|
|
* iteration of the algorithm.
|
2001-06-11 12:39:29 +00:00
|
|
|
*/
|
|
|
|
bcopy(&digest[8], seed0, 8);
|
|
|
|
|
|
|
|
if (0) { /* for debugging purposes only */
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printf("to: ");
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
printf("%02x", digest[i]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1999-11-22 02:45:11 +00:00
|
|
|
/*
|
2000-07-04 16:35:15 +00:00
|
|
|
* Get interface identifier for the specified interface.
|
|
|
|
* XXX assumes single sockaddr_dl (AF_LINK address) per an interface
|
2007-07-05 16:23:49 +00:00
|
|
|
*
|
|
|
|
* in6 - upper 64bits are preserved
|
1999-11-22 02:45:11 +00:00
|
|
|
*/
|
2005-10-19 16:43:57 +00:00
|
|
|
int
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
|
2000-07-04 16:35:15 +00:00
|
|
|
{
|
1999-11-22 02:45:11 +00:00
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct sockaddr_dl *sdl;
|
2000-07-04 16:35:15 +00:00
|
|
|
u_int8_t *addr;
|
|
|
|
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 };
|
|
|
|
|
|
|
|
for (ifa = ifp->if_addrlist.tqh_first;
|
|
|
|
ifa;
|
2003-10-08 18:26:08 +00:00
|
|
|
ifa = ifa->ifa_list.tqe_next) {
|
2000-07-04 16:35:15 +00:00
|
|
|
if (ifa->ifa_addr->sa_family != AF_LINK)
|
1999-11-22 02:45:11 +00:00
|
|
|
continue;
|
2000-07-04 16:35:15 +00:00
|
|
|
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
|
|
|
|
if (sdl == NULL)
|
|
|
|
continue;
|
|
|
|
if (sdl->sdl_alen == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
goto found;
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
return -1;
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
found:
|
2000-07-04 16:35:15 +00:00
|
|
|
addr = LLADDR(sdl);
|
|
|
|
addrlen = sdl->sdl_alen;
|
|
|
|
|
|
|
|
/* get EUI64 */
|
|
|
|
switch (ifp->if_type) {
|
|
|
|
case IFT_ETHER:
|
|
|
|
case IFT_FDDI:
|
2003-09-14 02:32:31 +00:00
|
|
|
case IFT_ISO88025:
|
2000-07-04 16:35:15 +00:00
|
|
|
case IFT_ATM:
|
2001-06-11 12:39:29 +00:00
|
|
|
case IFT_IEEE1394:
|
|
|
|
#ifdef IFT_IEEE80211
|
|
|
|
case IFT_IEEE80211:
|
|
|
|
#endif
|
2000-07-04 16:35:15 +00:00
|
|
|
/* IEEE802/EUI64 cases - what others? */
|
2001-06-11 12:39:29 +00:00
|
|
|
/* IEEE1394 uses 16byte length address starting with EUI64 */
|
|
|
|
if (addrlen > 8)
|
|
|
|
addrlen = 8;
|
2000-07-04 16:35:15 +00: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.
|
|
|
|
*/
|
|
|
|
if (bcmp(addr, allzero, addrlen) == 0)
|
|
|
|
return -1;
|
|
|
|
if (bcmp(addr, allone, addrlen) == 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* make EUI64 address */
|
|
|
|
if (addrlen == 8)
|
|
|
|
bcopy(addr, &in6->s6_addr[8], 8);
|
|
|
|
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;
|
|
|
|
in6->s6_addr[12] = 0xfe;
|
|
|
|
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;
|
|
|
|
|
|
|
|
bzero(&in6->s6_addr[8], 8);
|
|
|
|
in6->s6_addr[15] = addr[0];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* due to insufficient bitwidth, we mark it local.
|
|
|
|
*/
|
|
|
|
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:
|
1999-11-22 02:45:11 +00:00
|
|
|
#endif
|
2000-07-04 16:35:15 +00:00
|
|
|
/*
|
2001-06-11 12:39:29 +00:00
|
|
|
* RFC2893 says: "SHOULD use IPv4 address as ifid source".
|
2000-07-04 16:35:15 +00:00
|
|
|
* however, IPv4 address is not very suitable as unique
|
|
|
|
* identifier source (can be renumbered).
|
|
|
|
* we don't do this.
|
|
|
|
*/
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -1;
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/* 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 &&
|
|
|
|
bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-07-04 16:35:15 +00:00
|
|
|
* Get interface identifier for the specified interface. If it is not
|
|
|
|
* available on ifp0, borrow interface identifier from other information
|
|
|
|
* sources.
|
2007-07-05 16:23:49 +00:00
|
|
|
*
|
|
|
|
* altifp - secondary EUI64 source
|
1999-11-22 02:45:11 +00:00
|
|
|
*/
|
2000-07-04 16:35:15 +00:00
|
|
|
static int
|
2007-07-05 16:23:49 +00:00
|
|
|
get_ifid(struct ifnet *ifp0, struct ifnet *altifp,
|
|
|
|
struct in6_addr *in6)
|
1999-11-22 02:45:11 +00:00
|
|
|
{
|
|
|
|
struct ifnet *ifp;
|
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
/* first, try to get it from the interface itself */
|
2005-10-19 16:43:57 +00:00
|
|
|
if (in6_get_hw_ifid(ifp0, in6) == 0) {
|
2001-06-11 12:39:29 +00:00
|
|
|
nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
|
|
|
|
if_name(ifp0)));
|
2000-07-04 16:35:15 +00:00
|
|
|
goto success;
|
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
/* try secondary EUI64 source. this basically is for ATM PVC */
|
2005-10-19 16:43:57 +00:00
|
|
|
if (altifp && in6_get_hw_ifid(altifp, in6) == 0) {
|
2001-06-11 12:39:29 +00:00
|
|
|
nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
|
|
|
|
if_name(ifp0), if_name(altifp)));
|
2000-07-04 16:35:15 +00:00
|
|
|
goto success;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* next, try to get it from some other hardware interface */
|
2002-12-22 05:35:03 +00:00
|
|
|
IFNET_RLOCK();
|
2003-10-08 18:26:08 +00:00
|
|
|
for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
|
2000-07-04 16:35:15 +00:00
|
|
|
if (ifp == ifp0)
|
|
|
|
continue;
|
2005-10-19 16:43:57 +00:00
|
|
|
if (in6_get_hw_ifid(ifp, in6) != 0)
|
2000-07-04 16:35:15 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* to borrow ifid from other interface, ifid needs to be
|
|
|
|
* globally unique
|
|
|
|
*/
|
|
|
|
if (IFID_UNIVERSAL(in6)) {
|
2001-06-11 12:39:29 +00:00
|
|
|
nd6log((LOG_DEBUG,
|
|
|
|
"%s: borrow interface identifier from %s\n",
|
|
|
|
if_name(ifp0), if_name(ifp)));
|
2002-12-22 05:35:03 +00:00
|
|
|
IFNET_RUNLOCK();
|
2000-07-04 16:35:15 +00:00
|
|
|
goto success;
|
|
|
|
}
|
|
|
|
}
|
2002-12-22 05:35:03 +00:00
|
|
|
IFNET_RUNLOCK();
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/* last resort: get from random number source */
|
|
|
|
if (get_rand_ifid(ifp, in6) == 0) {
|
2001-06-11 12:39:29 +00:00
|
|
|
nd6log((LOG_DEBUG,
|
|
|
|
"%s: interface identifier generated by random number\n",
|
|
|
|
if_name(ifp0)));
|
2000-07-04 16:35:15 +00:00
|
|
|
goto success;
|
|
|
|
}
|
|
|
|
|
2000-10-01 10:59:02 +00:00
|
|
|
printf("%s: failed to get interface identifier\n", if_name(ifp0));
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
success:
|
2003-10-08 18:26:08 +00: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-07-04 16:35:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-07-05 16:23:49 +00:00
|
|
|
/*
|
|
|
|
* altifp - secondary EUI64 source
|
|
|
|
*/
|
2000-07-04 16:35:15 +00:00
|
|
|
static int
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
|
2000-07-04 16:35:15 +00:00
|
|
|
{
|
2001-06-11 12:39:29 +00:00
|
|
|
struct in6_ifaddr *ia;
|
|
|
|
struct in6_aliasreq ifra;
|
2005-10-21 16:23:01 +00:00
|
|
|
struct nd_prefixctl pr0;
|
2001-06-11 12:39:29 +00:00
|
|
|
int i, error;
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/*
|
2001-06-11 12:39:29 +00:00
|
|
|
* configure link-local address.
|
2000-07-04 16:35:15 +00:00
|
|
|
*/
|
2001-06-11 12:39:29 +00:00
|
|
|
bzero(&ifra, sizeof(ifra));
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/*
|
2001-06-11 12:39:29 +00:00
|
|
|
* in6_update_ifa() does not use ifra_name, but we accurately set it
|
|
|
|
* for safety.
|
2000-07-04 16:35:15 +00:00
|
|
|
*/
|
2001-06-11 12:39:29 +00:00
|
|
|
strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
|
2000-07-04 16:35:15 +00:00
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
ifra.ifra_addr.sin6_family = AF_INET6;
|
|
|
|
ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
|
2005-07-25 12:31:43 +00:00
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000);
|
2001-06-11 12:39:29 +00: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)));
|
2003-10-08 18:26:08 +00:00
|
|
|
return (-1);
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
|
|
|
}
|
2005-07-25 12:31:43 +00:00
|
|
|
if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL))
|
|
|
|
return (-1);
|
2000-07-04 16:35:15 +00:00
|
|
|
|
2001-06-11 12:39:29 +00: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-07-04 16:35:15 +00:00
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
/*
|
|
|
|
* Now call in6_update_ifa() to do a bunch of procedures to configure
|
2005-10-19 10:09:19 +00:00
|
|
|
* a link-local address. We can set the 3rd argument to NULL, because
|
2002-04-19 04:46:24 +00:00
|
|
|
* we know there's no other link-local address on the interface
|
|
|
|
* and therefore we are adding one (instead of updating one).
|
2001-06-11 12:39:29 +00:00
|
|
|
*/
|
2005-10-21 16:23:01 +00:00
|
|
|
if ((error = in6_update_ifa(ifp, &ifra, NULL,
|
|
|
|
IN6_IFAUPDATE_DADDELAY)) != 0) {
|
2000-07-04 16:35:15 +00:00
|
|
|
/*
|
2001-06-11 12:39:29 +00: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
|
2003-10-08 18:26:08 +00:00
|
|
|
* suppress it. (jinmei@kame.net 20010130)
|
2000-07-04 16:35:15 +00:00
|
|
|
*/
|
2001-06-11 12:39:29 +00:00
|
|
|
if (error != EAFNOSUPPORT)
|
2005-10-19 10:09:19 +00:00
|
|
|
nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
|
2001-06-11 12:39:29 +00:00
|
|
|
"configure a link-local address on %s "
|
|
|
|
"(errno=%d)\n",
|
2005-10-19 10:09:19 +00:00
|
|
|
if_name(ifp), error));
|
2003-10-06 14:02:09 +00:00
|
|
|
return (-1);
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (!ia) {
|
|
|
|
panic("ia == NULL in in6_ifattach_linklocal");
|
2002-04-19 04:46:24 +00:00
|
|
|
/* NOTREACHED */
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
#endif
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
/*
|
2003-10-08 18:26:08 +00:00
|
|
|
* Make the link-local prefix (fe80::%link/64) as on-link.
|
2001-06-11 12:39:29 +00:00
|
|
|
* 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...
|
|
|
|
*/
|
|
|
|
bzero(&pr0, sizeof(pr0));
|
|
|
|
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] &=
|
2003-10-08 18:26:08 +00:00
|
|
|
in6mask64.s6_addr32[i];
|
2001-06-11 12:39:29 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* 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)
|
2003-10-06 14:02:09 +00:00
|
|
|
return (error);
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-07-05 16:23:49 +00:00
|
|
|
/*
|
|
|
|
* ifp - must be IFT_LOOP
|
|
|
|
*/
|
2000-07-04 16:35:15 +00:00
|
|
|
static int
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_ifattach_loopback(struct ifnet *ifp)
|
2000-07-04 16:35:15 +00:00
|
|
|
{
|
2001-06-11 12:39:29 +00:00
|
|
|
struct in6_aliasreq ifra;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
bzero(&ifra, sizeof(ifra));
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/*
|
2001-06-11 12:39:29 +00:00
|
|
|
* in6_update_ifa() does not use ifra_name, but we accurately set it
|
|
|
|
* for safety.
|
2000-07-04 16:35:15 +00:00
|
|
|
*/
|
2001-06-11 12:39:29 +00: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-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Always initialize ia_dstaddr (= broadcast address) to loopback
|
2001-06-11 12:39:29 +00:00
|
|
|
* address. Follows IPv4 practice - see in_ifinit().
|
2000-07-04 16:35:15 +00:00
|
|
|
*/
|
2001-06-11 12:39:29 +00:00
|
|
|
ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
ifra.ifra_dstaddr.sin6_family = AF_INET6;
|
|
|
|
ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
|
2000-07-04 16:35:15 +00:00
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
ifra.ifra_addr.sin6_family = AF_INET6;
|
|
|
|
ifra.ifra_addr.sin6_addr = in6addr_loopback;
|
2000-07-04 16:35:15 +00:00
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
/* the loopback address should NEVER expire. */
|
|
|
|
ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
|
|
|
|
ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
|
2000-07-04 16:35:15 +00:00
|
|
|
|
2002-04-19 04:46:24 +00:00
|
|
|
/* we don't need to perform DAD on loopback interfaces. */
|
2001-06-11 12:39:29 +00:00
|
|
|
ifra.ifra_flags |= IN6_IFF_NODAD;
|
|
|
|
|
|
|
|
/* skip registration to the prefix list. XXX should be temporary. */
|
|
|
|
ifra.ifra_flags |= IN6_IFF_NOPFX;
|
|
|
|
|
|
|
|
/*
|
2002-04-19 04:46:24 +00:00
|
|
|
* We are sure that this is a newly assigned address, so we can set
|
|
|
|
* NULL to the 3rd arg.
|
2001-06-11 12:39:29 +00:00
|
|
|
*/
|
2005-10-21 16:23:01 +00:00
|
|
|
if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) {
|
2005-10-19 10:09:19 +00:00
|
|
|
nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure "
|
2001-06-11 12:39:29 +00:00
|
|
|
"the loopback address on %s (errno=%d)\n",
|
2005-10-19 10:09:19 +00:00
|
|
|
if_name(ifp), error));
|
2003-10-06 14:02:09 +00:00
|
|
|
return (-1);
|
2000-07-04 16:35:15 +00: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.
|
|
|
|
*/
|
2001-06-11 12:39:29 +00:00
|
|
|
int
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_nigroup(struct ifnet *ifp, const char *name, int namelen,
|
|
|
|
struct in6_addr *in6)
|
2000-07-04 16:35:15 +00:00
|
|
|
{
|
|
|
|
const char *p;
|
2001-06-11 12:39:29 +00:00
|
|
|
u_char *q;
|
2000-07-04 16:35:15 +00:00
|
|
|
MD5_CTX ctxt;
|
|
|
|
u_int8_t digest[16];
|
|
|
|
char l;
|
2001-06-11 12:39:29 +00:00
|
|
|
char n[64]; /* a single label must not exceed 63 chars */
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
if (!namelen || !name)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
p = name;
|
|
|
|
while (p && *p && *p != '.' && p - name < namelen)
|
|
|
|
p++;
|
2001-06-11 12:39:29 +00:00
|
|
|
if (p - name > sizeof(n) - 1)
|
2002-04-19 04:46:24 +00:00
|
|
|
return -1; /* label too long */
|
2000-07-04 16:35:15 +00:00
|
|
|
l = p - name;
|
2001-06-11 12:39:29 +00:00
|
|
|
strncpy(n, name, l);
|
|
|
|
n[(int)l] = '\0';
|
|
|
|
for (q = n; *q; q++) {
|
|
|
|
if ('A' <= *q && *q <= 'Z')
|
|
|
|
*q = *q - 'A' + 'a';
|
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/* generate 8 bytes of pseudo-random value. */
|
|
|
|
bzero(&ctxt, sizeof(ctxt));
|
|
|
|
MD5Init(&ctxt);
|
|
|
|
MD5Update(&ctxt, &l, sizeof(l));
|
2001-06-11 12:39:29 +00:00
|
|
|
MD5Update(&ctxt, n, l);
|
2000-07-04 16:35:15 +00:00
|
|
|
MD5Final(digest, &ctxt);
|
|
|
|
|
|
|
|
bzero(in6, sizeof(*in6));
|
2005-10-19 10:09:19 +00:00
|
|
|
in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL;
|
2000-07-04 16:35:15 +00:00
|
|
|
in6->s6_addr8[11] = 2;
|
|
|
|
bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
|
2005-07-25 12:31:43 +00:00
|
|
|
if (in6_setscope(in6, ifp, NULL))
|
|
|
|
return (-1); /* XXX: should not fail */
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX multiple loopback interface needs more care. for instance,
|
|
|
|
* nodelocal address needs to be configured onto only one of them.
|
|
|
|
* XXX multiple link-local address case
|
2007-07-05 16:23:49 +00:00
|
|
|
*
|
|
|
|
* altifp - secondary EUI64 source
|
2000-07-04 16:35:15 +00:00
|
|
|
*/
|
|
|
|
void
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
|
2000-07-04 16:35:15 +00:00
|
|
|
{
|
|
|
|
struct in6_ifaddr *ia;
|
|
|
|
struct in6_addr in6;
|
2001-06-11 12:39:29 +00:00
|
|
|
|
|
|
|
/* some of the interfaces are inherently not IPv6 capable */
|
|
|
|
switch (ifp->if_type) {
|
2004-02-26 03:53:54 +00:00
|
|
|
case IFT_PFLOG:
|
|
|
|
case IFT_PFSYNC:
|
2005-02-22 13:04:05 +00:00
|
|
|
case IFT_CARP:
|
2004-02-26 03:53:54 +00:00
|
|
|
return;
|
2001-06-11 12:39:29 +00:00
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
/*
|
2000-07-04 16:35:15 +00:00
|
|
|
* quirks based on interface type
|
1999-11-22 02:45:11 +00:00
|
|
|
*/
|
2000-07-04 16:35:15 +00:00
|
|
|
switch (ifp->if_type) {
|
|
|
|
#ifdef IFT_STF
|
|
|
|
case IFT_STF:
|
|
|
|
/*
|
2002-04-19 04:46:24 +00: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-07-04 16:35:15 +00:00
|
|
|
*/
|
|
|
|
goto statinit;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
break;
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-07-04 16:35:15 +00:00
|
|
|
* usually, we require multicast capability to the interface
|
1999-11-22 02:45:11 +00:00
|
|
|
*/
|
2000-07-04 16:35:15 +00:00
|
|
|
if ((ifp->if_flags & IFF_MULTICAST) == 0) {
|
2005-10-19 10:09:19 +00:00
|
|
|
nd6log((LOG_INFO, "in6_ifattach: "
|
2001-06-11 12:39:29 +00:00
|
|
|
"%s is not multicast capable, IPv6 not enabled\n",
|
2005-10-19 10:09:19 +00:00
|
|
|
if_name(ifp)));
|
2000-07-04 16:35:15 +00:00
|
|
|
return;
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
/*
|
2001-06-11 12:39:29 +00:00
|
|
|
* assign loopback address for loopback interface.
|
|
|
|
* XXX multiple loopback interface case.
|
1999-11-22 02:45:11 +00:00
|
|
|
*/
|
2001-06-11 12:39:29 +00:00
|
|
|
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
|
|
|
|
in6 = in6addr_loopback;
|
2000-07-04 16:35:15 +00:00
|
|
|
if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
|
|
|
|
if (in6_ifattach_loopback(ifp) != 0)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
/*
|
2003-10-08 18:26:08 +00:00
|
|
|
* assign a link-local address, if there's none.
|
1999-11-22 02:45:11 +00:00
|
|
|
*/
|
2005-09-06 21:11:59 +00:00
|
|
|
if (ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) {
|
2001-06-11 12:39:29 +00:00
|
|
|
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-07-04 16:35:15 +00:00
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
#ifdef IFT_STF /* XXX */
|
2003-10-08 18:26:08 +00:00
|
|
|
statinit:
|
2001-06-11 12:39:29 +00:00
|
|
|
#endif
|
2000-07-04 16:35:15 +00:00
|
|
|
|
1999-11-22 02:45:11 +00:00
|
|
|
/* update dynamically. */
|
|
|
|
if (in6_maxmtu < ifp->if_mtu)
|
|
|
|
in6_maxmtu = ifp->if_mtu;
|
|
|
|
}
|
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
/*
|
|
|
|
* NOTE: in6_ifdetach() does not support loopback if at this moment.
|
2001-06-11 12:39:29 +00:00
|
|
|
* We don't need this function in bsdi, because interfaces are never removed
|
|
|
|
* from the ifnet list in bsdi.
|
2000-07-04 16:35:15 +00:00
|
|
|
*/
|
1999-11-22 02:45:11 +00:00
|
|
|
void
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_ifdetach(struct ifnet *ifp)
|
1999-11-22 02:45:11 +00:00
|
|
|
{
|
|
|
|
struct in6_ifaddr *ia, *oia;
|
2000-07-04 16:35:15 +00:00
|
|
|
struct ifaddr *ifa, *next;
|
1999-11-22 02:45:11 +00:00
|
|
|
struct rtentry *rt;
|
|
|
|
short rtflags;
|
2000-07-04 16:35:15 +00:00
|
|
|
struct sockaddr_in6 sin6;
|
2007-06-02 08:02:36 +00:00
|
|
|
struct in6_multi_mship *imm;
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
/* remove neighbor management table */
|
|
|
|
nd6_purge(ifp);
|
|
|
|
|
|
|
|
/* nuke any of IPv6 addresses we have */
|
2003-10-08 18:26:08 +00:00
|
|
|
for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) {
|
2000-07-04 16:35:15 +00:00
|
|
|
next = ifa->ifa_list.tqe_next;
|
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET6)
|
|
|
|
continue;
|
2001-06-11 12:39:29 +00:00
|
|
|
in6_purgeaddr(ifa);
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* undo everything done by in6_ifattach(), just in case */
|
2003-10-08 18:26:08 +00:00
|
|
|
for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) {
|
2000-07-04 16:35:15 +00:00
|
|
|
next = ifa->ifa_list.tqe_next;
|
|
|
|
|
1999-11-22 02:45:11 +00: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;
|
|
|
|
|
2007-06-02 08:02:36 +00:00
|
|
|
/*
|
|
|
|
* leave from multicast groups we have joined for the interface
|
|
|
|
*/
|
|
|
|
while ((imm = ia->ia6_memberships.lh_first) != NULL) {
|
|
|
|
LIST_REMOVE(imm, i6mm_chain);
|
|
|
|
in6_leavegroup(imm);
|
|
|
|
}
|
|
|
|
|
1999-11-22 02:45:11 +00:00
|
|
|
/* remove from the routing table */
|
2003-10-08 18:26:08 +00:00
|
|
|
if ((ia->ia_flags & IFA_ROUTE) &&
|
|
|
|
(rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
|
1999-11-22 02:45:11 +00:00
|
|
|
rtflags = rt->rt_flags;
|
|
|
|
rtfree(rt);
|
2003-10-08 18:26:08 +00:00
|
|
|
rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
|
|
|
|
(struct sockaddr *)&ia->ia_addr,
|
|
|
|
(struct sockaddr *)&ia->ia_prefixmask,
|
|
|
|
rtflags, (struct rtentry **)0);
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* remove from the linked list */
|
|
|
|
TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
|
2000-07-04 16:35:15 +00:00
|
|
|
IFAFREE(&ia->ia_ifa);
|
1999-11-22 02:45:11 +00: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-06-11 12:39:29 +00:00
|
|
|
else {
|
2003-10-08 18:26:08 +00:00
|
|
|
nd6log((LOG_ERR,
|
|
|
|
"%s: didn't unlink in6ifaddr from list\n",
|
|
|
|
if_name(ifp)));
|
2001-06-11 12:39:29 +00:00
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
IFAFREE(&oia->ia_ifa);
|
|
|
|
}
|
|
|
|
|
2006-04-23 15:06:16 +00:00
|
|
|
in6_pcbpurgeif0(&udbinfo, ifp);
|
|
|
|
in6_pcbpurgeif0(&ripcbinfo, ifp);
|
Import rewrite of IPv4 socket multicast layer to support source-specific
and protocol-independent host mode multicast. The code is written to
accomodate IPv6, IGMPv3 and MLDv2 with only a little additional work.
This change only pertains to FreeBSD's use as a multicast end-station and
does not concern multicast routing; for an IGMPv3/MLDv2 router
implementation, consider the XORP project.
The work is based on Wilbert de Graaf's IGMPv3 code drop for FreeBSD 4.6,
which is available at: http://www.kloosterhof.com/wilbert/igmpv3.html
Summary
* IPv4 multicast socket processing is now moved out of ip_output.c
into a new module, in_mcast.c.
* The in_mcast.c module implements the IPv4 legacy any-source API in
terms of the protocol-independent source-specific API.
* Source filters are lazy allocated as the common case does not use them.
They are part of per inpcb state and are covered by the inpcb lock.
* struct ip_mreqn is now supported to allow applications to specify
multicast joins by interface index in the legacy IPv4 any-source API.
* In UDP, an incoming multicast datagram only requires that the source
port matches the 4-tuple if the socket was already bound by source port.
An unbound socket SHOULD be able to receive multicasts sent from an
ephemeral source port.
* The UDP socket multicast filter mode defaults to exclusive, that is,
sources present in the per-socket list will be blocked from delivery.
* The RFC 3678 userland functions have been added to libc: setsourcefilter,
getsourcefilter, setipv4sourcefilter, getipv4sourcefilter.
* Definitions for IGMPv3 are merged but not yet used.
* struct sockaddr_storage is now referenced from <netinet/in.h>. It
is therefore defined there if not already declared in the same way
as for the C99 types.
* The RFC 1724 hack (specify 0.0.0.0/8 addresses to IP_MULTICAST_IF
which are then interpreted as interface indexes) is now deprecated.
* A patch for the Rhyolite.com routed in the FreeBSD base system
is available in the -net archives. This only affects individuals
running RIPv1 or RIPv2 via point-to-point and/or unnumbered interfaces.
* Make IPv6 detach path similar to IPv4's in code flow; functionally same.
* Bump __FreeBSD_version to 700048; see UPDATING.
This work was financially supported by another FreeBSD committer.
Obtained from: p4://bms_netdev
Submitted by: Wilbert de Graaf (original work)
Reviewed by: rwatson (locking), silence from fenner,
net@ (but with encouragement)
2007-06-12 16:24:56 +00:00
|
|
|
/* leave from all multicast groups joined */
|
|
|
|
in6_purgemaddrs(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
|
2001-06-11 12:39:29 +00: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-07-04 16:35:15 +00:00
|
|
|
nd6_purge(ifp);
|
|
|
|
|
|
|
|
/* remove route to link-local allnodes multicast (ff02::1) */
|
|
|
|
bzero(&sin6, sizeof(sin6));
|
|
|
|
sin6.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
sin6.sin6_family = AF_INET6;
|
|
|
|
sin6.sin6_addr = in6addr_linklocal_allnodes;
|
2005-07-25 12:31:43 +00:00
|
|
|
if (in6_setscope(&sin6.sin6_addr, ifp, NULL))
|
|
|
|
/* XXX: should not fail */
|
|
|
|
return;
|
2003-10-30 23:02:51 +00:00
|
|
|
/* XXX grab lock first to avoid LOR */
|
Add code to allow the system to handle multiple routing tables.
This particular implementation is designed to be fully backwards compatible
and to be MFC-able to 7.x (and 6.x)
Currently the only protocol that can make use of the multiple tables is IPv4
Similar functionality exists in OpenBSD and Linux.
From my notes:
-----
One thing where FreeBSD has been falling behind, and which by chance I
have some time to work on is "policy based routing", which allows
different
packet streams to be routed by more than just the destination address.
Constraints:
------------
I want to make some form of this available in the 6.x tree
(and by extension 7.x) , but FreeBSD in general needs it so I might as
well do it in -current and back port the portions I need.
One of the ways that this can be done is to have the ability to
instantiate multiple kernel routing tables (which I will now
refer to as "Forwarding Information Bases" or "FIBs" for political
correctness reasons). Which FIB a particular packet uses to make
the next hop decision can be decided by a number of mechanisms.
The policies these mechanisms implement are the "Policies" referred
to in "Policy based routing".
One of the constraints I have if I try to back port this work to
6.x is that it must be implemented as a EXTENSION to the existing
ABIs in 6.x so that third party applications do not need to be
recompiled in timespan of the branch.
This first version will not have some of the bells and whistles that
will come with later versions. It will, for example, be limited to 16
tables in the first commit.
Implementation method, Compatible version. (part 1)
-------------------------------
For this reason I have implemented a "sufficient subset" of a
multiple routing table solution in Perforce, and back-ported it
to 6.x. (also in Perforce though not always caught up with what I
have done in -current/P4). The subset allows a number of FIBs
to be defined at compile time (8 is sufficient for my purposes in 6.x)
and implements the changes needed to allow IPV4 to use them. I have not
done the changes for ipv6 simply because I do not need it, and I do not
have enough knowledge of ipv6 (e.g. neighbor discovery) needed to do it.
Other protocol families are left untouched and should there be
users with proprietary protocol families, they should continue to work
and be oblivious to the existence of the extra FIBs.
To understand how this is done, one must know that the current FIB
code starts everything off with a single dimensional array of
pointers to FIB head structures (One per protocol family), each of
which in turn points to the trie of routes available to that family.
The basic change in the ABI compatible version of the change is to
extent that array to be a 2 dimensional array, so that
instead of protocol family X looking at rt_tables[X] for the
table it needs, it looks at rt_tables[Y][X] when for all
protocol families except ipv4 Y is always 0.
Code that is unaware of the change always just sees the first row
of the table, which of course looks just like the one dimensional
array that existed before.
The entry points rtrequest(), rtalloc(), rtalloc1(), rtalloc_ign()
are all maintained, but refer only to the first row of the array,
so that existing callers in proprietary protocols can continue to
do the "right thing".
Some new entry points are added, for the exclusive use of ipv4 code
called in_rtrequest(), in_rtalloc(), in_rtalloc1() and in_rtalloc_ign(),
which have an extra argument which refers the code to the correct row.
In addition, there are some new entry points (currently called
rtalloc_fib() and friends) that check the Address family being
looked up and call either rtalloc() (and friends) if the protocol
is not IPv4 forcing the action to row 0 or to the appropriate row
if it IS IPv4 (and that info is available). These are for calling
from code that is not specific to any particular protocol. The way
these are implemented would change in the non ABI preserving code
to be added later.
One feature of the first version of the code is that for ipv4,
the interface routes show up automatically on all the FIBs, so
that no matter what FIB you select you always have the basic
direct attached hosts available to you. (rtinit() does this
automatically).
You CAN delete an interface route from one FIB should you want
to but by default it's there. ARP information is also available
in each FIB. It's assumed that the same machine would have the
same MAC address, regardless of which FIB you are using to get
to it.
This brings us as to how the correct FIB is selected for an outgoing
IPV4 packet.
Firstly, all packets have a FIB associated with them. if nothing
has been done to change it, it will be FIB 0. The FIB is changed
in the following ways.
Packets fall into one of a number of classes.
1/ locally generated packets, coming from a socket/PCB.
Such packets select a FIB from a number associated with the
socket/PCB. This in turn is inherited from the process,
but can be changed by a socket option. The process in turn
inherits it on fork. I have written a utility call setfib
that acts a bit like nice..
setfib -3 ping target.example.com # will use fib 3 for ping.
It is an obvious extension to make it a property of a jail
but I have not done so. It can be achieved by combining the setfib and
jail commands.
2/ packets received on an interface for forwarding.
By default these packets would use table 0,
(or possibly a number settable in a sysctl(not yet)).
but prior to routing the firewall can inspect them (see below).
(possibly in the future you may be able to associate a FIB
with packets received on an interface.. An ifconfig arg, but not yet.)
3/ packets inspected by a packet classifier, which can arbitrarily
associate a fib with it on a packet by packet basis.
A fib assigned to a packet by a packet classifier
(such as ipfw) would over-ride a fib associated by
a more default source. (such as cases 1 or 2).
4/ a tcp listen socket associated with a fib will generate
accept sockets that are associated with that same fib.
5/ Packets generated in response to some other packet (e.g. reset
or icmp packets). These should use the FIB associated with the
packet being reponded to.
6/ Packets generated during encapsulation.
gif, tun and other tunnel interfaces will encapsulate using the FIB
that was in effect withthe proces that set up the tunnel.
thus setfib 1 ifconfig gif0 [tunnel instructions]
will set the fib for the tunnel to use to be fib 1.
Routing messages would be associated with their
process, and thus select one FIB or another.
messages from the kernel would be associated with the fib they
refer to and would only be received by a routing socket associated
with that fib. (not yet implemented)
In addition Netstat has been edited to be able to cope with the
fact that the array is now 2 dimensional. (It looks in system
memory using libkvm (!)). Old versions of netstat see only the first FIB.
In addition two sysctls are added to give:
a) the number of FIBs compiled in (active)
b) the default FIB of the calling process.
Early testing experience:
-------------------------
Basically our (IronPort's) appliance does this functionality already
using ipfw fwd but that method has some drawbacks.
For example,
It can't fully simulate a routing table because it can't influence the
socket's choice of local address when a connect() is done.
Testing during the generating of these changes has been
remarkably smooth so far. Multiple tables have co-existed
with no notable side effects, and packets have been routes
accordingly.
ipfw has grown 2 new keywords:
setfib N ip from anay to any
count ip from any to any fib N
In pf there seems to be a requirement to be able to give symbolic names to the
fibs but I do not have that capacity. I am not sure if it is required.
SCTP has interestingly enough built in support for this, called VRFs
in Cisco parlance. it will be interesting to see how that handles it
when it suddenly actually does something.
Where to next:
--------------------
After committing the ABI compatible version and MFCing it, I'd
like to proceed in a forward direction in -current. this will
result in some roto-tilling in the routing code.
Firstly: the current code's idea of having a separate tree per
protocol family, all of the same format, and pointed to by the
1 dimensional array is a bit silly. Especially when one considers that
there is code that makes assumptions about every protocol having the
same internal structures there. Some protocols don't WANT that
sort of structure. (for example the whole idea of a netmask is foreign
to appletalk). This needs to be made opaque to the external code.
My suggested first change is to add routing method pointers to the
'domain' structure, along with information pointing the data.
instead of having an array of pointers to uniform structures,
there would be an array pointing to the 'domain' structures
for each protocol address domain (protocol family),
and the methods this reached would be called. The methods would have
an argument that gives FIB number, but the protocol would be free
to ignore it.
When the ABI can be changed it raises the possibilty of the
addition of a fib entry into the "struct route". Currently,
the structure contains the sockaddr of the desination, and the resulting
fib entry. To make this work fully, one could add a fib number
so that given an address and a fib, one can find the third element, the
fib entry.
Interaction with the ARP layer/ LL layer would need to be
revisited as well. Qing Li has been working on this already.
This work was sponsored by Ironport Systems/Cisco
Reviewed by: several including rwatson, bz and mlair (parts each)
Obtained from: Ironport systems/Cisco
2008-05-09 23:03:00 +00:00
|
|
|
if (rt_tables[0][AF_INET6] != NULL) {
|
|
|
|
RADIX_NODE_HEAD_LOCK(rt_tables[0][AF_INET6]);
|
2004-01-10 08:14:27 +00:00
|
|
|
rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
|
|
|
|
if (rt) {
|
|
|
|
if (rt->rt_ifp == ifp)
|
|
|
|
rtexpunge(rt);
|
|
|
|
RTFREE_LOCKED(rt);
|
|
|
|
}
|
Add code to allow the system to handle multiple routing tables.
This particular implementation is designed to be fully backwards compatible
and to be MFC-able to 7.x (and 6.x)
Currently the only protocol that can make use of the multiple tables is IPv4
Similar functionality exists in OpenBSD and Linux.
From my notes:
-----
One thing where FreeBSD has been falling behind, and which by chance I
have some time to work on is "policy based routing", which allows
different
packet streams to be routed by more than just the destination address.
Constraints:
------------
I want to make some form of this available in the 6.x tree
(and by extension 7.x) , but FreeBSD in general needs it so I might as
well do it in -current and back port the portions I need.
One of the ways that this can be done is to have the ability to
instantiate multiple kernel routing tables (which I will now
refer to as "Forwarding Information Bases" or "FIBs" for political
correctness reasons). Which FIB a particular packet uses to make
the next hop decision can be decided by a number of mechanisms.
The policies these mechanisms implement are the "Policies" referred
to in "Policy based routing".
One of the constraints I have if I try to back port this work to
6.x is that it must be implemented as a EXTENSION to the existing
ABIs in 6.x so that third party applications do not need to be
recompiled in timespan of the branch.
This first version will not have some of the bells and whistles that
will come with later versions. It will, for example, be limited to 16
tables in the first commit.
Implementation method, Compatible version. (part 1)
-------------------------------
For this reason I have implemented a "sufficient subset" of a
multiple routing table solution in Perforce, and back-ported it
to 6.x. (also in Perforce though not always caught up with what I
have done in -current/P4). The subset allows a number of FIBs
to be defined at compile time (8 is sufficient for my purposes in 6.x)
and implements the changes needed to allow IPV4 to use them. I have not
done the changes for ipv6 simply because I do not need it, and I do not
have enough knowledge of ipv6 (e.g. neighbor discovery) needed to do it.
Other protocol families are left untouched and should there be
users with proprietary protocol families, they should continue to work
and be oblivious to the existence of the extra FIBs.
To understand how this is done, one must know that the current FIB
code starts everything off with a single dimensional array of
pointers to FIB head structures (One per protocol family), each of
which in turn points to the trie of routes available to that family.
The basic change in the ABI compatible version of the change is to
extent that array to be a 2 dimensional array, so that
instead of protocol family X looking at rt_tables[X] for the
table it needs, it looks at rt_tables[Y][X] when for all
protocol families except ipv4 Y is always 0.
Code that is unaware of the change always just sees the first row
of the table, which of course looks just like the one dimensional
array that existed before.
The entry points rtrequest(), rtalloc(), rtalloc1(), rtalloc_ign()
are all maintained, but refer only to the first row of the array,
so that existing callers in proprietary protocols can continue to
do the "right thing".
Some new entry points are added, for the exclusive use of ipv4 code
called in_rtrequest(), in_rtalloc(), in_rtalloc1() and in_rtalloc_ign(),
which have an extra argument which refers the code to the correct row.
In addition, there are some new entry points (currently called
rtalloc_fib() and friends) that check the Address family being
looked up and call either rtalloc() (and friends) if the protocol
is not IPv4 forcing the action to row 0 or to the appropriate row
if it IS IPv4 (and that info is available). These are for calling
from code that is not specific to any particular protocol. The way
these are implemented would change in the non ABI preserving code
to be added later.
One feature of the first version of the code is that for ipv4,
the interface routes show up automatically on all the FIBs, so
that no matter what FIB you select you always have the basic
direct attached hosts available to you. (rtinit() does this
automatically).
You CAN delete an interface route from one FIB should you want
to but by default it's there. ARP information is also available
in each FIB. It's assumed that the same machine would have the
same MAC address, regardless of which FIB you are using to get
to it.
This brings us as to how the correct FIB is selected for an outgoing
IPV4 packet.
Firstly, all packets have a FIB associated with them. if nothing
has been done to change it, it will be FIB 0. The FIB is changed
in the following ways.
Packets fall into one of a number of classes.
1/ locally generated packets, coming from a socket/PCB.
Such packets select a FIB from a number associated with the
socket/PCB. This in turn is inherited from the process,
but can be changed by a socket option. The process in turn
inherits it on fork. I have written a utility call setfib
that acts a bit like nice..
setfib -3 ping target.example.com # will use fib 3 for ping.
It is an obvious extension to make it a property of a jail
but I have not done so. It can be achieved by combining the setfib and
jail commands.
2/ packets received on an interface for forwarding.
By default these packets would use table 0,
(or possibly a number settable in a sysctl(not yet)).
but prior to routing the firewall can inspect them (see below).
(possibly in the future you may be able to associate a FIB
with packets received on an interface.. An ifconfig arg, but not yet.)
3/ packets inspected by a packet classifier, which can arbitrarily
associate a fib with it on a packet by packet basis.
A fib assigned to a packet by a packet classifier
(such as ipfw) would over-ride a fib associated by
a more default source. (such as cases 1 or 2).
4/ a tcp listen socket associated with a fib will generate
accept sockets that are associated with that same fib.
5/ Packets generated in response to some other packet (e.g. reset
or icmp packets). These should use the FIB associated with the
packet being reponded to.
6/ Packets generated during encapsulation.
gif, tun and other tunnel interfaces will encapsulate using the FIB
that was in effect withthe proces that set up the tunnel.
thus setfib 1 ifconfig gif0 [tunnel instructions]
will set the fib for the tunnel to use to be fib 1.
Routing messages would be associated with their
process, and thus select one FIB or another.
messages from the kernel would be associated with the fib they
refer to and would only be received by a routing socket associated
with that fib. (not yet implemented)
In addition Netstat has been edited to be able to cope with the
fact that the array is now 2 dimensional. (It looks in system
memory using libkvm (!)). Old versions of netstat see only the first FIB.
In addition two sysctls are added to give:
a) the number of FIBs compiled in (active)
b) the default FIB of the calling process.
Early testing experience:
-------------------------
Basically our (IronPort's) appliance does this functionality already
using ipfw fwd but that method has some drawbacks.
For example,
It can't fully simulate a routing table because it can't influence the
socket's choice of local address when a connect() is done.
Testing during the generating of these changes has been
remarkably smooth so far. Multiple tables have co-existed
with no notable side effects, and packets have been routes
accordingly.
ipfw has grown 2 new keywords:
setfib N ip from anay to any
count ip from any to any fib N
In pf there seems to be a requirement to be able to give symbolic names to the
fibs but I do not have that capacity. I am not sure if it is required.
SCTP has interestingly enough built in support for this, called VRFs
in Cisco parlance. it will be interesting to see how that handles it
when it suddenly actually does something.
Where to next:
--------------------
After committing the ABI compatible version and MFCing it, I'd
like to proceed in a forward direction in -current. this will
result in some roto-tilling in the routing code.
Firstly: the current code's idea of having a separate tree per
protocol family, all of the same format, and pointed to by the
1 dimensional array is a bit silly. Especially when one considers that
there is code that makes assumptions about every protocol having the
same internal structures there. Some protocols don't WANT that
sort of structure. (for example the whole idea of a netmask is foreign
to appletalk). This needs to be made opaque to the external code.
My suggested first change is to add routing method pointers to the
'domain' structure, along with information pointing the data.
instead of having an array of pointers to uniform structures,
there would be an array pointing to the 'domain' structures
for each protocol address domain (protocol family),
and the methods this reached would be called. The methods would have
an argument that gives FIB number, but the protocol would be free
to ignore it.
When the ABI can be changed it raises the possibilty of the
addition of a fib entry into the "struct route". Currently,
the structure contains the sockaddr of the desination, and the resulting
fib entry. To make this work fully, one could add a fib number
so that given an address and a fib, one can find the third element, the
fib entry.
Interaction with the ARP layer/ LL layer would need to be
revisited as well. Qing Li has been working on this already.
This work was sponsored by Ironport Systems/Cisco
Reviewed by: several including rwatson, bz and mlair (parts each)
Obtained from: Ironport systems/Cisco
2008-05-09 23:03:00 +00:00
|
|
|
RADIX_NODE_HEAD_UNLOCK(rt_tables[0][AF_INET6]);
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
}
|
2001-06-11 12:39:29 +00:00
|
|
|
|
2005-10-21 16:23:01 +00:00
|
|
|
int
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_get_tmpifid(struct ifnet *ifp, u_int8_t *retbuf,
|
|
|
|
const u_int8_t *baseid, int generate)
|
2001-06-11 12:39:29 +00:00
|
|
|
{
|
|
|
|
u_int8_t nullbuf[8];
|
2003-10-17 15:46:31 +00:00
|
|
|
struct nd_ifinfo *ndi = ND_IFINFO(ifp);
|
2001-06-11 12:39:29 +00:00
|
|
|
|
|
|
|
bzero(nullbuf, sizeof(nullbuf));
|
|
|
|
if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
|
|
|
|
/* we've never created a random ID. Create a new one. */
|
|
|
|
generate = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (generate) {
|
|
|
|
bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
|
|
|
|
|
|
|
|
/* generate_tmp_ifid will update seedn and buf */
|
|
|
|
(void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
|
2003-10-08 18:26:08 +00:00
|
|
|
ndi->randomid);
|
2001-06-11 12:39:29 +00:00
|
|
|
}
|
|
|
|
bcopy(ndi->randomid, retbuf, 8);
|
2005-10-21 16:23:01 +00:00
|
|
|
|
|
|
|
return (0);
|
2001-06-11 12:39:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_tmpaddrtimer(void *ignored_arg)
|
2001-06-11 12:39:29 +00:00
|
|
|
{
|
|
|
|
struct nd_ifinfo *ndi;
|
|
|
|
u_int8_t nullbuf[8];
|
2003-10-17 15:46:31 +00:00
|
|
|
struct ifnet *ifp;
|
2001-06-11 12:39:29 +00:00
|
|
|
int s = splnet();
|
|
|
|
|
|
|
|
callout_reset(&in6_tmpaddrtimer_ch,
|
2003-10-08 18:26:08 +00:00
|
|
|
(ip6_temp_preferred_lifetime - ip6_desync_factor -
|
|
|
|
ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL);
|
2001-06-11 12:39:29 +00:00
|
|
|
|
|
|
|
bzero(nullbuf, sizeof(nullbuf));
|
2003-10-17 15:46:31 +00:00
|
|
|
for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
|
|
|
|
ndi = ND_IFINFO(ifp);
|
2001-06-11 12:39:29 +00:00
|
|
|
if (bcmp(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,
|
2003-10-08 18:26:08 +00:00
|
|
|
ndi->randomseed1, ndi->randomid);
|
2001-06-11 12:39:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
splx(s);
|
|
|
|
}
|
Import rewrite of IPv4 socket multicast layer to support source-specific
and protocol-independent host mode multicast. The code is written to
accomodate IPv6, IGMPv3 and MLDv2 with only a little additional work.
This change only pertains to FreeBSD's use as a multicast end-station and
does not concern multicast routing; for an IGMPv3/MLDv2 router
implementation, consider the XORP project.
The work is based on Wilbert de Graaf's IGMPv3 code drop for FreeBSD 4.6,
which is available at: http://www.kloosterhof.com/wilbert/igmpv3.html
Summary
* IPv4 multicast socket processing is now moved out of ip_output.c
into a new module, in_mcast.c.
* The in_mcast.c module implements the IPv4 legacy any-source API in
terms of the protocol-independent source-specific API.
* Source filters are lazy allocated as the common case does not use them.
They are part of per inpcb state and are covered by the inpcb lock.
* struct ip_mreqn is now supported to allow applications to specify
multicast joins by interface index in the legacy IPv4 any-source API.
* In UDP, an incoming multicast datagram only requires that the source
port matches the 4-tuple if the socket was already bound by source port.
An unbound socket SHOULD be able to receive multicasts sent from an
ephemeral source port.
* The UDP socket multicast filter mode defaults to exclusive, that is,
sources present in the per-socket list will be blocked from delivery.
* The RFC 3678 userland functions have been added to libc: setsourcefilter,
getsourcefilter, setipv4sourcefilter, getipv4sourcefilter.
* Definitions for IGMPv3 are merged but not yet used.
* struct sockaddr_storage is now referenced from <netinet/in.h>. It
is therefore defined there if not already declared in the same way
as for the C99 types.
* The RFC 1724 hack (specify 0.0.0.0/8 addresses to IP_MULTICAST_IF
which are then interpreted as interface indexes) is now deprecated.
* A patch for the Rhyolite.com routed in the FreeBSD base system
is available in the -net archives. This only affects individuals
running RIPv1 or RIPv2 via point-to-point and/or unnumbered interfaces.
* Make IPv6 detach path similar to IPv4's in code flow; functionally same.
* Bump __FreeBSD_version to 700048; see UPDATING.
This work was financially supported by another FreeBSD committer.
Obtained from: p4://bms_netdev
Submitted by: Wilbert de Graaf (original work)
Reviewed by: rwatson (locking), silence from fenner,
net@ (but with encouragement)
2007-06-12 16:24:56 +00:00
|
|
|
|
|
|
|
static void
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_purgemaddrs(struct ifnet *ifp)
|
Import rewrite of IPv4 socket multicast layer to support source-specific
and protocol-independent host mode multicast. The code is written to
accomodate IPv6, IGMPv3 and MLDv2 with only a little additional work.
This change only pertains to FreeBSD's use as a multicast end-station and
does not concern multicast routing; for an IGMPv3/MLDv2 router
implementation, consider the XORP project.
The work is based on Wilbert de Graaf's IGMPv3 code drop for FreeBSD 4.6,
which is available at: http://www.kloosterhof.com/wilbert/igmpv3.html
Summary
* IPv4 multicast socket processing is now moved out of ip_output.c
into a new module, in_mcast.c.
* The in_mcast.c module implements the IPv4 legacy any-source API in
terms of the protocol-independent source-specific API.
* Source filters are lazy allocated as the common case does not use them.
They are part of per inpcb state and are covered by the inpcb lock.
* struct ip_mreqn is now supported to allow applications to specify
multicast joins by interface index in the legacy IPv4 any-source API.
* In UDP, an incoming multicast datagram only requires that the source
port matches the 4-tuple if the socket was already bound by source port.
An unbound socket SHOULD be able to receive multicasts sent from an
ephemeral source port.
* The UDP socket multicast filter mode defaults to exclusive, that is,
sources present in the per-socket list will be blocked from delivery.
* The RFC 3678 userland functions have been added to libc: setsourcefilter,
getsourcefilter, setipv4sourcefilter, getipv4sourcefilter.
* Definitions for IGMPv3 are merged but not yet used.
* struct sockaddr_storage is now referenced from <netinet/in.h>. It
is therefore defined there if not already declared in the same way
as for the C99 types.
* The RFC 1724 hack (specify 0.0.0.0/8 addresses to IP_MULTICAST_IF
which are then interpreted as interface indexes) is now deprecated.
* A patch for the Rhyolite.com routed in the FreeBSD base system
is available in the -net archives. This only affects individuals
running RIPv1 or RIPv2 via point-to-point and/or unnumbered interfaces.
* Make IPv6 detach path similar to IPv4's in code flow; functionally same.
* Bump __FreeBSD_version to 700048; see UPDATING.
This work was financially supported by another FreeBSD committer.
Obtained from: p4://bms_netdev
Submitted by: Wilbert de Graaf (original work)
Reviewed by: rwatson (locking), silence from fenner,
net@ (but with encouragement)
2007-06-12 16:24:56 +00:00
|
|
|
{
|
|
|
|
struct in6_multi *in6m;
|
|
|
|
struct in6_multi *oin6m;
|
|
|
|
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
printf("%s: purging ifp %p\n", __func__, ifp);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
IFF_LOCKGIANT(ifp);
|
|
|
|
LIST_FOREACH_SAFE(in6m, &in6_multihead, in6m_entry, oin6m) {
|
|
|
|
if (in6m->in6m_ifp == ifp)
|
|
|
|
in6_delmulti(in6m);
|
|
|
|
}
|
|
|
|
IFF_UNLOCKGIANT(ifp);
|
|
|
|
}
|