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>
|
2009-05-29 21:27:12 +00:00
|
|
|
#include <sys/jail.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
#include <sys/kernel.h>
|
2009-08-01 19:26:27 +00:00
|
|
|
#include <sys/proc.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>
|
2008-12-02 21:37:28 +00:00
|
|
|
#include <net/vnet.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
#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>
|
Build on Jeff Roberson's linker-set based dynamic per-CPU allocator
(DPCPU), as suggested by Peter Wemm, and implement a new per-virtual
network stack memory allocator. Modify vnet to use the allocator
instead of monolithic global container structures (vinet, ...). This
change solves many binary compatibility problems associated with
VIMAGE, and restores ELF symbols for virtualized global variables.
Each virtualized global variable exists as a "reference copy", and also
once per virtual network stack. Virtualized global variables are
tagged at compile-time, placing the in a special linker set, which is
loaded into a contiguous region of kernel memory. Virtualized global
variables in the base kernel are linked as normal, but those in modules
are copied and relocated to a reserved portion of the kernel's vnet
region with the help of a the kernel linker.
Virtualized global variables exist in per-vnet memory set up when the
network stack instance is created, and are initialized statically from
the reference copy. Run-time access occurs via an accessor macro, which
converts from the current vnet and requested symbol to a per-vnet
address. When "options VIMAGE" is not compiled into the kernel, normal
global ELF symbols will be used instead and indirection is avoided.
This change restores static initialization for network stack global
variables, restores support for non-global symbols and types, eliminates
the need for many subsystem constructors, eliminates large per-subsystem
structures that caused many binary compatibility issues both for
monitoring applications (netstat) and kernel modules, removes the
per-function INIT_VNET_*() macros throughout the stack, eliminates the
need for vnet_symmap ksym(2) munging, and eliminates duplicate
definitions of virtualized globals under VIMAGE_GLOBALS.
Bump __FreeBSD_version and update UPDATING.
Portions submitted by: bz
Reviewed by: bz, zec
Discussed with: gnn, jamie, jeff, jhb, julian, sam
Suggested by: peter
Approved by: re (kensmith)
2009-07-14 22:48:30 +00:00
|
|
|
#include <netinet/ip_var.h>
|
|
|
|
#include <netinet/udp.h>
|
|
|
|
#include <netinet/udp_var.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>
|
Bite the bullet, and make the IPv6 SSM and MLDv2 mega-commit:
import from p4 bms_netdev. Summary of changes:
* Connect netinet6/in6_mcast.c to build.
The legacy KAME KPIs are mostly preserved.
* Eliminate now dead code from ip6_output.c.
Don't do mbuf bingo, we are not going to do RFC 2292 style
CMSG tricks for multicast options as they are not required
by any current IPv6 normative reference.
* Refactor transports (UDP, raw_ip6) to do own mcast filtering.
SCTP, TCP unaffected by this change.
* Add ip6_msource, in6_msource structs to in6_var.h.
* Hookup mld_ifinfo state to in6_ifextra, allocate from
domifattach path.
* Eliminate IN6_LOOKUP_MULTI(), it is no longer referenced.
Kernel consumers which need this should use in6m_lookup().
* Refactor IPv6 socket group memberships to use a vector (like IPv4).
* Update ifmcstat(8) for IPv6 SSM.
* Add witness lock order for IN6_MULTI_LOCK.
* Move IN6_MULTI_LOCK out of lower ip6_output()/ip6_input() paths.
* Introduce IP6STAT_ADD/SUB/INC/DEC as per rwatson's IPv4 cleanup.
* Update carp(4) for new IPv6 SSM KPIs.
* Virtualize ip6_mrouter socket.
Changes mostly localized to IPv6 MROUTING.
* Don't do a local group lookup in MROUTING.
* Kill unused KAME prototypes in6_purgemkludge(), in6_restoremkludge().
* Preserve KAME DAD timer jitter behaviour in MLDv1 compatibility mode.
* Bump __FreeBSD_version to 800084.
* Update UPDATING.
NOTE WELL:
* This code hasn't been tested against real MLDv2 queriers
(yet), although the on-wire protocol has been verified in Wireshark.
* There are a few unresolved issues in the socket layer APIs to
do with scope ID propagation.
* There is a LOR present in ip6_output()'s use of
in6_setscope() which needs to be resolved. See comments in mld6.c.
This is believed to be benign and can't be avoided for the moment
without re-introducing an indirect netisr.
This work was mostly derived from the IGMPv3 implementation, and
has been sponsored by a third party.
2009-04-29 19:19:13 +00:00
|
|
|
#include <netinet6/mld6_var.h>
|
2000-07-04 16:35:15 +00:00
|
|
|
#include <netinet6/scope6_var.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2010-04-29 11:52:42 +00:00
|
|
|
VNET_DEFINE(unsigned long, in6_maxmtu) = 0;
|
|
|
|
|
|
|
|
#ifdef IP6_AUTO_LINKLOCAL
|
|
|
|
VNET_DEFINE(int, ip6_auto_linklocal) = IP6_AUTO_LINKLOCAL;
|
|
|
|
#else
|
|
|
|
VNET_DEFINE(int, ip6_auto_linklocal) = 1; /* enabled by default */
|
|
|
|
#endif
|
Build on Jeff Roberson's linker-set based dynamic per-CPU allocator
(DPCPU), as suggested by Peter Wemm, and implement a new per-virtual
network stack memory allocator. Modify vnet to use the allocator
instead of monolithic global container structures (vinet, ...). This
change solves many binary compatibility problems associated with
VIMAGE, and restores ELF symbols for virtualized global variables.
Each virtualized global variable exists as a "reference copy", and also
once per virtual network stack. Virtualized global variables are
tagged at compile-time, placing the in a special linker set, which is
loaded into a contiguous region of kernel memory. Virtualized global
variables in the base kernel are linked as normal, but those in modules
are copied and relocated to a reserved portion of the kernel's vnet
region with the help of a the kernel linker.
Virtualized global variables exist in per-vnet memory set up when the
network stack instance is created, and are initialized statically from
the reference copy. Run-time access occurs via an accessor macro, which
converts from the current vnet and requested symbol to a per-vnet
address. When "options VIMAGE" is not compiled into the kernel, normal
global ELF symbols will be used instead and indirection is avoided.
This change restores static initialization for network stack global
variables, restores support for non-global symbols and types, eliminates
the need for many subsystem constructors, eliminates large per-subsystem
structures that caused many binary compatibility issues both for
monitoring applications (netstat) and kernel modules, removes the
per-function INIT_VNET_*() macros throughout the stack, eliminates the
need for vnet_symmap ksym(2) munging, and eliminates duplicate
definitions of virtualized globals under VIMAGE_GLOBALS.
Bump __FreeBSD_version and update UPDATING.
Portions submitted by: bz
Reviewed by: bz, zec
Discussed with: gnn, jamie, jeff, jhb, julian, sam
Suggested by: peter
Approved by: re (kensmith)
2009-07-14 22:48:30 +00:00
|
|
|
|
2010-04-29 11:52:42 +00:00
|
|
|
VNET_DEFINE(struct callout, in6_tmpaddrtimer_ch);
|
2009-07-16 21:13:04 +00:00
|
|
|
#define V_in6_tmpaddrtimer_ch VNET(in6_tmpaddrtimer_ch)
|
Build on Jeff Roberson's linker-set based dynamic per-CPU allocator
(DPCPU), as suggested by Peter Wemm, and implement a new per-virtual
network stack memory allocator. Modify vnet to use the allocator
instead of monolithic global container structures (vinet, ...). This
change solves many binary compatibility problems associated with
VIMAGE, and restores ELF symbols for virtualized global variables.
Each virtualized global variable exists as a "reference copy", and also
once per virtual network stack. Virtualized global variables are
tagged at compile-time, placing the in a special linker set, which is
loaded into a contiguous region of kernel memory. Virtualized global
variables in the base kernel are linked as normal, but those in modules
are copied and relocated to a reserved portion of the kernel's vnet
region with the help of a the kernel linker.
Virtualized global variables exist in per-vnet memory set up when the
network stack instance is created, and are initialized statically from
the reference copy. Run-time access occurs via an accessor macro, which
converts from the current vnet and requested symbol to a per-vnet
address. When "options VIMAGE" is not compiled into the kernel, normal
global ELF symbols will be used instead and indirection is avoided.
This change restores static initialization for network stack global
variables, restores support for non-global symbols and types, eliminates
the need for many subsystem constructors, eliminates large per-subsystem
structures that caused many binary compatibility issues both for
monitoring applications (netstat) and kernel modules, removes the
per-function INIT_VNET_*() macros throughout the stack, eliminates the
need for vnet_symmap ksym(2) munging, and eliminates duplicate
definitions of virtualized globals under VIMAGE_GLOBALS.
Bump __FreeBSD_version and update UPDATING.
Portions submitted by: bz
Reviewed by: bz, zec
Discussed with: gnn, jamie, jeff, jhb, julian, sam
Suggested by: peter
Approved by: re (kensmith)
2009-07-14 22:48:30 +00:00
|
|
|
|
|
|
|
VNET_DECLARE(struct inpcbinfo, ripcbinfo);
|
2009-07-16 21:13:04 +00:00
|
|
|
#define V_ripcbinfo VNET(ripcbinfo)
|
2001-08-04 17:10:14 +00:00
|
|
|
|
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;
|
2009-05-29 21:27:12 +00:00
|
|
|
struct prison *pr;
|
1999-11-22 02:45:11 +00:00
|
|
|
u_int8_t digest[16];
|
2008-07-05 13:10:10 +00:00
|
|
|
int hostnamelen;
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2009-05-29 21:27:12 +00:00
|
|
|
pr = curthread->td_ucred->cr_prison;
|
|
|
|
mtx_lock(&pr->pr_mtx);
|
2009-06-13 15:39:12 +00:00
|
|
|
hostnamelen = strlen(pr->pr_hostname);
|
2000-07-04 16:35:15 +00:00
|
|
|
#if 0
|
|
|
|
/* we need at least several letters as seed for ifid */
|
2009-05-29 21:27:12 +00:00
|
|
|
if (hostnamelen < 3) {
|
|
|
|
mtx_unlock(&pr->pr_mtx);
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
2009-05-29 21:27:12 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* generate 8 bytes of pseudo-random value. */
|
1999-11-22 02:45:11 +00:00
|
|
|
bzero(&ctxt, sizeof(ctxt));
|
|
|
|
MD5Init(&ctxt);
|
2009-06-13 15:39:12 +00:00
|
|
|
MD5Update(&ctxt, pr->pr_hostname, hostnamelen);
|
2009-05-29 21:27:12 +00:00
|
|
|
mtx_unlock(&pr->pr_mtx);
|
1999-11-22 02:45:11 +00:00
|
|
|
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 };
|
|
|
|
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RLOCK(ifp);
|
2009-04-20 22:45:21 +00:00
|
|
|
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
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
|
|
|
}
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
return -1;
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
found:
|
2009-06-23 20:19:09 +00:00
|
|
|
IF_ADDR_LOCK_ASSERT(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
addr = LLADDR(sdl);
|
|
|
|
addrlen = sdl->sdl_alen;
|
|
|
|
|
|
|
|
/* get EUI64 */
|
|
|
|
switch (ifp->if_type) {
|
2013-07-02 16:58:15 +00:00
|
|
|
case IFT_BRIDGE:
|
2000-07-04 16:35:15 +00:00
|
|
|
case IFT_ETHER:
|
2010-12-22 11:58:31 +00:00
|
|
|
case IFT_L2VLAN:
|
2000-07-04 16:35:15 +00:00
|
|
|
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 */
|
2009-04-20 21:37:46 +00:00
|
|
|
if (addrlen != 8 && addrlen != 6) {
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
2009-04-20 21:37:46 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* check for invalid MAC address - on bsdi, we see it a lot
|
|
|
|
* since wildboar configures all-zero MAC on pccard before
|
|
|
|
* card insertion.
|
|
|
|
*/
|
2009-04-20 21:37:46 +00:00
|
|
|
if (bcmp(addr, allzero, addrlen) == 0) {
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
2009-04-20 21:37:46 +00:00
|
|
|
}
|
|
|
|
if (bcmp(addr, allone, addrlen) == 0) {
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
2009-04-20 21:37:46 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/* 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:
|
2009-04-20 21:37:46 +00:00
|
|
|
if (addrlen != 1) {
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
2009-04-20 21:37:46 +00:00
|
|
|
}
|
|
|
|
if (!addr[0]) {
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
2009-04-20 21:37:46 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
default:
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
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" */
|
2009-04-20 21:37:46 +00:00
|
|
|
if (EUI64_GROUP(in6)) {
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
2009-04-20 21:37:46 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/* 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) {
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(ifp);
|
2000-07-04 16:35:15 +00:00
|
|
|
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 */
|
2009-08-23 20:40:19 +00:00
|
|
|
IFNET_RLOCK_NOSLEEP();
|
2011-12-29 18:25:18 +00:00
|
|
|
TAILQ_FOREACH(ifp, &V_ifnet, if_list) {
|
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)));
|
2009-08-23 20:40:19 +00:00
|
|
|
IFNET_RUNLOCK_NOSLEEP();
|
2000-07-04 16:35:15 +00:00
|
|
|
goto success;
|
|
|
|
}
|
|
|
|
}
|
2009-08-23 20:40:19 +00:00
|
|
|
IFNET_RUNLOCK_NOSLEEP();
|
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 */
|
2012-01-05 01:13:25 +00:00
|
|
|
KASSERT(ia != NULL, ("%s: ia == NULL, ifp=%p", __func__, ifp));
|
|
|
|
|
2009-06-23 20:19:09 +00:00
|
|
|
ifa_free(&ia->ia_ifa);
|
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.
|
2013-05-04 19:16:26 +00:00
|
|
|
* see RFC 4620.
|
2000-07-04 16:35:15 +00:00
|
|
|
*
|
|
|
|
* when ifp == NULL, the caller is responsible for filling scopeid.
|
2013-05-04 19:16:26 +00:00
|
|
|
*
|
|
|
|
* If oldmcprefix == 1, FF02:0:0:0:0:2::/96 is used for NI group address
|
|
|
|
* while it is FF02:0:0:0:0:2:FF00::/104 in RFC 4620.
|
2000-07-04 16:35:15 +00:00
|
|
|
*/
|
2013-05-04 19:16:26 +00:00
|
|
|
static int
|
|
|
|
in6_nigroup0(struct ifnet *ifp, const char *name, int namelen,
|
|
|
|
struct in6_addr *in6, int oldmcprefix)
|
2000-07-04 16:35:15 +00:00
|
|
|
{
|
2009-05-29 21:27:12 +00:00
|
|
|
struct prison *pr;
|
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
|
|
|
|
2009-05-27 14:11:23 +00:00
|
|
|
/*
|
|
|
|
* If no name is given and namelen is -1,
|
|
|
|
* we try to do the hostname lookup ourselves.
|
|
|
|
*/
|
|
|
|
if (!name && namelen == -1) {
|
2009-05-29 21:27:12 +00:00
|
|
|
pr = curthread->td_ucred->cr_prison;
|
|
|
|
mtx_lock(&pr->pr_mtx);
|
2009-06-13 15:39:12 +00:00
|
|
|
name = pr->pr_hostname;
|
2009-05-27 14:11:23 +00:00
|
|
|
namelen = strlen(name);
|
|
|
|
} else
|
2009-05-29 21:27:12 +00:00
|
|
|
pr = NULL;
|
2009-05-27 14:11:23 +00:00
|
|
|
if (!name || !namelen) {
|
2009-05-29 21:27:12 +00:00
|
|
|
if (pr != NULL)
|
|
|
|
mtx_unlock(&pr->pr_mtx);
|
2000-07-04 16:35:15 +00:00
|
|
|
return -1;
|
2009-05-27 14:11:23 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
p = name;
|
|
|
|
while (p && *p && *p != '.' && p - name < namelen)
|
|
|
|
p++;
|
2009-05-27 14:11:23 +00:00
|
|
|
if (p == name || p - name > sizeof(n) - 1) {
|
2009-05-29 21:27:12 +00:00
|
|
|
if (pr != NULL)
|
|
|
|
mtx_unlock(&pr->pr_mtx);
|
2002-04-19 04:46:24 +00:00
|
|
|
return -1; /* label too long */
|
2009-05-27 14:11:23 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
l = p - name;
|
2001-06-11 12:39:29 +00:00
|
|
|
strncpy(n, name, l);
|
2009-05-29 21:27:12 +00:00
|
|
|
if (pr != NULL)
|
|
|
|
mtx_unlock(&pr->pr_mtx);
|
2001-06-11 12:39:29 +00:00
|
|
|
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
|
|
|
|
2013-05-04 19:16:26 +00:00
|
|
|
/* generate 16 bytes of pseudo-random value. */
|
2000-07-04 16:35:15 +00:00
|
|
|
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;
|
2013-05-04 19:16:26 +00:00
|
|
|
if (oldmcprefix == 0) {
|
|
|
|
in6->s6_addr8[12] = 0xff;
|
|
|
|
/* Copy the first 24 bits of 128-bit hash into the address. */
|
|
|
|
bcopy(digest, &in6->s6_addr8[13], 3);
|
|
|
|
} else {
|
|
|
|
/* Copy the first 32 bits of 128-bit hash into the address. */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-05-04 19:16:26 +00:00
|
|
|
int
|
|
|
|
in6_nigroup(struct ifnet *ifp, const char *name, int namelen,
|
|
|
|
struct in6_addr *in6)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (in6_nigroup0(ifp, name, namelen, in6, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
in6_nigroup_oldmcprefix(struct ifnet *ifp, const char *name, int namelen,
|
|
|
|
struct in6_addr *in6)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (in6_nigroup0(ifp, name, namelen, in6, 1));
|
|
|
|
}
|
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
2013-07-31 16:24:49 +00:00
|
|
|
if (ifp->if_afdata[AF_INET6] == NULL)
|
2004-02-26 03:53:54 +00:00
|
|
|
return;
|
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) {
|
|
|
|
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
|
|
|
*/
|
2013-07-02 16:58:15 +00:00
|
|
|
ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL;
|
|
|
|
break;
|
2000-07-04 16:35:15 +00:00
|
|
|
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) {
|
2009-06-23 20:19:09 +00:00
|
|
|
struct ifaddr *ifa;
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
in6 = in6addr_loopback;
|
2009-06-23 20:19:09 +00:00
|
|
|
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &in6);
|
|
|
|
if (ifa == NULL) {
|
2000-07-04 16:35:15 +00:00
|
|
|
if (in6_ifattach_loopback(ifp) != 0)
|
|
|
|
return;
|
2009-06-23 20:19:09 +00:00
|
|
|
} else
|
|
|
|
ifa_free(ifa);
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
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
|
|
|
*/
|
2013-07-02 16:58:15 +00:00
|
|
|
if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
|
2009-09-12 22:08:20 +00:00
|
|
|
ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) {
|
|
|
|
int error;
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
ia = in6ifa_ifpforlinklocal(ifp, 0);
|
|
|
|
if (ia == NULL) {
|
2009-09-12 22:08:20 +00:00
|
|
|
error = in6_ifattach_linklocal(ifp, altifp);
|
2009-10-12 18:54:02 +00:00
|
|
|
#if 0
|
2009-09-12 22:08:20 +00:00
|
|
|
if (error)
|
|
|
|
log(LOG_NOTICE, "in6_ifattach_linklocal: "
|
|
|
|
"failed to add a link-local addr to %s\n",
|
|
|
|
if_name(ifp));
|
2009-10-12 18:54:02 +00:00
|
|
|
#endif
|
2009-06-23 20:19:09 +00:00
|
|
|
} else
|
|
|
|
ifa_free(&ia->ia_ifa);
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* update dynamically. */
|
Commit step 1 of the vimage project, (network stack)
virtualization work done by Marko Zec (zec@).
This is the first in a series of commits over the course
of the next few weeks.
Mark all uses of global variables to be virtualized
with a V_ prefix.
Use macros to map them back to their global names for
now, so this is a NOP change only.
We hope to have caught at least 85-90% of what is needed
so we do not invalidate a lot of outstanding patches again.
Obtained from: //depot/projects/vimage-commit2/...
Reviewed by: brooks, des, ed, mav, julian,
jamie, kris, rwatson, zec, ...
(various people I forgot, different versions)
md5 (with a bit of help)
Sponsored by: NLnet Foundation, The FreeBSD Foundation
X-MFC after: never
V_Commit_Message_Reviewed_By: more people than the patch
2008-08-17 23:27:27 +00:00
|
|
|
if (V_in6_maxmtu < ifp->if_mtu)
|
|
|
|
V_in6_maxmtu = ifp->if_mtu;
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2009-06-24 21:00:25 +00:00
|
|
|
struct in6_ifaddr *ia;
|
2000-07-04 16:35:15 +00:00
|
|
|
struct ifaddr *ifa, *next;
|
2009-06-01 15:49:42 +00:00
|
|
|
struct radix_node_head *rnh;
|
1999-11-22 02:45:11 +00:00
|
|
|
struct rtentry *rt;
|
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 */
|
2009-04-20 22:45:21 +00:00
|
|
|
TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
|
2000-07-04 16:35:15 +00:00
|
|
|
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 */
|
2009-04-20 22:45:21 +00:00
|
|
|
TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, 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
|
|
|
|
*/
|
2011-12-29 18:25:18 +00:00
|
|
|
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
|
2007-06-02 08:02:36 +00:00
|
|
|
LIST_REMOVE(imm, i6mm_chain);
|
|
|
|
in6_leavegroup(imm);
|
|
|
|
}
|
|
|
|
|
2012-02-03 13:08:44 +00:00
|
|
|
/* Remove link-local from the routing table. */
|
|
|
|
if (ia->ia_flags & IFA_ROUTE)
|
|
|
|
(void)rtinit(&ia->ia_ifa, RTM_DELETE, ia->ia_flags);
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
/* remove from the linked list */
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_WLOCK(ifp);
|
2009-06-24 21:00:25 +00:00
|
|
|
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_WUNLOCK(ifp);
|
2009-06-24 21:00:25 +00:00
|
|
|
ifa_free(ifa); /* if_addrhead */
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2009-06-25 16:35:28 +00:00
|
|
|
IN6_IFADDR_WLOCK();
|
2009-06-24 21:00:25 +00:00
|
|
|
TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link);
|
2009-06-25 16:35:28 +00:00
|
|
|
IN6_IFADDR_WUNLOCK();
|
2009-06-24 21:00:25 +00:00
|
|
|
ifa_free(ifa);
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
|
|
|
|
Commit step 1 of the vimage project, (network stack)
virtualization work done by Marko Zec (zec@).
This is the first in a series of commits over the course
of the next few weeks.
Mark all uses of global variables to be virtualized
with a V_ prefix.
Use macros to map them back to their global names for
now, so this is a NOP change only.
We hope to have caught at least 85-90% of what is needed
so we do not invalidate a lot of outstanding patches again.
Obtained from: //depot/projects/vimage-commit2/...
Reviewed by: brooks, des, ed, mav, julian,
jamie, kris, rwatson, zec, ...
(various people I forgot, different versions)
md5 (with a bit of help)
Sponsored by: NLnet Foundation, The FreeBSD Foundation
X-MFC after: never
V_Commit_Message_Reviewed_By: more people than the patch
2008-08-17 23:27:27 +00:00
|
|
|
in6_pcbpurgeif0(&V_udbinfo, ifp);
|
|
|
|
in6_pcbpurgeif0(&V_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);
|
|
|
|
|
2012-02-03 13:08:44 +00:00
|
|
|
/*
|
|
|
|
* Remove route to link-local allnodes multicast (ff02::1).
|
|
|
|
* These only get automatically installed for the default FIB.
|
|
|
|
*/
|
2000-07-04 16:35:15 +00:00
|
|
|
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 */
|
2012-02-03 13:08:44 +00:00
|
|
|
rnh = rt_tables_get_rnh(RT_DEFAULT_FIB, AF_INET6);
|
2009-06-01 15:49:42 +00:00
|
|
|
if (rnh != NULL) {
|
|
|
|
RADIX_NODE_HEAD_LOCK(rnh);
|
2012-02-03 13:08:44 +00:00
|
|
|
rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED,
|
|
|
|
RT_DEFAULT_FIB);
|
2004-01-10 08:14:27 +00:00
|
|
|
if (rt) {
|
|
|
|
if (rt->rt_ifp == ifp)
|
|
|
|
rtexpunge(rt);
|
|
|
|
RTFREE_LOCKED(rt);
|
|
|
|
}
|
2009-06-01 15:49:42 +00:00
|
|
|
RADIX_NODE_HEAD_UNLOCK(rnh);
|
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
|
Permit buiding kernels with options VIMAGE, restricted to only a single
active network stack instance. Turning on options VIMAGE at compile
time yields the following changes relative to default kernel build:
1) V_ accessor macros for virtualized variables resolve to structure
fields via base pointers, instead of being resolved as fields in global
structs or plain global variables. As an example, V_ifnet becomes:
options VIMAGE: ((struct vnet_net *) vnet_net)->_ifnet
default build: vnet_net_0._ifnet
options VIMAGE_GLOBALS: ifnet
2) INIT_VNET_* macros will declare and set up base pointers to be used
by V_ accessor macros, instead of resolving to whitespace:
INIT_VNET_NET(ifp->if_vnet); becomes
struct vnet_net *vnet_net = (ifp->if_vnet)->mod_data[VNET_MOD_NET];
3) Memory for vnet modules registered via vnet_mod_register() is now
allocated at run time in sys/kern/kern_vimage.c, instead of per vnet
module structs being declared as globals. If required, vnet modules
can now request the framework to provide them with allocated bzeroed
memory by filling in the vmi_size field in their vmi_modinfo structures.
4) structs socket, ifnet, inpcbinfo, tcpcb and syncache_head are
extended to hold a pointer to the parent vnet. options VIMAGE builds
will fill in those fields as required.
5) curvnet is introduced as a new global variable in options VIMAGE
builds, always pointing to the default and only struct vnet.
6) struct sysctl_oid has been extended with additional two fields to
store major and minor virtualization module identifiers, oid_v_subs and
oid_v_mod. SYSCTL_V_* family of macros will fill in those fields
accordingly, and store the offset in the appropriate vnet container
struct in oid_arg1.
In sysctl handlers dealing with virtualized sysctls, the
SYSCTL_RESOLVE_V_ARG1() macro will compute the address of the target
variable and make it available in arg1 variable for further processing.
Unused fields in structs vnet_inet, vnet_inet6 and vnet_ipfw have
been deleted.
Reviewed by: bz, rwatson
Approved by: julian (mentor)
2009-04-30 13:36:26 +00:00
|
|
|
in6_tmpaddrtimer(void *arg)
|
2001-06-11 12:39:29 +00:00
|
|
|
{
|
Permit buiding kernels with options VIMAGE, restricted to only a single
active network stack instance. Turning on options VIMAGE at compile
time yields the following changes relative to default kernel build:
1) V_ accessor macros for virtualized variables resolve to structure
fields via base pointers, instead of being resolved as fields in global
structs or plain global variables. As an example, V_ifnet becomes:
options VIMAGE: ((struct vnet_net *) vnet_net)->_ifnet
default build: vnet_net_0._ifnet
options VIMAGE_GLOBALS: ifnet
2) INIT_VNET_* macros will declare and set up base pointers to be used
by V_ accessor macros, instead of resolving to whitespace:
INIT_VNET_NET(ifp->if_vnet); becomes
struct vnet_net *vnet_net = (ifp->if_vnet)->mod_data[VNET_MOD_NET];
3) Memory for vnet modules registered via vnet_mod_register() is now
allocated at run time in sys/kern/kern_vimage.c, instead of per vnet
module structs being declared as globals. If required, vnet modules
can now request the framework to provide them with allocated bzeroed
memory by filling in the vmi_size field in their vmi_modinfo structures.
4) structs socket, ifnet, inpcbinfo, tcpcb and syncache_head are
extended to hold a pointer to the parent vnet. options VIMAGE builds
will fill in those fields as required.
5) curvnet is introduced as a new global variable in options VIMAGE
builds, always pointing to the default and only struct vnet.
6) struct sysctl_oid has been extended with additional two fields to
store major and minor virtualization module identifiers, oid_v_subs and
oid_v_mod. SYSCTL_V_* family of macros will fill in those fields
accordingly, and store the offset in the appropriate vnet container
struct in oid_arg1.
In sysctl handlers dealing with virtualized sysctls, the
SYSCTL_RESOLVE_V_ARG1() macro will compute the address of the target
variable and make it available in arg1 variable for further processing.
Unused fields in structs vnet_inet, vnet_inet6 and vnet_ipfw have
been deleted.
Reviewed by: bz, rwatson
Approved by: julian (mentor)
2009-04-30 13:36:26 +00:00
|
|
|
CURVNET_SET((struct vnet *) 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
|
|
|
|
Commit step 1 of the vimage project, (network stack)
virtualization work done by Marko Zec (zec@).
This is the first in a series of commits over the course
of the next few weeks.
Mark all uses of global variables to be virtualized
with a V_ prefix.
Use macros to map them back to their global names for
now, so this is a NOP change only.
We hope to have caught at least 85-90% of what is needed
so we do not invalidate a lot of outstanding patches again.
Obtained from: //depot/projects/vimage-commit2/...
Reviewed by: brooks, des, ed, mav, julian,
jamie, kris, rwatson, zec, ...
(various people I forgot, different versions)
md5 (with a bit of help)
Sponsored by: NLnet Foundation, The FreeBSD Foundation
X-MFC after: never
V_Commit_Message_Reviewed_By: more people than the patch
2008-08-17 23:27:27 +00:00
|
|
|
callout_reset(&V_in6_tmpaddrtimer_ch,
|
|
|
|
(V_ip6_temp_preferred_lifetime - V_ip6_desync_factor -
|
Permit buiding kernels with options VIMAGE, restricted to only a single
active network stack instance. Turning on options VIMAGE at compile
time yields the following changes relative to default kernel build:
1) V_ accessor macros for virtualized variables resolve to structure
fields via base pointers, instead of being resolved as fields in global
structs or plain global variables. As an example, V_ifnet becomes:
options VIMAGE: ((struct vnet_net *) vnet_net)->_ifnet
default build: vnet_net_0._ifnet
options VIMAGE_GLOBALS: ifnet
2) INIT_VNET_* macros will declare and set up base pointers to be used
by V_ accessor macros, instead of resolving to whitespace:
INIT_VNET_NET(ifp->if_vnet); becomes
struct vnet_net *vnet_net = (ifp->if_vnet)->mod_data[VNET_MOD_NET];
3) Memory for vnet modules registered via vnet_mod_register() is now
allocated at run time in sys/kern/kern_vimage.c, instead of per vnet
module structs being declared as globals. If required, vnet modules
can now request the framework to provide them with allocated bzeroed
memory by filling in the vmi_size field in their vmi_modinfo structures.
4) structs socket, ifnet, inpcbinfo, tcpcb and syncache_head are
extended to hold a pointer to the parent vnet. options VIMAGE builds
will fill in those fields as required.
5) curvnet is introduced as a new global variable in options VIMAGE
builds, always pointing to the default and only struct vnet.
6) struct sysctl_oid has been extended with additional two fields to
store major and minor virtualization module identifiers, oid_v_subs and
oid_v_mod. SYSCTL_V_* family of macros will fill in those fields
accordingly, and store the offset in the appropriate vnet container
struct in oid_arg1.
In sysctl handlers dealing with virtualized sysctls, the
SYSCTL_RESOLVE_V_ARG1() macro will compute the address of the target
variable and make it available in arg1 variable for further processing.
Unused fields in structs vnet_inet, vnet_inet6 and vnet_ipfw have
been deleted.
Reviewed by: bz, rwatson
Approved by: julian (mentor)
2009-04-30 13:36:26 +00:00
|
|
|
V_ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, curvnet);
|
2001-06-11 12:39:29 +00:00
|
|
|
|
|
|
|
bzero(nullbuf, sizeof(nullbuf));
|
2011-12-29 18:25:18 +00:00
|
|
|
TAILQ_FOREACH(ifp, &V_ifnet, if_list) {
|
2003-10-17 15:46:31 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Permit buiding kernels with options VIMAGE, restricted to only a single
active network stack instance. Turning on options VIMAGE at compile
time yields the following changes relative to default kernel build:
1) V_ accessor macros for virtualized variables resolve to structure
fields via base pointers, instead of being resolved as fields in global
structs or plain global variables. As an example, V_ifnet becomes:
options VIMAGE: ((struct vnet_net *) vnet_net)->_ifnet
default build: vnet_net_0._ifnet
options VIMAGE_GLOBALS: ifnet
2) INIT_VNET_* macros will declare and set up base pointers to be used
by V_ accessor macros, instead of resolving to whitespace:
INIT_VNET_NET(ifp->if_vnet); becomes
struct vnet_net *vnet_net = (ifp->if_vnet)->mod_data[VNET_MOD_NET];
3) Memory for vnet modules registered via vnet_mod_register() is now
allocated at run time in sys/kern/kern_vimage.c, instead of per vnet
module structs being declared as globals. If required, vnet modules
can now request the framework to provide them with allocated bzeroed
memory by filling in the vmi_size field in their vmi_modinfo structures.
4) structs socket, ifnet, inpcbinfo, tcpcb and syncache_head are
extended to hold a pointer to the parent vnet. options VIMAGE builds
will fill in those fields as required.
5) curvnet is introduced as a new global variable in options VIMAGE
builds, always pointing to the default and only struct vnet.
6) struct sysctl_oid has been extended with additional two fields to
store major and minor virtualization module identifiers, oid_v_subs and
oid_v_mod. SYSCTL_V_* family of macros will fill in those fields
accordingly, and store the offset in the appropriate vnet container
struct in oid_arg1.
In sysctl handlers dealing with virtualized sysctls, the
SYSCTL_RESOLVE_V_ARG1() macro will compute the address of the target
variable and make it available in arg1 variable for further processing.
Unused fields in structs vnet_inet, vnet_inet6 and vnet_ipfw have
been deleted.
Reviewed by: bz, rwatson
Approved by: julian (mentor)
2009-04-30 13:36:26 +00:00
|
|
|
CURVNET_RESTORE();
|
2001-06-11 12:39:29 +00:00
|
|
|
}
|
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
|
|
|
{
|
Bite the bullet, and make the IPv6 SSM and MLDv2 mega-commit:
import from p4 bms_netdev. Summary of changes:
* Connect netinet6/in6_mcast.c to build.
The legacy KAME KPIs are mostly preserved.
* Eliminate now dead code from ip6_output.c.
Don't do mbuf bingo, we are not going to do RFC 2292 style
CMSG tricks for multicast options as they are not required
by any current IPv6 normative reference.
* Refactor transports (UDP, raw_ip6) to do own mcast filtering.
SCTP, TCP unaffected by this change.
* Add ip6_msource, in6_msource structs to in6_var.h.
* Hookup mld_ifinfo state to in6_ifextra, allocate from
domifattach path.
* Eliminate IN6_LOOKUP_MULTI(), it is no longer referenced.
Kernel consumers which need this should use in6m_lookup().
* Refactor IPv6 socket group memberships to use a vector (like IPv4).
* Update ifmcstat(8) for IPv6 SSM.
* Add witness lock order for IN6_MULTI_LOCK.
* Move IN6_MULTI_LOCK out of lower ip6_output()/ip6_input() paths.
* Introduce IP6STAT_ADD/SUB/INC/DEC as per rwatson's IPv4 cleanup.
* Update carp(4) for new IPv6 SSM KPIs.
* Virtualize ip6_mrouter socket.
Changes mostly localized to IPv6 MROUTING.
* Don't do a local group lookup in MROUTING.
* Kill unused KAME prototypes in6_purgemkludge(), in6_restoremkludge().
* Preserve KAME DAD timer jitter behaviour in MLDv1 compatibility mode.
* Bump __FreeBSD_version to 800084.
* Update UPDATING.
NOTE WELL:
* This code hasn't been tested against real MLDv2 queriers
(yet), although the on-wire protocol has been verified in Wireshark.
* There are a few unresolved issues in the socket layer APIs to
do with scope ID propagation.
* There is a LOR present in ip6_output()'s use of
in6_setscope() which needs to be resolved. See comments in mld6.c.
This is believed to be benign and can't be avoided for the moment
without re-introducing an indirect netisr.
This work was mostly derived from the IGMPv3 implementation, and
has been sponsored by a third party.
2009-04-29 19:19:13 +00:00
|
|
|
LIST_HEAD(,in6_multi) purgeinms;
|
|
|
|
struct in6_multi *inm, *tinm;
|
|
|
|
struct ifmultiaddr *ifma;
|
|
|
|
|
|
|
|
LIST_INIT(&purgeinms);
|
|
|
|
IN6_MULTI_LOCK();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extract list of in6_multi associated with the detaching ifp
|
|
|
|
* which the PF_INET6 layer is about to release.
|
|
|
|
* We need to do this as IF_ADDR_LOCK() may be re-acquired
|
|
|
|
* by code further down.
|
|
|
|
*/
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RLOCK(ifp);
|
Bite the bullet, and make the IPv6 SSM and MLDv2 mega-commit:
import from p4 bms_netdev. Summary of changes:
* Connect netinet6/in6_mcast.c to build.
The legacy KAME KPIs are mostly preserved.
* Eliminate now dead code from ip6_output.c.
Don't do mbuf bingo, we are not going to do RFC 2292 style
CMSG tricks for multicast options as they are not required
by any current IPv6 normative reference.
* Refactor transports (UDP, raw_ip6) to do own mcast filtering.
SCTP, TCP unaffected by this change.
* Add ip6_msource, in6_msource structs to in6_var.h.
* Hookup mld_ifinfo state to in6_ifextra, allocate from
domifattach path.
* Eliminate IN6_LOOKUP_MULTI(), it is no longer referenced.
Kernel consumers which need this should use in6m_lookup().
* Refactor IPv6 socket group memberships to use a vector (like IPv4).
* Update ifmcstat(8) for IPv6 SSM.
* Add witness lock order for IN6_MULTI_LOCK.
* Move IN6_MULTI_LOCK out of lower ip6_output()/ip6_input() paths.
* Introduce IP6STAT_ADD/SUB/INC/DEC as per rwatson's IPv4 cleanup.
* Update carp(4) for new IPv6 SSM KPIs.
* Virtualize ip6_mrouter socket.
Changes mostly localized to IPv6 MROUTING.
* Don't do a local group lookup in MROUTING.
* Kill unused KAME prototypes in6_purgemkludge(), in6_restoremkludge().
* Preserve KAME DAD timer jitter behaviour in MLDv1 compatibility mode.
* Bump __FreeBSD_version to 800084.
* Update UPDATING.
NOTE WELL:
* This code hasn't been tested against real MLDv2 queriers
(yet), although the on-wire protocol has been verified in Wireshark.
* There are a few unresolved issues in the socket layer APIs to
do with scope ID propagation.
* There is a LOR present in ip6_output()'s use of
in6_setscope() which needs to be resolved. See comments in mld6.c.
This is believed to be benign and can't be avoided for the moment
without re-introducing an indirect netisr.
This work was mostly derived from the IGMPv3 implementation, and
has been sponsored by a third party.
2009-04-29 19:19:13 +00:00
|
|
|
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
|
|
|
|
if (ifma->ifma_addr->sa_family != AF_INET6 ||
|
|
|
|
ifma->ifma_protospec == NULL)
|
|
|
|
continue;
|
|
|
|
inm = (struct in6_multi *)ifma->ifma_protospec;
|
|
|
|
LIST_INSERT_HEAD(&purgeinms, inm, in6m_entry);
|
|
|
|
}
|
2012-01-05 19:00:36 +00:00
|
|
|
IF_ADDR_RUNLOCK(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
|
|
|
|
Bite the bullet, and make the IPv6 SSM and MLDv2 mega-commit:
import from p4 bms_netdev. Summary of changes:
* Connect netinet6/in6_mcast.c to build.
The legacy KAME KPIs are mostly preserved.
* Eliminate now dead code from ip6_output.c.
Don't do mbuf bingo, we are not going to do RFC 2292 style
CMSG tricks for multicast options as they are not required
by any current IPv6 normative reference.
* Refactor transports (UDP, raw_ip6) to do own mcast filtering.
SCTP, TCP unaffected by this change.
* Add ip6_msource, in6_msource structs to in6_var.h.
* Hookup mld_ifinfo state to in6_ifextra, allocate from
domifattach path.
* Eliminate IN6_LOOKUP_MULTI(), it is no longer referenced.
Kernel consumers which need this should use in6m_lookup().
* Refactor IPv6 socket group memberships to use a vector (like IPv4).
* Update ifmcstat(8) for IPv6 SSM.
* Add witness lock order for IN6_MULTI_LOCK.
* Move IN6_MULTI_LOCK out of lower ip6_output()/ip6_input() paths.
* Introduce IP6STAT_ADD/SUB/INC/DEC as per rwatson's IPv4 cleanup.
* Update carp(4) for new IPv6 SSM KPIs.
* Virtualize ip6_mrouter socket.
Changes mostly localized to IPv6 MROUTING.
* Don't do a local group lookup in MROUTING.
* Kill unused KAME prototypes in6_purgemkludge(), in6_restoremkludge().
* Preserve KAME DAD timer jitter behaviour in MLDv1 compatibility mode.
* Bump __FreeBSD_version to 800084.
* Update UPDATING.
NOTE WELL:
* This code hasn't been tested against real MLDv2 queriers
(yet), although the on-wire protocol has been verified in Wireshark.
* There are a few unresolved issues in the socket layer APIs to
do with scope ID propagation.
* There is a LOR present in ip6_output()'s use of
in6_setscope() which needs to be resolved. See comments in mld6.c.
This is believed to be benign and can't be avoided for the moment
without re-introducing an indirect netisr.
This work was mostly derived from the IGMPv3 implementation, and
has been sponsored by a third party.
2009-04-29 19:19:13 +00:00
|
|
|
LIST_FOREACH_SAFE(inm, &purgeinms, in6m_entry, tinm) {
|
|
|
|
LIST_REMOVE(inm, in6m_entry);
|
|
|
|
in6m_release_locked(inm);
|
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
|
|
|
}
|
Bite the bullet, and make the IPv6 SSM and MLDv2 mega-commit:
import from p4 bms_netdev. Summary of changes:
* Connect netinet6/in6_mcast.c to build.
The legacy KAME KPIs are mostly preserved.
* Eliminate now dead code from ip6_output.c.
Don't do mbuf bingo, we are not going to do RFC 2292 style
CMSG tricks for multicast options as they are not required
by any current IPv6 normative reference.
* Refactor transports (UDP, raw_ip6) to do own mcast filtering.
SCTP, TCP unaffected by this change.
* Add ip6_msource, in6_msource structs to in6_var.h.
* Hookup mld_ifinfo state to in6_ifextra, allocate from
domifattach path.
* Eliminate IN6_LOOKUP_MULTI(), it is no longer referenced.
Kernel consumers which need this should use in6m_lookup().
* Refactor IPv6 socket group memberships to use a vector (like IPv4).
* Update ifmcstat(8) for IPv6 SSM.
* Add witness lock order for IN6_MULTI_LOCK.
* Move IN6_MULTI_LOCK out of lower ip6_output()/ip6_input() paths.
* Introduce IP6STAT_ADD/SUB/INC/DEC as per rwatson's IPv4 cleanup.
* Update carp(4) for new IPv6 SSM KPIs.
* Virtualize ip6_mrouter socket.
Changes mostly localized to IPv6 MROUTING.
* Don't do a local group lookup in MROUTING.
* Kill unused KAME prototypes in6_purgemkludge(), in6_restoremkludge().
* Preserve KAME DAD timer jitter behaviour in MLDv1 compatibility mode.
* Bump __FreeBSD_version to 800084.
* Update UPDATING.
NOTE WELL:
* This code hasn't been tested against real MLDv2 queriers
(yet), although the on-wire protocol has been verified in Wireshark.
* There are a few unresolved issues in the socket layer APIs to
do with scope ID propagation.
* There is a LOR present in ip6_output()'s use of
in6_setscope() which needs to be resolved. See comments in mld6.c.
This is believed to be benign and can't be avoided for the moment
without re-introducing an indirect netisr.
This work was mostly derived from the IGMPv3 implementation, and
has been sponsored by a third party.
2009-04-29 19:19:13 +00:00
|
|
|
mld_ifdetach(ifp);
|
|
|
|
|
|
|
|
IN6_MULTI_UNLOCK();
|
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
|
|
|
}
|