2007-08-07 08:35:42 +04:00
|
|
|
/* $NetBSD: nd6.c,v 1.118 2007/08/07 04:35:42 dyoung Exp $ */
|
2002-06-09 01:22:29 +04:00
|
|
|
/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
|
1999-07-04 01:24:45 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
2000-04-16 19:00:56 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the project nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
2000-04-16 19:00:56 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2001-11-13 03:56:55 +03:00
|
|
|
#include <sys/cdefs.h>
|
2007-08-07 08:35:42 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.118 2007/08/07 04:35:42 dyoung Exp $");
|
2003-08-23 02:11:44 +04:00
|
|
|
|
|
|
|
#include "opt_ipsec.h"
|
2001-11-13 03:56:55 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
2000-03-23 10:01:25 +03:00
|
|
|
#include <sys/callout.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/kernel.h>
|
2000-02-26 11:39:18 +03:00
|
|
|
#include <sys/protosw.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <sys/errno.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/syslog.h>
|
|
|
|
#include <sys/queue.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_dl.h>
|
|
|
|
#include <net/if_types.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
#include <net/if_ether.h>
|
|
|
|
#include <net/if_fddi.h>
|
2002-06-03 04:51:47 +04:00
|
|
|
#include <net/if_arc.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/in6_var.h>
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/ip6.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/ip6_var.h>
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
#include <netinet6/scope6_var.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/nd6.h>
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/icmp6.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2003-08-23 02:11:44 +04:00
|
|
|
#ifdef IPSEC
|
|
|
|
#include <netinet6/ipsec.h>
|
|
|
|
#endif
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <net/net_osdep.h>
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
#define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */
|
|
|
|
#define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */
|
|
|
|
|
|
|
|
/* timer values */
|
|
|
|
int nd6_prune = 1; /* walk list every 1 seconds */
|
|
|
|
int nd6_delay = 5; /* delay first probe time 5 second */
|
|
|
|
int nd6_umaxtries = 3; /* maximum unicast query */
|
|
|
|
int nd6_mmaxtries = 3; /* maximum multicast query */
|
|
|
|
int nd6_useloopback = 1; /* use loopback interface for local traffic */
|
2001-02-23 11:02:41 +03:00
|
|
|
int nd6_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
/* preventing too many loops in ND option parsing */
|
|
|
|
int nd6_maxndopt = 10; /* max # of ND options allowed */
|
|
|
|
|
2000-07-06 16:36:18 +04:00
|
|
|
int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
int nd6_maxqueuelen = 1; /* max # of packets cached in unresolved ND entries */
|
|
|
|
|
2001-02-07 11:59:47 +03:00
|
|
|
#ifdef ND6_DEBUG
|
|
|
|
int nd6_debug = 1;
|
|
|
|
#else
|
|
|
|
int nd6_debug = 0;
|
|
|
|
#endif
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* for debugging? */
|
|
|
|
static int nd6_inuse, nd6_allocated;
|
|
|
|
|
2006-09-02 11:22:44 +04:00
|
|
|
struct llinfo_nd6 llinfo_nd6 = {
|
|
|
|
.ln_prev = &llinfo_nd6,
|
|
|
|
.ln_next = &llinfo_nd6,
|
|
|
|
};
|
1999-12-13 18:17:17 +03:00
|
|
|
struct nd_drhead nd_defrouter;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct nd_prhead nd_prefix = { 0 };
|
|
|
|
|
|
|
|
int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL;
|
1999-12-13 18:17:17 +03:00
|
|
|
static struct sockaddr_in6 all1_sa;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-05-30 09:06:28 +04:00
|
|
|
static void nd6_setmtu0 __P((struct ifnet *, struct nd_ifinfo *));
|
1999-06-28 10:36:47 +04:00
|
|
|
static void nd6_slowtimo __P((void *));
|
2006-03-06 02:47:08 +03:00
|
|
|
static int regen_tmpaddr __P((struct in6_ifaddr *));
|
2001-10-17 14:55:09 +04:00
|
|
|
static struct llinfo_nd6 *nd6_free __P((struct rtentry *, int));
|
2003-06-27 12:41:08 +04:00
|
|
|
static void nd6_llinfo_timer __P((void *));
|
2006-03-24 22:24:38 +03:00
|
|
|
static void clear_llinfo_pqueue __P((struct llinfo_nd6 *));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_t nd6_slowtimo_ch;
|
|
|
|
callout_t nd6_timer_ch;
|
|
|
|
extern callout_t in6_tmpaddrtimer_ch;
|
2000-03-23 10:01:25 +03:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
static int fill_drlist __P((void *, size_t *, size_t));
|
|
|
|
static int fill_prlist __P((void *, size_t *, size_t));
|
|
|
|
|
2003-02-01 09:23:35 +03:00
|
|
|
MALLOC_DEFINE(M_IP6NDP, "NDP", "IPv6 Neighbour Discovery");
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
void
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_init(void)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
static int nd6_init_done = 0;
|
1999-12-13 18:17:17 +03:00
|
|
|
int i;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (nd6_init_done) {
|
|
|
|
log(LOG_NOTICE, "nd6_init called more than once(ignored)\n");
|
|
|
|
return;
|
|
|
|
}
|
1999-12-13 18:17:17 +03:00
|
|
|
|
|
|
|
all1_sa.sin6_family = AF_INET6;
|
|
|
|
all1_sa.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
for (i = 0; i < sizeof(all1_sa.sin6_addr); i++)
|
|
|
|
all1_sa.sin6_addr.s6_addr[i] = 0xff;
|
|
|
|
|
|
|
|
/* initialization of the default router list */
|
|
|
|
TAILQ_INIT(&nd_defrouter);
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
nd6_init_done = 1;
|
|
|
|
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&nd6_slowtimo_ch, 0);
|
|
|
|
callout_init(&nd6_timer_ch, 0);
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* start timer */
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
|
|
|
|
nd6_slowtimo, NULL);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
struct nd_ifinfo *
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_ifattach(struct ifnet *ifp)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2002-05-29 11:53:39 +04:00
|
|
|
struct nd_ifinfo *nd;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK);
|
|
|
|
bzero(nd, sizeof(*nd));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
nd->initialized = 1;
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
nd->chlim = IPV6_DEFHLIM;
|
|
|
|
nd->basereachable = REACHABLE_TIME;
|
|
|
|
nd->reachable = ND_COMPUTE_RTIME(nd->basereachable);
|
|
|
|
nd->retrans = RETRANS_TIMER;
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* Note that the default value of ip6_accept_rtadv is 0, which means
|
|
|
|
* we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV
|
|
|
|
* here.
|
|
|
|
*/
|
|
|
|
nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV);
|
2002-05-30 09:06:28 +04:00
|
|
|
|
|
|
|
/* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */
|
|
|
|
nd6_setmtu0(ifp, nd);
|
2000-04-12 14:36:38 +04:00
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
return nd;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_ifdetach(struct nd_ifinfo *nd)
|
2002-05-29 11:53:39 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
free(nd, M_IP6NDP);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_setmtu(struct ifnet *ifp)
|
2002-05-30 09:06:28 +04:00
|
|
|
{
|
|
|
|
nd6_setmtu0(ifp, ND_IFINFO(ifp));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2002-05-30 09:06:28 +04:00
|
|
|
u_int32_t omaxmtu;
|
|
|
|
|
|
|
|
omaxmtu = ndi->maxmtu;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2001-02-21 20:23:09 +03:00
|
|
|
switch (ifp->if_type) {
|
2002-06-03 04:51:47 +04:00
|
|
|
case IFT_ARCNET:
|
|
|
|
ndi->maxmtu = MIN(ARC_PHDS_MAXMTU, ifp->if_mtu); /* RFC2497 */
|
2001-02-21 19:28:43 +03:00
|
|
|
break;
|
2002-05-29 11:53:39 +04:00
|
|
|
case IFT_FDDI:
|
|
|
|
ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu);
|
|
|
|
break;
|
2001-02-21 19:28:43 +03:00
|
|
|
default:
|
|
|
|
ndi->maxmtu = ifp->if_mtu;
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2002-05-30 09:06:28 +04:00
|
|
|
/*
|
|
|
|
* Decreasing the interface MTU under IPV6 minimum MTU may cause
|
|
|
|
* undesirable situation. We thus notify the operator of the change
|
|
|
|
* explicitly. The check for omaxmtu is necessary to restrict the
|
2002-06-03 06:09:37 +04:00
|
|
|
* log to the case of changing the MTU, not initializing it.
|
2002-05-30 09:06:28 +04:00
|
|
|
*/
|
|
|
|
if (omaxmtu >= IPV6_MMTU && ndi->maxmtu < IPV6_MMTU) {
|
2003-05-04 17:43:09 +04:00
|
|
|
log(LOG_NOTICE, "nd6_setmtu0: new link MTU on %s (%lu) is too"
|
|
|
|
" small for IPv6 which needs %lu\n",
|
|
|
|
if_name(ifp), (unsigned long)ndi->maxmtu, (unsigned long)
|
|
|
|
IPV6_MMTU);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-05-29 11:53:39 +04:00
|
|
|
|
|
|
|
if (ndi->maxmtu > in6_maxmtu)
|
|
|
|
in6_setmaxmtu(); /* check all interfaces just in case */
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_option_init(void *opt, int icmp6len, union nd_opts *ndopts)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2002-05-29 11:53:39 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
bzero(ndopts, sizeof(*ndopts));
|
|
|
|
ndopts->nd_opts_search = (struct nd_opt_hdr *)opt;
|
|
|
|
ndopts->nd_opts_last
|
|
|
|
= (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len);
|
|
|
|
|
|
|
|
if (icmp6len == 0) {
|
|
|
|
ndopts->nd_opts_done = 1;
|
|
|
|
ndopts->nd_opts_search = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Take one ND option.
|
|
|
|
*/
|
|
|
|
struct nd_opt_hdr *
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_option(union nd_opts *ndopts)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct nd_opt_hdr *nd_opt;
|
|
|
|
int olen;
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ndopts == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ndopts == NULL in nd6_option");
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ndopts->nd_opts_last == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("uninitialized ndopts in nd6_option");
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ndopts->nd_opts_search == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
return NULL;
|
|
|
|
if (ndopts->nd_opts_done)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
nd_opt = ndopts->nd_opts_search;
|
|
|
|
|
2001-02-21 20:23:09 +03:00
|
|
|
/* make sure nd_opt_len is inside the buffer */
|
2007-03-04 08:59:00 +03:00
|
|
|
if ((void *)&nd_opt->nd_opt_len >= (void *)ndopts->nd_opts_last) {
|
2001-02-21 20:23:09 +03:00
|
|
|
bzero(ndopts, sizeof(*ndopts));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
olen = nd_opt->nd_opt_len << 3;
|
|
|
|
if (olen == 0) {
|
|
|
|
/*
|
|
|
|
* Message validation requires that all included
|
|
|
|
* options have a length that is greater than zero.
|
|
|
|
*/
|
|
|
|
bzero(ndopts, sizeof(*ndopts));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-03-04 08:59:00 +03:00
|
|
|
ndopts->nd_opts_search = (struct nd_opt_hdr *)((char *)nd_opt + olen);
|
2001-02-21 20:23:09 +03:00
|
|
|
if (ndopts->nd_opts_search > ndopts->nd_opts_last) {
|
|
|
|
/* option overruns the end of buffer, invalid */
|
|
|
|
bzero(ndopts, sizeof(*ndopts));
|
|
|
|
return NULL;
|
|
|
|
} else if (ndopts->nd_opts_search == ndopts->nd_opts_last) {
|
|
|
|
/* reached the end of options chain */
|
1999-06-28 10:36:47 +04:00
|
|
|
ndopts->nd_opts_done = 1;
|
|
|
|
ndopts->nd_opts_search = NULL;
|
|
|
|
}
|
|
|
|
return nd_opt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse multiple ND options.
|
|
|
|
* This function is much easier to use, for ND routines that do not need
|
|
|
|
* multiple options of the same type.
|
|
|
|
*/
|
|
|
|
int
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_options(union nd_opts *ndopts)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct nd_opt_hdr *nd_opt;
|
|
|
|
int i = 0;
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ndopts == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ndopts == NULL in nd6_options");
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ndopts->nd_opts_last == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("uninitialized ndopts in nd6_options");
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ndopts->nd_opts_search == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
return 0;
|
2006-03-06 02:47:08 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
while (1) {
|
|
|
|
nd_opt = nd6_option(ndopts);
|
2006-03-06 02:47:08 +03:00
|
|
|
if (nd_opt == NULL && ndopts->nd_opts_last == NULL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Message validation requires that all included
|
|
|
|
* options have a length that is greater than zero.
|
|
|
|
*/
|
2001-02-07 11:59:47 +03:00
|
|
|
icmp6stat.icp6s_nd_badopt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
bzero(ndopts, sizeof(*ndopts));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
if (nd_opt == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
goto skip1;
|
|
|
|
|
|
|
|
switch (nd_opt->nd_opt_type) {
|
|
|
|
case ND_OPT_SOURCE_LINKADDR:
|
|
|
|
case ND_OPT_TARGET_LINKADDR:
|
|
|
|
case ND_OPT_MTU:
|
|
|
|
case ND_OPT_REDIRECTED_HEADER:
|
|
|
|
if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_INFO,
|
|
|
|
"duplicated ND6 option found (type=%d)\n",
|
|
|
|
nd_opt->nd_opt_type));
|
1999-06-28 10:36:47 +04:00
|
|
|
/* XXX bark? */
|
|
|
|
} else {
|
|
|
|
ndopts->nd_opt_array[nd_opt->nd_opt_type]
|
|
|
|
= nd_opt;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ND_OPT_PREFIX_INFORMATION:
|
|
|
|
if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) {
|
|
|
|
ndopts->nd_opt_array[nd_opt->nd_opt_type]
|
|
|
|
= nd_opt;
|
|
|
|
}
|
|
|
|
ndopts->nd_opts_pi_end =
|
|
|
|
(struct nd_opt_prefix_info *)nd_opt;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* Unknown options must be silently ignored,
|
2006-11-24 22:46:58 +03:00
|
|
|
* to accommodate future extension to the protocol.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_DEBUG,
|
1999-06-28 10:36:47 +04:00
|
|
|
"nd6_options: unsupported option %d - "
|
2001-02-07 11:59:47 +03:00
|
|
|
"option ignored\n", nd_opt->nd_opt_type));
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
skip1:
|
|
|
|
i++;
|
1999-12-13 18:17:17 +03:00
|
|
|
if (i > nd6_maxndopt) {
|
|
|
|
icmp6stat.icp6s_nd_toomanyopt++;
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_INFO, "too many loop in nd opt\n"));
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ndopts->nd_opts_done)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2003-06-27 12:41:08 +04:00
|
|
|
* ND6 timer routine to handle ND6 entries
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
void
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_llinfo_settimer(struct llinfo_nd6 *ln, long xtick)
|
2003-06-27 12:41:08 +04:00
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
|
|
|
s = splsoftnet();
|
|
|
|
|
2005-05-30 01:43:51 +04:00
|
|
|
if (xtick < 0) {
|
2003-06-27 12:41:08 +04:00
|
|
|
ln->ln_expire = 0;
|
|
|
|
ln->ln_ntick = 0;
|
|
|
|
callout_stop(&ln->ln_timer_ch);
|
|
|
|
} else {
|
2006-06-08 02:33:33 +04:00
|
|
|
ln->ln_expire = time_second + xtick / hz;
|
2005-05-30 01:43:51 +04:00
|
|
|
if (xtick > INT_MAX) {
|
|
|
|
ln->ln_ntick = xtick - INT_MAX;
|
2003-06-27 12:41:08 +04:00
|
|
|
callout_reset(&ln->ln_timer_ch, INT_MAX,
|
|
|
|
nd6_llinfo_timer, ln);
|
|
|
|
} else {
|
|
|
|
ln->ln_ntick = 0;
|
2005-05-30 01:43:51 +04:00
|
|
|
callout_reset(&ln->ln_timer_ch, xtick,
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_timer, ln);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_llinfo_timer(void *arg)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
int s;
|
2001-02-10 07:14:26 +03:00
|
|
|
struct llinfo_nd6 *ln;
|
2003-06-27 12:41:08 +04:00
|
|
|
struct rtentry *rt;
|
|
|
|
const struct sockaddr_in6 *dst;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct ifnet *ifp;
|
2003-06-27 12:41:08 +04:00
|
|
|
struct nd_ifinfo *ndi = NULL;
|
2002-06-03 06:09:37 +04:00
|
|
|
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2003-06-27 12:41:08 +04:00
|
|
|
ln = (struct llinfo_nd6 *)arg;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2003-06-27 12:41:08 +04:00
|
|
|
if (ln->ln_ntick > 0) {
|
2006-03-02 08:11:31 +03:00
|
|
|
nd6_llinfo_settimer(ln, ln->ln_ntick);
|
2003-06-27 12:41:08 +04:00
|
|
|
splx(s);
|
|
|
|
return;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2003-06-27 12:41:08 +04:00
|
|
|
if ((rt = ln->ln_rt) == NULL)
|
|
|
|
panic("ln->ln_rt == NULL");
|
|
|
|
if ((ifp = rt->rt_ifp) == NULL)
|
|
|
|
panic("ln->ln_rt->rt_ifp == NULL");
|
|
|
|
ndi = ND_IFINFO(ifp);
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
dst = satocsin6(rt_getkey(rt));
|
2003-06-27 12:41:08 +04:00
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln)
|
|
|
|
panic("rt_llinfo(%p) is not equal to ln(%p)",
|
|
|
|
rt->rt_llinfo, ln);
|
|
|
|
if (!dst)
|
|
|
|
panic("dst=0 in nd6_timer(ln=%p)", ln);
|
|
|
|
|
|
|
|
switch (ln->ln_state) {
|
|
|
|
case ND6_LLINFO_INCOMPLETE:
|
|
|
|
if (ln->ln_asked < nd6_mmaxtries) {
|
|
|
|
ln->ln_asked++;
|
|
|
|
nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
|
|
|
|
nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0);
|
|
|
|
} else {
|
|
|
|
struct mbuf *m = ln->ln_hold;
|
|
|
|
if (m) {
|
2006-03-24 22:24:38 +03:00
|
|
|
struct mbuf *m0;
|
|
|
|
|
2003-06-27 12:41:08 +04:00
|
|
|
/*
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
* assuming every packet in ln_hold has
|
|
|
|
* the same IP header
|
2003-06-27 12:41:08 +04:00
|
|
|
*/
|
2006-03-24 22:24:38 +03:00
|
|
|
m0 = m->m_nextpkt;
|
|
|
|
m->m_nextpkt = NULL;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
icmp6_error2(m, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_ADDR, 0, rt->rt_ifp);
|
2006-03-24 22:24:38 +03:00
|
|
|
|
|
|
|
ln->ln_hold = m0;
|
|
|
|
clear_llinfo_pqueue(ln);
|
|
|
|
}
|
2003-06-27 12:41:08 +04:00
|
|
|
(void)nd6_free(rt, 0);
|
|
|
|
ln = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ND6_LLINFO_REACHABLE:
|
|
|
|
if (!ND6_LLINFO_PERMANENT(ln)) {
|
|
|
|
ln->ln_state = ND6_LLINFO_STALE;
|
|
|
|
nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
|
|
|
|
}
|
|
|
|
break;
|
2001-02-23 11:02:41 +03:00
|
|
|
|
2003-06-27 12:41:08 +04:00
|
|
|
case ND6_LLINFO_STALE:
|
|
|
|
/* Garbage Collection(RFC 2461 5.3) */
|
|
|
|
if (!ND6_LLINFO_PERMANENT(ln)) {
|
|
|
|
(void)nd6_free(rt, 1);
|
|
|
|
ln = NULL;
|
|
|
|
}
|
|
|
|
break;
|
2001-02-23 11:02:41 +03:00
|
|
|
|
2003-06-27 12:41:08 +04:00
|
|
|
case ND6_LLINFO_DELAY:
|
|
|
|
if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) {
|
|
|
|
/* We need NUD */
|
|
|
|
ln->ln_asked = 1;
|
|
|
|
ln->ln_state = ND6_LLINFO_PROBE;
|
|
|
|
nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
|
|
|
|
nd6_ns_output(ifp, &dst->sin6_addr,
|
|
|
|
&dst->sin6_addr, ln, 0);
|
|
|
|
} else {
|
|
|
|
ln->ln_state = ND6_LLINFO_STALE; /* XXX */
|
|
|
|
nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ND6_LLINFO_PROBE:
|
|
|
|
if (ln->ln_asked < nd6_umaxtries) {
|
|
|
|
ln->ln_asked++;
|
|
|
|
nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
|
|
|
|
nd6_ns_output(ifp, &dst->sin6_addr,
|
|
|
|
&dst->sin6_addr, ln, 0);
|
|
|
|
} else {
|
|
|
|
(void)nd6_free(rt, 0);
|
|
|
|
ln = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2003-06-27 12:41:08 +04:00
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-06-03 06:09:37 +04:00
|
|
|
|
2003-06-27 12:41:08 +04:00
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ND6 timer routine to expire default route list and prefix list
|
|
|
|
*/
|
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
nd6_timer(void *ignored_arg)
|
2003-06-27 12:41:08 +04:00
|
|
|
{
|
|
|
|
int s;
|
2006-11-20 07:34:16 +03:00
|
|
|
struct nd_defrouter *next_dr, *dr;
|
|
|
|
struct nd_prefix *next_pr, *pr;
|
2003-06-27 12:41:08 +04:00
|
|
|
struct in6_ifaddr *ia6, *nia6;
|
2006-03-06 02:47:08 +03:00
|
|
|
struct in6_addrlifetime *lt6;
|
2003-06-27 12:41:08 +04:00
|
|
|
|
|
|
|
s = splsoftnet();
|
|
|
|
callout_reset(&nd6_timer_ch, nd6_prune * hz,
|
|
|
|
nd6_timer, NULL);
|
|
|
|
|
2001-03-08 13:49:32 +03:00
|
|
|
/* expire default router list */
|
2006-11-20 07:34:16 +03:00
|
|
|
|
|
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr != NULL; dr = next_dr) {
|
|
|
|
next_dr = TAILQ_NEXT(dr, dr_entry);
|
2006-06-08 02:33:33 +04:00
|
|
|
if (dr->expire && dr->expire < time_second) {
|
1999-06-28 10:36:47 +04:00
|
|
|
defrtrlist_del(dr);
|
2000-07-06 16:36:18 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* expire interface addresses.
|
|
|
|
* in the past the loop was inside prefix expiry processing.
|
|
|
|
* However, from a stricter speci-confrmance standpoint, we should
|
|
|
|
* rather separate address lifetimes and prefix lifetimes.
|
|
|
|
*/
|
2006-03-06 02:47:08 +03:00
|
|
|
addrloop:
|
2002-06-09 01:22:29 +04:00
|
|
|
for (ia6 = in6_ifaddr; ia6; ia6 = nia6) {
|
|
|
|
nia6 = ia6->ia_next;
|
|
|
|
/* check address lifetime */
|
2006-03-06 02:47:08 +03:00
|
|
|
lt6 = &ia6->ia6_lifetime;
|
2002-06-09 01:22:29 +04:00
|
|
|
if (IFA6_IS_INVALID(ia6)) {
|
2006-03-06 02:47:08 +03:00
|
|
|
int regen = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the expiring address is temporary, try
|
|
|
|
* regenerating a new one. This would be useful when
|
|
|
|
* we suspended a laptop PC, then turned it on after a
|
|
|
|
* period that could invalidate all temporary
|
|
|
|
* addresses. Although we may have to restart the
|
|
|
|
* loop (see below), it must be after purging the
|
|
|
|
* address. Otherwise, we'd see an infinite loop of
|
|
|
|
* regeneration.
|
|
|
|
*/
|
|
|
|
if (ip6_use_tempaddr &&
|
|
|
|
(ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
|
|
|
|
if (regen_tmpaddr(ia6) == 0)
|
|
|
|
regen = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
in6_purgeaddr(&ia6->ia_ifa);
|
|
|
|
|
|
|
|
if (regen)
|
|
|
|
goto addrloop; /* XXX: see below */
|
|
|
|
} else if (IFA6_IS_DEPRECATED(ia6)) {
|
|
|
|
int oldflags = ia6->ia6_flags;
|
|
|
|
|
|
|
|
ia6->ia6_flags |= IN6_IFF_DEPRECATED;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If a temporary address has just become deprecated,
|
|
|
|
* regenerate a new one if possible.
|
|
|
|
*/
|
|
|
|
if (ip6_use_tempaddr &&
|
|
|
|
(ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
|
|
|
|
(oldflags & IN6_IFF_DEPRECATED) == 0) {
|
|
|
|
|
|
|
|
if (regen_tmpaddr(ia6) == 0) {
|
|
|
|
/*
|
|
|
|
* A new temporary address is
|
|
|
|
* generated.
|
|
|
|
* XXX: this means the address chain
|
|
|
|
* has changed while we are still in
|
|
|
|
* the loop. Although the change
|
|
|
|
* would not cause disaster (because
|
|
|
|
* it's not a deletion, but an
|
|
|
|
* addition,) we'd rather restart the
|
|
|
|
* loop just for safety. Or does this
|
|
|
|
* significantly reduce performance??
|
|
|
|
*/
|
|
|
|
goto addrloop;
|
|
|
|
}
|
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* A new RA might have made a deprecated address
|
|
|
|
* preferred.
|
|
|
|
*/
|
|
|
|
ia6->ia6_flags &= ~IN6_IFF_DEPRECATED;
|
|
|
|
}
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* expire prefix list */
|
2006-11-20 07:34:16 +03:00
|
|
|
for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = next_pr) {
|
|
|
|
next_pr = LIST_NEXT(pr, ndpr_entry);
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* check prefix lifetime.
|
|
|
|
* since pltime is just for autoconf, pltime processing for
|
|
|
|
* prefix is not necessary.
|
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME &&
|
2006-06-08 02:33:33 +04:00
|
|
|
time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) {
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* address expiration and prefix expiration are
|
2002-06-09 01:22:29 +04:00
|
|
|
* separate. NEVER perform in6_purgeaddr here.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
prelist_remove(pr);
|
2006-11-20 07:34:16 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
2007-03-16 02:35:25 +03:00
|
|
|
/* ia6: deprecated/invalidated temporary address */
|
2006-03-06 02:47:08 +03:00
|
|
|
static int
|
2007-03-16 02:35:25 +03:00
|
|
|
regen_tmpaddr(struct in6_ifaddr *ia6)
|
2006-03-06 02:47:08 +03:00
|
|
|
{
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
struct in6_ifaddr *public_ifa6 = NULL;
|
|
|
|
|
|
|
|
ifp = ia6->ia_ifa.ifa_ifp;
|
2006-11-20 07:34:16 +03:00
|
|
|
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
|
2006-03-06 02:47:08 +03:00
|
|
|
struct in6_ifaddr *it6;
|
|
|
|
|
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET6)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
it6 = (struct in6_ifaddr *)ifa;
|
|
|
|
|
|
|
|
/* ignore no autoconf addresses. */
|
|
|
|
if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* ignore autoconf addresses with different prefixes. */
|
|
|
|
if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we are looking at an autoconf address with the same
|
|
|
|
* prefix as ours. If the address is temporary and is still
|
|
|
|
* preferred, do not create another one. It would be rare, but
|
|
|
|
* could happen, for example, when we resume a laptop PC after
|
|
|
|
* a long period.
|
|
|
|
*/
|
|
|
|
if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
|
|
|
|
!IFA6_IS_DEPRECATED(it6)) {
|
|
|
|
public_ifa6 = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is a public autoconf address that has the same prefix
|
|
|
|
* as ours. If it is preferred, keep it. We can't break the
|
|
|
|
* loop here, because there may be a still-preferred temporary
|
|
|
|
* address with the prefix.
|
|
|
|
*/
|
|
|
|
if (!IFA6_IS_DEPRECATED(it6))
|
|
|
|
public_ifa6 = it6;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (public_ifa6 != NULL) {
|
|
|
|
int e;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Random factor is introduced in the preferred lifetime, so
|
|
|
|
* we do not need additional delay (3rd arg to in6_tmpifadd).
|
|
|
|
*/
|
|
|
|
if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) {
|
|
|
|
log(LOG_NOTICE, "regen_tmpaddr: failed to create a new"
|
|
|
|
" tmp addr, errno=%d\n", e);
|
2007-03-16 02:35:25 +03:00
|
|
|
return -1;
|
2006-03-06 02:47:08 +03:00
|
|
|
}
|
2007-03-16 02:35:25 +03:00
|
|
|
return 0;
|
2006-03-06 02:47:08 +03:00
|
|
|
}
|
|
|
|
|
2007-03-16 02:35:25 +03:00
|
|
|
return -1;
|
2006-03-06 02:47:08 +03:00
|
|
|
}
|
|
|
|
|
2000-02-04 17:34:22 +03:00
|
|
|
/*
|
|
|
|
* Nuke neighbor cache/prefix/default router management table, right before
|
|
|
|
* ifp goes away.
|
|
|
|
*/
|
|
|
|
void
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_purge(struct ifnet *ifp)
|
2000-02-04 17:34:22 +03:00
|
|
|
{
|
|
|
|
struct llinfo_nd6 *ln, *nln;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct nd_defrouter *dr, *ndr;
|
2000-02-04 17:34:22 +03:00
|
|
|
struct nd_prefix *pr, *npr;
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* Nuke default router list entries toward ifp.
|
|
|
|
* We defer removal of default router list entries that is installed
|
|
|
|
* in the routing table, in order to keep additional side effects as
|
|
|
|
* small as possible.
|
|
|
|
*/
|
|
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) {
|
|
|
|
ndr = TAILQ_NEXT(dr, dr_entry);
|
|
|
|
if (dr->installed)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (dr->ifp == ifp)
|
|
|
|
defrtrlist_del(dr);
|
|
|
|
}
|
|
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) {
|
|
|
|
ndr = TAILQ_NEXT(dr, dr_entry);
|
|
|
|
if (!dr->installed)
|
|
|
|
continue;
|
|
|
|
|
2000-02-04 17:34:22 +03:00
|
|
|
if (dr->ifp == ifp)
|
|
|
|
defrtrlist_del(dr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Nuke prefix list entries toward ifp */
|
2006-11-20 07:34:16 +03:00
|
|
|
for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = npr) {
|
|
|
|
npr = LIST_NEXT(pr, ndpr_entry);
|
2000-02-04 17:34:22 +03:00
|
|
|
if (pr->ndpr_ifp == ifp) {
|
2005-04-03 15:02:27 +04:00
|
|
|
/*
|
|
|
|
* Because if_detach() does *not* release prefixes
|
|
|
|
* while purging addresses the reference count will
|
|
|
|
* still be above zero. We therefore reset it to
|
|
|
|
* make sure that the prefix really gets purged.
|
|
|
|
*/
|
|
|
|
pr->ndpr_refcnt = 0;
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* Previously, pr->ndpr_addr is removed as well,
|
|
|
|
* but I strongly believe we don't have to do it.
|
|
|
|
* nd6_purge() is only called from in6_ifdetach(),
|
|
|
|
* which removes all the associated interface addresses
|
|
|
|
* by itself.
|
|
|
|
* (jinmei@kame.net 20010129)
|
|
|
|
*/
|
2000-02-04 17:34:22 +03:00
|
|
|
prelist_remove(pr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cancel default outgoing interface setting */
|
|
|
|
if (nd6_defifindex == ifp->if_index)
|
|
|
|
nd6_setdefaultiface(0);
|
|
|
|
|
2001-06-27 21:36:14 +04:00
|
|
|
if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */
|
|
|
|
/* refresh default router list */
|
|
|
|
defrouter_select();
|
|
|
|
}
|
2000-02-04 17:34:22 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Nuke neighbor cache entries for the ifp.
|
|
|
|
* Note that rt->rt_ifp may not be the same as ifp,
|
|
|
|
* due to KAME goto ours hack. See RTM_RESOLVE case in
|
2000-02-26 11:39:18 +03:00
|
|
|
* nd6_rtrequest(), and ip6_input().
|
2000-02-04 17:34:22 +03:00
|
|
|
*/
|
|
|
|
ln = llinfo_nd6.ln_next;
|
|
|
|
while (ln && ln != &llinfo_nd6) {
|
|
|
|
struct rtentry *rt;
|
2007-08-07 08:35:42 +04:00
|
|
|
const struct sockaddr_dl *sdl;
|
2000-02-04 17:34:22 +03:00
|
|
|
|
|
|
|
nln = ln->ln_next;
|
|
|
|
rt = ln->ln_rt;
|
|
|
|
if (rt && rt->rt_gateway &&
|
|
|
|
rt->rt_gateway->sa_family == AF_LINK) {
|
2007-08-07 08:35:42 +04:00
|
|
|
sdl = satocsdl(rt->rt_gateway);
|
2000-02-04 17:34:22 +03:00
|
|
|
if (sdl->sdl_index == ifp->if_index)
|
2001-10-17 14:55:09 +04:00
|
|
|
nln = nd6_free(rt, 0);
|
2000-02-04 17:34:22 +03:00
|
|
|
}
|
|
|
|
ln = nln;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
struct rtentry *
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct rtentry *rt;
|
|
|
|
struct sockaddr_in6 sin6;
|
|
|
|
|
|
|
|
bzero(&sin6, sizeof(sin6));
|
|
|
|
sin6.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
sin6.sin6_family = AF_INET6;
|
|
|
|
sin6.sin6_addr = *addr6;
|
2000-01-06 18:46:07 +03:00
|
|
|
rt = rtalloc1((struct sockaddr *)&sin6, create);
|
1999-06-28 10:36:47 +04:00
|
|
|
if (rt && (rt->rt_flags & RTF_LLINFO) == 0) {
|
|
|
|
/*
|
|
|
|
* This is the case for the default route.
|
2000-04-16 19:00:56 +04:00
|
|
|
* If we want to create a neighbor cache for the address, we
|
1999-06-28 10:36:47 +04:00
|
|
|
* should free the route for the destination and allocate an
|
|
|
|
* interface route.
|
|
|
|
*/
|
|
|
|
if (create) {
|
|
|
|
RTFREE(rt);
|
2006-03-06 02:47:08 +03:00
|
|
|
rt = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
2007-03-16 02:35:25 +03:00
|
|
|
if (rt != NULL)
|
|
|
|
;
|
|
|
|
else if (create && ifp) {
|
|
|
|
int e;
|
2000-04-16 19:00:56 +04:00
|
|
|
|
2007-03-16 02:35:25 +03:00
|
|
|
/*
|
|
|
|
* If no route is available and create is set,
|
|
|
|
* we allocate a host route for the destination
|
|
|
|
* and treat it like an interface route.
|
|
|
|
* This hack is necessary for a neighbor which can't
|
|
|
|
* be covered by our own prefix.
|
|
|
|
*/
|
|
|
|
struct ifaddr *ifa =
|
|
|
|
ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp);
|
|
|
|
if (ifa == NULL)
|
|
|
|
return NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2007-03-16 02:35:25 +03:00
|
|
|
/*
|
|
|
|
* Create a new route. RTF_LLINFO is necessary
|
|
|
|
* to create a Neighbor Cache entry for the
|
|
|
|
* destination in nd6_rtrequest which will be
|
|
|
|
* called in rtrequest via ifa->ifa_rtrequest.
|
|
|
|
*/
|
|
|
|
if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6,
|
|
|
|
ifa->ifa_addr, (struct sockaddr *)&all1_sa,
|
|
|
|
(ifa->ifa_flags | RTF_HOST | RTF_LLINFO) &
|
|
|
|
~RTF_CLONING, &rt)) != 0) {
|
2001-10-17 14:55:09 +04:00
|
|
|
#if 0
|
2007-03-16 02:35:25 +03:00
|
|
|
log(LOG_ERR,
|
|
|
|
"nd6_lookup: failed to add route for a "
|
|
|
|
"neighbor(%s), errno=%d\n",
|
|
|
|
ip6_sprintf(addr6), e);
|
2001-10-17 14:55:09 +04:00
|
|
|
#endif
|
2007-03-16 02:35:25 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (rt == NULL)
|
|
|
|
return NULL;
|
|
|
|
if (rt->rt_llinfo) {
|
|
|
|
struct llinfo_nd6 *ln =
|
|
|
|
(struct llinfo_nd6 *)rt->rt_llinfo;
|
|
|
|
ln->ln_state = ND6_LLINFO_NOSTATE;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
return NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
rt->rt_refcnt--;
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
|
|
|
* Validation for the entry.
|
2002-06-09 01:22:29 +04:00
|
|
|
* Note that the check for rt_llinfo is necessary because a cloned
|
|
|
|
* route from a parent route that has the L flag (e.g. the default
|
|
|
|
* route to a p2p interface) may have the flag, too, while the
|
|
|
|
* destination is not actually a neighbor.
|
1999-12-13 18:17:17 +03:00
|
|
|
* XXX: we can't use rt->rt_ifp to check for the interface, since
|
|
|
|
* it might be the loopback interface if the entry is for our
|
|
|
|
* own address on a non-loopback interface. Instead, we should
|
2002-06-09 01:22:29 +04:00
|
|
|
* use rt->rt_ifa->ifa_ifp, which would specify the REAL
|
|
|
|
* interface.
|
2006-03-06 02:47:08 +03:00
|
|
|
* Note also that ifa_ifp and ifp may differ when we connect two
|
|
|
|
* interfaces to a same link, install a link prefix to an interface,
|
|
|
|
* and try to install a neighbor cache on an interface that does not
|
|
|
|
* have a route to the prefix.
|
1999-12-13 18:17:17 +03:00
|
|
|
*/
|
1999-06-28 10:36:47 +04:00
|
|
|
if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 ||
|
2002-06-09 01:22:29 +04:00
|
|
|
rt->rt_gateway->sa_family != AF_LINK || rt->rt_llinfo == NULL ||
|
1999-12-13 18:17:17 +03:00
|
|
|
(ifp && rt->rt_ifa->ifa_ifp != ifp)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
if (create) {
|
2002-10-10 00:22:16 +04:00
|
|
|
nd6log((LOG_DEBUG,
|
2002-06-09 01:22:29 +04:00
|
|
|
"nd6_lookup: failed to lookup %s (if = %s)\n",
|
|
|
|
ip6_sprintf(addr6),
|
2002-10-10 00:22:16 +04:00
|
|
|
ifp ? if_name(ifp) : "unspec"));
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2007-03-16 02:35:25 +03:00
|
|
|
return NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2007-03-16 02:35:25 +03:00
|
|
|
return rt;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
1999-07-06 16:23:19 +04:00
|
|
|
/*
|
|
|
|
* Detect if a given IPv6 address identifies a neighbor on a given link.
|
2000-04-16 19:00:56 +04:00
|
|
|
* XXX: should take care of the destination of a p2p link?
|
1999-07-06 16:23:19 +04:00
|
|
|
*/
|
|
|
|
int
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
|
1999-07-06 16:23:19 +04:00
|
|
|
{
|
2002-06-09 01:22:29 +04:00
|
|
|
struct nd_prefix *pr;
|
1999-07-06 16:23:19 +04:00
|
|
|
|
2000-05-09 15:51:12 +04:00
|
|
|
/*
|
|
|
|
* A link-local address is always a neighbor.
|
2001-10-16 10:24:44 +04:00
|
|
|
* XXX: a link does not necessarily specify a single interface.
|
2000-05-09 15:51:12 +04:00
|
|
|
*/
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
|
|
|
|
struct sockaddr_in6 sin6_copy;
|
|
|
|
u_int32_t zone;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need sin6_copy since sa6_recoverscope() may modify the
|
|
|
|
* content (XXX).
|
|
|
|
*/
|
|
|
|
sin6_copy = *addr;
|
|
|
|
if (sa6_recoverscope(&sin6_copy))
|
2007-03-16 02:35:25 +03:00
|
|
|
return 0; /* XXX: should be impossible */
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone))
|
2007-03-16 02:35:25 +03:00
|
|
|
return 0;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (sin6_copy.sin6_scope_id == zone)
|
2007-03-16 02:35:25 +03:00
|
|
|
return 1;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
else
|
2007-03-16 02:35:25 +03:00
|
|
|
return 0;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
}
|
1999-07-06 16:23:19 +04:00
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* If the address matches one of our on-link prefixes, it should be a
|
|
|
|
* neighbor.
|
1999-07-06 16:23:19 +04:00
|
|
|
*/
|
2006-11-20 07:34:16 +03:00
|
|
|
LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
|
2002-06-09 01:22:29 +04:00
|
|
|
if (pr->ndpr_ifp != ifp)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(pr->ndpr_stateflags & NDPRF_ONLINK))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr,
|
|
|
|
&addr->sin6_addr, &pr->ndpr_mask))
|
2007-03-16 02:35:25 +03:00
|
|
|
return 1;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the default router list is empty, all addresses are regarded
|
|
|
|
* as on-link, and thus, as a neighbor.
|
|
|
|
* XXX: we restrict the condition to hosts, because routers usually do
|
|
|
|
* not have the "default router list".
|
|
|
|
*/
|
|
|
|
if (!ip6_forwarding && TAILQ_FIRST(&nd_defrouter) == NULL &&
|
|
|
|
nd6_defifindex == ifp->if_index) {
|
2007-03-16 02:35:25 +03:00
|
|
|
return 1;
|
1999-07-06 16:23:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Even if the address matches none of our addresses, it might be
|
|
|
|
* in the neighbor cache.
|
|
|
|
*/
|
2003-10-30 04:43:08 +03:00
|
|
|
if (nd6_lookup(&addr->sin6_addr, 0, ifp) != NULL)
|
2007-03-16 02:35:25 +03:00
|
|
|
return 1;
|
1999-07-06 16:23:19 +04:00
|
|
|
|
2007-03-16 02:35:25 +03:00
|
|
|
return 0;
|
1999-07-06 16:23:19 +04:00
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Free an nd6 llinfo entry.
|
2001-10-17 14:55:09 +04:00
|
|
|
* Since the function would cause significant changes in the kernel, DO NOT
|
|
|
|
* make it global, unless you have a strong reason for the change, and are sure
|
|
|
|
* that the change is safe.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2001-10-17 14:55:09 +04:00
|
|
|
static struct llinfo_nd6 *
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_free(struct rtentry *rt, int gc)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2001-02-08 15:57:54 +03:00
|
|
|
struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next;
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
struct in6_addr in6 = satocsin6(rt_getkey(rt))->sin6_addr;
|
1999-12-13 18:17:17 +03:00
|
|
|
struct nd_defrouter *dr;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-02-26 11:39:18 +03:00
|
|
|
/*
|
2001-10-17 14:55:09 +04:00
|
|
|
* we used to have pfctlinput(PRC_HOSTDEAD) here.
|
|
|
|
* even though it is not harmful, it was not really necessary.
|
2000-02-26 11:39:18 +03:00
|
|
|
*/
|
|
|
|
|
2003-06-27 12:41:08 +04:00
|
|
|
/* cancel timer */
|
|
|
|
nd6_llinfo_settimer(ln, -1);
|
|
|
|
|
2003-06-24 11:54:47 +04:00
|
|
|
if (!ip6_forwarding) {
|
1999-06-28 10:36:47 +04:00
|
|
|
int s;
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
dr = defrouter_lookup(&satocsin6(rt_getkey(rt))->sin6_addr,
|
2002-06-09 01:22:29 +04:00
|
|
|
rt->rt_ifp);
|
2001-10-17 14:55:09 +04:00
|
|
|
|
|
|
|
if (dr != NULL && dr->expire &&
|
|
|
|
ln->ln_state == ND6_LLINFO_STALE && gc) {
|
|
|
|
/*
|
|
|
|
* If the reason for the deletion is just garbage
|
|
|
|
* collection, and the neighbor is an active default
|
|
|
|
* router, do not delete it. Instead, reset the GC
|
|
|
|
* timer using the router's lifetime.
|
|
|
|
* Simply deleting the entry would affect default
|
|
|
|
* router selection, which is not necessarily a good
|
|
|
|
* thing, especially when we're using router preference
|
|
|
|
* values.
|
|
|
|
* XXX: the check for ln_state would be redundant,
|
|
|
|
* but we intentionally keep it just in case.
|
|
|
|
*/
|
2006-06-08 02:33:33 +04:00
|
|
|
if (dr->expire > time_second)
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_settimer(ln,
|
2006-06-08 02:33:33 +04:00
|
|
|
(dr->expire - time_second) * hz);
|
2003-06-27 12:41:08 +04:00
|
|
|
else
|
|
|
|
nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
|
2001-10-17 14:55:09 +04:00
|
|
|
splx(s);
|
2007-03-16 02:35:25 +03:00
|
|
|
return ln->ln_next;
|
2001-10-17 14:55:09 +04:00
|
|
|
}
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
if (ln->ln_router || dr) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
1999-12-13 18:17:17 +03:00
|
|
|
* rt6_flush must be called whether or not the neighbor
|
|
|
|
* is in the Default Router List.
|
|
|
|
* See a corresponding comment in nd6_na_input().
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
1999-12-13 18:17:17 +03:00
|
|
|
rt6_flush(&in6, rt->rt_ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dr) {
|
|
|
|
/*
|
|
|
|
* Unreachablity of a router might affect the default
|
|
|
|
* router selection and on-link detection of advertised
|
|
|
|
* prefixes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Temporarily fake the state to choose a new default
|
|
|
|
* router and to perform on-link determination of
|
2001-10-17 14:55:09 +04:00
|
|
|
* prefixes correctly.
|
1999-12-13 18:17:17 +03:00
|
|
|
* Below the state will be set correctly,
|
|
|
|
* or the entry itself will be deleted.
|
|
|
|
*/
|
|
|
|
ln->ln_state = ND6_LLINFO_INCOMPLETE;
|
|
|
|
|
2001-10-17 14:55:09 +04:00
|
|
|
/*
|
|
|
|
* Since defrouter_select() does not affect the
|
|
|
|
* on-link determination and MIP6 needs the check
|
|
|
|
* before the default router selection, we perform
|
|
|
|
* the check now.
|
|
|
|
*/
|
|
|
|
pfxlist_onlink_check();
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* refresh default router list
|
|
|
|
*/
|
|
|
|
defrouter_select();
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
}
|
1999-12-13 18:17:17 +03:00
|
|
|
|
2001-02-08 15:57:54 +03:00
|
|
|
/*
|
|
|
|
* Before deleting the entry, remember the next entry as the
|
|
|
|
* return value. We need this because pfxlist_onlink_check() above
|
|
|
|
* might have freed other entries (particularly the old next entry) as
|
2001-10-16 10:24:44 +04:00
|
|
|
* a side effect (XXX).
|
2001-02-08 15:57:54 +03:00
|
|
|
*/
|
|
|
|
next = ln->ln_next;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Detach the route from the routing tree and the list of neighbor
|
|
|
|
* caches, and disable the route entry not to be used in already
|
|
|
|
* cached routes.
|
|
|
|
*/
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
rtrequest(RTM_DELETE, rt_getkey(rt), (struct sockaddr *)0,
|
2002-06-09 01:22:29 +04:00
|
|
|
rt_mask(rt), 0, (struct rtentry **)0);
|
2001-02-08 15:57:54 +03:00
|
|
|
|
2007-03-16 02:35:25 +03:00
|
|
|
return next;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Upper-layer reachability hint for Neighbor Unreachability Detection.
|
|
|
|
*
|
2006-03-03 17:07:06 +03:00
|
|
|
* XXX cost-effective methods?
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
void
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_nud_hint(struct rtentry *rt, struct in6_addr *dst6, int force)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct llinfo_nd6 *ln;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the caller specified "rt", use that. Otherwise, resolve the
|
|
|
|
* routing table by supplied "dst6".
|
|
|
|
*/
|
2006-03-06 02:47:08 +03:00
|
|
|
if (rt == NULL) {
|
|
|
|
if (dst6 == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
return;
|
2006-03-06 02:47:08 +03:00
|
|
|
if ((rt = nd6_lookup(dst6, 0, NULL)) == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-07-06 16:36:18 +04:00
|
|
|
if ((rt->rt_flags & RTF_GATEWAY) != 0 ||
|
|
|
|
(rt->rt_flags & RTF_LLINFO) == 0 ||
|
|
|
|
!rt->rt_llinfo || !rt->rt_gateway ||
|
|
|
|
rt->rt_gateway->sa_family != AF_LINK) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/* This is not a host route. */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
|
2000-04-13 18:11:06 +04:00
|
|
|
if (ln->ln_state < ND6_LLINFO_REACHABLE)
|
1999-06-28 10:36:47 +04:00
|
|
|
return;
|
|
|
|
|
2000-07-06 16:36:18 +04:00
|
|
|
/*
|
|
|
|
* if we get upper-layer reachability confirmation many times,
|
|
|
|
* it is possible we have false information.
|
|
|
|
*/
|
|
|
|
if (!force) {
|
|
|
|
ln->ln_byhint++;
|
|
|
|
if (ln->ln_byhint > nd6_maxnudhint)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
ln->ln_state = ND6_LLINFO_REACHABLE;
|
2003-06-27 12:41:08 +04:00
|
|
|
if (!ND6_LLINFO_PERMANENT(ln)) {
|
|
|
|
nd6_llinfo_settimer(ln,
|
|
|
|
(long)ND_IFINFO(rt->rt_ifp)->reachable * hz);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct sockaddr *gate = rt->rt_gateway;
|
|
|
|
struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo;
|
2006-09-02 11:22:44 +04:00
|
|
|
static const struct sockaddr_dl null_sdl = {
|
|
|
|
.sdl_len = sizeof(null_sdl),
|
|
|
|
.sdl_family = AF_LINK,
|
|
|
|
};
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ifnet *ifp = rt->rt_ifp;
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((rt->rt_flags & RTF_GATEWAY) != 0)
|
1999-06-28 10:36:47 +04:00
|
|
|
return;
|
|
|
|
|
2001-10-17 14:55:09 +04:00
|
|
|
if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) {
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
2001-10-17 14:55:09 +04:00
|
|
|
/*
|
|
|
|
* This is probably an interface direct route for a link
|
|
|
|
* which does not need neighbor caches (e.g. fe80::%lo0/64).
|
|
|
|
* We do not need special treatment below for such a route.
|
|
|
|
* Moreover, the RTF_LLINFO flag which would be set below
|
|
|
|
* would annoy the ndp(8) command.
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
if (req == RTM_RESOLVE &&
|
|
|
|
(nd6_need_cache(ifp) == 0 || /* stf case */
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
!nd6_is_addr_neighbor(satocsin6(rt_getkey(rt)), ifp))) {
|
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* FreeBSD and BSD/OS often make a cloned host route based
|
|
|
|
* on a less-specific route (e.g. the default route).
|
|
|
|
* If the less specific route does not have a "gateway"
|
|
|
|
* (this is the case when the route just goes to a p2p or an
|
|
|
|
* stf interface), we'll mistakenly make a neighbor cache for
|
|
|
|
* the host route, and will see strange neighbor solicitation
|
|
|
|
* for the corresponding destination. In order to avoid the
|
|
|
|
* confusion, we check if the destination of the route is
|
|
|
|
* a neighbor in terms of neighbor discovery, and stop the
|
|
|
|
* process if not. Additionally, we remove the LLINFO flag
|
|
|
|
* so that ndp(8) will not try to get the neighbor information
|
|
|
|
* of the destination.
|
|
|
|
*/
|
|
|
|
rt->rt_flags &= ~RTF_LLINFO;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
switch (req) {
|
|
|
|
case RTM_ADD:
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* There is no backward compatibility :)
|
|
|
|
*
|
|
|
|
* if ((rt->rt_flags & RTF_HOST) == 0 &&
|
|
|
|
* SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
|
|
|
|
* rt->rt_flags |= RTF_CLONING;
|
|
|
|
*/
|
2003-06-24 11:49:03 +04:00
|
|
|
if ((rt->rt_flags & RTF_CLONING) ||
|
|
|
|
((rt->rt_flags & RTF_LLINFO) && !ln)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
2003-06-24 11:49:03 +04:00
|
|
|
* Case 1: This route should come from a route to
|
|
|
|
* interface (RTF_CLONING case) or the route should be
|
|
|
|
* treated as on-link but is currently not
|
|
|
|
* (RTF_LLINFO && !ln case).
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
rt_setgate(rt, (const struct sockaddr *)&null_sdl);
|
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
1999-06-28 10:36:47 +04:00
|
|
|
gate = rt->rt_gateway;
|
2007-08-07 08:35:42 +04:00
|
|
|
satosdl(gate)->sdl_type = ifp->if_type;
|
|
|
|
satosdl(gate)->sdl_index = ifp->if_index;
|
1999-06-28 10:36:47 +04:00
|
|
|
if (ln)
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_settimer(ln, 0);
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((rt->rt_flags & RTF_CLONING) != 0)
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
}
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
2000-02-26 11:39:18 +03:00
|
|
|
/*
|
|
|
|
* In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here.
|
|
|
|
* We don't do that here since llinfo is not ready yet.
|
|
|
|
*
|
|
|
|
* There are also couple of other things to be discussed:
|
|
|
|
* - unsolicited NA code needs improvement beforehand
|
|
|
|
* - RFC2461 says we MAY send multicast unsolicited NA
|
|
|
|
* (7.2.6 paragraph 4), however, it also says that we
|
|
|
|
* SHOULD provide a mechanism to prevent multicast NA storm.
|
|
|
|
* we don't have anything like it right now.
|
2001-02-10 07:14:26 +03:00
|
|
|
* note that the mechanism needs a mutual agreement
|
2000-02-26 11:39:18 +03:00
|
|
|
* between proxies, which means that we need to implement
|
2001-02-10 07:14:26 +03:00
|
|
|
* a new protocol, or a new kludge.
|
|
|
|
* - from RFC2461 6.2.4, host MUST NOT send an unsolicited NA.
|
2000-02-26 11:39:18 +03:00
|
|
|
* we need to check ip6forwarding before sending it.
|
|
|
|
* (or should we allow proxy ND configuration only for
|
|
|
|
* routers? there's no mention about proxy ND from hosts)
|
|
|
|
*/
|
|
|
|
#if 0
|
|
|
|
/* XXX it does not work */
|
1999-06-28 10:36:47 +04:00
|
|
|
if (rt->rt_flags & RTF_ANNOUNCE)
|
|
|
|
nd6_na_output(ifp,
|
2007-08-07 08:35:42 +04:00
|
|
|
&satocsin6(rt_getkey(rt))->sin6_addr,
|
|
|
|
&satocsin6(rt_getkey(rt))->sin6_addr,
|
2000-02-26 11:39:18 +03:00
|
|
|
ip6_forwarding ? ND_NA_FLAG_ROUTER : 0,
|
|
|
|
1, NULL);
|
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
/* FALLTHROUGH */
|
|
|
|
case RTM_RESOLVE:
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) {
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
2000-04-16 19:27:59 +04:00
|
|
|
/*
|
|
|
|
* Address resolution isn't necessary for a point to
|
|
|
|
* point link, so we can skip this test for a p2p link.
|
|
|
|
*/
|
|
|
|
if (gate->sa_family != AF_LINK ||
|
|
|
|
gate->sa_len < sizeof(null_sdl)) {
|
|
|
|
log(LOG_DEBUG,
|
2001-02-07 11:59:47 +03:00
|
|
|
"nd6_rtrequest: bad gateway value: %s\n",
|
|
|
|
if_name(ifp));
|
2000-04-16 19:27:59 +04:00
|
|
|
break;
|
|
|
|
}
|
2007-08-07 08:35:42 +04:00
|
|
|
satosdl(gate)->sdl_type = ifp->if_type;
|
|
|
|
satosdl(gate)->sdl_index = ifp->if_index;
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2000-04-16 19:27:59 +04:00
|
|
|
if (ln != NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
break; /* This happens on a route change */
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Case 2: This route may come from cloning, or a manual route
|
|
|
|
* add with a LL address.
|
|
|
|
*/
|
|
|
|
R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln));
|
2007-03-04 08:59:00 +03:00
|
|
|
rt->rt_llinfo = (void *)ln;
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ln == NULL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n");
|
|
|
|
break;
|
|
|
|
}
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
1999-06-28 10:36:47 +04:00
|
|
|
nd6_inuse++;
|
|
|
|
nd6_allocated++;
|
2006-03-06 02:47:08 +03:00
|
|
|
bzero(ln, sizeof(*ln));
|
1999-06-28 10:36:47 +04:00
|
|
|
ln->ln_rt = rt;
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&ln->ln_timer_ch, 0);
|
1999-06-28 10:36:47 +04:00
|
|
|
/* this is required for "ndp" command. - shin */
|
|
|
|
if (req == RTM_ADD) {
|
|
|
|
/*
|
|
|
|
* gate should have some valid AF_LINK entry,
|
|
|
|
* and ln->ln_expire should have some lifetime
|
|
|
|
* which is specified by ndp command.
|
|
|
|
*/
|
|
|
|
ln->ln_state = ND6_LLINFO_REACHABLE;
|
2000-07-06 16:36:18 +04:00
|
|
|
ln->ln_byhint = 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
} else {
|
2000-04-16 19:00:56 +04:00
|
|
|
/*
|
1999-06-28 10:36:47 +04:00
|
|
|
* When req == RTM_RESOLVE, rt is created and
|
|
|
|
* initialized in rtrequest(), so rt_expire is 0.
|
|
|
|
*/
|
1999-12-13 18:17:17 +03:00
|
|
|
ln->ln_state = ND6_LLINFO_NOSTATE;
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_settimer(ln, 0);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
1999-06-28 10:36:47 +04:00
|
|
|
rt->rt_flags |= RTF_LLINFO;
|
1999-07-02 16:43:42 +04:00
|
|
|
ln->ln_next = llinfo_nd6.ln_next;
|
|
|
|
llinfo_nd6.ln_next = ln;
|
|
|
|
ln->ln_prev = &llinfo_nd6;
|
|
|
|
ln->ln_next->ln_prev = ln;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
* check if rt_getkey(rt) is an address assigned
|
1999-06-28 10:36:47 +04:00
|
|
|
* to the interface.
|
|
|
|
*/
|
|
|
|
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp,
|
2007-08-07 08:35:42 +04:00
|
|
|
&satocsin6(rt_getkey(rt))->sin6_addr);
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
|
|
|
|
__LINE__, (void *)rt->_rt_key);
|
1999-06-28 10:36:47 +04:00
|
|
|
if (ifa) {
|
2007-03-04 08:59:00 +03:00
|
|
|
void *macp = nd6_ifptomac(ifp);
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_settimer(ln, -1);
|
1999-06-28 10:36:47 +04:00
|
|
|
ln->ln_state = ND6_LLINFO_REACHABLE;
|
2000-07-06 16:36:18 +04:00
|
|
|
ln->ln_byhint = 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
if (macp) {
|
2007-08-07 08:35:42 +04:00
|
|
|
/* XXX check for error */
|
|
|
|
(void)sockaddr_dl_setaddr(satosdl(gate), macp,
|
|
|
|
ifp->if_addrlen);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
if (nd6_useloopback) {
|
2004-12-04 19:10:25 +03:00
|
|
|
rt->rt_ifp = lo0ifp; /* XXX */
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Make sure rt_ifa be equal to the ifaddr
|
|
|
|
* corresponding to the address.
|
|
|
|
* We need this because when we refer
|
|
|
|
* rt_ifa->ia6_flags in ip6_input, we assume
|
|
|
|
* that the rt_ifa points to the address instead
|
|
|
|
* of the loopback address.
|
|
|
|
*/
|
2006-11-13 08:13:38 +03:00
|
|
|
if (ifa != rt->rt_ifa)
|
|
|
|
rt_replace_ifa(rt, ifa);
|
2007-03-17 09:32:46 +03:00
|
|
|
rt->rt_flags &= ~RTF_CLONED;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2000-02-26 11:39:18 +03:00
|
|
|
} else if (rt->rt_flags & RTF_ANNOUNCE) {
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_settimer(ln, -1);
|
2000-02-26 11:39:18 +03:00
|
|
|
ln->ln_state = ND6_LLINFO_REACHABLE;
|
2000-07-06 16:36:18 +04:00
|
|
|
ln->ln_byhint = 0;
|
2000-02-26 11:39:18 +03:00
|
|
|
|
|
|
|
/* join solicited node multicast for proxy ND */
|
|
|
|
if (ifp->if_flags & IFF_MULTICAST) {
|
|
|
|
struct in6_addr llsol;
|
|
|
|
int error;
|
|
|
|
|
2007-08-07 08:35:42 +04:00
|
|
|
llsol = satocsin6(rt_getkey(rt))->sin6_addr;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
llsol.s6_addr32[0] = htonl(0xff020000);
|
2000-02-26 11:39:18 +03:00
|
|
|
llsol.s6_addr32[1] = 0;
|
|
|
|
llsol.s6_addr32[2] = htonl(1);
|
|
|
|
llsol.s6_addr8[12] = 0xff;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (in6_setscope(&llsol, ifp, NULL))
|
|
|
|
break;
|
2006-03-06 02:47:08 +03:00
|
|
|
if (!in6_addmulti(&llsol, ifp, &error, 0)) {
|
2001-10-17 14:55:09 +04:00
|
|
|
nd6log((LOG_ERR, "%s: failed to join "
|
|
|
|
"%s (errno=%d)\n", if_name(ifp),
|
|
|
|
ip6_sprintf(&llsol), error));
|
2001-05-24 12:17:22 +04:00
|
|
|
}
|
2000-02-26 11:39:18 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTM_DELETE:
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ln == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
2000-02-26 11:39:18 +03:00
|
|
|
/* leave from solicited node multicast for proxy ND */
|
|
|
|
if ((rt->rt_flags & RTF_ANNOUNCE) != 0 &&
|
|
|
|
(ifp->if_flags & IFF_MULTICAST) != 0) {
|
|
|
|
struct in6_addr llsol;
|
|
|
|
struct in6_multi *in6m;
|
|
|
|
|
2007-08-07 08:35:42 +04:00
|
|
|
llsol = satocsin6(rt_getkey(rt))->sin6_addr;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
llsol.s6_addr32[0] = htonl(0xff020000);
|
2000-02-26 11:39:18 +03:00
|
|
|
llsol.s6_addr32[1] = 0;
|
|
|
|
llsol.s6_addr32[2] = htonl(1);
|
|
|
|
llsol.s6_addr8[12] = 0xff;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (in6_setscope(&llsol, ifp, NULL) == 0) {
|
|
|
|
IN6_LOOKUP_MULTI(llsol, ifp, in6m);
|
|
|
|
if (in6m)
|
|
|
|
in6_delmulti(in6m);
|
2006-09-02 11:22:44 +04:00
|
|
|
}
|
2000-02-26 11:39:18 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
nd6_inuse--;
|
1999-07-02 16:43:42 +04:00
|
|
|
ln->ln_next->ln_prev = ln->ln_prev;
|
|
|
|
ln->ln_prev->ln_next = ln->ln_next;
|
|
|
|
ln->ln_prev = NULL;
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_settimer(ln, -1);
|
1999-06-28 10:36:47 +04:00
|
|
|
rt->rt_llinfo = 0;
|
|
|
|
rt->rt_flags &= ~RTF_LLINFO;
|
2006-03-24 22:24:38 +03:00
|
|
|
clear_llinfo_pqueue(ln);
|
2007-03-04 08:59:00 +03:00
|
|
|
Free((void *)ln);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct in6_drlist *drl = (struct in6_drlist *)data;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct in6_oprlist *oprl = (struct in6_oprlist *)data;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct in6_ndireq *ndi = (struct in6_ndireq *)data;
|
|
|
|
struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data;
|
1999-12-13 18:17:17 +03:00
|
|
|
struct in6_ndifreq *ndif = (struct in6_ndifreq *)data;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct nd_defrouter *dr;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct nd_prefix *pr;
|
|
|
|
struct rtentry *rt;
|
|
|
|
int i = 0, error = 0;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCGDRLST_IN6:
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* obsolete API, use sysctl under net.inet6.icmp6
|
|
|
|
*/
|
1999-06-28 10:36:47 +04:00
|
|
|
bzero(drl, sizeof(*drl));
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
2006-11-20 07:34:16 +03:00
|
|
|
TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) {
|
|
|
|
if (i >= DRLSTSIZ)
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
drl->defrouter[i].rtaddr = dr->rtaddr;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
in6_clearscope(&drl->defrouter[i].rtaddr);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
drl->defrouter[i].flags = dr->flags;
|
|
|
|
drl->defrouter[i].rtlifetime = dr->rtlifetime;
|
|
|
|
drl->defrouter[i].expire = dr->expire;
|
|
|
|
drl->defrouter[i].if_index = dr->ifp->if_index;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
break;
|
|
|
|
case SIOCGPRLST_IN6:
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* obsolete API, use sysctl under net.inet6.icmp6
|
|
|
|
*
|
|
|
|
* XXX the structure in6_prlist was changed in backward-
|
|
|
|
* incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6,
|
|
|
|
* in6_prlist is used for nd6_sysctl() - fill_prlist().
|
|
|
|
*/
|
2000-02-26 11:39:18 +03:00
|
|
|
/*
|
|
|
|
* XXX meaning of fields, especialy "raflags", is very
|
|
|
|
* differnet between RA prefix list and RR/static prefix list.
|
|
|
|
* how about separating ioctls into two?
|
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
bzero(oprl, sizeof(*oprl));
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
2006-11-20 07:34:16 +03:00
|
|
|
LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
|
1999-06-28 10:36:47 +04:00
|
|
|
struct nd_pfxrouter *pfr;
|
|
|
|
int j;
|
|
|
|
|
2006-11-20 07:34:16 +03:00
|
|
|
if (i >= PRLSTSIZ)
|
|
|
|
break;
|
2002-06-09 01:22:29 +04:00
|
|
|
oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr;
|
|
|
|
oprl->prefix[i].raflags = pr->ndpr_raf;
|
|
|
|
oprl->prefix[i].prefixlen = pr->ndpr_plen;
|
|
|
|
oprl->prefix[i].vltime = pr->ndpr_vltime;
|
|
|
|
oprl->prefix[i].pltime = pr->ndpr_pltime;
|
|
|
|
oprl->prefix[i].if_index = pr->ndpr_ifp->if_index;
|
2006-03-06 02:47:08 +03:00
|
|
|
if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME)
|
|
|
|
oprl->prefix[i].expire = 0;
|
|
|
|
else {
|
|
|
|
time_t maxexpire;
|
|
|
|
|
|
|
|
/* XXX: we assume time_t is signed. */
|
|
|
|
maxexpire = (-1) &
|
|
|
|
~((time_t)1 <<
|
|
|
|
((sizeof(maxexpire) * 8) - 1));
|
|
|
|
if (pr->ndpr_vltime <
|
|
|
|
maxexpire - pr->ndpr_lastupdate) {
|
|
|
|
oprl->prefix[i].expire =
|
|
|
|
pr->ndpr_lastupdate +
|
|
|
|
pr->ndpr_vltime;
|
|
|
|
} else
|
|
|
|
oprl->prefix[i].expire = maxexpire;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
j = 0;
|
2006-11-20 07:34:16 +03:00
|
|
|
LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) {
|
1999-06-28 10:36:47 +04:00
|
|
|
if (j < DRLSTSIZ) {
|
2002-06-09 01:22:29 +04:00
|
|
|
#define RTRADDR oprl->prefix[i].advrtr[j]
|
1999-06-28 10:36:47 +04:00
|
|
|
RTRADDR = pfr->router->rtaddr;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
in6_clearscope(&RTRADDR);
|
1999-06-28 10:36:47 +04:00
|
|
|
#undef RTRADDR
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
oprl->prefix[i].advrtrs = j;
|
|
|
|
oprl->prefix[i].origin = PR_ORIG_RA;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
2000-02-26 11:39:18 +03:00
|
|
|
splx(s);
|
1999-12-13 18:17:17 +03:00
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
break;
|
|
|
|
case OSIOCGIFINFO_IN6:
|
2006-03-06 02:47:08 +03:00
|
|
|
#define ND ndi->ndi
|
2002-05-29 11:53:39 +04:00
|
|
|
/* XXX: old ndp(8) assumes a positive value for linkmtu. */
|
2006-03-06 02:47:08 +03:00
|
|
|
memset(&ND, 0, sizeof(ND));
|
|
|
|
ND.linkmtu = IN6_LINKMTU(ifp);
|
|
|
|
ND.maxmtu = ND_IFINFO(ifp)->maxmtu;
|
|
|
|
ND.basereachable = ND_IFINFO(ifp)->basereachable;
|
|
|
|
ND.reachable = ND_IFINFO(ifp)->reachable;
|
|
|
|
ND.retrans = ND_IFINFO(ifp)->retrans;
|
|
|
|
ND.flags = ND_IFINFO(ifp)->flags;
|
|
|
|
ND.recalctm = ND_IFINFO(ifp)->recalctm;
|
|
|
|
ND.chlim = ND_IFINFO(ifp)->chlim;
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
case SIOCGIFINFO_IN6:
|
2006-03-06 02:47:08 +03:00
|
|
|
ND = *ND_IFINFO(ifp);
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
2006-03-06 02:47:08 +03:00
|
|
|
case SIOCSIFINFO_IN6:
|
|
|
|
/*
|
|
|
|
* used to change host variables from userland.
|
|
|
|
* intented for a use on router to reflect RA configurations.
|
|
|
|
*/
|
|
|
|
/* 0 means 'unspecified' */
|
|
|
|
if (ND.linkmtu != 0) {
|
|
|
|
if (ND.linkmtu < IPV6_MMTU ||
|
|
|
|
ND.linkmtu > IN6_LINKMTU(ifp)) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ND_IFINFO(ifp)->linkmtu = ND.linkmtu;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ND.basereachable != 0) {
|
|
|
|
int obasereachable = ND_IFINFO(ifp)->basereachable;
|
|
|
|
|
|
|
|
ND_IFINFO(ifp)->basereachable = ND.basereachable;
|
|
|
|
if (ND.basereachable != obasereachable)
|
|
|
|
ND_IFINFO(ifp)->reachable =
|
|
|
|
ND_COMPUTE_RTIME(ND.basereachable);
|
|
|
|
}
|
|
|
|
if (ND.retrans != 0)
|
|
|
|
ND_IFINFO(ifp)->retrans = ND.retrans;
|
|
|
|
if (ND.chlim != 0)
|
|
|
|
ND_IFINFO(ifp)->chlim = ND.chlim;
|
|
|
|
/* FALLTHROUGH */
|
2000-04-16 19:27:59 +04:00
|
|
|
case SIOCSIFINFO_FLAGS:
|
2006-03-06 02:47:08 +03:00
|
|
|
ND_IFINFO(ifp)->flags = ND.flags;
|
2000-04-16 19:27:59 +04:00
|
|
|
break;
|
2006-03-06 02:47:08 +03:00
|
|
|
#undef ND
|
1999-12-13 18:17:17 +03:00
|
|
|
case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */
|
2002-06-09 01:22:29 +04:00
|
|
|
/* sync kernel routing table with the default router list */
|
|
|
|
defrouter_reset();
|
1999-12-13 18:17:17 +03:00
|
|
|
defrouter_select();
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
case SIOCSPFXFLUSH_IN6:
|
2002-06-09 01:22:29 +04:00
|
|
|
{
|
1999-06-28 10:36:47 +04:00
|
|
|
/* flush all the prefix advertised by routers */
|
2005-05-30 01:43:51 +04:00
|
|
|
struct nd_prefix *pfx, *next;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
2006-11-20 07:34:16 +03:00
|
|
|
for (pfx = LIST_FIRST(&nd_prefix); pfx; pfx = next) {
|
2002-06-09 01:22:29 +04:00
|
|
|
struct in6_ifaddr *ia, *ia_next;
|
|
|
|
|
2006-11-20 07:34:16 +03:00
|
|
|
next = LIST_NEXT(pfx, ndpr_entry);
|
2002-06-09 01:22:29 +04:00
|
|
|
|
2005-05-30 01:43:51 +04:00
|
|
|
if (IN6_IS_ADDR_LINKLOCAL(&pfx->ndpr_prefix.sin6_addr))
|
2002-06-09 01:22:29 +04:00
|
|
|
continue; /* XXX */
|
|
|
|
|
|
|
|
/* do we really have to remove addresses as well? */
|
|
|
|
for (ia = in6_ifaddr; ia; ia = ia_next) {
|
|
|
|
/* ia might be removed. keep the next ptr. */
|
|
|
|
ia_next = ia->ia_next;
|
|
|
|
|
|
|
|
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
|
|
|
|
continue;
|
|
|
|
|
2005-05-30 01:43:51 +04:00
|
|
|
if (ia->ia6_ndpr == pfx)
|
2002-06-09 01:22:29 +04:00
|
|
|
in6_purgeaddr(&ia->ia_ifa);
|
|
|
|
}
|
2005-05-30 01:43:51 +04:00
|
|
|
prelist_remove(pfx);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
break;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
case SIOCSRTRFLUSH_IN6:
|
2002-06-09 01:22:29 +04:00
|
|
|
{
|
1999-06-28 10:36:47 +04:00
|
|
|
/* flush all the default routers */
|
2005-05-30 01:43:51 +04:00
|
|
|
struct nd_defrouter *drtr, *next;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
2002-06-09 01:22:29 +04:00
|
|
|
defrouter_reset();
|
2005-05-30 01:43:51 +04:00
|
|
|
for (drtr = TAILQ_FIRST(&nd_defrouter); drtr; drtr = next) {
|
|
|
|
next = TAILQ_NEXT(drtr, dr_entry);
|
|
|
|
defrtrlist_del(drtr);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
defrouter_select();
|
1999-06-28 10:36:47 +04:00
|
|
|
splx(s);
|
|
|
|
break;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
case SIOCGNBRINFO_IN6:
|
2006-03-06 02:47:08 +03:00
|
|
|
{
|
1999-12-13 18:17:17 +03:00
|
|
|
struct llinfo_nd6 *ln;
|
|
|
|
struct in6_addr nb_addr = nbi->addr; /* make local for safety */
|
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if ((error = in6_setscope(&nb_addr, ifp, NULL)) != 0)
|
2007-03-16 02:35:25 +03:00
|
|
|
return error;
|
1999-12-13 18:17:17 +03:00
|
|
|
|
|
|
|
s = splsoftnet();
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL ||
|
|
|
|
(ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) {
|
1999-12-13 18:17:17 +03:00
|
|
|
error = EINVAL;
|
|
|
|
splx(s);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nbi->state = ln->ln_state;
|
|
|
|
nbi->asked = ln->ln_asked;
|
|
|
|
nbi->isrouter = ln->ln_router;
|
|
|
|
nbi->expire = ln->ln_expire;
|
|
|
|
splx(s);
|
2002-06-03 06:09:37 +04:00
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
break;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
1999-12-13 18:17:17 +03:00
|
|
|
case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */
|
|
|
|
ndif->ifindex = nd6_defifindex;
|
|
|
|
break;
|
|
|
|
case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */
|
2007-03-16 02:35:25 +03:00
|
|
|
return nd6_setdefaultiface(ndif->ifindex);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2007-03-16 02:35:25 +03:00
|
|
|
return error;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2007-05-17 04:53:26 +04:00
|
|
|
void
|
|
|
|
nd6_llinfo_release_pkts(struct llinfo_nd6 *ln, struct ifnet *ifp,
|
|
|
|
struct rtentry *rt)
|
|
|
|
{
|
|
|
|
struct mbuf *m_hold, *m_hold_next;
|
|
|
|
|
|
|
|
for (m_hold = ln->ln_hold, ln->ln_hold = NULL;
|
|
|
|
m_hold != NULL;
|
|
|
|
m_hold = m_hold_next) {
|
|
|
|
m_hold_next = m_hold->m_nextpkt;
|
|
|
|
m_hold->m_nextpkt = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we assume ifp is not a p2p here, so
|
|
|
|
* just set the 2nd argument as the
|
|
|
|
* 1st one.
|
|
|
|
*/
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
nd6_output(ifp, ifp, m_hold, satocsin6(rt_getkey(rt)), rt);
|
2007-05-17 04:53:26 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Create neighbor cache entry and cache link-layer address,
|
2001-10-16 10:24:44 +04:00
|
|
|
* on reception of inbound ND6 packets. (RS/RA/NS/redirect)
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
struct rtentry *
|
2006-10-12 05:30:41 +04:00
|
|
|
nd6_cache_lladdr(
|
|
|
|
struct ifnet *ifp,
|
|
|
|
struct in6_addr *from,
|
|
|
|
char *lladdr,
|
2006-11-16 04:32:37 +03:00
|
|
|
int lladdrlen,
|
2006-10-12 05:30:41 +04:00
|
|
|
int type, /* ICMP6 type */
|
|
|
|
int code /* type dependent information */
|
|
|
|
)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct rtentry *rt = NULL;
|
|
|
|
struct llinfo_nd6 *ln = NULL;
|
|
|
|
int is_newentry;
|
|
|
|
struct sockaddr_dl *sdl = NULL;
|
|
|
|
int do_update;
|
|
|
|
int olladdr;
|
|
|
|
int llchange;
|
|
|
|
int newstate = 0;
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ifp == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
panic("ifp == NULL in nd6_cache_lladdr");
|
2006-03-06 02:47:08 +03:00
|
|
|
if (from == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
panic("from == NULL in nd6_cache_lladdr");
|
|
|
|
|
|
|
|
/* nothing must be updated for unspecified address */
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(from))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validation about ifp->if_addrlen and lladdrlen must be done in
|
|
|
|
* the caller.
|
|
|
|
*
|
|
|
|
* XXX If the link does not have link-layer adderss, what should
|
|
|
|
* we do? (ifp->if_addrlen == 0)
|
|
|
|
* Spec says nothing in sections for RA, RS and NA. There's small
|
|
|
|
* description on it in NS section (RFC 2461 7.2.3).
|
|
|
|
*/
|
|
|
|
|
|
|
|
rt = nd6_lookup(from, 0, ifp);
|
2006-03-06 02:47:08 +03:00
|
|
|
if (rt == NULL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
#if 0
|
|
|
|
/* nothing must be done if there's no lladdr */
|
|
|
|
if (!lladdr || !lladdrlen)
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
rt = nd6_lookup(from, 1, ifp);
|
|
|
|
is_newentry = 1;
|
2001-03-08 13:49:32 +03:00
|
|
|
} else {
|
|
|
|
/* do nothing if static ndp is set */
|
|
|
|
if (rt->rt_flags & RTF_STATIC)
|
|
|
|
return NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
is_newentry = 0;
|
2001-03-08 13:49:32 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
if (rt == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
return NULL;
|
|
|
|
if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) {
|
|
|
|
fail:
|
2001-10-17 14:55:09 +04:00
|
|
|
(void)nd6_free(rt, 0);
|
1999-06-28 10:36:47 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ln == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
goto fail;
|
2006-03-06 02:47:08 +03:00
|
|
|
if (rt->rt_gateway == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
goto fail;
|
|
|
|
if (rt->rt_gateway->sa_family != AF_LINK)
|
|
|
|
goto fail;
|
2007-08-07 08:35:42 +04:00
|
|
|
sdl = satosdl(rt->rt_gateway);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
olladdr = (sdl->sdl_alen) ? 1 : 0;
|
|
|
|
if (olladdr && lladdr) {
|
2007-08-07 08:35:42 +04:00
|
|
|
if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen))
|
1999-06-28 10:36:47 +04:00
|
|
|
llchange = 1;
|
|
|
|
else
|
|
|
|
llchange = 0;
|
|
|
|
} else
|
|
|
|
llchange = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* newentry olladdr lladdr llchange (*=record)
|
|
|
|
* 0 n n -- (1)
|
|
|
|
* 0 y n -- (2)
|
|
|
|
* 0 n y -- (3) * STALE
|
|
|
|
* 0 y y n (4) *
|
|
|
|
* 0 y y y (5) * STALE
|
|
|
|
* 1 -- n -- (6) NOSTATE(= PASSIVE)
|
|
|
|
* 1 -- y -- (7) * STALE
|
|
|
|
*/
|
|
|
|
|
2001-10-16 10:24:44 +04:00
|
|
|
if (lladdr) { /* (3-5) and (7) */
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Record source link-layer address
|
|
|
|
* XXX is it dependent to ifp->if_type?
|
|
|
|
*/
|
2007-08-07 08:35:42 +04:00
|
|
|
/* XXX check for error */
|
|
|
|
(void)sockaddr_dl_setaddr(sdl, lladdr, ifp->if_addrlen);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_newentry) {
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((!olladdr && lladdr) || /* (3) */
|
|
|
|
(olladdr && lladdr && llchange)) { /* (5) */
|
1999-06-28 10:36:47 +04:00
|
|
|
do_update = 1;
|
|
|
|
newstate = ND6_LLINFO_STALE;
|
2001-10-16 10:24:44 +04:00
|
|
|
} else /* (1-2,4) */
|
1999-06-28 10:36:47 +04:00
|
|
|
do_update = 0;
|
|
|
|
} else {
|
|
|
|
do_update = 1;
|
2006-03-06 02:47:08 +03:00
|
|
|
if (lladdr == NULL) /* (6) */
|
1999-06-28 10:36:47 +04:00
|
|
|
newstate = ND6_LLINFO_NOSTATE;
|
2001-10-16 10:24:44 +04:00
|
|
|
else /* (7) */
|
1999-06-28 10:36:47 +04:00
|
|
|
newstate = ND6_LLINFO_STALE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (do_update) {
|
|
|
|
/*
|
|
|
|
* Update the state of the neighbor cache.
|
|
|
|
*/
|
|
|
|
ln->ln_state = newstate;
|
|
|
|
|
|
|
|
if (ln->ln_state == ND6_LLINFO_STALE) {
|
2001-03-22 00:56:29 +03:00
|
|
|
/*
|
|
|
|
* XXX: since nd6_output() below will cause
|
|
|
|
* state tansition to DELAY and reset the timer,
|
|
|
|
* we must set the timer now, although it is actually
|
|
|
|
* meaningless.
|
|
|
|
*/
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
|
2001-03-22 00:56:29 +03:00
|
|
|
|
2007-05-17 04:53:26 +04:00
|
|
|
nd6_llinfo_release_pkts(ln, ifp, rt);
|
1999-06-28 10:36:47 +04:00
|
|
|
} else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
|
|
|
|
/* probe right away */
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_settimer((void *)ln, 0);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ICMP6 type dependent behavior.
|
|
|
|
*
|
|
|
|
* NS: clear IsRouter if new entry
|
|
|
|
* RS: clear IsRouter
|
|
|
|
* RA: set IsRouter if there's lladdr
|
|
|
|
* redir: clear IsRouter if new entry
|
|
|
|
*
|
|
|
|
* RA case, (1):
|
|
|
|
* The spec says that we must set IsRouter in the following cases:
|
|
|
|
* - If lladdr exist, set IsRouter. This means (1-5).
|
|
|
|
* - If it is old entry (!newentry), set IsRouter. This means (7).
|
|
|
|
* So, based on the spec, in (1-5) and (7) cases we must set IsRouter.
|
|
|
|
* A quetion arises for (1) case. (1) case has no lladdr in the
|
|
|
|
* neighbor cache, this is similar to (6).
|
|
|
|
* This case is rare but we figured that we MUST NOT set IsRouter.
|
|
|
|
*
|
|
|
|
* newentry olladdr lladdr llchange NS RS RA redir
|
1999-07-31 22:41:15 +04:00
|
|
|
* D R
|
|
|
|
* 0 n n -- (1) c ? s
|
|
|
|
* 0 y n -- (2) c s s
|
|
|
|
* 0 n y -- (3) c s s
|
|
|
|
* 0 y y n (4) c s s
|
|
|
|
* 0 y y y (5) c s s
|
|
|
|
* 1 -- n -- (6) c c c s
|
|
|
|
* 1 -- y -- (7) c c s c s
|
1999-06-28 10:36:47 +04:00
|
|
|
*
|
|
|
|
* (c=clear s=set)
|
|
|
|
*/
|
|
|
|
switch (type & 0xff) {
|
|
|
|
case ND_NEIGHBOR_SOLICIT:
|
|
|
|
/*
|
|
|
|
* New entry must have is_router flag cleared.
|
|
|
|
*/
|
2001-10-16 10:24:44 +04:00
|
|
|
if (is_newentry) /* (6-7) */
|
1999-06-28 10:36:47 +04:00
|
|
|
ln->ln_router = 0;
|
|
|
|
break;
|
1999-07-31 22:41:15 +04:00
|
|
|
case ND_REDIRECT:
|
|
|
|
/*
|
|
|
|
* If the icmp is a redirect to a better router, always set the
|
2001-10-16 10:24:44 +04:00
|
|
|
* is_router flag. Otherwise, if the entry is newly created,
|
|
|
|
* clear the flag. [RFC 2461, sec 8.3]
|
1999-07-31 22:41:15 +04:00
|
|
|
*/
|
|
|
|
if (code == ND_REDIRECT_ROUTER)
|
|
|
|
ln->ln_router = 1;
|
2001-10-16 10:24:44 +04:00
|
|
|
else if (is_newentry) /* (6-7) */
|
1999-07-31 22:41:15 +04:00
|
|
|
ln->ln_router = 0;
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
case ND_ROUTER_SOLICIT:
|
|
|
|
/*
|
|
|
|
* is_router flag must always be cleared.
|
|
|
|
*/
|
|
|
|
ln->ln_router = 0;
|
|
|
|
break;
|
|
|
|
case ND_ROUTER_ADVERT:
|
|
|
|
/*
|
|
|
|
* Mark an entry with lladdr as a router.
|
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */
|
|
|
|
(is_newentry && lladdr)) { /* (7) */
|
1999-06-28 10:36:47 +04:00
|
|
|
ln->ln_router = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-06-22 17:36:12 +04:00
|
|
|
/*
|
|
|
|
* When the link-layer address of a router changes, select the
|
|
|
|
* best router again. In particular, when the neighbor entry is newly
|
|
|
|
* created, it might affect the selection policy.
|
|
|
|
* Question: can we restrict the first condition to the "is_newentry"
|
|
|
|
* case?
|
|
|
|
* XXX: when we hear an RA from a new router with the link-layer
|
|
|
|
* address option, defrouter_select() is called twice, since
|
|
|
|
* defrtrlist_update called the function as well. However, I believe
|
|
|
|
* we can compromise the overhead, since it only happens the first
|
|
|
|
* time.
|
2001-10-16 10:24:44 +04:00
|
|
|
* XXX: although defrouter_select() should not have a bad effect
|
|
|
|
* for those are not autoconfigured hosts, we explicitly avoid such
|
|
|
|
* cases for safety.
|
2001-06-22 17:36:12 +04:00
|
|
|
*/
|
2001-06-29 20:01:47 +04:00
|
|
|
if (do_update && ln->ln_router && !ip6_forwarding && ip6_accept_rtadv)
|
2001-06-22 17:36:12 +04:00
|
|
|
defrouter_select();
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
return rt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
nd6_slowtimo(void *ignored_arg)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
1999-07-04 06:01:15 +04:00
|
|
|
int s = splsoftnet();
|
2001-02-10 07:14:26 +03:00
|
|
|
struct nd_ifinfo *nd6if;
|
2002-05-29 11:53:39 +04:00
|
|
|
struct ifnet *ifp;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
|
|
|
|
nd6_slowtimo, NULL);
|
2006-11-20 07:34:16 +03:00
|
|
|
TAILQ_FOREACH(ifp, &ifnet, if_list) {
|
2002-05-29 11:53:39 +04:00
|
|
|
nd6if = ND_IFINFO(ifp);
|
1999-06-28 10:36:47 +04:00
|
|
|
if (nd6if->basereachable && /* already initialized */
|
|
|
|
(nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) {
|
|
|
|
/*
|
|
|
|
* Since reachable time rarely changes by router
|
|
|
|
* advertisements, we SHOULD insure that a new random
|
|
|
|
* value gets recomputed at least once every few hours.
|
|
|
|
* (RFC 2461, 6.3.4)
|
|
|
|
*/
|
|
|
|
nd6if->recalctm = nd6_recalc_reachtm_interval;
|
|
|
|
nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define senderr(e) { error = (e); goto bad;}
|
|
|
|
int
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
const struct sockaddr_in6 *dst, struct rtentry *rt0)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2001-02-10 07:14:26 +03:00
|
|
|
struct mbuf *m = m0;
|
|
|
|
struct rtentry *rt = rt0;
|
2000-05-09 15:51:12 +04:00
|
|
|
struct sockaddr_in6 *gw6 = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct llinfo_nd6 *ln = NULL;
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
|
|
|
|
goto sendpkt;
|
|
|
|
|
2001-10-17 14:55:09 +04:00
|
|
|
if (nd6_need_cache(ifp) == 0)
|
1999-06-28 10:36:47 +04:00
|
|
|
goto sendpkt;
|
|
|
|
|
|
|
|
/*
|
2006-03-03 17:07:06 +03:00
|
|
|
* next hop determination. This routine is derived from ether_output.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
if (rt) {
|
|
|
|
if ((rt->rt_flags & RTF_UP) == 0) {
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
if ((rt0 = rt = rtalloc1(sin6tocsa(dst), 1)) != NULL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
rt->rt_refcnt--;
|
2004-05-19 21:45:05 +04:00
|
|
|
if (rt->rt_ifp != ifp)
|
|
|
|
senderr(EHOSTUNREACH);
|
2000-04-16 19:00:56 +04:00
|
|
|
} else
|
1999-06-28 10:36:47 +04:00
|
|
|
senderr(EHOSTUNREACH);
|
|
|
|
}
|
2000-05-09 15:51:12 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
if (rt->rt_flags & RTF_GATEWAY) {
|
2000-05-09 15:51:12 +04:00
|
|
|
gw6 = (struct sockaddr_in6 *)rt->rt_gateway;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We skip link-layer address resolution and NUD
|
|
|
|
* if the gateway is not a neighbor from ND point
|
2002-06-09 01:22:29 +04:00
|
|
|
* of view, regardless of the value of nd_ifinfo.flags.
|
2001-12-18 06:04:02 +03:00
|
|
|
* The second condition is a bit tricky; we skip
|
2000-05-09 15:51:12 +04:00
|
|
|
* if the gateway is our own address, which is
|
|
|
|
* sometimes used to install a route to a p2p link.
|
|
|
|
*/
|
|
|
|
if (!nd6_is_addr_neighbor(gw6, ifp) ||
|
|
|
|
in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) {
|
|
|
|
/*
|
|
|
|
* We allow this kind of tricky route only
|
|
|
|
* when the outgoing interface is p2p.
|
|
|
|
* XXX: we may need a more generic rule here.
|
|
|
|
*/
|
|
|
|
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
|
|
|
|
senderr(EHOSTUNREACH);
|
|
|
|
|
|
|
|
goto sendpkt;
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
if (rt->rt_gwroute == 0)
|
|
|
|
goto lookup;
|
|
|
|
if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
|
|
|
|
rtfree(rt); rt = rt0;
|
2001-07-21 00:26:35 +04:00
|
|
|
lookup:
|
|
|
|
rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
|
1999-06-28 10:36:47 +04:00
|
|
|
if ((rt = rt->rt_gwroute) == 0)
|
|
|
|
senderr(EHOSTUNREACH);
|
2001-07-21 00:26:35 +04:00
|
|
|
/* the "G" test below also prevents rt == rt0 */
|
|
|
|
if ((rt->rt_flags & RTF_GATEWAY) ||
|
|
|
|
(rt->rt_ifp != ifp)) {
|
|
|
|
rt->rt_refcnt--;
|
|
|
|
rt0->rt_gwroute = 0;
|
|
|
|
senderr(EHOSTUNREACH);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Address resolution or Neighbor Unreachability Detection
|
|
|
|
* for the next hop.
|
|
|
|
* At this point, the destination of the packet must be a unicast
|
|
|
|
* or an anycast address(i.e. not a multicast).
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Look up the neighbor cache for the nexthop */
|
|
|
|
if (rt && (rt->rt_flags & RTF_LLINFO) != 0)
|
|
|
|
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
|
|
|
|
else {
|
2000-05-09 15:51:12 +04:00
|
|
|
/*
|
|
|
|
* Since nd6_is_addr_neighbor() internally calls nd6_lookup(),
|
2001-10-16 10:24:44 +04:00
|
|
|
* the condition below is not very efficient. But we believe
|
2000-05-09 15:51:12 +04:00
|
|
|
* it is tolerable, because this should be a rare case.
|
|
|
|
*/
|
|
|
|
if (nd6_is_addr_neighbor(dst, ifp) &&
|
|
|
|
(rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
|
|
|
|
}
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ln == NULL || rt == NULL) {
|
2000-05-09 15:51:12 +04:00
|
|
|
if ((ifp->if_flags & IFF_POINTOPOINT) == 0 &&
|
2002-05-29 11:53:39 +04:00
|
|
|
!(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) {
|
2000-05-09 15:51:12 +04:00
|
|
|
log(LOG_DEBUG,
|
|
|
|
"nd6_output: can't allocate llinfo for %s "
|
|
|
|
"(ln=%p, rt=%p)\n",
|
|
|
|
ip6_sprintf(&dst->sin6_addr), ln, rt);
|
|
|
|
senderr(EIO); /* XXX: good error? */
|
|
|
|
}
|
|
|
|
|
|
|
|
goto sendpkt; /* send anyway */
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2000-04-16 19:27:59 +04:00
|
|
|
/* We don't have to do link-layer address resolution on a p2p link. */
|
|
|
|
if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
|
2001-02-23 11:02:41 +03:00
|
|
|
ln->ln_state < ND6_LLINFO_REACHABLE) {
|
2000-04-16 19:27:59 +04:00
|
|
|
ln->ln_state = ND6_LLINFO_STALE;
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
|
2001-02-23 11:02:41 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The first time we send a packet to a neighbor whose entry is
|
|
|
|
* STALE, we have to change the state to DELAY and a sets a timer to
|
|
|
|
* expire in DELAY_FIRST_PROBE_TIME seconds to ensure do
|
|
|
|
* neighbor unreachability detection on expiration.
|
|
|
|
* (RFC 2461 7.3.3)
|
|
|
|
*/
|
|
|
|
if (ln->ln_state == ND6_LLINFO_STALE) {
|
|
|
|
ln->ln_asked = 0;
|
|
|
|
ln->ln_state = ND6_LLINFO_DELAY;
|
2006-03-06 02:47:08 +03:00
|
|
|
nd6_llinfo_settimer(ln, (long)nd6_delay * hz);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the neighbor cache entry has a state other than INCOMPLETE
|
2001-10-16 10:24:44 +04:00
|
|
|
* (i.e. its link-layer address is already resolved), just
|
1999-06-28 10:36:47 +04:00
|
|
|
* send the packet.
|
|
|
|
*/
|
|
|
|
if (ln->ln_state > ND6_LLINFO_INCOMPLETE)
|
|
|
|
goto sendpkt;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There is a neighbor cache entry, but no ethernet address
|
2006-03-06 02:47:08 +03:00
|
|
|
* response yet. Append this latest packet to the end of the
|
|
|
|
* packet queue in the mbuf, unless the number of the packet
|
|
|
|
* does not exceed nd6_maxqueuelen. When it exceeds nd6_maxqueuelen,
|
|
|
|
* the oldest packet in the queue will be removed.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2001-02-23 09:41:50 +03:00
|
|
|
if (ln->ln_state == ND6_LLINFO_NOSTATE)
|
1999-06-28 10:36:47 +04:00
|
|
|
ln->ln_state = ND6_LLINFO_INCOMPLETE;
|
2006-03-06 02:47:08 +03:00
|
|
|
if (ln->ln_hold) {
|
|
|
|
struct mbuf *m_hold;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) {
|
|
|
|
i++;
|
|
|
|
if (m_hold->m_nextpkt == NULL) {
|
|
|
|
m_hold->m_nextpkt = m;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (i >= nd6_maxqueuelen) {
|
|
|
|
m_hold = ln->ln_hold;
|
|
|
|
ln->ln_hold = ln->ln_hold->m_nextpkt;
|
2006-03-24 22:24:38 +03:00
|
|
|
m_freem(m_hold);
|
2006-03-06 02:47:08 +03:00
|
|
|
i--;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ln->ln_hold = m;
|
|
|
|
}
|
|
|
|
|
2002-06-07 21:15:12 +04:00
|
|
|
/*
|
|
|
|
* If there has been no NS for the neighbor after entering the
|
|
|
|
* INCOMPLETE state, send the first solicitation.
|
|
|
|
*/
|
2003-06-27 12:41:08 +04:00
|
|
|
if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) {
|
2002-06-07 21:15:12 +04:00
|
|
|
ln->ln_asked++;
|
2003-06-27 12:41:08 +04:00
|
|
|
nd6_llinfo_settimer(ln,
|
|
|
|
(long)ND_IFINFO(ifp)->retrans * hz / 1000);
|
2002-06-07 21:15:12 +04:00
|
|
|
nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2007-03-16 02:35:25 +03:00
|
|
|
return 0;
|
2002-06-03 06:09:37 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
sendpkt:
|
2006-03-06 02:47:08 +03:00
|
|
|
/* discard the packet if IPv6 operation is disabled on the interface */
|
|
|
|
if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) {
|
|
|
|
error = ENETDOWN; /* better error? */
|
|
|
|
goto bad;
|
|
|
|
}
|
2000-05-19 05:40:18 +04:00
|
|
|
|
2003-01-17 11:11:49 +03:00
|
|
|
#ifdef IPSEC
|
|
|
|
/* clean ipsec history once it goes out of the node */
|
|
|
|
ipsec_delaux(m);
|
|
|
|
#endif
|
2001-03-08 13:49:32 +03:00
|
|
|
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
return (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt);
|
2000-05-19 05:40:18 +04:00
|
|
|
}
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
return (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt);
|
2000-04-16 19:00:56 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
bad:
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
if (m != NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(m);
|
2007-03-16 02:35:25 +03:00
|
|
|
return error;
|
2002-06-03 06:09:37 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
#undef senderr
|
|
|
|
|
2001-10-17 14:55:09 +04:00
|
|
|
int
|
2007-03-16 02:35:25 +03:00
|
|
|
nd6_need_cache(struct ifnet *ifp)
|
2001-10-17 14:55:09 +04:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* XXX: we currently do not make neighbor cache on any interface
|
|
|
|
* other than ARCnet, Ethernet, FDDI and GIF.
|
|
|
|
*
|
|
|
|
* RFC2893 says:
|
|
|
|
* - unidirectional tunnels needs no ND
|
|
|
|
*/
|
|
|
|
switch (ifp->if_type) {
|
|
|
|
case IFT_ARCNET:
|
|
|
|
case IFT_ETHER:
|
|
|
|
case IFT_FDDI:
|
|
|
|
case IFT_IEEE1394:
|
2006-05-18 13:05:49 +04:00
|
|
|
case IFT_CARP:
|
2001-10-17 14:55:09 +04:00
|
|
|
case IFT_GIF: /* XXX need more cases? */
|
2006-03-06 02:47:08 +03:00
|
|
|
case IFT_PPP:
|
|
|
|
case IFT_TUNNEL:
|
2007-03-16 02:35:25 +03:00
|
|
|
return 1;
|
2001-10-17 14:55:09 +04:00
|
|
|
default:
|
2007-03-16 02:35:25 +03:00
|
|
|
return 0;
|
2001-10-17 14:55:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
int
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
nd6_storelladdr(const struct ifnet *ifp, const struct rtentry *rt,
|
|
|
|
struct mbuf *m, const struct sockaddr *dst, u_char *lldst,
|
|
|
|
size_t dstsize)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
const struct sockaddr_dl *sdl;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (m->m_flags & M_MCAST) {
|
|
|
|
switch (ifp->if_type) {
|
|
|
|
case IFT_ETHER:
|
2002-06-03 06:09:37 +04:00
|
|
|
case IFT_FDDI:
|
2007-08-07 08:35:42 +04:00
|
|
|
ETHER_MAP_IPV6_MULTICAST(&satocsin6(dst)->sin6_addr,
|
|
|
|
lldst);
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
return 1;
|
2000-11-05 20:17:12 +03:00
|
|
|
case IFT_IEEE1394:
|
2007-08-07 08:35:42 +04:00
|
|
|
memcpy(lldst, ifp->if_broadcastaddr,
|
|
|
|
MIN(dstsize, ifp->if_addrlen));
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
return 1;
|
1999-09-20 01:31:33 +04:00
|
|
|
case IFT_ARCNET:
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
*lldst = 0;
|
|
|
|
return 1;
|
1999-06-28 10:36:47 +04:00
|
|
|
default:
|
2001-03-08 13:49:32 +03:00
|
|
|
m_freem(m);
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
return 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-10-15 19:39:11 +04:00
|
|
|
if (rt == NULL) {
|
|
|
|
/* this could happen, if we could not allocate memory */
|
2001-03-08 13:49:32 +03:00
|
|
|
m_freem(m);
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
return 0;
|
2000-10-15 19:39:11 +04:00
|
|
|
}
|
|
|
|
if (rt->rt_gateway->sa_family != AF_LINK) {
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
printf("%s: something odd happens\n", __func__);
|
2001-03-08 13:49:32 +03:00
|
|
|
m_freem(m);
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
return 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2007-08-07 08:35:42 +04:00
|
|
|
sdl = satocsdl(rt->rt_gateway);
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
if (sdl->sdl_alen == 0 || sdl->sdl_alen > dstsize) {
|
2000-04-13 20:27:00 +04:00
|
|
|
/* this should be impossible, but we bark here for debugging */
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
printf("%s: sdl_alen == 0, dst=%s, if=%s\n", __func__,
|
2007-08-07 08:35:42 +04:00
|
|
|
ip6_sprintf(&satocsin6(dst)->sin6_addr), if_name(ifp));
|
2001-03-08 13:49:32 +03:00
|
|
|
m_freem(m);
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
return 0;
|
2000-04-13 18:32:53 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
memcpy(lldst, CLLADDR(sdl), MIN(dstsize, sdl->sdl_alen));
|
|
|
|
return 1;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
|
2006-03-24 22:24:38 +03:00
|
|
|
static void
|
2007-03-16 02:35:25 +03:00
|
|
|
clear_llinfo_pqueue(struct llinfo_nd6 *ln)
|
2006-03-24 22:24:38 +03:00
|
|
|
{
|
|
|
|
struct mbuf *m_hold, *m_hold_next;
|
|
|
|
|
|
|
|
for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) {
|
|
|
|
m_hold_next = m_hold->m_nextpkt;
|
|
|
|
m_hold->m_nextpkt = NULL;
|
|
|
|
m_freem(m_hold);
|
|
|
|
}
|
|
|
|
|
|
|
|
ln->ln_hold = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
int
|
2006-10-12 05:30:41 +04:00
|
|
|
nd6_sysctl(
|
|
|
|
int name,
|
|
|
|
void *oldp, /* syscall arg, need copyout */
|
|
|
|
size_t *oldlenp,
|
|
|
|
void *newp, /* syscall arg, need copyin */
|
2006-11-16 04:32:37 +03:00
|
|
|
size_t newlen
|
2006-10-12 05:30:41 +04:00
|
|
|
)
|
2002-06-09 01:22:29 +04:00
|
|
|
{
|
2002-08-20 03:14:39 +04:00
|
|
|
void *p;
|
2003-10-30 04:43:08 +03:00
|
|
|
size_t ol;
|
2002-06-09 01:22:29 +04:00
|
|
|
int error;
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
|
|
|
|
if (newp)
|
|
|
|
return EPERM;
|
|
|
|
if (oldp && !oldlenp)
|
|
|
|
return EINVAL;
|
|
|
|
ol = oldlenp ? *oldlenp : 0;
|
|
|
|
|
2002-08-20 03:14:39 +04:00
|
|
|
if (oldp) {
|
|
|
|
p = malloc(*oldlenp, M_TEMP, M_WAITOK);
|
2006-03-06 02:47:08 +03:00
|
|
|
if (p == NULL)
|
2002-08-20 03:14:39 +04:00
|
|
|
return ENOMEM;
|
|
|
|
} else
|
|
|
|
p = NULL;
|
2002-06-09 01:22:29 +04:00
|
|
|
switch (name) {
|
|
|
|
case ICMPV6CTL_ND6_DRLIST:
|
2002-08-20 03:14:39 +04:00
|
|
|
error = fill_drlist(p, oldlenp, ol);
|
2006-03-06 02:47:08 +03:00
|
|
|
if (!error && p != NULL && oldp != NULL)
|
2002-08-20 03:23:22 +04:00
|
|
|
error = copyout(p, oldp, *oldlenp);
|
2002-06-09 01:22:29 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ICMPV6CTL_ND6_PRLIST:
|
2002-08-20 03:14:39 +04:00
|
|
|
error = fill_prlist(p, oldlenp, ol);
|
2006-03-06 02:47:08 +03:00
|
|
|
if (!error && p != NULL && oldp != NULL)
|
2002-08-20 03:23:22 +04:00
|
|
|
error = copyout(p, oldp, *oldlenp);
|
2002-06-09 01:22:29 +04:00
|
|
|
break;
|
|
|
|
|
2006-03-06 02:47:08 +03:00
|
|
|
case ICMPV6CTL_ND6_MAXQLEN:
|
|
|
|
break;
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
default:
|
|
|
|
error = ENOPROTOOPT;
|
|
|
|
break;
|
|
|
|
}
|
2002-08-20 03:14:39 +04:00
|
|
|
if (p)
|
|
|
|
free(p, M_TEMP);
|
2002-06-09 01:22:29 +04:00
|
|
|
|
2007-03-16 02:35:25 +03:00
|
|
|
return error;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2007-03-16 02:35:25 +03:00
|
|
|
fill_drlist(void *oldp, size_t *oldlenp, size_t ol)
|
2002-06-09 01:22:29 +04:00
|
|
|
{
|
|
|
|
int error = 0, s;
|
|
|
|
struct in6_defrouter *d = NULL, *de = NULL;
|
|
|
|
struct nd_defrouter *dr;
|
|
|
|
size_t l;
|
|
|
|
|
|
|
|
s = splsoftnet();
|
2002-06-09 18:43:10 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
if (oldp) {
|
|
|
|
d = (struct in6_defrouter *)oldp;
|
2007-03-04 08:59:00 +03:00
|
|
|
de = (struct in6_defrouter *)((char *)oldp + *oldlenp);
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
|
|
|
l = 0;
|
|
|
|
|
2006-11-20 07:34:16 +03:00
|
|
|
TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) {
|
2002-06-09 01:22:29 +04:00
|
|
|
|
|
|
|
if (oldp && d + 1 <= de) {
|
|
|
|
bzero(d, sizeof(*d));
|
|
|
|
d->rtaddr.sin6_family = AF_INET6;
|
|
|
|
d->rtaddr.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
d->rtaddr.sin6_addr = dr->rtaddr;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (sa6_recoverscope(&d->rtaddr)) {
|
|
|
|
log(LOG_ERR,
|
|
|
|
"scope error in router list (%s)\n",
|
|
|
|
ip6_sprintf(&d->rtaddr.sin6_addr));
|
|
|
|
/* XXX: press on... */
|
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
d->flags = dr->flags;
|
|
|
|
d->rtlifetime = dr->rtlifetime;
|
|
|
|
d->expire = dr->expire;
|
|
|
|
d->if_index = dr->ifp->if_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
l += sizeof(*d);
|
|
|
|
if (d)
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldp) {
|
|
|
|
if (l > ol)
|
|
|
|
error = ENOMEM;
|
2006-04-15 04:09:29 +04:00
|
|
|
}
|
|
|
|
if (oldlenp)
|
2007-03-04 08:59:00 +03:00
|
|
|
*oldlenp = l; /* (void *)d - (void *)oldp */
|
2002-06-09 01:22:29 +04:00
|
|
|
|
|
|
|
splx(s);
|
|
|
|
|
2007-03-16 02:35:25 +03:00
|
|
|
return error;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2007-03-16 02:35:25 +03:00
|
|
|
fill_prlist(void *oldp, size_t *oldlenp, size_t ol)
|
2002-06-09 01:22:29 +04:00
|
|
|
{
|
|
|
|
int error = 0, s;
|
|
|
|
struct nd_prefix *pr;
|
|
|
|
struct in6_prefix *p = NULL;
|
|
|
|
struct in6_prefix *pe = NULL;
|
|
|
|
size_t l;
|
|
|
|
|
|
|
|
s = splsoftnet();
|
|
|
|
|
|
|
|
if (oldp) {
|
|
|
|
p = (struct in6_prefix *)oldp;
|
2007-03-04 08:59:00 +03:00
|
|
|
pe = (struct in6_prefix *)((char *)oldp + *oldlenp);
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
|
|
|
l = 0;
|
|
|
|
|
2006-11-20 07:34:16 +03:00
|
|
|
LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
|
2002-06-09 01:22:29 +04:00
|
|
|
u_short advrtrs;
|
|
|
|
size_t advance;
|
|
|
|
struct sockaddr_in6 *sin6;
|
|
|
|
struct sockaddr_in6 *s6;
|
|
|
|
struct nd_pfxrouter *pfr;
|
|
|
|
|
|
|
|
if (oldp && p + 1 <= pe)
|
|
|
|
{
|
|
|
|
bzero(p, sizeof(*p));
|
|
|
|
sin6 = (struct sockaddr_in6 *)(p + 1);
|
|
|
|
|
|
|
|
p->prefix = pr->ndpr_prefix;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (sa6_recoverscope(&p->prefix)) {
|
2002-06-09 01:22:29 +04:00
|
|
|
log(LOG_ERR,
|
|
|
|
"scope error in prefix list (%s)\n",
|
|
|
|
ip6_sprintf(&p->prefix.sin6_addr));
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/* XXX: press on... */
|
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
p->raflags = pr->ndpr_raf;
|
|
|
|
p->prefixlen = pr->ndpr_plen;
|
|
|
|
p->vltime = pr->ndpr_vltime;
|
|
|
|
p->pltime = pr->ndpr_pltime;
|
|
|
|
p->if_index = pr->ndpr_ifp->if_index;
|
|
|
|
if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME)
|
|
|
|
p->expire = 0;
|
|
|
|
else {
|
|
|
|
time_t maxexpire;
|
|
|
|
|
|
|
|
/* XXX: we assume time_t is signed. */
|
|
|
|
maxexpire = (-1) &
|
2006-03-06 02:47:08 +03:00
|
|
|
~((time_t)1 <<
|
|
|
|
((sizeof(maxexpire) * 8) - 1));
|
2002-06-09 01:22:29 +04:00
|
|
|
if (pr->ndpr_vltime <
|
|
|
|
maxexpire - pr->ndpr_lastupdate) {
|
|
|
|
p->expire = pr->ndpr_lastupdate +
|
|
|
|
pr->ndpr_vltime;
|
|
|
|
} else
|
|
|
|
p->expire = maxexpire;
|
|
|
|
}
|
|
|
|
p->refcnt = pr->ndpr_refcnt;
|
|
|
|
p->flags = pr->ndpr_stateflags;
|
|
|
|
p->origin = PR_ORIG_RA;
|
|
|
|
advrtrs = 0;
|
2006-11-20 07:34:16 +03:00
|
|
|
LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) {
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((void *)&sin6[advrtrs + 1] > (void *)pe) {
|
|
|
|
advrtrs++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
s6 = &sin6[advrtrs];
|
|
|
|
s6->sin6_family = AF_INET6;
|
|
|
|
s6->sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
s6->sin6_addr = pfr->router->rtaddr;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
s6->sin6_scope_id = 0;
|
|
|
|
if (sa6_recoverscope(s6)) {
|
|
|
|
log(LOG_ERR,
|
|
|
|
"scope error in "
|
|
|
|
"prefix list (%s)\n",
|
|
|
|
ip6_sprintf(&pfr->router->rtaddr));
|
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
advrtrs++;
|
|
|
|
}
|
|
|
|
p->advrtrs = advrtrs;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
advrtrs = 0;
|
2006-11-20 07:34:16 +03:00
|
|
|
LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry)
|
2002-06-09 01:22:29 +04:00
|
|
|
advrtrs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
advance = sizeof(*p) + sizeof(*sin6) * advrtrs;
|
|
|
|
l += advance;
|
|
|
|
if (p)
|
2007-03-04 08:59:00 +03:00
|
|
|
p = (struct in6_prefix *)((char *)p + advance);
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (oldp) {
|
2007-03-04 08:59:00 +03:00
|
|
|
*oldlenp = l; /* (void *)d - (void *)oldp */
|
2002-06-09 01:22:29 +04:00
|
|
|
if (l > ol)
|
|
|
|
error = ENOMEM;
|
|
|
|
} else
|
|
|
|
*oldlenp = l;
|
|
|
|
|
|
|
|
splx(s);
|
|
|
|
|
2007-03-16 02:35:25 +03:00
|
|
|
return error;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|