This commit is contained in:
Attilio Rao 2011-06-06 21:38:39 +00:00
commit 81c02539f1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/largeSMP/; revision=222783
101 changed files with 4483 additions and 2066 deletions

View File

@ -409,6 +409,7 @@ evalsubshell(union node *n, int flags)
struct job *jp;
int backgnd = (n->type == NBACKGND);
oexitstatus = exitstatus;
expredir(n->nredir.redirect);
if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
forkshell(jp = makejob(n, 1), n, backgnd) == 0) {
@ -436,6 +437,7 @@ evalredir(union node *n, int flags)
struct jmploc *savehandler;
volatile int in_redirect = 1;
oexitstatus = exitstatus;
expredir(n->nredir.redirect);
savehandler = handler;
if (setjmp(jmploc.loc)) {
@ -478,7 +480,6 @@ expredir(union node *n)
for (redir = n ; redir ; redir = redir->nfile.next) {
struct arglist fn;
fn.lastp = &fn.list;
oexitstatus = exitstatus;
switch (redir->type) {
case NFROM:
case NTO:

View File

@ -83,6 +83,7 @@ void
procargs(int argc, char **argv)
{
int i;
char *scriptname;
argptr = argv;
if (argc > 0)
@ -105,8 +106,9 @@ procargs(int argc, char **argv)
optlist[i].val = 0;
arg0 = argv[0];
if (sflag == 0 && minusc == NULL) {
commandname = arg0 = *argptr++;
setinputfile(commandname, 0);
scriptname = *argptr++;
setinputfile(scriptname, 0);
commandname = arg0 = scriptname;
}
/* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
if (argptr && minusc && *argptr)

View File

@ -100,25 +100,19 @@ ifconfig_up()
# inet6 specific
if afexists inet6; then
if ipv6if $1; then
if checkyesno ipv6_gateway_enable; then
_ipv6_opts="-accept_rtadv"
fi
else
if checkyesno ipv6_activate_all_interfaces; then
_ipv6_opts="-ifdisabled"
else
_ipv6_opts="ifdisabled"
fi
# backward compatibility: $ipv6_enable
case $ipv6_enable in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
_ipv6_opts="${_ipv6_opts} accept_rtadv"
;;
esac
if checkyesno ipv6_activate_all_interfaces; then
_ipv6_opts="-ifdisabled"
elif [ "$1" != "lo0" ]; then
_ipv6_opts="ifdisabled"
fi
# backward compatibility: $ipv6_enable
case $ipv6_enable in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
_ipv6_opts="${_ipv6_opts} accept_rtadv"
;;
esac
if [ -n "${_ipv6_opts}" ]; then
ifconfig $1 inet6 ${_ipv6_opts}
fi

View File

@ -19,7 +19,6 @@ SRCS= citrus_bcs.c citrus_bcs_strtol.c citrus_bcs_strtoul.c \
citrus_module.c citrus_none.c citrus_pivot_factory.c \
citrus_prop.c citrus_stdenc.c iconv.c
WARNS?= 6
CFLAGS+= --param max-inline-insns-single=128 -I ${.CURDIR}/../../include -I${.CURDIR}/../libc/include
.include <bsd.lib.mk>

View File

@ -48,28 +48,32 @@ EFIPART=efipart.sys
if [ $bootable = yes ]; then
EFISZ=65536
MNT=/mnt
dd if=/dev/zero of=$BASE/$EFIPART count=$EFISZ
md=`mdconfig -a -t vnode -f $BASE/$EFIPART`
dd if=/dev/zero of=$EFIPART count=$EFISZ
md=`mdconfig -a -t vnode -f $EFIPART`
newfs_msdos -F 12 -S 512 -h 4 -o 0 -s $EFISZ -u 16 $md
mount -t msdosfs /dev/$md $MNT
mkdir -p $MNT/efi/boot $MNT/boot $MNT/boot/kernel
cp -R $BASE/boot/defaults $MNT/boot
cp $BASE/boot/kernel/kernel $MNT/boot/kernel
cp $BASE/boot/kernel/ispfw.ko $MNT/boot/kernel
if [ -s $BASE/boot/kernel/ispfw.ko ]; then
cp $BASE/boot/kernel/ispfw.ko $MNT/boot/kernel
fi
cp $BASE/boot/device.hints $MNT/boot
cp $BASE/boot/loader.* $MNT/boot
cp $BASE/boot/mfsroot.gz $MNT/boot
if [ -s $BASE/boot/mfsroot.gz ]; then
cp $BASE/boot/mfsroot.gz $MNT/boot
fi
cp $BASE/boot/support.4th $MNT/boot
mv $MNT/boot/loader.efi $MNT/efi/boot/bootia64.efi
umount $MNT
mdconfig -d -u $md
BOOTOPTS="-b bootimage=i386;$EFIPART -o no-emul-boot"
BOOTOPTS="-o bootimage=i386;$EFIPART -o no-emul-boot"
else
BOOTOPTS=""
fi
echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > $1/etc/fstab
echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > $BASE/etc/fstab
makefs -t cd9660 $BOOTOPTS -o rockridge -o label=$LABEL $NAME $BASE $*
rm -f $BASE/$EFIPART
rm $1/etc/fstab
rm $BASE/etc/fstab
rm -f $EFIPART
exit 0

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 30, 2011
.Dd June 6, 2011
.Dt GPART 8
.Os
.Sh NAME
@ -530,16 +530,17 @@ about its use.
.El
.\"
.Sh PARTITION TYPES
Partition types are identified on disk by particular strings or magic
values.
The
.Nm
utility uses symbolic names for common partition types to avoid that the
user needs to know what the partitioning scheme in question is and what
the actual number or identification needs to be used for a particular
type.
utility uses symbolic names for common partition types to avoid the
user needing to know these values or other details of the partitioning
scheme in question.
The
.Nm
utility also allows the user to specify scheme-specific partition types
for partition types that do not have symbol names.
for partition types that do not have symbolic names.
The symbolic names currently understood are:
.Bl -tag -width ".Cm freebsd-vinum"
.It Cm bios-boot
@ -740,30 +741,30 @@ action or reverted with the
.Cm undo
action.
.Sh RECOVERING
The GEOM class PART supports recovering of partition tables only for GPT.
The GEOM PART class supports recovering of partition tables only for GPT.
The GUID partition table has a primary and secondary (backup) copy of
metadata for redundance.
They are stored in the begining and in the end of device respectively.
Therefore it is acceptable to have some corruptions in the metadata that
are not fatal to work with GPT.
When kernel detects corrupt metadata it marks this table as corrupt and
reports about corruption.
Any changes in corrupt table are prohibited except
metadata for redundance, these are stored at the begining and the end
of the device respectively.
As a result of having two copies, it is acceptable to have some corruption
within the metadata that is not fatal to the working of GPT.
When the kernel detects corrupt metadata it marks this table as corrupt and
reports the corruption.
Any operations on corrupt tables are prohibited except for
.Cm destroy
and
.Cm recover .
.Pp
In case when only first sector is corrupt kernel can not detect GPT even
if partition table is not corrupt.
You can write protective MBR with
If the first sector of a provider is corrupt, the kernel can not detect GPT
even if partition table itself is not corrupt.
You can rewrite the protective MBR using the
.Xr dd 1
command to restore ability of GPT detection.
The copy of protective MBR is usually located in the
command, to restore the ability to detect the GPT.
The copy of the protective MBR is usually located in the
.Pa /boot/pmbr
file.
.Pp
In case when some of metadata is corrupt you will get to know about this
from kernel's messages like these:
If one GPT header appears to be corrupt but the other copy remains intact,
the kernel will log the following:
.Bd -literal -offset indent
GEOM: provider: the primary GPT table is corrupt or invalid.
GEOM: provider: using the secondary instead -- recovery strongly advised.
@ -777,32 +778,31 @@ GEOM: provider: using the primary only -- recovery suggested.
.Pp
Also
.Nm
commands like
commands such as
.Cm show , status
and
.Cm list
will report about corrupt table.
will report about corrupt tables.
.Pp
In case when the size of device has changed (e.g.\& volume expansion) the
secondary GPT header will become located not in the last sector.
If the size of the device has changed (e.g.\& volume expansion) the
secondary GPT header will no longer be located in the last sector.
This is not a metadata corruption, but it is dangerous because any
corruption of the primary GPT will lead to lost of partition table.
Kernel reports about this problem with message:
corruption of the primary GPT will lead to loss of partition table.
This problem is reported by the kernel with the message:
.Bd -literal -offset indent
GEOM: provider: the secondary GPT header is not in the last LBA.
.Ed
.Pp
A corrupt table can be recovered with
This situation can be recovered with the
.Cm recover
command.
This command does reconstruction of corrupt metadata using
known valid metadata.
Also it can relocate secondary GPT to the end of device.
This command reconstructs the corrupt metadata using known valid
metadata and relocates the secondary GPT to the end of the device.
.Pp
.Em NOTE :
The GEOM class PART can detect the same partition table on different GEOM
providers and some of them will be marked as corrupt.
Be careful when choosing a provider for recovering.
The GEOM PART class can detect the same partition table visible through
different GEOM providers, and some of them will be marked as corrupt.
Be careful when choosing a provider for recovery.
If you choose incorrectly you can destroy the metadata of another GEOM class,
e.g.\& GEOM MIRROR or GEOM LABEL.
.Sh SYSCTL VARIABLES
@ -815,11 +815,11 @@ The default value is shown next to each variable.
.Bl -tag -width indent
.It Va kern.geom.part.check_integrity : No 1
This variable controls the behaviour of metadata integrity checks.
When integrity checks are enabled
When integrity checks are enabled, the
.Nm PART
GEOM class verifies all generic partition parameters that it gets from the
GEOM class verifies all generic partition parameters obtained from the
disk metadata.
If some inconsistency is detected, partition table will be
If some inconsistency is detected, the partition table will be
rejected with a diagnostic message:
.Sy "GEOM_PART: Integrity check failed (provider, scheme)" .
.El

View File

@ -5,6 +5,4 @@
GEOM_CLASS= sched
WARNS?= 6
.include <bsd.lib.mk>

View File

@ -69,6 +69,7 @@ static int explicit_prefix = 0;
extern void setnd6flags(const char *, int, int, const struct afswtch *);
extern void setnd6defif(const char *, int, int, const struct afswtch *);
extern void nd6_status(int);
static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
@ -498,6 +499,8 @@ static struct cmd inet6_cmds[] = {
DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
DEF_CMD("accept_rtadv", ND6_IFF_ACCEPT_RTADV, setnd6flags),
DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV, setnd6flags),
DEF_CMD("no_radr", ND6_IFF_NO_RADR, setnd6flags),
DEF_CMD("-no_radr", -ND6_IFF_NO_RADR, setnd6flags),
DEF_CMD("defaultif", 1, setnd6defif),
DEF_CMD("-defaultif", -1, setnd6defif),
DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags),
@ -519,6 +522,7 @@ static struct afswtch af_inet6 = {
.af_status = in6_status,
.af_getaddr = in6_getaddr,
.af_getprefix = in6_getprefix,
.af_other_status = nd6_status,
.af_postproc = in6_postproc,
.af_status_tunnel = in6_status_tunnel,
.af_settunnel = in6_set_tunnel,

View File

@ -58,11 +58,12 @@ static const char rcsid[] =
#define MAX_SYSCTL_TRY 5
#define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
"\004IFDISABLED\005DONT_SET_IFROUTE\006AUTO_LINKLOCAL" \
"\020DEFAULTIF"
"\007NO_RADR\020DEFAULTIF"
static int isnd6defif(int);
void setnd6flags(const char *, int, int, const struct afswtch *);
void setnd6defif(const char *, int, int, const struct afswtch *);
void nd6_status(int);
void
setnd6flags(const char *dummyaddr __unused,
@ -136,64 +137,13 @@ isnd6defif(int s)
return (ndifreq.ifindex == ifindex);
}
static void
void
nd6_status(int s)
{
struct in6_ndireq nd;
struct rt_msghdr *rtm;
size_t needed;
char *buf, *next;
int mib[6], ntry;
int s6;
int error;
int isinet6, isdefif;
/* Check if the interface has at least one IPv6 address. */
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET6;
mib[4] = NET_RT_IFLIST;
mib[5] = if_nametoindex(ifr.ifr_name);
/* Try to prevent a race between two sysctls. */
ntry = 0;
do {
error = sysctl(mib, 6, NULL, &needed, NULL, 0);
if (error) {
warn("sysctl(NET_RT_IFLIST)/estimate");
return;
}
buf = malloc(needed);
if (buf == NULL) {
warn("malloc for sysctl(NET_RT_IFLIST) failed");
return;
}
if ((error = sysctl(mib, 6, buf, &needed, NULL, 0)) < 0) {
if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
warn("sysctl(NET_RT_IFLIST)/get");
free(buf);
return;
}
free(buf);
buf = NULL;
}
} while (buf == NULL);
isinet6 = 0;
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
if (rtm->rtm_type == RTM_NEWADDR) {
isinet6 = 1;
break;
}
}
free(buf);
if (!isinet6)
return;
int isdefif;
memset(&nd, 0, sizeof(nd));
strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
@ -215,19 +165,3 @@ nd6_status(int s)
(unsigned int)(nd.ndi.flags | (isdefif << 15)), ND6BITS);
putchar('\n');
}
static struct afswtch af_nd6 = {
.af_name = "nd6",
.af_af = AF_LOCAL,
.af_other_status= nd6_status,
};
static __constructor void
nd6_ctor(void)
{
if (!feature_present("inet6"))
return;
af_register(&af_nd6);
}

View File

@ -356,6 +356,7 @@ ipfw_main(int oldac, char **oldav)
*/
co.do_nat = 0;
co.do_pipe = 0;
co.use_set = 0;
if (!strncmp(*av, "nat", strlen(*av)))
co.do_nat = 1;
else if (!strncmp(*av, "pipe", strlen(*av)))
@ -444,7 +445,7 @@ static void
ipfw_readfile(int ac, char *av[])
{
#define MAX_ARGS 32
char buf[BUFSIZ];
char buf[4096];
char *progname = av[0]; /* original program name */
const char *cmd = NULL; /* preprocessor name, if any */
const char *filename = av[ac-1]; /* file to read */
@ -552,7 +553,7 @@ ipfw_readfile(int ac, char *av[])
}
}
while (fgets(buf, BUFSIZ, f)) { /* read commands */
while (fgets(buf, sizeof(buf), f)) { /* read commands */
char linename[20];
char *args[2];

View File

@ -28,7 +28,7 @@
.\" @(#)mount.8 8.8 (Berkeley) 6/16/94
.\" $FreeBSD$
.\"
.Dd April 28, 2011
.Dd June 6, 2011
.Dt MOUNT 8
.Os
.Sh NAME
@ -348,7 +348,6 @@ option) may be passed as a comma separated list; these options are
distinguished by a leading
.Dq \&-
(dash).
Options that take a value are specified using the syntax -option=value.
For example, the
.Nm
command:
@ -363,6 +362,16 @@ to execute the equivalent of:
/sbin/mount_cd9660 -e /dev/cd0 /cdrom
.Ed
.Pp
Options that take a value are specified using the -option=value syntax:
.Bd -literal -offset indent
mount -t msdosfs -o -u=fred,-g=wheel /dev/da0s1 /mnt
.Ed
.Pp
is equivalent to
.Bd -literal -offset indent
/sbin/mount_msdosfs -u fred -g wheel /dev/da0s1 /mnt
.Ed
.Pp
Additional options specific to file system types
which are not internally known
(see the description of the

View File

@ -31,7 +31,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd June 9, 2008
.Dd June 6, 2011
.Dt RCORDER 8
.Os
.Sh NAME
@ -89,6 +89,12 @@ and
lines may appear, but all such lines must appear in a sequence without
any intervening lines, as once a line that does not follow the format
is reached, parsing stops.
Note that for historical reasons,
.Dq Li REQUIRES ,
.Dq Li PROVIDES ,
and
.Dq Li KEYWORDS
are also accepted in addition to the above.
.Pp
The options are as follows:
.Bl -tag -width indent

View File

@ -61,12 +61,14 @@ AMD SB600 and SB7xx south bridge chips.
The
.Nm
driver first appeared in
.Fx 9.0 .
.Fx 7.3
and
.Fx 8.1 .
.Sh AUTHORS
.An -nosplit
The
.Nm
driver was written by
.An Andiry Gapon Aq avg@FreeBSD.org .
.An Andriy Gapon Aq avg@FreeBSD.org .
This manual page was written by
.An Andiry Gapon Aq avg@FreeBSD.org .
.An Andriy Gapon Aq avg@FreeBSD.org .

View File

@ -242,8 +242,11 @@ topo_probe_0x4(void)
* logical processors that belong to the same core
* as BSP thus deducing number of threads per core.
*/
cpuid_count(0x04, 0, p);
max_cores = ((p[0] >> 26) & 0x3f) + 1;
if (cpu_high >= 0x4) {
cpuid_count(0x04, 0, p);
max_cores = ((p[0] >> 26) & 0x3f) + 1;
} else
max_cores = 1;
core_id_bits = mask_width(max_logical/max_cores);
if (core_id_bits < 0)
return;

View File

@ -40,8 +40,6 @@
extern void atomic_add_64(volatile uint64_t *target, int64_t delta);
extern void atomic_dec_64(volatile uint64_t *target);
#endif
#ifndef __LP64__
#endif
#ifndef __sparc64__
extern uint32_t atomic_cas_32(volatile uint32_t *target, uint32_t cmp,
uint32_t newval);

View File

@ -2748,6 +2748,7 @@ netinet/ip_gre.c optional gre inet
netinet/ip_id.c optional inet
netinet/in_mcast.c optional inet
netinet/in_pcb.c optional inet | inet6
netinet/in_pcbgroup.c optional inet pcbgroup | inet6 pcbgroup
netinet/in_proto.c optional inet | inet6 \
compile-with "${NORMAL_C} -I$S/contrib/pf"
netinet/in_rmx.c optional inet
@ -2825,6 +2826,7 @@ netinet6/in6_gif.c optional gif inet6 | netgraph_gif inet6
netinet6/in6_ifattach.c optional inet6
netinet6/in6_mcast.c optional inet6
netinet6/in6_pcb.c optional inet6
netinet6/in6_pcbgroup.c optional inet6 pcbgroup
netinet6/in6_proto.c optional inet6
netinet6/in6_rmx.c optional inet6
netinet6/in6_src.c optional inet6

View File

@ -419,6 +419,7 @@ MROUTING opt_mrouting.h
NCP
NETATALK opt_atalk.h
NFSLOCKD
PCBGROUP opt_pcbgroup.h
RADIX_MPATH opt_mpath.h
ROUTETABLES opt_route.h
SLIP_IFF_OPTS opt_slip.h

View File

@ -3473,7 +3473,15 @@ ath_rx_proc(void *arg, int npending)
if (rs->rs_status & HAL_RXERR_PHY) {
sc->sc_stats.ast_rx_phyerr++;
/* Process DFS radar events */
ath_dfs_process_phy_err(sc, mtod(m, char *), tsf, rs);
if ((rs->rs_phyerr == HAL_PHYERR_RADAR) ||
(rs->rs_phyerr == HAL_PHYERR_FALSE_RADAR_EXT)) {
/* Since we're touching the frame data, sync it */
bus_dmamap_sync(sc->sc_dmat,
bf->bf_dmamap,
BUS_DMASYNC_POSTREAD);
/* Now pass it to the radar processing code */
ath_dfs_process_phy_err(sc, mtod(m, char *), tsf, rs);
}
/* Be suitably paranoid about receiving phy errors out of the stats array bounds */
if (rs->rs_phyerr < 64)

View File

@ -324,7 +324,7 @@ decode_tuple_bar(device_t cbdev, device_t child, int id,
* hint when the cardbus bridge is a child of pci0 (the main
* bus). The PC Card spec seems to indicate that this should
* only be done on x86 based machines, which suggests that on
* non-x86 machines the adddresses can be anywhere. Since the
* non-x86 machines the addresses can be anywhere. Since the
* hardware can do it on non-x86 machines, it should be able
* to do it on x86 machines too. Therefore, we can and should
* ignore this hint. Furthermore, the PC Card spec recommends
@ -430,7 +430,6 @@ cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
{
if (res != CIS_CONFIG_SPACE) {
bus_release_resource(child, SYS_RES_MEMORY, rid, res);
bus_delete_resource(child, SYS_RES_MEMORY, rid);
}
}
@ -467,7 +466,7 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
}
/* allocate the memory space to read CIS */
res = bus_alloc_resource(child, SYS_RES_MEMORY, rid, 0, ~0, 1,
res = bus_alloc_resource_any(child, SYS_RES_MEMORY, rid,
rman_make_alignment_flags(4096) | RF_ACTIVE);
if (res == NULL) {
device_printf(cbdev, "Unable to allocate resource "

View File

@ -396,6 +396,7 @@ struct sge_ctrlq {
struct sge {
uint16_t timer_val[SGE_NTIMERS];
uint8_t counter_val[SGE_NCOUNTERS];
int fl_starve_threshold;
int nrxq; /* total rx queues (all ports and the rest) */
int ntxq; /* total tx queues (all ports and the rest) */

View File

@ -492,6 +492,8 @@ t4_attach(device_t dev)
V_RXTSHIFTMAXR2(15) | V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
V_KEEPALIVEMAXR1(4) | V_KEEPALIVEMAXR2(9));
t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
t4_set_reg_field(sc, A_TP_PARA_REG3, F_TUNNELCNGDROP0 |
F_TUNNELCNGDROP1 | F_TUNNELCNGDROP2 | F_TUNNELCNGDROP3, 0);
setup_memwin(sc);

View File

@ -203,6 +203,9 @@ t4_sge_init(struct adapter *sc)
FL_BUF_SIZE(i));
}
i = t4_read_reg(sc, A_SGE_CONM_CTRL);
s->fl_starve_threshold = G_EGRTHRESHOLD(i) * 2 + 1;
t4_write_reg(sc, A_SGE_INGRESS_RX_THRESHOLD,
V_THRESHOLD_0(s->counter_val[0]) |
V_THRESHOLD_1(s->counter_val[1]) |
@ -1233,7 +1236,8 @@ alloc_iq_fl(struct port_info *pi, struct sge_iq *iq, struct sge_fl *fl,
sc->sge.eqmap[cntxt_id] = (void *)fl;
FL_LOCK(fl);
refill_fl(sc, fl, -1, 8);
/* Just enough to make sure it doesn't starve right away. */
refill_fl(sc, fl, roundup(sc->sge.fl_starve_threshold, 8), 8);
FL_UNLOCK(fl);
}
@ -1389,6 +1393,10 @@ alloc_rxq(struct port_info *pi, struct sge_rxq *rxq, int intr_idx, int idx)
if (rc != 0)
return (rc);
FL_LOCK(&rxq->fl);
refill_fl(pi->adapter, &rxq->fl, rxq->fl.needed / 8, 8);
FL_UNLOCK(&rxq->fl);
#ifdef INET
rc = tcp_lro_init(&rxq->lro);
if (rc != 0)

View File

@ -1405,8 +1405,8 @@ pccard_ccr_read_impl(device_t brdev, device_t child, uint32_t offset,
struct pccard_ivar *devi = PCCARD_IVAR(child);
*val = pccard_ccr_read(devi->pf, offset);
device_printf(child, "ccr_read of %#x (%#x) is %#x\n", offset,
devi->pf->pf_ccr_offset, *val);
DEVPRINTF((child, "ccr_read of %#x (%#x) is %#x\n", offset,
devi->pf->pf_ccr_offset, *val));
return 0;
}
@ -1421,8 +1421,8 @@ pccard_ccr_write_impl(device_t brdev, device_t child, uint32_t offset,
* Can't use pccard_ccr_write since client drivers may access
* registers not contained in the 'mask' if they are non-standard.
*/
device_printf(child, "ccr_write of %#x to %#x (%#x)\n", val, offset,
devi->pf->pf_ccr_offset);
DEVPRINTF((child, "ccr_write of %#x to %#x (%#x)\n", val, offset,
devi->pf->pf_ccr_offset));
bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, pf->pf_ccr_offset + offset,
val);
return 0;

View File

@ -2576,6 +2576,17 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl,
uint16_t cmd;
struct resource *res;
/*
* The BAR may already exist if the device is a CardBus card
* whose CIS is stored in this BAR.
*/
pm = pci_find_bar(dev, reg);
if (pm != NULL) {
maprange = pci_maprange(pm->pm_value);
barlen = maprange == 64 ? 2 : 1;
return (barlen);
}
pci_read_bar(dev, reg, &map, &testval);
if (PCI_BAR_MEM(map)) {
type = SYS_RES_MEMORY;

View File

@ -51,12 +51,12 @@ static puc_config_f puc_config_amc;
static puc_config_f puc_config_diva;
static puc_config_f puc_config_exar;
static puc_config_f puc_config_icbook;
static puc_config_f puc_config_oxford_pcie;
static puc_config_f puc_config_quatech;
static puc_config_f puc_config_syba;
static puc_config_f puc_config_siig;
static puc_config_f puc_config_timedia;
static puc_config_f puc_config_titan;
static puc_config_f puc_config_oxford_pcie;
const struct puc_cfg puc_pci_devices[] = {
@ -1366,14 +1366,12 @@ puc_config_oxford_pcie(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port,
bar = puc_get_bar(sc, cfg->rid);
if (bar == NULL)
return (ENXIO);
for (idx = 0; idx < sc->sc_nports; idx++) {
value = bus_read_1(bar->b_res, 0x1000 + (idx << 9)
+ 0x92);
value = bus_read_1(bar->b_res, 0x1000 + (idx << 9) +
0x92);
bus_write_1(bar->b_res, 0x1000 + (idx << 9) + 0x92,
value | 0x10);
value | 0x10);
}
return (0);
case PUC_CFG_GET_LEN:
*res = 0x200;

View File

@ -401,10 +401,10 @@ int nfsrpc_readdirplus(vnode_t, struct uio *, nfsuint64 *,
int nfsrpc_commit(vnode_t, u_quad_t, int, struct ucred *,
NFSPROC_T *, u_char *, struct nfsvattr *, int *, void *);
int nfsrpc_advlock(vnode_t, off_t, int, struct flock *, int,
struct ucred *, NFSPROC_T *);
struct ucred *, NFSPROC_T *, void *, int);
int nfsrpc_lockt(struct nfsrv_descript *, vnode_t,
struct nfsclclient *, u_int64_t, u_int64_t, struct flock *,
struct ucred *, NFSPROC_T *);
struct ucred *, NFSPROC_T *, void *, int);
int nfsrpc_lock(struct nfsrv_descript *, struct nfsmount *, vnode_t,
u_int8_t *, int, struct nfscllockowner *, int, int, u_int64_t,
u_int64_t, short, struct ucred *, NFSPROC_T *, int);
@ -439,16 +439,16 @@ struct nfsclclient *nfscl_findcl(struct nfsmount *);
void nfscl_clientrelease(struct nfsclclient *);
void nfscl_freelock(struct nfscllock *, int);
int nfscl_getbytelock(vnode_t, u_int64_t, u_int64_t, short,
struct ucred *, NFSPROC_T *, struct nfsclclient *, int, u_int8_t *,
u_int8_t *, struct nfscllockowner **, int *, int *);
struct ucred *, NFSPROC_T *, struct nfsclclient *, int, void *, int,
u_int8_t *, u_int8_t *, struct nfscllockowner **, int *, int *);
int nfscl_relbytelock(vnode_t, u_int64_t, u_int64_t,
struct ucred *, NFSPROC_T *, int, struct nfsclclient *,
struct nfscllockowner **, int *);
void *, int, struct nfscllockowner **, int *);
int nfscl_checkwritelocked(vnode_t, struct flock *,
struct ucred *, NFSPROC_T *);
struct ucred *, NFSPROC_T *, void *, int);
void nfscl_lockrelease(struct nfscllockowner *, int, int);
void nfscl_fillclid(u_int64_t, char *, u_int8_t *, u_int16_t);
void nfscl_filllockowner(NFSPROC_T *, u_int8_t *);
void nfscl_filllockowner(void *, u_int8_t *, int);
void nfscl_freeopen(struct nfsclopen *, int);
void nfscl_umount(struct nfsmount *, NFSPROC_T *);
void nfscl_renewthread(struct nfsclclient *, NFSPROC_T *);
@ -466,9 +466,10 @@ void nfscl_lockexcl(struct nfsv4lock *, void *);
void nfscl_lockunlock(struct nfsv4lock *);
void nfscl_lockderef(struct nfsv4lock *);
void nfscl_docb(struct nfsrv_descript *, NFSPROC_T *);
void nfscl_releasealllocks(struct nfsclclient *, vnode_t, NFSPROC_T *);
void nfscl_releasealllocks(struct nfsclclient *, vnode_t, NFSPROC_T *, void *,
int);
int nfscl_lockt(vnode_t, struct nfsclclient *, u_int64_t,
u_int64_t, struct flock *, NFSPROC_T *);
u_int64_t, struct flock *, NFSPROC_T *, void *, int);
int nfscl_mustflush(vnode_t);
int nfscl_nodeleg(vnode_t, int);
int nfscl_removedeleg(vnode_t, NFSPROC_T *, nfsv4stateid_t *);

View File

@ -500,7 +500,7 @@ nfscl_fillclid(u_int64_t clval, char *uuid, u_int8_t *cp, u_int16_t idlen)
* Fill in a lock owner name. For now, pid + the process's creation time.
*/
void
nfscl_filllockowner(struct thread *td, u_int8_t *cp)
nfscl_filllockowner(void *id, u_int8_t *cp, int flags)
{
union {
u_int32_t lval;
@ -508,37 +508,35 @@ nfscl_filllockowner(struct thread *td, u_int8_t *cp)
} tl;
struct proc *p;
if (td == NULL) {
printf("NULL td\n");
bzero(cp, 12);
return;
}
p = td->td_proc;
if (p == NULL) {
printf("NULL pid\n");
bzero(cp, 12);
return;
}
tl.lval = p->p_pid;
*cp++ = tl.cval[0];
*cp++ = tl.cval[1];
*cp++ = tl.cval[2];
*cp++ = tl.cval[3];
if (p->p_stats == NULL) {
printf("pstats null\n");
bzero(cp, 8);
return;
}
tl.lval = p->p_stats->p_start.tv_sec;
*cp++ = tl.cval[0];
*cp++ = tl.cval[1];
*cp++ = tl.cval[2];
*cp++ = tl.cval[3];
tl.lval = p->p_stats->p_start.tv_usec;
*cp++ = tl.cval[0];
*cp++ = tl.cval[1];
*cp++ = tl.cval[2];
*cp = tl.cval[3];
if (id == NULL) {
printf("NULL id\n");
bzero(cp, NFSV4CL_LOCKNAMELEN);
return;
}
if ((flags & F_POSIX) != 0) {
p = (struct proc *)id;
tl.lval = p->p_pid;
*cp++ = tl.cval[0];
*cp++ = tl.cval[1];
*cp++ = tl.cval[2];
*cp++ = tl.cval[3];
tl.lval = p->p_stats->p_start.tv_sec;
*cp++ = tl.cval[0];
*cp++ = tl.cval[1];
*cp++ = tl.cval[2];
*cp++ = tl.cval[3];
tl.lval = p->p_stats->p_start.tv_usec;
*cp++ = tl.cval[0];
*cp++ = tl.cval[1];
*cp++ = tl.cval[2];
*cp = tl.cval[3];
} else if ((flags & F_FLOCK) != 0) {
bcopy(&id, cp, sizeof(id));
bzero(&cp[sizeof(id)], NFSV4CL_LOCKNAMELEN - sizeof(id));
} else {
printf("nfscl_filllockowner: not F_POSIX or F_FLOCK\n");
bzero(cp, NFSV4CL_LOCKNAMELEN);
}
}
/*
@ -943,6 +941,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
sad.sin_family = AF_INET;
sad.sin_len = sizeof (struct sockaddr_in);
sad.sin_addr.s_addr = sin->sin_addr.s_addr;
CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
rt = rtalloc1((struct sockaddr *)&sad, 0, 0UL);
if (rt != NULL) {
if (rt->rt_ifp != NULL &&
@ -956,6 +955,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
}
RTFREE_LOCKED(rt);
}
CURVNET_RESTORE();
#ifdef INET6
} else if (nmp->nm_nam->sa_family == AF_INET6) {
struct sockaddr_in6 sad6, *sin6;
@ -966,6 +966,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
sad6.sin6_family = AF_INET6;
sad6.sin6_len = sizeof (struct sockaddr_in6);
sad6.sin6_addr = sin6->sin6_addr;
CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
rt = rtalloc1((struct sockaddr *)&sad6, 0, 0UL);
if (rt != NULL) {
if (rt->rt_ifp != NULL &&
@ -980,6 +981,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
}
RTFREE_LOCKED(rt);
}
CURVNET_RESTORE();
#endif
}
return (retp);

View File

@ -3459,7 +3459,7 @@ nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
*/
APPLESTATIC int
nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
int reclaim, struct ucred *cred, NFSPROC_T *p)
int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
{
struct nfscllockowner *lp;
struct nfsclclient *clp;
@ -3511,11 +3511,11 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
error = nfscl_getcl(vp, cred, p, &clp);
if (error)
return (error);
error = nfscl_lockt(vp, clp, off, len, fl, p);
error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
if (!error) {
clidrev = clp->nfsc_clientidrev;
error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
p);
p, id, flags);
} else if (error == -1) {
error = 0;
}
@ -3530,7 +3530,7 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
return (error);
do {
error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
clp, &lp, &dorpc);
clp, id, flags, &lp, &dorpc);
/*
* If it returns a NULL lp, we're done.
*/
@ -3538,7 +3538,7 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
if (callcnt == 0)
nfscl_clientrelease(clp);
else
nfscl_releasealllocks(clp, vp, p);
nfscl_releasealllocks(clp, vp, p, id, flags);
return (error);
}
if (nmp->nm_clp != NULL)
@ -3572,10 +3572,10 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
}
callcnt++;
} while (error == 0 && nd->nd_repstat == 0);
nfscl_releasealllocks(clp, vp, p);
nfscl_releasealllocks(clp, vp, p, id, flags);
} else if (op == F_SETLK) {
error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
NULL, 0, NULL, NULL, &lp, &newone, &donelocally);
NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
if (error || donelocally) {
return (error);
}
@ -3625,7 +3625,7 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
APPLESTATIC int
nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
struct ucred *cred, NFSPROC_T *p)
struct ucred *cred, NFSPROC_T *p, void *id, int flags)
{
u_int32_t *tl;
int error, type, size;
@ -3643,7 +3643,7 @@ nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
tl += 2;
*tl++ = clp->nfsc_clientid.lval[0];
*tl = clp->nfsc_clientid.lval[1];
nfscl_filllockowner(p, own);
nfscl_filllockowner(id, own, flags);
(void) nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN);
error = nfscl_request(nd, vp, p, cred, NULL);
if (error)

View File

@ -226,7 +226,7 @@ nfscl_open(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t amode, int usedeleg,
* If none found, add the new one or return error, depending upon
* "create".
*/
nfscl_filllockowner(p, own);
nfscl_filllockowner(p->td_proc, own, F_POSIX);
NFSLOCKCLSTATE();
dp = NULL;
/* First check the delegation list */
@ -521,7 +521,7 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode,
* If p != NULL, we want to search the parentage tree
* for a matching OpenOwner and use that.
*/
nfscl_filllockowner(p, own);
nfscl_filllockowner(p->td_proc, own, F_POSIX);
error = nfscl_getopen(&clp->nfsc_owner, nfhp, fhlen, NULL, p,
mode, NULL, &op);
if (error == 0) {
@ -596,7 +596,7 @@ nfscl_getopen(struct nfsclownerhead *ohp, u_int8_t *nfhp, int fhlen,
op = NULL;
while (op == NULL && (nproc != NULL || rown != NULL)) {
if (nproc != NULL) {
nfscl_filllockowner(nproc, own);
nfscl_filllockowner(nproc->td_proc, own, F_POSIX);
ownp = own;
} else {
ownp = rown;
@ -881,7 +881,7 @@ nfscl_clientrelease(struct nfsclclient *clp)
APPLESTATIC int
nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
short type, struct ucred *cred, NFSPROC_T *p, struct nfsclclient *rclp,
int recovery, u_int8_t *rownp, u_int8_t *ropenownp,
int recovery, void *id, int flags, u_int8_t *rownp, u_int8_t *ropenownp,
struct nfscllockowner **lpp, int *newonep, int *donelocallyp)
{
struct nfscllockowner *lp;
@ -942,7 +942,7 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
if (recovery) {
ownp = rownp;
} else {
nfscl_filllockowner(p, own);
nfscl_filllockowner(id, own, flags);
ownp = own;
}
if (!recovery) {
@ -1079,7 +1079,8 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
APPLESTATIC int
nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
__unused struct ucred *cred, NFSPROC_T *p, int callcnt,
struct nfsclclient *clp, struct nfscllockowner **lpp, int *dorpcp)
struct nfsclclient *clp, void *id, int flags,
struct nfscllockowner **lpp, int *dorpcp)
{
struct nfscllockowner *lp;
struct nfsclowner *owp;
@ -1116,7 +1117,7 @@ nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
*other_lop = *nlop;
}
nfscl_filllockowner(p, own);
nfscl_filllockowner(id, own, flags);
dp = NULL;
NFSLOCKCLSTATE();
if (callcnt == 0)
@ -1188,7 +1189,8 @@ nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
* Release all lockowners marked in progess for this process and file.
*/
APPLESTATIC void
nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p)
nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p,
void *id, int flags)
{
struct nfsclowner *owp;
struct nfsclopen *op;
@ -1197,7 +1199,7 @@ nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p)
u_int8_t own[NFSV4CL_LOCKNAMELEN];
np = VTONFS(vp);
nfscl_filllockowner(p, own);
nfscl_filllockowner(id, own, flags);
NFSLOCKCLSTATE();
LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
@ -1226,7 +1228,7 @@ nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p)
*/
APPLESTATIC int
nfscl_checkwritelocked(vnode_t vp, struct flock *fl,
struct ucred *cred, NFSPROC_T *p)
struct ucred *cred, NFSPROC_T *p, void *id, int flags)
{
struct nfsclowner *owp;
struct nfscllockowner *lp;
@ -1266,7 +1268,7 @@ nfscl_checkwritelocked(vnode_t vp, struct flock *fl,
error = nfscl_getcl(vp, cred, p, &clp);
if (error)
return (1);
nfscl_filllockowner(p, own);
nfscl_filllockowner(id, own, flags);
NFSLOCKCLSTATE();
/*
@ -1641,7 +1643,7 @@ nfscl_cleanup(NFSPROC_T *p)
if (!nfscl_inited)
return;
nfscl_filllockowner(p, own);
nfscl_filllockowner(p->td_proc, own, F_POSIX);
NFSLOCKCLSTATE();
/*
@ -3322,7 +3324,7 @@ nfscl_checkconflict(struct nfscllockownerhead *lhp, struct nfscllock *nlop,
*/
APPLESTATIC int
nfscl_lockt(vnode_t vp, struct nfsclclient *clp, u_int64_t off,
u_int64_t len, struct flock *fl, NFSPROC_T *p)
u_int64_t len, struct flock *fl, NFSPROC_T *p, void *id, int flags)
{
struct nfscllock *lop, nlck;
struct nfscldeleg *dp;
@ -3340,7 +3342,7 @@ nfscl_lockt(vnode_t vp, struct nfsclclient *clp, u_int64_t off,
return (NFSERR_INVAL);
}
np = VTONFS(vp);
nfscl_filllockowner(p, own);
nfscl_filllockowner(id, own, flags);
NFSLOCKCLSTATE();
dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
error = nfscl_localconflict(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
@ -3615,7 +3617,7 @@ nfscl_relock(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp,
off = lop->nfslo_first;
len = lop->nfslo_end - lop->nfslo_first;
error = nfscl_getbytelock(vp, off, len, lop->nfslo_type, cred, p,
clp, 1, lp->nfsl_owner, lp->nfsl_openowner, &nlp, &newone,
clp, 1, NULL, 0, lp->nfsl_owner, lp->nfsl_openowner, &nlp, &newone,
&donelocally);
if (error || donelocally)
return (error);

View File

@ -2884,8 +2884,11 @@ nfs_advlock(struct vop_advlock_args *ap)
int ret, error = EOPNOTSUPP;
u_quad_t size;
if (NFS_ISV4(vp) && (ap->a_flags & F_POSIX)) {
cred = p->p_ucred;
if (NFS_ISV4(vp) && (ap->a_flags & (F_POSIX | F_FLOCK)) != 0) {
if ((ap->a_flags & F_POSIX) != 0)
cred = p->p_ucred;
else
cred = td->td_ucred;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
if (vp->v_iflag & VI_DOOMED) {
VOP_UNLOCK(vp, 0);
@ -2898,7 +2901,8 @@ nfs_advlock(struct vop_advlock_args *ap)
* RFC3530 Sec. 9.3.2.
*/
if (ap->a_op == F_UNLCK &&
nfscl_checkwritelocked(vp, ap->a_fl, cred, td))
nfscl_checkwritelocked(vp, ap->a_fl, cred, td, ap->a_id,
ap->a_flags))
(void) ncl_flush(vp, MNT_WAIT, cred, td, 1, 0);
/*
@ -2907,7 +2911,7 @@ nfs_advlock(struct vop_advlock_args *ap)
*/
do {
ret = nfsrpc_advlock(vp, np->n_size, ap->a_op,
ap->a_fl, 0, cred, td);
ap->a_fl, 0, cred, td, ap->a_id, ap->a_flags);
if (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) &&
ap->a_op == F_SETLK) {
VOP_UNLOCK(vp, 0);

View File

@ -290,8 +290,11 @@ topo_probe_0x4(void)
* logical processors that belong to the same core
* as BSP thus deducing number of threads per core.
*/
cpuid_count(0x04, 0, p);
max_cores = ((p[0] >> 26) & 0x3f) + 1;
if (cpu_high >= 0x4) {
cpuid_count(0x04, 0, p);
max_cores = ((p[0] >> 26) & 0x3f) + 1;
} else
max_cores = 1;
core_id_bits = mask_width(max_logical/max_cores);
if (core_id_bits < 0)
return;

View File

@ -56,7 +56,14 @@ acpi_machdep_quirks(int *quirks)
void
acpi_cpu_c1()
{
#ifdef INVARIANTS
register_t ie;
ie = intr_disable();
KASSERT(ie == 0, ("%s called with interrupts enabled\n", __func__));
#endif
ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0);
ia64_enable_intr();
}
void *

View File

@ -411,12 +411,34 @@ cpu_halt()
void
cpu_idle(int busy)
{
struct ia64_pal_result res;
register_t ie;
if (cpu_idle_hook != NULL)
#if 0
if (!busy) {
critical_enter();
cpu_idleclock();
}
#endif
ie = intr_disable();
KASSERT(ie != 0, ("%s called with interrupts disabled\n", __func__));
if (sched_runnable())
ia64_enable_intr();
else if (cpu_idle_hook != NULL) {
(*cpu_idle_hook)();
else
res = ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0);
/* The hook must enable interrupts! */
} else {
ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0);
ia64_enable_intr();
}
#if 0
if (!busy) {
cpu_activeclock();
critical_exit();
}
#endif
}
int
@ -644,9 +666,12 @@ calculate_frequencies(void)
{
struct ia64_sal_result sal;
struct ia64_pal_result pal;
register_t ie;
ie = intr_disable();
sal = ia64_sal_entry(SAL_FREQ_BASE, 0, 0, 0, 0, 0, 0, 0);
pal = ia64_call_pal_static(PAL_FREQ_RATIOS, 0, 0, 0);
intr_restore(ie);
if (sal.sal_status == 0 && pal.pal_status == 0) {
if (bootverbose) {

View File

@ -38,43 +38,40 @@ ia64_pal_entry: .quad 0
* u_int64_t arg1, u_int64_t arg2, u_int64_t arg3)
*/
ENTRY(ia64_call_pal_static, 4)
.regstk 4,5,0,0
.regstk 4,4,0,0
palret = loc0
entry = loc1
rpsave = loc2
pfssave = loc3
psrsave = loc4
alloc pfssave=ar.pfs,4,5,0,0
alloc pfssave=ar.pfs,4,4,0,0
;;
mov rpsave=rp
movl entry=@gprel(ia64_pal_entry)
1: mov palret=ip // for return address
;;
add entry=entry,gp
mov psrsave=psr
add palret=2f-1b,palret // calculate return address
mov r28=in0 // procedure number
;;
ld8 entry=[entry] // read entry point
mov r29=in1 // copy arguments
mov r30=in2
mov r31=in3
;;
mov b6=entry
add palret=2f-1b,palret // calculate return address
;;
ld8 entry=[entry] // read entry point
mov b0=palret
rsm psr.i // disable interrupts
;;
mov b6=entry
;;
br.cond.sptk b6 // call into firmware
2: mov psr.l=psrsave
;;
2:
mov rp=rpsave
mov ar.pfs=pfssave
;;
srlz.d
br.ret.sptk rp
;;
END(ia64_call_pal_static)
/*

View File

@ -839,6 +839,7 @@ int_rman_release_resource(struct rman *rm, struct resource_i *r)
* without freeing anything.
*/
r->r_flags &= ~RF_ALLOCATED;
r->r_dev = NULL;
return 0;
}

View File

@ -297,8 +297,9 @@ struct nd_opt_hdr { /* Neighbor discovery option header */
#define ND_OPT_PREFIX_INFORMATION 3
#define ND_OPT_REDIRECTED_HEADER 4
#define ND_OPT_MTU 5
#define ND_OPT_ROUTE_INFO 200 /* draft-ietf-ipngwg-router-preference, not officially assigned yet */
#define ND_OPT_ROUTE_INFO 24 /* RFC 4191 */
#define ND_OPT_RDNSS 25 /* RFC 6016 */
#define ND_OPT_DNSSL 31 /* RFC 6016 */
struct nd_opt_prefix_info { /* prefix information */
u_int8_t nd_opt_pi_type;
@ -338,6 +339,22 @@ struct nd_opt_route_info { /* route info */
/* prefix follows */
} __packed;
struct nd_opt_rdnss { /* RDNSS option (RFC 6106) */
u_int8_t nd_opt_rdnss_type;
u_int8_t nd_opt_rdnss_len;
u_int16_t nd_opt_rdnss_reserved;
u_int32_t nd_opt_rdnss_lifetime;
/* followed by list of recursive DNS servers */
} __packed;
struct nd_opt_dnssl { /* DNSSL option (RFC 6106) */
u_int8_t nd_opt_dnssl_type;
u_int8_t nd_opt_dnssl_len;
u_int16_t nd_opt_dnssl_reserved;
u_int32_t nd_opt_dnssl_lifetime;
/* followed by list of DNS search domains */
} __packed;
/*
* icmp6 namelookup
*/

View File

@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include "opt_ipsec.h"
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_pcbgroup.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -212,7 +213,7 @@ void
in_pcbinfo_init(struct inpcbinfo *pcbinfo, const char *name,
struct inpcbhead *listhead, int hash_nelements, int porthash_nelements,
char *inpcbzone_name, uma_init inpcbzone_init, uma_fini inpcbzone_fini,
uint32_t inpcbzone_flags)
uint32_t inpcbzone_flags, u_int hashfields)
{
INP_INFO_LOCK_INIT(pcbinfo, name);
@ -227,6 +228,9 @@ in_pcbinfo_init(struct inpcbinfo *pcbinfo, const char *name,
&pcbinfo->ipi_hashmask);
pcbinfo->ipi_porthashbase = hashinit(porthash_nelements, M_PCB,
&pcbinfo->ipi_porthashmask);
#ifdef PCBGROUP
in_pcbgroup_init(pcbinfo, hashfields, hash_nelements);
#endif
pcbinfo->ipi_zone = uma_zcreate(inpcbzone_name, sizeof(struct inpcb),
NULL, NULL, inpcbzone_init, inpcbzone_fini, UMA_ALIGN_PTR,
inpcbzone_flags);
@ -246,6 +250,9 @@ in_pcbinfo_destroy(struct inpcbinfo *pcbinfo)
hashdestroy(pcbinfo->ipi_hashbase, M_PCB, pcbinfo->ipi_hashmask);
hashdestroy(pcbinfo->ipi_porthashbase, M_PCB,
pcbinfo->ipi_porthashmask);
#ifdef PCBGROUP
in_pcbgroup_destroy(pcbinfo);
#endif
uma_zdestroy(pcbinfo->ipi_zone);
INP_HASH_LOCK_DESTROY(pcbinfo);
INP_INFO_LOCK_DESTROY(pcbinfo);
@ -1053,7 +1060,8 @@ in_pcbdetach(struct inpcb *inp)
* in_pcbref() bumps the reference count on an inpcb in order to maintain
* stability of an inpcb pointer despite the inpcb lock being released. This
* is used in TCP when the inpcbinfo lock needs to be acquired or upgraded,
* but where the inpcb lock is already held.
* but where the inpcb lock may already held, or when acquiring a reference
* via a pcbgroup.
*
* in_pcbref() should be used only to provide brief memory stability, and
* must always be followed by a call to INP_WLOCK() and in_pcbrele() to
@ -1223,6 +1231,9 @@ in_pcbdrop(struct inpcb *inp)
}
INP_HASH_WUNLOCK(inp->inp_pcbinfo);
inp->inp_flags &= ~INP_INHASHLIST;
#ifdef PCBGROUP
in_pcbgroup_remove(inp);
#endif
}
}
@ -1472,6 +1483,148 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
}
#undef INP_LOOKUP_MAPPED_PCB_COST
#ifdef PCBGROUP
/*
* Lookup PCB in hash list, using pcbgroup tables.
*/
static struct inpcb *
in_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup,
struct in_addr faddr, u_int fport_arg, struct in_addr laddr,
u_int lport_arg, int lookupflags, struct ifnet *ifp)
{
struct inpcbhead *head;
struct inpcb *inp, *tmpinp;
u_short fport = fport_arg, lport = lport_arg;
/*
* First look for an exact match.
*/
tmpinp = NULL;
INP_GROUP_LOCK(pcbgroup);
head = &pcbgroup->ipg_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport,
pcbgroup->ipg_hashmask)];
LIST_FOREACH(inp, head, inp_pcbgrouphash) {
#ifdef INET6
/* XXX inp locking */
if ((inp->inp_vflag & INP_IPV4) == 0)
continue;
#endif
if (inp->inp_faddr.s_addr == faddr.s_addr &&
inp->inp_laddr.s_addr == laddr.s_addr &&
inp->inp_fport == fport &&
inp->inp_lport == lport) {
/*
* XXX We should be able to directly return
* the inp here, without any checks.
* Well unless both bound with SO_REUSEPORT?
*/
if (prison_flag(inp->inp_cred, PR_IP4))
goto found;
if (tmpinp == NULL)
tmpinp = inp;
}
}
if (tmpinp != NULL) {
inp = tmpinp;
goto found;
}
/*
* Then look for a wildcard match, if requested.
*/
if ((lookupflags & INPLOOKUP_WILDCARD) != 0) {
struct inpcb *local_wild = NULL, *local_exact = NULL;
#ifdef INET6
struct inpcb *local_wild_mapped = NULL;
#endif
struct inpcb *jail_wild = NULL;
struct inpcbhead *head;
int injail;
/*
* Order of socket selection - we always prefer jails.
* 1. jailed, non-wild.
* 2. jailed, wild.
* 3. non-jailed, non-wild.
* 4. non-jailed, wild.
*/
head = &pcbinfo->ipi_wildbase[INP_PCBHASH(INADDR_ANY, lport,
0, pcbinfo->ipi_wildmask)];
LIST_FOREACH(inp, head, inp_pcbgroup_wild) {
#ifdef INET6
/* XXX inp locking */
if ((inp->inp_vflag & INP_IPV4) == 0)
continue;
#endif
if (inp->inp_faddr.s_addr != INADDR_ANY ||
inp->inp_lport != lport)
continue;
/* XXX inp locking */
if (ifp && ifp->if_type == IFT_FAITH &&
(inp->inp_flags & INP_FAITH) == 0)
continue;
injail = prison_flag(inp->inp_cred, PR_IP4);
if (injail) {
if (prison_check_ip4(inp->inp_cred,
&laddr) != 0)
continue;
} else {
if (local_exact != NULL)
continue;
}
if (inp->inp_laddr.s_addr == laddr.s_addr) {
if (injail)
goto found;
else
local_exact = inp;
} else if (inp->inp_laddr.s_addr == INADDR_ANY) {
#ifdef INET6
/* XXX inp locking, NULL check */
if (inp->inp_vflag & INP_IPV6PROTO)
local_wild_mapped = inp;
else
#endif /* INET6 */
if (injail)
jail_wild = inp;
else
local_wild = inp;
}
} /* LIST_FOREACH */
inp = jail_wild;
if (inp == NULL)
inp = local_exact;
if (inp == NULL)
inp = local_wild;
#ifdef INET6
if (inp == NULL)
inp = local_wild_mapped;
#endif /* defined(INET6) */
if (inp != NULL)
goto found;
} /* if (lookupflags & INPLOOKUP_WILDCARD) */
INP_GROUP_UNLOCK(pcbgroup);
return (NULL);
found:
in_pcbref(inp);
INP_GROUP_UNLOCK(pcbgroup);
if (lookupflags & INPLOOKUP_WLOCKPCB) {
INP_WLOCK(inp);
if (in_pcbrele_wlocked(inp))
return (NULL);
} else if (lookupflags & INPLOOKUP_RLOCKPCB) {
INP_RLOCK(inp);
if (in_pcbrele_rlocked(inp))
return (NULL);
} else
panic("%s: locking bug", __func__);
return (inp);
}
#endif /* PCBGROUP */
/*
* Lookup PCB in hash list, using pcbinfo tables. This variation assumes
* that the caller has locked the hash list, and will not perform any further
@ -1636,17 +1789,30 @@ in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
/*
* Public inpcb lookup routines, accepting a 4-tuple, and optionally, an mbuf
* from which a pre-calculated hash value may be extracted.
*
* Possibly more of this logic should be in in_pcbgroup.c.
*/
struct inpcb *
in_pcblookup(struct inpcbinfo *pcbinfo, struct in_addr faddr, u_int fport,
struct in_addr laddr, u_int lport, int lookupflags, struct ifnet *ifp)
{
#if defined(PCBGROUP)
struct inpcbgroup *pcbgroup;
#endif
KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
("%s: invalid lookup flags %d", __func__, lookupflags));
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
("%s: LOCKPCB not set", __func__));
#if defined(PCBGROUP)
if (in_pcbgroup_enabled(pcbinfo)) {
pcbgroup = in_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
fport);
return (in_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
laddr, lport, lookupflags, ifp));
}
#endif
return (in_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
lookupflags, ifp));
}
@ -1656,12 +1822,28 @@ in_pcblookup_mbuf(struct inpcbinfo *pcbinfo, struct in_addr faddr,
u_int fport, struct in_addr laddr, u_int lport, int lookupflags,
struct ifnet *ifp, struct mbuf *m)
{
#ifdef PCBGROUP
struct inpcbgroup *pcbgroup;
#endif
KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
("%s: invalid lookup flags %d", __func__, lookupflags));
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
("%s: LOCKPCB not set", __func__));
#ifdef PCBGROUP
if (in_pcbgroup_enabled(pcbinfo)) {
pcbgroup = in_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
m->m_pkthdr.flowid);
if (pcbgroup != NULL)
return (in_pcblookup_group(pcbinfo, pcbgroup, faddr,
fport, laddr, lport, lookupflags, ifp));
pcbgroup = in_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
fport);
return (in_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
laddr, lport, lookupflags, ifp));
}
#endif
return (in_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
lookupflags, ifp));
}
@ -1670,8 +1852,8 @@ in_pcblookup_mbuf(struct inpcbinfo *pcbinfo, struct in_addr faddr,
/*
* Insert PCB onto various hash lists.
*/
int
in_pcbinshash(struct inpcb *inp)
static int
in_pcbinshash_internal(struct inpcb *inp, int do_pcbgroup_update)
{
struct inpcbhead *pcbhash;
struct inpcbporthead *pcbporthash;
@ -1721,9 +1903,38 @@ in_pcbinshash(struct inpcb *inp)
LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
inp->inp_flags |= INP_INHASHLIST;
#ifdef PCBGROUP
if (do_pcbgroup_update)
in_pcbgroup_update(inp);
#endif
return (0);
}
/*
* For now, there are two public interfaces to insert an inpcb into the hash
* lists -- one that does update pcbgroups, and one that doesn't. The latter
* is used only in the TCP syncache, where in_pcbinshash is called before the
* full 4-tuple is set for the inpcb, and we don't want to install in the
* pcbgroup until later.
*
* XXXRW: This seems like a misfeature. in_pcbinshash should always update
* connection groups, and partially initialised inpcbs should not be exposed
* to either reservation hash tables or pcbgroups.
*/
int
in_pcbinshash(struct inpcb *inp)
{
return (in_pcbinshash_internal(inp, 1));
}
int
in_pcbinshash_nopcbgroup(struct inpcb *inp)
{
return (in_pcbinshash_internal(inp, 0));
}
/*
* Move PCB to the proper hash bucket when { faddr, fport } have been
* changed. NOTE: This does not handle the case of the lport changing (the
@ -1755,6 +1966,13 @@ in_pcbrehash_mbuf(struct inpcb *inp, struct mbuf *m)
LIST_REMOVE(inp, inp_hash);
LIST_INSERT_HEAD(head, inp, inp_hash);
#ifdef PCBGROUP
if (m != NULL)
in_pcbgroup_update_mbuf(inp, m);
else
in_pcbgroup_update(inp);
#endif
}
void
@ -1791,6 +2009,9 @@ in_pcbremlists(struct inpcb *inp)
}
LIST_REMOVE(inp, inp_list);
pcbinfo->ipi_count--;
#ifdef PCBGROUP
in_pcbgroup_remove(inp);
#endif
}
/*

View File

@ -141,6 +141,7 @@ struct icmp6_filter;
*
* Key:
* (c) - Constant after initialization
* (g) - Protected by the pcbgroup lock
* (i) - Protected by the inpcb lock
* (p) - Protected by the pcbinfo lock for the inpcb
* (s) - Protected by another subsystem's locks
@ -160,9 +161,12 @@ struct icmp6_filter;
*/
struct inpcb {
LIST_ENTRY(inpcb) inp_hash; /* (i/p) hash list */
LIST_ENTRY(inpcb) inp_pcbgrouphash; /* (g/i) hash list */
LIST_ENTRY(inpcb) inp_list; /* (i/p) list for all PCBs for proto */
void *inp_ppcb; /* (i) pointer to per-protocol pcb */
struct inpcbinfo *inp_pcbinfo; /* (c) PCB list info */
struct inpcbgroup *inp_pcbgroup; /* (g/i) PCB group list */
LIST_ENTRY(inpcb) inp_pcbgroup_wild; /* (g/i/p) group wildcard entry */
struct socket *inp_socket; /* (i) back pointer to socket */
struct ucred *inp_cred; /* (c) cache of socket cred */
u_int32_t inp_flow; /* (i) IPv6 flow information */
@ -272,13 +276,14 @@ struct inpcbport {
* the former covering mutable global fields (such as the global pcb list),
* and the latter covering the hashed lookup tables. The lock order is:
*
* ipi_lock (before) inpcb locks (before) ipi_hash_lock
* ipi_lock (before) inpcb locks (before) {ipi_hash_lock, pcbgroup locks}
*
* Locking key:
*
* (c) Constant or nearly constant after initialisation
* (g) Locked by ipi_lock
* (h) Read using either ipi_hash_lock or inpcb lock; write requires both.
* (h) Read using either ipi_hash_lock or inpcb lock; write requires both
* (p) Protected by one or more pcbgroup locks
* (x) Synchronisation properties poorly defined
*/
struct inpcbinfo {
@ -312,7 +317,16 @@ struct inpcbinfo {
struct uma_zone *ipi_zone; /* (c) */
/*
* Global lock protecting hash lookup tables.
* Connection groups associated with this protocol. These fields are
* constant, but pcbgroup structures themselves are protected by
* per-pcbgroup locks.
*/
struct inpcbgroup *ipi_pcbgroups; /* (c) */
u_int ipi_npcbgroups; /* (c) */
u_int ipi_hashfields; /* (c) */
/*
* Global lock protecting non-pcbgroup hash lookup tables.
*/
struct rwlock ipi_hash_lock;
@ -329,6 +343,14 @@ struct inpcbinfo {
struct inpcbporthead *ipi_porthashbase; /* (h) */
u_long ipi_porthashmask; /* (h) */
/*
* List of wildcard inpcbs for use with pcbgroups. In the past, was
* per-pcbgroup but is now global. All pcbgroup locks must be held
* to modify the list, so any is sufficient to read it.
*/
struct inpcbhead *ipi_wildbase; /* (p) */
u_long ipi_wildmask; /* (p) */
/*
* Pointer to network stack instance
*/
@ -340,6 +362,31 @@ struct inpcbinfo {
void *ipi_pspare[2];
};
/*
* Connection groups hold sets of connections that have similar CPU/thread
* affinity. Each connection belongs to exactly one connection group.
*/
struct inpcbgroup {
/*
* Per-connection group hash of inpcbs, hashed by local and foreign
* addresses and port numbers.
*/
struct inpcbhead *ipg_hashbase; /* (c) */
u_long ipg_hashmask; /* (c) */
/*
* Notional affinity of this pcbgroup.
*/
u_int ipg_cpu; /* (p) */
/*
* Per-connection group lock, not to be confused with ipi_lock.
* Protects the hash table hung off the group, but also the global
* wildcard list in inpcbinfo.
*/
struct mtx ipg_lock;
} __aligned(CACHE_LINE_SIZE);
#define INP_LOCK_INIT(inp, d, t) \
rw_init_flags(&(inp)->inp_lock, (t), RW_RECURSE | RW_DUPOK)
#define INP_LOCK_DESTROY(inp) rw_destroy(&(inp)->inp_lock)
@ -423,6 +470,14 @@ void inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp,
#define INP_HASH_WLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_hash_lock, \
RA_WLOCKED)
#define INP_GROUP_LOCK_INIT(ipg, d) mtx_init(&(ipg)->ipg_lock, (d), NULL, \
MTX_DEF | MTX_DUPOK)
#define INP_GROUP_LOCK_DESTROY(ipg) mtx_destroy(&(ipg)->ipg_lock)
#define INP_GROUP_LOCK(ipg) mtx_lock(&(ipg)->ipg_lock)
#define INP_GROUP_LOCK_ASSERT(ipg) mtx_assert(&(ipg)->ipg_lock, MA_OWNED)
#define INP_GROUP_UNLOCK(ipg) mtx_unlock(&(ipg)->ipg_lock)
#define INP_PCBHASH(faddr, lport, fport, mask) \
(((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport))) & (mask))
#define INP_PCBPORTHASH(lport, mask) \
@ -482,6 +537,7 @@ void inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp,
*/
#define INP_LLE_VALID 0x00000001 /* cached lle is valid */
#define INP_RT_VALID 0x00000002 /* cached rtentry is valid */
#define INP_PCBGROUPWILD 0x00000004 /* in pcbgroup wildcard list */
/*
* Flags passed to in_pcblookup*() functions.
@ -500,6 +556,13 @@ void inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp,
#define INP_CHECK_SOCKAF(so, af) (INP_SOCKAF(so) == af)
/*
* Constants for pcbinfo.ipi_hashfields.
*/
#define IPI_HASHFIELDS_NONE 0
#define IPI_HASHFIELDS_2TUPLE 1
#define IPI_HASHFIELDS_4TUPLE 2
#ifdef _KERNEL
VNET_DECLARE(int, ipport_reservedhigh);
VNET_DECLARE(int, ipport_reservedlow);
@ -531,7 +594,21 @@ VNET_DECLARE(int, ipport_tcpallocs);
void in_pcbinfo_destroy(struct inpcbinfo *);
void in_pcbinfo_init(struct inpcbinfo *, const char *, struct inpcbhead *,
int, int, char *, uma_init, uma_fini, uint32_t);
int, int, char *, uma_init, uma_fini, uint32_t, u_int);
struct inpcbgroup *
in_pcbgroup_byhash(struct inpcbinfo *, u_int, uint32_t);
struct inpcbgroup *
in_pcbgroup_byinpcb(struct inpcb *);
struct inpcbgroup *
in_pcbgroup_bytuple(struct inpcbinfo *, struct in_addr, u_short,
struct in_addr, u_short);
void in_pcbgroup_destroy(struct inpcbinfo *);
int in_pcbgroup_enabled(struct inpcbinfo *);
void in_pcbgroup_init(struct inpcbinfo *, u_int, int);
void in_pcbgroup_remove(struct inpcb *);
void in_pcbgroup_update(struct inpcb *);
void in_pcbgroup_update_mbuf(struct inpcb *, struct mbuf *);
void in_pcbpurgeif0(struct inpcbinfo *, struct ifnet *);
int in_pcballoc(struct socket *, struct inpcbinfo *);
@ -551,6 +628,7 @@ void in_pcbdisconnect(struct inpcb *);
void in_pcbdrop(struct inpcb *);
void in_pcbfree(struct inpcb *);
int in_pcbinshash(struct inpcb *);
int in_pcbinshash_nopcbgroup(struct inpcb *);
struct inpcb *
in_pcblookup_local(struct inpcbinfo *,
struct in_addr, u_short, int, struct ucred *);

457
sys/netinet/in_pcbgroup.c Normal file
View File

@ -0,0 +1,457 @@
/*-
* Copyright (c) 2010-2011 Juniper Networks, Inc.
* All rights reserved.
*
* This software was developed by Robert N. M. Watson under contract
* to Juniper Networks, Inc.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/smp.h>
#include <sys/socketvar.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>
#ifdef INET6
#include <netinet6/in6_pcb.h>
#endif /* INET6 */
/*
* pcbgroups, or "connection groups" are based on Willman, Rixner, and Cox's
* 2006 USENIX paper, "An Evaluation of Network Stack Parallelization
* Strategies in Modern Operating Systems". This implementation differs
* significantly from that described in the paper, in that it attempts to
* introduce not just notions of affinity for connections and distribute work
* so as to reduce lock contention, but also align those notions with
* hardware work distribution strategies such as RSS. In this construction,
* connection groups supplement, rather than replace, existing reservation
* tables for protocol 4-tuples, offering CPU-affine lookup tables with
* minimal cache line migration and lock contention during steady state
* operation.
*
* Internet protocols, such as UDP and TCP, register to use connection groups
* by providing an ipi_hashfields value other than IPI_HASHFIELDS_NONE; this
* indicates to the connection group code whether a 2-tuple or 4-tuple is
* used as an argument to hashes that assign a connection to a particular
* group. This must be aligned with any hardware offloaded distribution
* model, such as RSS or similar approaches taken in embedded network boards.
* Wildcard sockets require special handling, as in Willman 2006, and are
* shared between connection groups -- while being protected by group-local
* locks. This means that connection establishment and teardown can be
* signficantly more expensive than without connection groups, but that
* steady-state processing can be significantly faster.
*
* Most of the implementation of connection groups is in this file; however,
* connection group lookup is implemented in in_pcb.c alongside reservation
* table lookups -- see in_pcblookup_group().
*
* TODO:
*
* Implement dynamic rebalancing of buckets with connection groups; when
* load is unevenly distributed, search for more optimal balancing on
* demand. This might require scaling up the number of connection groups
* by <<1.
*
* Provide an IP 2-tuple or 4-tuple netisr m2cpu handler based on connection
* groups for ip_input and ip6_input, allowing non-offloaded work
* distribution.
*
* Expose effective CPU affinity of connections to userspace using socket
* options.
*
* Investigate per-connection affinity overrides based on socket options; an
* option could be set, certainly resulting in work being distributed
* differently in software, and possibly propagated to supporting hardware
* with TCAMs or hardware hash tables. This might require connections to
* exist in more than one connection group at a time.
*
* Hook netisr thread reconfiguration events, and propagate those to RSS so
* that rebalancing can occur when the thread pool grows or shrinks.
*
* Expose per-pcbgroup statistics to userspace monitoring tools such as
* netstat, in order to allow better debugging and profiling.
*/
void
in_pcbgroup_init(struct inpcbinfo *pcbinfo, u_int hashfields,
int hash_nelements)
{
struct inpcbgroup *pcbgroup;
u_int numpcbgroups, pgn;
/*
* Only enable connection groups for a protocol if it has been
* specifically requested.
*/
if (hashfields == IPI_HASHFIELDS_NONE)
return;
/*
* Connection groups are about multi-processor load distribution,
* lock contention, and connection CPU affinity. As such, no point
* in turning them on for a uniprocessor machine, it only wastes
* memory.
*/
if (mp_ncpus == 1)
return;
/*
* Use one group per CPU for now. If we decide to do dynamic
* rebalancing a la RSS, we'll need to shift left by at least 1.
*/
numpcbgroups = mp_ncpus;
pcbinfo->ipi_hashfields = hashfields;
pcbinfo->ipi_pcbgroups = malloc(numpcbgroups *
sizeof(*pcbinfo->ipi_pcbgroups), M_PCB, M_WAITOK | M_ZERO);
pcbinfo->ipi_npcbgroups = numpcbgroups;
pcbinfo->ipi_wildbase = hashinit(hash_nelements, M_PCB,
&pcbinfo->ipi_wildmask);
for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++) {
pcbgroup = &pcbinfo->ipi_pcbgroups[pgn];
pcbgroup->ipg_hashbase = hashinit(hash_nelements, M_PCB,
&pcbgroup->ipg_hashmask);
INP_GROUP_LOCK_INIT(pcbgroup, "pcbgroup");
/*
* Initialise notional affinity of the pcbgroup -- for RSS,
* we want the same notion of affinity as NICs to be used.
* Just round robin for the time being.
*/
pcbgroup->ipg_cpu = (pgn % mp_ncpus);
}
}
void
in_pcbgroup_destroy(struct inpcbinfo *pcbinfo)
{
struct inpcbgroup *pcbgroup;
u_int pgn;
if (pcbinfo->ipi_npcbgroups == 0)
return;
for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++) {
pcbgroup = &pcbinfo->ipi_pcbgroups[pgn];
KASSERT(LIST_EMPTY(pcbinfo->ipi_listhead),
("in_pcbinfo_destroy: listhead not empty"));
INP_GROUP_LOCK_DESTROY(pcbgroup);
hashdestroy(pcbgroup->ipg_hashbase, M_PCB,
pcbgroup->ipg_hashmask);
}
hashdestroy(pcbinfo->ipi_wildbase, M_PCB, pcbinfo->ipi_wildmask);
free(pcbinfo->ipi_pcbgroups, M_PCB);
pcbinfo->ipi_pcbgroups = NULL;
pcbinfo->ipi_npcbgroups = 0;
pcbinfo->ipi_hashfields = 0;
}
/*
* Given a hash of whatever the covered tuple might be, return a pcbgroup
* index.
*/
static __inline u_int
in_pcbgroup_getbucket(struct inpcbinfo *pcbinfo, uint32_t hash)
{
return (hash % pcbinfo->ipi_npcbgroups);
}
/*
* Map a (hashtype, hash) tuple into a connection group, or NULL if the hash
* information is insufficient to identify the pcbgroup.
*/
struct inpcbgroup *
in_pcbgroup_byhash(struct inpcbinfo *pcbinfo, u_int hashtype, uint32_t hash)
{
return (NULL);
}
static struct inpcbgroup *
in_pcbgroup_bymbuf(struct inpcbinfo *pcbinfo, struct mbuf *m)
{
return (in_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
m->m_pkthdr.flowid));
}
struct inpcbgroup *
in_pcbgroup_bytuple(struct inpcbinfo *pcbinfo, struct in_addr laddr,
u_short lport, struct in_addr faddr, u_short fport)
{
uint32_t hash;
switch (pcbinfo->ipi_hashfields) {
case IPI_HASHFIELDS_4TUPLE:
hash = faddr.s_addr ^ fport;
break;
case IPI_HASHFIELDS_2TUPLE:
hash = faddr.s_addr ^ laddr.s_addr;
break;
default:
hash = 0;
}
return (&pcbinfo->ipi_pcbgroups[in_pcbgroup_getbucket(pcbinfo,
hash)]);
}
struct inpcbgroup *
in_pcbgroup_byinpcb(struct inpcb *inp)
{
return (in_pcbgroup_bytuple(inp->inp_pcbinfo, inp->inp_laddr,
inp->inp_lport, inp->inp_faddr, inp->inp_fport));
}
static void
in_pcbwild_add(struct inpcb *inp)
{
struct inpcbinfo *pcbinfo;
struct inpcbhead *head;
u_int pgn;
INP_WLOCK_ASSERT(inp);
KASSERT(!(inp->inp_flags2 & INP_PCBGROUPWILD),
("%s: is wild",__func__));
pcbinfo = inp->inp_pcbinfo;
for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++)
INP_GROUP_LOCK(&pcbinfo->ipi_pcbgroups[pgn]);
head = &pcbinfo->ipi_wildbase[INP_PCBHASH(INADDR_ANY, inp->inp_lport,
0, pcbinfo->ipi_wildmask)];
LIST_INSERT_HEAD(head, inp, inp_pcbgroup_wild);
inp->inp_flags2 |= INP_PCBGROUPWILD;
for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++)
INP_GROUP_UNLOCK(&pcbinfo->ipi_pcbgroups[pgn]);
}
static void
in_pcbwild_remove(struct inpcb *inp)
{
struct inpcbinfo *pcbinfo;
u_int pgn;
INP_WLOCK_ASSERT(inp);
KASSERT((inp->inp_flags2 & INP_PCBGROUPWILD),
("%s: not wild", __func__));
pcbinfo = inp->inp_pcbinfo;
for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++)
INP_GROUP_LOCK(&pcbinfo->ipi_pcbgroups[pgn]);
LIST_REMOVE(inp, inp_pcbgroup_wild);
for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++)
INP_GROUP_UNLOCK(&pcbinfo->ipi_pcbgroups[pgn]);
inp->inp_flags2 &= ~INP_PCBGROUPWILD;
}
static __inline int
in_pcbwild_needed(struct inpcb *inp)
{
#ifdef INET6
if (inp->inp_vflag & INP_IPV6)
return (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr));
else
#endif
return (inp->inp_faddr.s_addr == htonl(INADDR_ANY));
}
static void
in_pcbwild_update_internal(struct inpcb *inp)
{
int wildcard_needed;
wildcard_needed = in_pcbwild_needed(inp);
if (wildcard_needed && !(inp->inp_flags2 & INP_PCBGROUPWILD))
in_pcbwild_add(inp);
else if (!wildcard_needed && (inp->inp_flags2 & INP_PCBGROUPWILD))
in_pcbwild_remove(inp);
}
/*
* Update the pcbgroup of an inpcb, which might include removing an old
* pcbgroup reference and/or adding a new one. Wildcard processing is not
* performed here, although ideally we'll never install a pcbgroup for a
* wildcard inpcb (asserted below).
*/
static void
in_pcbgroup_update_internal(struct inpcbinfo *pcbinfo,
struct inpcbgroup *newpcbgroup, struct inpcb *inp)
{
struct inpcbgroup *oldpcbgroup;
struct inpcbhead *pcbhash;
uint32_t hashkey_faddr;
INP_WLOCK_ASSERT(inp);
oldpcbgroup = inp->inp_pcbgroup;
if (oldpcbgroup != NULL && oldpcbgroup != newpcbgroup) {
INP_GROUP_LOCK(oldpcbgroup);
LIST_REMOVE(inp, inp_pcbgrouphash);
inp->inp_pcbgroup = NULL;
INP_GROUP_UNLOCK(oldpcbgroup);
}
if (newpcbgroup != NULL && oldpcbgroup != newpcbgroup) {
#ifdef INET6
if (inp->inp_vflag & INP_IPV6)
hashkey_faddr = inp->in6p_faddr.s6_addr32[3]; /* XXX */
else
#endif
hashkey_faddr = inp->inp_faddr.s_addr;
INP_GROUP_LOCK(newpcbgroup);
pcbhash = &newpcbgroup->ipg_hashbase[
INP_PCBHASH(hashkey_faddr, inp->inp_lport, inp->inp_fport,
newpcbgroup->ipg_hashmask)];
LIST_INSERT_HEAD(pcbhash, inp, inp_pcbgrouphash);
inp->inp_pcbgroup = newpcbgroup;
INP_GROUP_UNLOCK(newpcbgroup);
}
KASSERT(!(newpcbgroup != NULL && in_pcbwild_needed(inp)),
("%s: pcbgroup and wildcard!", __func__));
}
/*
* Two update paths: one in which the 4-tuple on an inpcb has been updated
* and therefore connection groups may need to change (or a wildcard entry
* may needed to be installed), and another in which the 4-tuple has been
* set as a result of a packet received, in which case we may be able to use
* the hash on the mbuf to avoid doing a software hash calculation for RSS.
*
* In each case: first, let the wildcard code have a go at placing it as a
* wildcard socket. If it was a wildcard, or if the connection has been
* dropped, then no pcbgroup is required (so potentially clear it);
* otherwise, calculate and update the pcbgroup for the inpcb.
*/
void
in_pcbgroup_update(struct inpcb *inp)
{
struct inpcbinfo *pcbinfo;
struct inpcbgroup *newpcbgroup;
INP_WLOCK_ASSERT(inp);
pcbinfo = inp->inp_pcbinfo;
if (!in_pcbgroup_enabled(pcbinfo))
return;
in_pcbwild_update_internal(inp);
if (!(inp->inp_flags2 & INP_PCBGROUPWILD) &&
!(inp->inp_flags & INP_DROPPED)) {
#ifdef INET6
if (inp->inp_vflag & INP_IPV6)
newpcbgroup = in6_pcbgroup_byinpcb(inp);
else
#endif
newpcbgroup = in_pcbgroup_byinpcb(inp);
} else
newpcbgroup = NULL;
in_pcbgroup_update_internal(pcbinfo, newpcbgroup, inp);
}
void
in_pcbgroup_update_mbuf(struct inpcb *inp, struct mbuf *m)
{
struct inpcbinfo *pcbinfo;
struct inpcbgroup *newpcbgroup;
INP_WLOCK_ASSERT(inp);
pcbinfo = inp->inp_pcbinfo;
if (!in_pcbgroup_enabled(pcbinfo))
return;
/*
* Possibly should assert !INP_PCBGROUPWILD rather than testing for
* it; presumably this function should never be called for anything
* other than non-wildcard socket?
*/
in_pcbwild_update_internal(inp);
if (!(inp->inp_flags2 & INP_PCBGROUPWILD) &&
!(inp->inp_flags & INP_DROPPED)) {
newpcbgroup = in_pcbgroup_bymbuf(pcbinfo, m);
#ifdef INET6
if (inp->inp_vflag & INP_IPV6) {
if (newpcbgroup == NULL)
newpcbgroup = in6_pcbgroup_byinpcb(inp);
} else {
#endif
if (newpcbgroup == NULL)
newpcbgroup = in_pcbgroup_byinpcb(inp);
#ifdef INET6
}
#endif
} else
newpcbgroup = NULL;
in_pcbgroup_update_internal(pcbinfo, newpcbgroup, inp);
}
/*
* Remove pcbgroup entry and optional pcbgroup wildcard entry for this inpcb.
*/
void
in_pcbgroup_remove(struct inpcb *inp)
{
struct inpcbgroup *pcbgroup;
INP_WLOCK_ASSERT(inp);
if (!in_pcbgroup_enabled(inp->inp_pcbinfo))
return;
if (inp->inp_flags2 & INP_PCBGROUPWILD)
in_pcbwild_remove(inp);
pcbgroup = inp->inp_pcbgroup;
if (pcbgroup != NULL) {
INP_GROUP_LOCK(pcbgroup);
LIST_REMOVE(inp, inp_pcbgrouphash);
inp->inp_pcbgroup = NULL;
INP_GROUP_UNLOCK(pcbgroup);
}
}
/*
* Query whether or not it is appropriate to use pcbgroups to look up inpcbs
* for a protocol.
*/
int
in_pcbgroup_enabled(struct inpcbinfo *pcbinfo)
{
return (pcbinfo->ipi_npcbgroups > 0);
}

View File

@ -153,7 +153,8 @@ div_init(void)
* place for hashbase == NULL.
*/
in_pcbinfo_init(&V_divcbinfo, "div", &V_divcb, 1, 1, "divcb",
div_inpcb_init, div_inpcb_fini, UMA_ZONE_NOFREE);
div_inpcb_init, div_inpcb_fini, UMA_ZONE_NOFREE,
IPI_HASHFIELDS_NONE);
}
static void

View File

@ -692,6 +692,10 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
lookupflags |= INPLOOKUP_RLOCKPCB;
match = 0;
if (*ugid_lookupp == 0) {
/*
* XXXRW: If we had the mbuf here, could use
* in_pcblookup_mbuf().
*/
pcb = (oif) ?
in_pcblookup(pi,
dst_ip, htons(dst_port),

View File

@ -349,12 +349,13 @@ del_entry(struct ip_fw_chain *chain, uint32_t arg)
}
if (n == 0) {
/* A flush request (arg == 0) on empty ruleset
* returns with no error. On the contrary,
/* A flush request (arg == 0 or cmd == 1) on empty
* ruleset returns with no error. On the contrary,
* if there is no match on a specific request,
* we return EINVAL.
*/
error = (arg == 0) ? 0 : EINVAL;
if (arg != 0 && cmd != 1)
error = EINVAL;
break;
}

View File

@ -205,7 +205,8 @@ rip_init(void)
{
in_pcbinfo_init(&V_ripcbinfo, "rip", &V_ripcb, INP_PCBHASH_RAW_SIZE,
1, "ripcb", rip_inpcb_init, NULL, UMA_ZONE_NOFREE);
1, "ripcb", rip_inpcb_init, NULL, UMA_ZONE_NOFREE,
IPI_HASHFIELDS_NONE);
EVENTHANDLER_REGISTER(maxsockets_change, rip_zone_change, NULL,
EVENTHANDLER_PRI_ANY);
}

View File

@ -300,7 +300,8 @@ tcp_init(void)
hashsize = 512; /* safe default */
}
in_pcbinfo_init(&V_tcbinfo, "tcp", &V_tcb, hashsize, hashsize,
"tcp_inpcb", tcp_inpcb_init, NULL, UMA_ZONE_NOFREE);
"tcp_inpcb", tcp_inpcb_init, NULL, UMA_ZONE_NOFREE,
IPI_HASHFIELDS_4TUPLE);
/*
* These have to be type stable for the benefit of the timers.

View File

@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_pcbgroup.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -676,8 +677,14 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
#ifdef INET6
}
#endif
/*
* Install in the reservation hash table for now, but don't yet
* install a connection group since the full 4-tuple isn't yet
* configured.
*/
inp->inp_lport = sc->sc_inc.inc_lport;
if ((error = in_pcbinshash(inp)) != 0) {
if ((error = in_pcbinshash_nopcbgroup(inp)) != 0) {
/*
* Undo the assignments above if we failed to
* put the PCB on the hash lists.

View File

@ -186,7 +186,8 @@ udp_init(void)
{
in_pcbinfo_init(&V_udbinfo, "udp", &V_udb, UDBHASHSIZE, UDBHASHSIZE,
"udp_inpcb", udp_inpcb_init, NULL, UMA_ZONE_NOFREE);
"udp_inpcb", udp_inpcb_init, NULL, UMA_ZONE_NOFREE,
IPI_HASHFIELDS_2TUPLE);
V_udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
uma_zone_set_max(V_udpcb_zone, maxsockets);

View File

@ -652,8 +652,32 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
* that is, this address might make other addresses detached.
*/
pfxlist_onlink_check();
if (error == 0 && ia)
if (error == 0 && ia) {
if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) {
/*
* Try to clear the flag when a new
* IPv6 address is added onto an
* IFDISABLED interface and it
* succeeds.
*/
struct in6_ndireq nd;
memset(&nd, 0, sizeof(nd));
nd.ndi.flags = ND_IFINFO(ifp)->flags;
nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
if (nd6_ioctl(SIOCSIFINFO_FLAGS,
(caddr_t)&nd, ifp) < 0)
log(LOG_NOTICE, "SIOCAIFADDR_IN6: "
"SIOCSIFINFO_FLAGS for -ifdisabled "
"failed.");
/*
* Ignore failure of clearing the flag
* intentionally. The failure means
* address duplication was detected.
*/
}
EVENTHANDLER_INVOKE(ifaddr_event, ifp);
}
break;
}

View File

@ -611,7 +611,10 @@ struct ip6_mtuinfo {
#define IPV6CTL_STEALTH 45
#define ICMPV6CTL_ND6_ONLINKNSRFC4861 47
#define IPV6CTL_MAXID 48
#define IPV6CTL_NO_RADR 48 /* No defroute from RA */
#define IPV6CTL_NORBIT_RAIF 49 /* Disable R-bit in NA on RA
* receiving IF. */
#define IPV6CTL_MAXID 50
#endif /* __BSD_VISIBLE */
/*

View File

@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_pcbgroup.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -827,6 +828,141 @@ in6_rtchange(struct inpcb *inp, int errno)
return inp;
}
#ifdef PCBGROUP
/*
* Lookup PCB in hash list, using pcbgroup tables.
*/
static struct inpcb *
in6_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup,
struct in6_addr *faddr, u_int fport_arg, struct in6_addr *laddr,
u_int lport_arg, int lookupflags, struct ifnet *ifp)
{
struct inpcbhead *head;
struct inpcb *inp, *tmpinp;
u_short fport = fport_arg, lport = lport_arg;
int faith;
if (faithprefix_p != NULL)
faith = (*faithprefix_p)(laddr);
else
faith = 0;
/*
* First look for an exact match.
*/
tmpinp = NULL;
INP_GROUP_LOCK(pcbgroup);
head = &pcbgroup->ipg_hashbase[
INP_PCBHASH(faddr->s6_addr32[3] /* XXX */, lport, fport,
pcbgroup->ipg_hashmask)];
LIST_FOREACH(inp, head, inp_pcbgrouphash) {
/* XXX inp locking */
if ((inp->inp_vflag & INP_IPV6) == 0)
continue;
if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) &&
IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) &&
inp->inp_fport == fport &&
inp->inp_lport == lport) {
/*
* XXX We should be able to directly return
* the inp here, without any checks.
* Well unless both bound with SO_REUSEPORT?
*/
if (prison_flag(inp->inp_cred, PR_IP6))
goto found;
if (tmpinp == NULL)
tmpinp = inp;
}
}
if (tmpinp != NULL) {
inp = tmpinp;
goto found;
}
/*
* Then look for a wildcard match, if requested.
*/
if ((lookupflags & INPLOOKUP_WILDCARD) != 0) {
struct inpcb *local_wild = NULL, *local_exact = NULL;
struct inpcb *jail_wild = NULL;
int injail;
/*
* Order of socket selection - we always prefer jails.
* 1. jailed, non-wild.
* 2. jailed, wild.
* 3. non-jailed, non-wild.
* 4. non-jailed, wild.
*/
head = &pcbinfo->ipi_wildbase[INP_PCBHASH(INADDR_ANY, lport,
0, pcbinfo->ipi_wildmask)];
LIST_FOREACH(inp, head, inp_pcbgroup_wild) {
/* XXX inp locking */
if ((inp->inp_vflag & INP_IPV6) == 0)
continue;
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) ||
inp->inp_lport != lport) {
continue;
}
/* XXX inp locking */
if (faith && (inp->inp_flags & INP_FAITH) == 0)
continue;
injail = prison_flag(inp->inp_cred, PR_IP6);
if (injail) {
if (prison_check_ip6(inp->inp_cred,
laddr) != 0)
continue;
} else {
if (local_exact != NULL)
continue;
}
if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr)) {
if (injail)
goto found;
else
local_exact = inp;
} else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
if (injail)
jail_wild = inp;
else
local_wild = inp;
}
} /* LIST_FOREACH */
inp = jail_wild;
if (inp == NULL)
inp = jail_wild;
if (inp == NULL)
inp = local_exact;
if (inp == NULL)
inp = local_wild;
if (inp != NULL)
goto found;
} /* if ((lookupflags & INPLOOKUP_WILDCARD) != 0) */
INP_GROUP_UNLOCK(pcbgroup);
return (NULL);
found:
in_pcbref(inp);
INP_GROUP_UNLOCK(pcbgroup);
if (lookupflags & INPLOOKUP_WLOCKPCB) {
INP_WLOCK(inp);
if (in_pcbrele_wlocked(inp))
return (NULL);
} else if (lookupflags & INPLOOKUP_RLOCKPCB) {
INP_RLOCK(inp);
if (in_pcbrele_rlocked(inp))
return (NULL);
} else
panic("%s: locking buf", __func__);
return (inp);
}
#endif /* PCBGROUP */
/*
* Lookup PCB in hash list.
*/
@ -983,16 +1119,30 @@ in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
/*
* Public inpcb lookup routines, accepting a 4-tuple, and optionally, an mbuf
* from which a pre-calculated hash value may be extracted.
*
* Possibly more of this logic should be in in6_pcbgroup.c.
*/
struct inpcb *
in6_pcblookup(struct inpcbinfo *pcbinfo, struct in6_addr *faddr, u_int fport,
struct in6_addr *laddr, u_int lport, int lookupflags, struct ifnet *ifp)
{
#if defined(PCBGROUP)
struct inpcbgroup *pcbgroup;
#endif
KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
("%s: invalid lookup flags %d", __func__, lookupflags));
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
("%s: LOCKPCB not set", __func__));
#if defined(PCBGROUP)
if (in_pcbgroup_enabled(pcbinfo)) {
pcbgroup = in6_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
fport);
return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
laddr, lport, lookupflags, ifp));
}
#endif
return (in6_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
lookupflags, ifp));
}
@ -1002,11 +1152,28 @@ in6_pcblookup_mbuf(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
u_int fport, struct in6_addr *laddr, u_int lport, int lookupflags,
struct ifnet *ifp, struct mbuf *m)
{
#ifdef PCBGROUP
struct inpcbgroup *pcbgroup;
#endif
KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
("%s: invalid lookup flags %d", __func__, lookupflags));
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
("%s: LOCKPCB not set", __func__));
#ifdef PCBGROUP
if (in_pcbgroup_enabled(pcbinfo)) {
pcbgroup = in6_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
m->m_pkthdr.flowid);
if (pcbgroup != NULL)
return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr,
fport, laddr, lport, lookupflags, ifp));
pcbgroup = in6_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
fport);
return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
laddr, lport, lookupflags, ifp));
}
#endif
return (in6_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
lookupflags, ifp));
}

View File

@ -69,6 +69,16 @@
#define sin6tosa(sin6) ((struct sockaddr *)(sin6))
#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
struct inpcbgroup *
in6_pcbgroup_byhash(struct inpcbinfo *, u_int, uint32_t);
struct inpcbgroup *
in6_pcbgroup_byinpcb __P((struct inpcb *));
struct inpcbgroup *
in6_pcbgroup_bymbuf(struct inpcbinfo *, struct mbuf *);
struct inpcbgroup *
in6_pcbgroup_bytuple __P((struct inpcbinfo *, const struct in6_addr *,
u_short, const struct in6_addr *, u_short));
void in6_pcbpurgeif0 __P((struct inpcbinfo *, struct ifnet *));
void in6_losing __P((struct inpcb *));
int in6_pcbbind __P((struct inpcb *, struct sockaddr *, struct ucred *));

103
sys/netinet6/in6_pcbgroup.c Normal file
View File

@ -0,0 +1,103 @@
/*-
* Copyright (c) 2010-2011 Juniper Networks, Inc.
* All rights reserved.
*
* This software was developed by Robert N. M. Watson under contract
* to Juniper Networks, Inc.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/mbuf.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>
#ifdef INET6
#include <netinet6/in6_pcb.h>
#endif /* INET6 */
/*
* Given a hash of whatever the covered tuple might be, return a pcbgroup
* index.
*/
static __inline u_int
in6_pcbgroup_getbucket(struct inpcbinfo *pcbinfo, uint32_t hash)
{
return (hash % pcbinfo->ipi_npcbgroups);
}
/*
* Map a (hashtype, hash) tuple into a connection group, or NULL if the hash
* information is insufficient to identify the pcbgroup.
*/
struct inpcbgroup *
in6_pcbgroup_byhash(struct inpcbinfo *pcbinfo, u_int hashtype, uint32_t hash)
{
return (NULL);
}
struct inpcbgroup *
in6_pcbgroup_bymbuf(struct inpcbinfo *pcbinfo, struct mbuf *m)
{
return (in6_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
m->m_pkthdr.flowid));
}
struct inpcbgroup *
in6_pcbgroup_bytuple(struct inpcbinfo *pcbinfo, const struct in6_addr *laddrp,
u_short lport, const struct in6_addr *faddrp, u_short fport)
{
uint32_t hash;
switch (pcbinfo->ipi_hashfields) {
case IPI_HASHFIELDS_4TUPLE:
hash = faddrp->s6_addr32[3] ^ fport;
break;
case IPI_HASHFIELDS_2TUPLE:
hash = faddrp->s6_addr32[3] ^ laddrp->s6_addr32[3];
break;
default:
hash = 0;
}
return (&pcbinfo->ipi_pcbgroups[in6_pcbgroup_getbucket(pcbinfo,
hash)]);
}
struct inpcbgroup *
in6_pcbgroup_byinpcb(struct inpcb *inp)
{
return (in6_pcbgroup_bytuple(inp->inp_pcbinfo, &inp->in6p_laddr,
inp->inp_lport, &inp->in6p_faddr, inp->inp_fport));
}

View File

@ -409,6 +409,8 @@ VNET_DEFINE(int, ip6_sendredirects) = IPV6_SENDREDIRECTS;
VNET_DEFINE(int, ip6_defhlim) = IPV6_DEFHLIM;
VNET_DEFINE(int, ip6_defmcasthlim) = IPV6_DEFAULT_MULTICAST_HOPS;
VNET_DEFINE(int, ip6_accept_rtadv) = 0;
VNET_DEFINE(int, ip6_no_radr) = 0;
VNET_DEFINE(int, ip6_norbit_raif) = 0;
VNET_DEFINE(int, ip6_maxfragpackets); /* initialized in frag6.c:frag6_init() */
VNET_DEFINE(int, ip6_maxfrags); /* initialized in frag6.c:frag6_init() */
VNET_DEFINE(int, ip6_log_interval) = 5;
@ -537,6 +539,15 @@ SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_ACCEPT_RTADV, accept_rtadv,
CTLFLAG_RW, &VNET_NAME(ip6_accept_rtadv), 0,
"Default value of per-interface flag for accepting ICMPv6 Router"
"Advertisement messages");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_NO_RADR, no_radr,
CTLFLAG_RW, &VNET_NAME(ip6_no_radr), 0,
"Default value of per-interface flag to control whether routers "
"sending ICMPv6 RA messages on that interface are added into the "
"default router list.");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_NORBIT_RAIF, norbit_raif, CTLFLAG_RW,
&VNET_NAME(ip6_norbit_raif), 0,
"Always set 0 to R flag in ICMPv6 NA messages when accepting RA"
" on the interface.");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
&VNET_NAME(ip6_keepfaith), 0, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_LOG_INTERVAL, log_interval,

View File

@ -316,6 +316,9 @@ VNET_DECLARE(int, ip6_maxfragpackets); /* Maximum packets in reassembly
VNET_DECLARE(int, ip6_maxfrags); /* Maximum fragments in reassembly
* queue */
VNET_DECLARE(int, ip6_accept_rtadv); /* Acts as a host not a router */
VNET_DECLARE(int, ip6_no_radr); /* No defroute from RA */
VNET_DECLARE(int, ip6_norbit_raif); /* Disable R-bit in NA on RA
* receiving IF. */
VNET_DECLARE(int, ip6_keepfaith); /* Firewall Aided Internet Translator */
VNET_DECLARE(int, ip6_log_interval);
VNET_DECLARE(time_t, ip6_log_time);
@ -327,6 +330,8 @@ VNET_DECLARE(int, ip6_dad_count); /* DupAddrDetectionTransmits */
#define V_ip6_maxfragpackets VNET(ip6_maxfragpackets)
#define V_ip6_maxfrags VNET(ip6_maxfrags)
#define V_ip6_accept_rtadv VNET(ip6_accept_rtadv)
#define V_ip6_no_radr VNET(ip6_no_radr)
#define V_ip6_norbit_raif VNET(ip6_norbit_raif)
#define V_ip6_keepfaith VNET(ip6_keepfaith)
#define V_ip6_log_interval VNET(ip6_log_interval)
#define V_ip6_log_time VNET(ip6_log_time)

View File

@ -193,6 +193,8 @@ nd6_ifattach(struct ifnet *ifp)
/* A loopback interface does not need to accept RTADV. */
if (V_ip6_accept_rtadv && !(ifp->if_flags & IFF_LOOPBACK))
nd->flags |= ND6_IFF_ACCEPT_RTADV;
if (V_ip6_no_radr && !(ifp->if_flags & IFF_LOOPBACK))
nd->flags |= ND6_IFF_NO_RADR;
/* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */
nd6_setmtu0(ifp, nd);
@ -825,7 +827,7 @@ nd6_purge(struct ifnet *ifp)
if (V_nd6_defifindex == ifp->if_index)
nd6_setdefaultiface(0);
if (!V_ip6_forwarding && ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
/* Refresh default router list. */
defrouter_select();
}
@ -958,10 +960,9 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
/*
* 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 (!V_ip6_forwarding && TAILQ_FIRST(&V_nd_defrouter) == NULL &&
if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV &&
TAILQ_FIRST(&V_nd_defrouter) == NULL &&
V_nd6_defifindex == ifp->if_index) {
return (1);
}
@ -1022,8 +1023,7 @@ nd6_free(struct llentry *ln, int gc)
ifp = ln->lle_tbl->llt_ifp;
if (!V_ip6_forwarding) {
if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
dr = defrouter_lookup(&L3_ADDR_SIN6(ln)->sin6_addr, ifp);
if (dr != NULL && dr->expire &&
@ -1322,6 +1322,16 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
struct ifaddr *ifa;
struct in6_ifaddr *ia;
/*
* Try to clear ifdisabled flag when enabling
* accept_rtadv or auto_linklocal.
*/
if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
!(ND.flags & ND6_IFF_IFDISABLED) &&
(ND.flags & (ND6_IFF_ACCEPT_RTADV |
ND6_IFF_AUTO_LINKLOCAL)))
ND.flags &= ~ND6_IFF_IFDISABLED;
if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
!(ND.flags & ND6_IFF_IFDISABLED)) {
/* ifdisabled 1->0 transision */
@ -1340,7 +1350,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
continue;
ia = (struct in6_ifaddr *)ifa;
if ((ia->ia6_flags & IN6_IFF_DUPLICATED) &&
IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) {
IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) {
duplicated_linklocal = 1;
break;
}
@ -1379,6 +1389,28 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
/* If no link-local address on ifp, configure */
ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL;
in6_ifattach(ifp, NULL);
} else if ((ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) &&
!(ND.flags & ND6_IFF_IFDISABLED)) {
/*
* When the IF already has
* ND6_IFF_AUTO_LINKLOCAL and no link-local
* address is assigned, try to assign one.
*/
int haslinklocal = 0;
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ia = (struct in6_ifaddr *)ifa;
if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) {
haslinklocal = 1;
break;
}
}
IF_ADDR_UNLOCK(ifp);
if (!haslinklocal)
in6_ifattach(ifp, NULL);
}
}
ND_IFINFO(ifp)->flags = ND.flags;
@ -1718,7 +1750,7 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
* for those are not autoconfigured hosts, we explicitly avoid such
* cases for safety.
*/
if (do_update && router && !V_ip6_forwarding &&
if (do_update && router &&
ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
/*
* guaranteed recursion

View File

@ -85,6 +85,7 @@ struct nd_ifinfo {
*/
#define ND6_IFF_DONT_SET_IFROUTE 0x10
#define ND6_IFF_AUTO_LINKLOCAL 0x20
#define ND6_IFF_NO_RADR 0x40
#define ND6_CREATE LLE_CREATE
#define ND6_EXCLUSIVE LLE_EXCLUSIVE

View File

@ -112,10 +112,14 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
int lladdrlen = 0;
int anycast = 0, proxy = 0, tentative = 0;
int tlladdr;
int rflag;
union nd_opts ndopts;
struct sockaddr_dl proxydl;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
rflag = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0;
if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && V_ip6_norbit_raif)
rflag = 0;
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, icmp6len,);
nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
@ -339,8 +343,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
goto bad;
nd6_na_output(ifp, &in6_all, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
(V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL);
rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL);
goto freeit;
}
@ -349,8 +352,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
nd6_na_output(ifp, &saddr6, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
(V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL);
rflag | ND_NA_FLAG_SOLICITED, tlladdr,
proxy ? (struct sockaddr *)&proxydl : NULL);
freeit:
if (ifa != NULL)
ifa_free(ifa);
@ -862,7 +865,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
dr = defrouter_lookup(in6, ln->lle_tbl->llt_ifp);
if (dr)
defrtrlist_del(dr);
else if (!V_ip6_forwarding) {
else if (ND_IFINFO(ln->lle_tbl->llt_ifp)->flags &
ND6_IFF_ACCEPT_RTADV) {
/*
* Even if the neighbor is not in the default
* router list, the neighbor may be used

View File

@ -127,8 +127,11 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len)
union nd_opts ndopts;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
/* If I'm not a router, ignore it. */
if (!V_ip6_forwarding)
/*
* Accept RS only when V_ip6_forwarding=1 and the interface has
* no ND6_IFF_ACCEPT_RTADV.
*/
if (!V_ip6_forwarding || ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV)
goto freeit;
/* Sanity checks */
@ -213,11 +216,10 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
/*
* We only accept RAs only when
* the node is not a router and
* per-interface variable allows RAs on the receiving interface.
* We only accept RAs only when the per-interface flag
* ND6_IFF_ACCEPT_RTADV is on the receiving interface.
*/
if (V_ip6_forwarding || !(ndi->flags & ND6_IFF_ACCEPT_RTADV))
if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
goto freeit;
if (ip6->ip6_hlim != 255) {
@ -266,7 +268,15 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
bzero(&dr0, sizeof(dr0));
dr0.rtaddr = saddr6;
dr0.flags = nd_ra->nd_ra_flags_reserved;
dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
/*
* Effectively-disable the route in the RA packet
* when ND6_IFF_NO_RADR on the receiving interface or
* ip6.forwarding=1.
*/
if (ndi->flags & ND6_IFF_NO_RADR || V_ip6_forwarding)
dr0.rtlifetime = 0;
else
dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
dr0.expire = time_second + dr0.rtlifetime;
dr0.ifp = ifp;
/* unspecified or not? (RFC 2461 6.3.4) */
@ -557,7 +567,7 @@ defrtrlist_del(struct nd_defrouter *dr)
* Flush all the routing table entries that use the router
* as a next hop.
*/
if (!V_ip6_forwarding)
if (ND_IFINFO(dr->ifp)->flags & ND6_IFF_ACCEPT_RTADV)
rt6_flush(&dr->rtaddr, dr->ifp);
if (dr->installed) {
@ -615,20 +625,6 @@ defrouter_select(void)
struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
struct llentry *ln = NULL;
/*
* This function should be called only when acting as an autoconfigured
* host. Although the remaining part of this function is not effective
* if the node is not an autoconfigured host, we explicitly exclude
* such cases here for safety.
*/
if (V_ip6_forwarding) {
nd6log((LOG_WARNING,
"defrouter_select: called unexpectedly (forwarding=%d)\n",
V_ip6_forwarding));
splx(s);
return;
}
/*
* Let's handle easy case (3) first:
* If default router list is empty, there's nothing to be done.

View File

@ -33,7 +33,7 @@
#define SND_IN 1 /* Incoming traffic. */
struct sockaddr_send {
unsigned char send_len; /* total length */
uint8_t send_len; /* total length */
sa_family_t send_family; /* address family */
int send_direction;
int send_ifidx;

View File

@ -199,7 +199,9 @@ struct mbuf {
#define M_PROTO6 0x00080000 /* protocol-specific */
#define M_PROTO7 0x00100000 /* protocol-specific */
#define M_PROTO8 0x00200000 /* protocol-specific */
#define M_FLOWID 0x00400000 /* flowid is valid */
#define M_FLOWID 0x00400000 /* deprecated: flowid is valid */
#define M_HASHTYPEBITS 0x0F000000 /* mask of bits holding flowid hash type */
/*
* For RELENG_{6,7} steal these flags for limited multiple routing table
* support. In RELENG_8 and beyond, use just one flag and a tag.
@ -214,12 +216,46 @@ struct mbuf {
#define M_PROTOFLAGS \
(M_PROTO1|M_PROTO2|M_PROTO3|M_PROTO4|M_PROTO5|M_PROTO6|M_PROTO7|M_PROTO8)
/*
* Network interface cards are able to hash protocol fields (such as IPv4
* addresses and TCP port numbers) classify packets into flows. These flows
* can then be used to maintain ordering while delivering packets to the OS
* via parallel input queues, as well as to provide a stateless affinity
* model. NIC drivers can pass up the hash via m->m_pkthdr.flowid, and set
* m_flag fields to indicate how the hash should be interpreted by the
* network stack.
*
* Most NICs support RSS, which provides ordering and explicit affinity, and
* use the hash m_flag bits to indicate what header fields were covered by
* the hash. M_HASHTYPE_OPAQUE can be set by non-RSS cards or configurations
* that provide an opaque flow identifier, allowing for ordering and
* distribution without explicit affinity.
*/
#define M_HASHTYPE_SHIFT 24
#define M_HASHTYPE_NONE 0x0
#define M_HASHTYPE_RSS_IPV4 0x1 /* IPv4 2-tuple */
#define M_HASHTYPE_RSS_TCP_IPV4 0x2 /* TCPv4 4-tuple */
#define M_HASHTYPE_RSS_IPV6 0x3 /* IPv6 2-tuple */
#define M_HASHTYPE_RSS_TCP_IPV6 0x4 /* TCPv6 4-tuple */
#define M_HASHTYPE_RSS_IPV6_EX 0x5 /* IPv6 2-tuple + ext hdrs */
#define M_HASHTYPE_RSS_TCP_IPV6_EX 0x6 /* TCPv6 4-tiple + ext hdrs */
#define M_HASHTYPE_OPAQUE 0xf /* ordering, not affinity */
#define M_HASHTYPE_CLEAR(m) (m)->m_flags &= ~(M_HASHTYPEBITS)
#define M_HASHTYPE_GET(m) (((m)->m_flags & M_HASHTYPEBITS) >> \
M_HASHTYPE_SHIFT)
#define M_HASHTYPE_SET(m, v) do { \
(m)->m_flags &= ~M_HASHTYPEBITS; \
(m)->m_flags |= ((v) << M_HASHTYPE_SHIFT); \
} while (0)
#define M_HASHTYPE_TEST(m, v) (M_HASHTYPE_GET(m) == (v))
/*
* Flags preserved when copying m_pkthdr.
*/
#define M_COPYFLAGS \
(M_PKTHDR|M_EOR|M_RDONLY|M_PROTOFLAGS|M_SKIP_FIREWALL|M_BCAST|M_MCAST|\
M_FRAG|M_FIRSTFRAG|M_LASTFRAG|M_VLANTAG|M_PROMISC|M_FIB)
M_FRAG|M_FIRSTFRAG|M_LASTFRAG|M_VLANTAG|M_PROMISC|M_FIB|M_HASHTYPEBITS)
/*
* External buffer types: identify ext_buf type.

View File

@ -311,7 +311,8 @@ typedef struct _snd_capabilities {
* IOCTL Commands for /dev/sequencer
*/
#define SNDCTL_SEQ_RESET _IO ('Q', 0)
#define SNDCTL_SEQ_HALT _IO ('Q', 0)
#define SNDCTL_SEQ_RESET SNDCTL_SEQ_HALT /* Historic interface */
#define SNDCTL_SEQ_SYNC _IO ('Q', 1)
#define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info)
#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer res.(hz) */

View File

@ -420,13 +420,13 @@ ffs_realloccg(ip, lbprev, bprev, bpref, osize, nsize, flags, cred, bpp)
*/
if (reclaimed == 0) {
reclaimed = 1;
softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT);
UFS_UNLOCK(ump);
if (bp) {
brelse(bp);
bp = NULL;
}
UFS_LOCK(ump);
softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT);
goto retry;
}
UFS_UNLOCK(ump);
@ -2356,8 +2356,8 @@ ffs_fserr(fs, inum, cp)
* specified inode by the specified amount. Under normal
* operation the count should always go down. Decrementing
* the count to zero will cause the inode to be freed.
* adjblkcnt(inode, amt) - adjust the number of blocks used to
* by the specifed amount.
* adjblkcnt(inode, amt) - adjust the number of blocks used by the
* inode by the specified amount.
* adjndir, adjbfree, adjifree, adjffree, adjnumclusters(amt) -
* adjust the superblock summary.
* freedirs(inode, count) - directory inodes [inode..inode + count - 1]

View File

@ -0,0 +1,25 @@
# $FreeBSD$
f() { return $1; }
[ `f 42; { cat; } <<EOF
$?
EOF
` = 42 ] || echo compound command bad
[ `f 42; (cat) <<EOF
$?
EOF
` = 42 ] || echo subshell bad
long=`printf %08192d 0`
[ `f 42; { cat; } <<EOF
$long.$?
EOF
` = $long.42 ] || echo long compound command bad
[ `f 42; (cat) <<EOF
$long.$?
EOF
` = $long.42 ] || echo long subshell bad

View File

@ -0,0 +1,15 @@
# $FreeBSD$
f() { return $1; }
[ `f 42; cat <<EOF
$?
EOF
` = 42 ] || echo simple command bad
long=`printf %08192d 0`
[ `f 42; cat <<EOF
$long.$?
EOF
` = $long.42 ] || echo long simple command bad

View File

@ -346,7 +346,7 @@ closecal(FILE *fp)
write(pdes[1], pw->pw_name, strlen(pw->pw_name));
write(pdes[1], ">\nTo: <", 7);
write(pdes[1], pw->pw_name, strlen(pw->pw_name));
write(pdes[1], ">\nSubject: ", 12);
write(pdes[1], ">\nSubject: ", 11);
write(pdes[1], dayname, strlen(dayname));
write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30);

View File

@ -28,8 +28,6 @@ MLINKS= grep.1 egrep.1 \
bsdgrep.1: grep.1
cp ${.ALLSRC} ${.TARGET}
WARNS?= 6
LDADD= -lz -lbz2
DPADD= ${LIBZ} ${LIBBZ2}

View File

@ -7,8 +7,6 @@ PROG= iconv
#SRCS= iconv.c
MAN= iconv.1
WARNS?= 6
LDADD+= -lcrypt
DPADD+= ${LIBCRYPT}

View File

@ -345,7 +345,7 @@ auto_if_type "sockfamilyname" "AF_[[:alnum:]]+[[:space:]]+" "sys/socket.h"
auto_if_type "sockipprotoname" "IPPROTO_[[:alnum:]]+[[:space:]]+" "netinet/in.h"
auto_switch_type "sockoptname" "SO_[A-Z]+[[:space:]]+0x[0-9]+" "sys/socket.h"
auto_switch_type "socktypename" "SOCK_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/socket.h"
auto_switch_type "ptraceopname" "PT_[[:alnum:]]+[[:space:]]+[0-9]+" "sys/ptrace.h"
auto_switch_type "ptraceopname" "PT_[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/ptrace.h"
cat <<_EOF_
/*

View File

@ -6,6 +6,4 @@ MAN= rctl.8
DPADD= ${LIBUTIL}
LDADD= -lutil
WARNS?= 6
.include <bsd.prog.mk>

View File

@ -28,7 +28,7 @@
.\" @(#)su.1 8.2 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
.Dd July 1, 2008
.Dd June 6, 2011
.Dt SU 1
.Os
.Sh NAME
@ -193,16 +193,22 @@ PAM configuration for
.Sh EXAMPLES
.Bl -tag -width 5n -compact
.It Li "su -m man -c catman"
Runs the command
.Li catman
as user
.Li man .
Starts a shell as user
.Li man ,
and runs the command
.Li catman .
You will be asked for man's password unless your real UID is 0.
Note that the
.Fl m
option is required since user
.Dq man
does not have a valid shell by default.
In this example,
.Fl c
is passed to the shell of the user
.Dq man ,
and is not interpreted as an argument to
.Nm .
.It Li "su -m man -c 'catman /usr/share/man /usr/local/man'"
Same as above, but the target command consists of more than a
single word and hence is quoted for use with the

View File

@ -2,7 +2,6 @@
PROG= ath3kfw
MAN= ath3kfw.8
WARNS?= 6
DPADD+= ${LIBUSB}
LDADD+= -lusb

View File

@ -33,7 +33,6 @@
#
# TODO:
# - Add -R /sbin/resolvconf to rtsol once support is in tree.
# - Add DHCPv6 support once FreeBSD ships with it.
#

View File

@ -6,8 +6,6 @@ MOD= wlan
SRCS= wlan_snmp.c wlan_sys.c
CFLAGS+= -DSNMPTREE_TYPES
WARNS= 6
XSYM= begemotWlan
BMIBS= BEGEMOT-WIRELESS-MIB.txt

View File

@ -31,7 +31,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd January 11, 1996
.Dd June 6, 2011
.Dt LASTLOGIN 8
.Os
.Sh NAME
@ -39,6 +39,8 @@
.Nd indicate last login time of users
.Sh SYNOPSIS
.Nm
.Op Fl f Ar file
.Op Fl rt
.Op Ar user ...
.Sh DESCRIPTION
The
@ -54,8 +56,8 @@ If more than one
.Ar user
is given, the session information for each user is printed in
the order given on the command line.
Otherwise, information
for all users is printed, sorted by name.
Otherwise, information for all users is printed.
By default, the entries are sorted by user name.
.Pp
The
.Nm
@ -63,6 +65,18 @@ utility differs from
.Xr last 1
in that it only prints information regarding the very last login session.
The last login database is never turned over or deleted in standard usage.
.Pp
The following options are available:
.Bl -tag -width indent
.It Fl f Ar file
Open last login database
.Ar file
instead of the system-wide database.
.It Fl r
Print the entries in reverse sorted order.
.It Fl t
Sort the elements by last login time, instead of user name.
.El
.Sh FILES
.Bl -tag -width /var/log/utx.lastlogin -compact
.It Pa /var/log/utx.lastlogin

View File

@ -47,30 +47,59 @@ __RCSID("$NetBSD: lastlogin.c,v 1.4 1998/02/03 04:45:35 perry Exp $");
int main(int, char **);
static void output(struct utmpx *);
static void usage(void);
static int utcmp_user(const void *, const void *);
static int order = 1;
static const char *file = NULL;
static int (*utcmp)(const void *, const void *) = utcmp_user;
static int
utcmp(const void *u1, const void *u2)
utcmp_user(const void *u1, const void *u2)
{
return (strcmp(((const struct utmpx *)u1)->ut_user,
return (order * strcmp(((const struct utmpx *)u1)->ut_user,
((const struct utmpx *)u2)->ut_user));
}
static int
utcmp_time(const void *u1, const void *u2)
{
time_t t1, t2;
t1 = ((const struct utmpx *)u1)->ut_tv.tv_sec;
t2 = ((const struct utmpx *)u2)->ut_tv.tv_sec;
return (t1 < t2 ? order : t1 > t2 ? -order : 0);
}
int
main(int argc, char *argv[])
{
int ch, i, ulistsize;
struct utmpx *u, *ulist;
while ((ch = getopt(argc, argv, "")) != -1) {
usage();
while ((ch = getopt(argc, argv, "f:rt")) != -1) {
switch (ch) {
case 'f':
file = optarg;
break;
case 'r':
order = -1;
break;
case 't':
utcmp = utcmp_time;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
/* Process usernames given on the command line. */
if (argc > 1) {
for (i = 1; i < argc; ++i) {
if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0)
errx(1, "failed to open lastlog database");
if (argc > 0) {
/* Process usernames given on the command line. */
for (i = 0; i < argc; i++) {
if (setutxdb(UTXDB_LASTLOGIN, file) != 0)
err(1, "failed to open lastlog database");
if ((u = getutxuser(argv[i])) == NULL) {
warnx("user '%s' not found", argv[i]);
continue;
@ -78,11 +107,10 @@ main(int argc, char *argv[])
output(u);
endutxent();
}
}
/* Read all lastlog entries, looking for active ones */
else {
if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0)
errx(1, "failed to open lastlog database");
} else {
/* Read all lastlog entries, looking for active ones. */
if (setutxdb(UTXDB_LASTLOGIN, file) != 0)
err(1, "failed to open lastlog database");
ulist = NULL;
ulistsize = 0;
while ((u = getutxent()) != NULL) {
@ -119,6 +147,6 @@ output(struct utmpx *u)
static void
usage(void)
{
fprintf(stderr, "usage: lastlogin [user ...]\n");
fprintf(stderr, "usage: lastlogin [-f file] [-rt] [user ...]\n");
exit(1);
}

View File

@ -64,8 +64,6 @@
#define V_TERM "HOST"
#endif
char *RM;
/*
* termcap - routines for dealing with the terminal capability data base
*
@ -83,12 +81,11 @@ char *RM;
static char *tbuf;
static int hopcount; /* detect infinite loops in termcap, init 0 */
static char *remotefile;
extern char *conffile;
static const char *remotefile;
extern const char *conffile;
int tgetent(char *, char *);
int getent(char *, char *, char *);
int getent(char *, char *, const char *);
int tnchktc(void);
int tnamatch(char *);
static char *tskip(char *);
@ -103,22 +100,18 @@ static char *tdecode(char *, char **);
* we just notice escaped newlines.
*/
int
tgetent(bp, name)
char *bp, *name;
tgetent(char *bp, char *name)
{
char *cp;
remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF;
return (getent(bp, name, cp));
return (getent(bp, name, conffile));
}
int
getent(bp, name, cp)
char *bp, *name, *cp;
getent(char *bp, char *name, const char *cfile)
{
int c;
int i = 0, cnt = 0;
char ibuf[BUFSIZ];
char *cp;
int tf;
tbuf = bp;
@ -130,9 +123,9 @@ getent(bp, name, cp)
* use so we don't have to read the file. In this case it
* has to already have the newlines crunched out.
*/
if (cp && *cp) {
tf = open(RM = cp, O_RDONLY);
}
if (cfile && *cfile)
tf = open(cfile, O_RDONLY);
if (tf < 0) {
syslog(LOG_INFO,
"<%s> open: %s", __func__, strerror(errno));
@ -184,7 +177,7 @@ getent(bp, name, cp)
* Note that this works because of the left to right scan.
*/
int
tnchktc()
tnchktc(void)
{
char *p, *q;
char tcname[16]; /* name of similar terminal */
@ -233,8 +226,7 @@ tnchktc()
* name (before the first field) stops us.
*/
int
tnamatch(np)
char *np;
tnamatch(char *np)
{
char *Np, *Bp;
@ -260,8 +252,7 @@ tnamatch(np)
* into the termcap file in octal.
*/
static char *
tskip(bp)
char *bp;
tskip(char *bp)
{
int dquote;
@ -305,8 +296,7 @@ tskip(bp)
* Note that we handle octal numbers beginning with 0.
*/
int64_t
tgetnum(id)
char *id;
tgetnum(char *id)
{
int64_t i;
int base;
@ -341,8 +331,7 @@ tgetnum(id)
* not given.
*/
int
tgetflag(id)
char *id;
tgetflag(char *id)
{
char *bp = tbuf;
@ -369,8 +358,7 @@ tgetflag(id)
* No checking on area overflow.
*/
char *
tgetstr(id, area)
char *id, **area;
tgetstr(char *id, char **area)
{
char *bp = tbuf;
@ -395,13 +383,11 @@ tgetstr(id, area)
* string capability escapes.
*/
static char *
tdecode(str, area)
char *str;
char **area;
tdecode(char *str, char **area)
{
char *cp;
int c;
char *dp;
const char *dp;
int i;
char term;

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -30,7 +30,8 @@
* SUCH DAMAGE.
*/
extern void getconfig(char *);
extern int getconfig(int);
extern int rmconfig(int);
extern void delete_prefix(struct prefix *);
extern void invalidate_prefix(struct prefix *);
extern void update_prefix(struct prefix *);
@ -45,3 +46,5 @@ extern void get_prefix(struct rainfo *);
*/
#define MAXPREFIX 100
#define MAXROUTE 100
#define MAXRDNSSENT 100
#define MAXDNSSLENT 100

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 2000 WIDE Project.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -45,6 +45,7 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
@ -63,8 +64,9 @@ extern struct rainfo *ralist;
static char *ether_str(struct sockaddr_dl *);
static void if_dump(void);
static size_t dname_labeldec(char *, size_t, const char *);
static char *rtpref_str[] = {
static const char *rtpref_str[] = {
"medium", /* 00 */
"high", /* 01 */
"rsv", /* 10 */
@ -72,8 +74,7 @@ static char *rtpref_str[] = {
};
static char *
ether_str(sdl)
struct sockaddr_dl *sdl;
ether_str(struct sockaddr_dl *sdl)
{
static char hbuf[32];
u_char *cp;
@ -85,84 +86,86 @@ ether_str(sdl)
} else
snprintf(hbuf, sizeof(hbuf), "NONE");
return(hbuf);
return (hbuf);
}
static void
if_dump()
if_dump(void)
{
struct rainfo *rai;
struct prefix *pfx;
#ifdef ROUTEINFO
struct rtinfo *rti;
#endif
struct rdnss *rdn;
struct dnssl *dns;
char prefixbuf[INET6_ADDRSTRLEN];
int first;
struct timeval now;
gettimeofday(&now, NULL); /* XXX: unused in most cases */
for (rai = ralist; rai; rai = rai->next) {
fprintf(fp, "%s:\n", rai->ifname);
TAILQ_FOREACH(rai, &railist, rai_next) {
fprintf(fp, "%s:\n", rai->rai_ifname);
fprintf(fp, " Status: %s\n",
(iflist[rai->ifindex]->ifm_flags & IFF_UP) ? "UP" :
"DOWN");
(iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) ? "UP" :
"DOWN");
/* control information */
if (rai->lastsent.tv_sec) {
if (rai->rai_lastsent.tv_sec) {
/* note that ctime() appends CR by itself */
fprintf(fp, " Last RA sent: %s",
ctime((time_t *)&rai->lastsent.tv_sec));
ctime((time_t *)&rai->rai_lastsent.tv_sec));
}
if (rai->timer) {
if (rai->rai_timer)
fprintf(fp, " Next RA will be sent: %s",
ctime((time_t *)&rai->timer->tm.tv_sec));
}
ctime((time_t *)&rai->rai_timer->rat_tm.tv_sec));
else
fprintf(fp, " RA timer is stopped");
fprintf(fp, " waits: %d, initcount: %d\n",
rai->waiting, rai->initcounter);
rai->rai_waiting, rai->rai_initcounter);
/* statistics */
fprintf(fp, " statistics: RA(out/in/inconsistent): "
"%llu/%llu/%llu, ",
(unsigned long long)rai->raoutput,
(unsigned long long)rai->rainput,
(unsigned long long)rai->rainconsistent);
(unsigned long long)rai->rai_raoutput,
(unsigned long long)rai->rai_rainput,
(unsigned long long)rai->rai_rainconsistent);
fprintf(fp, "RS(input): %llu\n",
(unsigned long long)rai->rsinput);
(unsigned long long)rai->rai_rsinput);
/* interface information */
if (rai->advlinkopt)
if (rai->rai_advlinkopt)
fprintf(fp, " Link-layer address: %s\n",
ether_str(rai->sdl));
fprintf(fp, " MTU: %d\n", rai->phymtu);
ether_str(rai->rai_sdl));
fprintf(fp, " MTU: %d\n", rai->rai_phymtu);
/* Router configuration variables */
fprintf(fp, " DefaultLifetime: %d, MaxAdvInterval: %d, "
"MinAdvInterval: %d\n", rai->lifetime, rai->maxinterval,
rai->mininterval);
fprintf(fp, " Flags: %s%s%s, ",
rai->managedflg ? "M" : "", rai->otherflg ? "O" : "", "");
"MinAdvInterval: %d\n", rai->rai_lifetime,
rai->rai_maxinterval, rai->rai_mininterval);
fprintf(fp, " Flags: ");
if (rai->rai_managedflg || rai->rai_otherflg) {
fprintf(fp, "%s", rai->rai_managedflg ? "M" : "");
fprintf(fp, "%s", rai->rai_otherflg ? "O" : "");
} else
fprintf(fp, "<none>");
fprintf(fp, ", ");
fprintf(fp, "Preference: %s, ",
rtpref_str[(rai->rtpref >> 3) & 0xff]);
fprintf(fp, "MTU: %d\n", rai->linkmtu);
rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
fprintf(fp, "MTU: %d\n", rai->rai_linkmtu);
fprintf(fp, " ReachableTime: %d, RetransTimer: %d, "
"CurHopLimit: %d\n", rai->reachabletime,
rai->retranstimer, rai->hoplimit);
if (rai->clockskew)
"CurHopLimit: %d\n", rai->rai_reachabletime,
rai->rai_retranstimer, rai->rai_hoplimit);
if (rai->rai_clockskew)
fprintf(fp, " Clock skew: %ldsec\n",
rai->clockskew);
for (first = 1, pfx = rai->prefix.next; pfx != &rai->prefix;
pfx = pfx->next) {
if (first) {
rai->rai_clockskew);
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
if (pfx == TAILQ_FIRST(&rai->rai_prefix))
fprintf(fp, " Prefixes:\n");
first = 0;
}
fprintf(fp, " %s/%d(",
inet_ntop(AF_INET6, &pfx->prefix, prefixbuf,
sizeof(prefixbuf)), pfx->prefixlen);
switch (pfx->origin) {
inet_ntop(AF_INET6, &pfx->pfx_prefix, prefixbuf,
sizeof(prefixbuf)), pfx->pfx_prefixlen);
switch (pfx->pfx_origin) {
case PREFIX_FROM_KERNEL:
fprintf(fp, "KERNEL, ");
break;
@ -173,36 +176,42 @@ if_dump()
fprintf(fp, "DYNAMIC, ");
break;
}
if (pfx->validlifetime == ND6_INFINITE_LIFETIME)
if (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME)
fprintf(fp, "vltime: infinity");
else
fprintf(fp, "vltime: %ld",
(long)pfx->validlifetime);
if (pfx->vltimeexpire != 0)
fprintf(fp, "(decr,expire %ld), ", (long)
pfx->vltimeexpire > now.tv_sec ?
pfx->vltimeexpire - now.tv_sec : 0);
(long)pfx->pfx_validlifetime);
if (pfx->pfx_vltimeexpire != 0)
fprintf(fp, "(decr,expire %ld), ",
(long)pfx->pfx_vltimeexpire > now.tv_sec ?
(long)pfx->pfx_vltimeexpire - now.tv_sec :
0);
else
fprintf(fp, ", ");
if (pfx->preflifetime == ND6_INFINITE_LIFETIME)
if (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME)
fprintf(fp, "pltime: infinity");
else
fprintf(fp, "pltime: %ld",
(long)pfx->preflifetime);
if (pfx->pltimeexpire != 0)
fprintf(fp, "(decr,expire %ld), ", (long)
pfx->pltimeexpire > now.tv_sec ?
pfx->pltimeexpire - now.tv_sec : 0);
(long)pfx->pfx_preflifetime);
if (pfx->pfx_pltimeexpire != 0)
fprintf(fp, "(decr,expire %ld), ",
(long)pfx->pfx_pltimeexpire > now.tv_sec ?
(long)pfx->pfx_pltimeexpire - now.tv_sec :
0);
else
fprintf(fp, ", ");
fprintf(fp, "flags: %s%s%s",
pfx->onlinkflg ? "L" : "",
pfx->autoconfflg ? "A" : "",
"");
if (pfx->timer) {
fprintf(fp, "flags: ");
if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
fprintf(fp, "%s",
pfx->pfx_onlinkflg ? "L" : "");
fprintf(fp, "%s",
pfx->pfx_autoconfflg ? "A" : "");
} else
fprintf(fp, "<none>");
if (pfx->pfx_timer) {
struct timeval *rest;
rest = rtadvd_timer_rest(pfx->timer);
rest = rtadvd_timer_rest(pfx->pfx_timer);
if (rest) { /* XXX: what if not? */
fprintf(fp, ", expire in: %ld",
(long)rest->tv_sec);
@ -211,31 +220,64 @@ if_dump()
fprintf(fp, ")\n");
}
#ifdef ROUTEINFO
for (first = 1, rti = rai->route.next; rti != &rai->route;
rti = rti->next) {
if (first) {
TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
if (rti == TAILQ_FIRST(&rai->rai_route))
fprintf(fp, " Route Information:\n");
first = 0;
}
fprintf(fp, " %s/%d (",
inet_ntop(AF_INET6, &rti->prefix,
prefixbuf, sizeof(prefixbuf)),
rti->prefixlen);
inet_ntop(AF_INET6, &rti->rti_prefix,
prefixbuf, sizeof(prefixbuf)),
rti->rti_prefixlen);
fprintf(fp, "preference: %s, ",
rtpref_str[0xff & (rti->rtpref >> 3)]);
if (rti->ltime == ND6_INFINITE_LIFETIME)
rtpref_str[0xff & (rti->rti_rtpref >> 3)]);
if (rti->rti_ltime == ND6_INFINITE_LIFETIME)
fprintf(fp, "lifetime: infinity");
else
fprintf(fp, "lifetime: %ld", (long)rti->ltime);
fprintf(fp, "lifetime: %ld",
(long)rti->rti_ltime);
fprintf(fp, ")\n");
}
#endif
TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
struct rdnss_addr *rdna;
if (rdn == TAILQ_FIRST(&rai->rai_rdnss))
fprintf(fp, " Recursive DNS servers:\n"
" Lifetime\tServers\n");
fprintf(fp, " %8u\t", rdn->rd_ltime);
TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) {
inet_ntop(AF_INET6, &rdna->ra_dns,
prefixbuf, sizeof(prefixbuf));
if (rdna != TAILQ_FIRST(&rdn->rd_list))
fprintf(fp, " \t");
fprintf(fp, "%s\n", prefixbuf);
}
fprintf(fp, "\n");
}
TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
struct dnssl_addr *dnsa;
char buf[NI_MAXHOST];
if (dns == TAILQ_FIRST(&rai->rai_dnssl))
fprintf(fp, " DNS search list:\n"
" Lifetime\tDomains\n");
fprintf(fp, " %8u\t", dns->dn_ltime);
TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) {
dname_labeldec(buf, sizeof(buf), dnsa->da_dom);
if (dnsa != TAILQ_FIRST(&dns->dn_list))
fprintf(fp, " \t");
fprintf(fp, "%s(%d)\n", buf, dnsa->da_len);
}
fprintf(fp, "\n");
}
}
}
void
rtadvd_dump_file(dumpfile)
char *dumpfile;
rtadvd_dump_file(const char *dumpfile)
{
syslog(LOG_DEBUG, "<%s> dump current status to %s", __func__,
dumpfile);
@ -250,3 +292,30 @@ rtadvd_dump_file(dumpfile)
fclose(fp);
}
/* Decode domain name label encoding in RFC 1035 Section 3.1 */
static size_t
dname_labeldec(char *dst, size_t dlen, const char *src)
{
size_t len;
const char *src_origin;
const char *src_last;
const char *dst_origin;
src_origin = src;
src_last = strchr(src, '\0');
dst_origin = dst;
memset(dst, '\0', dlen);
while (src && (len = (uint8_t)(*src++) & 0x3f) &&
(src + len) <= src_last) {
if (dst != dst_origin)
*dst++ = '.';
syslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len);
memcpy(dst, src, len);
src += len;
dst += len;
}
*dst = '\0';
return (src - src_origin);
}

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -30,4 +30,4 @@
* SUCH DAMAGE.
*/
extern void rtadvd_dump_file(char *);
extern void rtadvd_dump_file(const char *);

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -44,34 +44,35 @@
#include <netinet/icmp6.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "rtadvd.h"
#include "if.h"
#define ROUNDUP(a, size) \
#define ROUNDUP(a, size) \
(((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
sizeof(u_long)) :\
sizeof(u_long)))
#define NEXT_SA(ap) \
(ap) = (struct sockaddr *)((caddr_t)(ap) + \
((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) : \
sizeof(u_long)))
struct if_msghdr **iflist;
int iflist_init_ok;
size_t ifblock_size;
char *ifblock;
static void get_iflist(char **buf, size_t *size);
static void parse_iflist(struct if_msghdr ***ifmlist_p, char *buf,
size_t bufsize);
static void get_iflist(char **buf, size_t *size);
static void parse_iflist(struct if_msghdr ***ifmlist_p,
char *buf, size_t bufsize);
static void
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
{
int i;
for (i = 0; i < RTAX_MAX; i++) {
if (addrs & (1 << i)) {
rti_info[i] = sa;
@ -93,12 +94,12 @@ if_nametosdl(char *name)
struct sockaddr_dl *sdl = NULL, *ret_sdl;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
return(NULL);
return (NULL);
if ((buf = malloc(len)) == NULL)
return(NULL);
return (NULL);
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
free(buf);
return(NULL);
return (NULL);
}
lim = buf + len;
@ -124,7 +125,7 @@ if_nametosdl(char *name)
if (next == lim) {
/* search failed */
free(buf);
return(NULL);
return (NULL);
}
if ((ret_sdl = malloc(sdl->sdl_len)) == NULL)
@ -133,7 +134,7 @@ if_nametosdl(char *name)
end:
free(buf);
return(ret_sdl);
return (ret_sdl);
}
int
@ -144,7 +145,7 @@ if_getmtu(char *name)
u_long mtu = 0;
if (getifaddrs(&ifap) < 0)
return(0);
return (0);
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcmp(ifa->ifa_name, name) == 0) {
ifd = ifa->ifa_data;
@ -161,14 +162,14 @@ if_getmtu(char *name)
int s;
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
return(0);
return (0);
ifr.ifr_addr.sa_family = AF_INET6;
strncpy(ifr.ifr_name, name,
sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) {
close(s);
return(0);
return (0);
}
close(s);
@ -176,7 +177,7 @@ if_getmtu(char *name)
}
#endif
return(mtu);
return (mtu);
}
/* give interface index and its old flags, then new flags returned */
@ -188,14 +189,14 @@ if_getflags(int ifindex, int oifflags)
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "<%s> socket: %s", __func__,
strerror(errno));
strerror(errno));
return (oifflags & ~IFF_UP);
}
if_indextoname(ifindex, ifr.ifr_name);
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
syslog(LOG_ERR, "<%s> ioctl:SIOCGIFFLAGS: failed for %s",
__func__, ifr.ifr_name);
__func__, ifr.ifr_name);
close(s);
return (oifflags & ~IFF_UP);
}
@ -209,9 +210,9 @@ lladdropt_length(struct sockaddr_dl *sdl)
{
switch (sdl->sdl_type) {
case IFT_ETHER:
return(ROUNDUP8(ETHER_ADDR_LEN + 2));
return (ROUNDUP8(ETHER_ADDR_LEN + 2));
default:
return(0);
return (0);
}
}
@ -238,16 +239,15 @@ lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
}
int
rtbuf_len()
rtbuf_len(void)
{
size_t len;
int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0};
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
return(-1);
return (-1);
return(len);
return (len);
}
#define FILTER_MATCH(type, filter) ((0x1 << type) & filter)
@ -267,14 +267,21 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
/* just for safety */
if (!rtm->rtm_msglen) {
syslog(LOG_WARNING, "<%s> rtm_msglen is 0 "
"(buf=%p lim=%p rtm=%p)", __func__,
buf, lim, rtm);
"(buf=%p lim=%p rtm=%p)", __func__,
buf, lim, rtm);
break;
}
if (FILTER_MATCH(rtm->rtm_type, filter) == 0) {
if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) {
syslog(LOG_WARNING,
"<%s> routing message version mismatch "
"(buf=%p lim=%p rtm=%p)", __func__,
buf, lim, rtm);
continue;
}
if (FILTER_MATCH(rtm->rtm_type, filter) == 0)
continue;
switch (rtm->rtm_type) {
case RTM_GET:
case RTM_ADD:
@ -328,6 +335,7 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
return (char *)rtm;
/* NOTREACHED */
case RTM_IFINFO:
case RTM_IFANNOUNCE:
/* found */
*lenp = rtm->rtm_msglen;
return (char *)rtm;
@ -335,7 +343,7 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
}
}
return (char *)rtm;
return ((char *)rtm);
}
#undef FILTER_MATCH
@ -348,7 +356,7 @@ get_addr(char *buf)
sa = (struct sockaddr *)(rtm + 1);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
return(&SIN6(rti_info[RTAX_DST])->sin6_addr);
return (&SIN6(rti_info[RTAX_DST])->sin6_addr);
}
int
@ -360,7 +368,7 @@ get_rtm_ifindex(char *buf)
sa = (struct sockaddr *)(rtm + 1);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
}
int
@ -393,7 +401,7 @@ get_prefixlen(char *buf)
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
struct sockaddr *sa, *rti_info[RTAX_MAX];
u_char *p, *lim;
sa = (struct sockaddr *)(rtm + 1);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
sa = rti_info[RTAX_NETMASK];
@ -437,11 +445,11 @@ prefixlen(u_char *p, u_char *lim)
case 0x00:
break;
default:
return(-1);
return (-1);
}
}
return(masklen);
return (masklen);
}
int
@ -449,7 +457,7 @@ rtmsg_type(char *buf)
{
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
return(rtm->rtm_type);
return (rtm->rtm_type);
}
int
@ -457,7 +465,7 @@ rtmsg_len(char *buf)
{
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
return(rtm->rtm_msglen);
return (rtm->rtm_msglen);
}
int
@ -465,7 +473,7 @@ ifmsg_len(char *buf)
{
struct if_msghdr *ifm = (struct if_msghdr *)buf;
return(ifm->ifm_msglen);
return (ifm->ifm_msglen);
}
/*
@ -486,7 +494,7 @@ get_iflist(char **buf, size_t *size)
if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) {
syslog(LOG_ERR, "<%s> sysctl: iflist size get failed",
__func__);
__func__);
exit(1);
}
if ((*buf = malloc(*size)) == NULL) {
@ -495,7 +503,7 @@ get_iflist(char **buf, size_t *size)
}
if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) {
syslog(LOG_ERR, "<%s> sysctl: iflist get failed",
__func__);
__func__);
exit(1);
}
return;
@ -529,8 +537,8 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) {
if (ifm->ifm_msglen == 0) {
syslog(LOG_WARNING, "<%s> ifm_msglen is 0 "
"(buf=%p lim=%p ifm=%p)", __func__,
buf, lim, ifm);
"(buf=%p lim=%p ifm=%p)", __func__,
buf, lim, ifm);
return;
}
@ -538,10 +546,10 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
(*ifmlist_p)[ifm->ifm_index] = ifm;
} else {
syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n"
"expected %d, got %d\n msglen = %d\n"
"buf:%p, ifm:%p, lim:%p\n",
RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
buf, ifm, lim);
"expected %d, got %d\n msglen = %d\n"
"buf:%p, ifm:%p, lim:%p\n",
RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
buf, ifm, lim);
exit (1);
}
for (ifam = (struct ifa_msghdr *)
@ -552,8 +560,8 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
/* just for safety */
if (!ifam->ifam_msglen) {
syslog(LOG_WARNING, "<%s> ifa_msglen is 0 "
"(buf=%p lim=%p ifam=%p)", __func__,
buf, lim, ifam);
"(buf=%p lim=%p ifam=%p)", __func__,
buf, lim, ifam);
return;
}
if (ifam->ifam_type != RTM_NEWADDR)
@ -564,8 +572,11 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
}
void
init_iflist()
init_iflist(void)
{
syslog(LOG_DEBUG,
"<%s> generate iflist.", __func__);
if (ifblock) {
free(ifblock);
ifblock_size = 0;

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

View File

@ -1,4 +1,7 @@
/* $KAME: pathnames.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */
/* $FreeBSD$ */
#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
#define _PATH_RTADVDDUMP "/var/run/rtadvd.dump"
#define _PATH_RTADVDPID "/var/run/rtadvd.pid"

View File

@ -45,6 +45,7 @@
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
@ -74,7 +75,7 @@ static int s = -1;
/*
* Check validity of a Prefix Control Operation(PCO).
* Return 0 on success, 1 on failure.
* return 0 on success, 1 on failure.
*/
static int
rr_pco_check(int len, struct rr_pco_match *rpm)
@ -86,8 +87,8 @@ rr_pco_check(int len, struct rr_pco_match *rpm)
if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */
(rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */
syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3",
__func__, rpm->rpm_len);
return 1;
__func__, rpm->rpm_len);
return (1);
}
/* rpm->rpm_code must be valid value */
switch (rpm->rpm_code) {
@ -97,14 +98,14 @@ rr_pco_check(int len, struct rr_pco_match *rpm)
break;
default:
syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __func__,
rpm->rpm_code);
return 1;
rpm->rpm_code);
return (1);
}
/* rpm->rpm_matchlen must be 0 to 128 inclusive */
if (rpm->rpm_matchlen > 128) {
syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128",
__func__, rpm->rpm_matchlen);
return 1;
__func__, rpm->rpm_matchlen);
return (1);
}
/*
@ -126,23 +127,22 @@ rr_pco_check(int len, struct rr_pco_match *rpm)
*/
if (checklen > 128) {
syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and"
" rpu_keeplen %d is %d(over 128)",
__func__, rpu->rpu_uselen,
rpu->rpu_keeplen,
rpu->rpu_uselen + rpu->rpu_keeplen);
return 1;
" rpu_keeplen %d is %d(over 128)",
__func__, rpu->rpu_uselen, rpu->rpu_keeplen,
rpu->rpu_uselen + rpu->rpu_keeplen);
return (1);
}
}
return 0;
return (0);
}
static void
do_use_prefix(int len, struct rr_pco_match *rpm,
struct in6_rrenumreq *irr, int ifindex)
struct in6_rrenumreq *irr, int ifindex)
{
struct rr_pco_use *rpu, *rpulim;
struct rainfo *rai;
struct prefix *pp;
struct prefix *pfx;
rpu = (struct rr_pco_use *)(rpm + 1);
rpulim = (struct rr_pco_use *)((char *)rpm + len);
@ -164,7 +164,7 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
errno != EADDRNOTAVAIL)
syslog(LOG_ERR, "<%s> ioctl: %s", __func__,
strerror(errno));
strerror(errno));
return;
}
@ -176,19 +176,23 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
irr->irr_u_uselen = rpu->rpu_uselen;
irr->irr_u_keeplen = rpu->rpu_keeplen;
irr->irr_raf_mask_onlink =
!!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
!!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
irr->irr_raf_mask_auto =
!!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
!!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
irr->irr_vltime = ntohl(rpu->rpu_vltime);
irr->irr_pltime = ntohl(rpu->rpu_pltime);
irr->irr_raf_onlink =
(rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 0 : 1;
(rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ?
0 : 1;
irr->irr_raf_auto =
(rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 0 : 1;
(rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ?
0 : 1;
irr->irr_rrf_decrvalid =
(rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 0 : 1;
(rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ?
0 : 1;
irr->irr_rrf_decrprefd =
(rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 0 : 1;
(rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ?
0 : 1;
irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix);
irr->irr_useprefix.sin6_family = AF_INET6;
irr->irr_useprefix.sin6_addr = rpu->rpu_prefix;
@ -196,7 +200,7 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
errno != EADDRNOTAVAIL)
syslog(LOG_ERR, "<%s> ioctl: %s", __func__,
strerror(errno));
strerror(errno));
/* very adhoc: should be rewritten */
if (rpm->rpm_code == RPM_PCO_CHANGE &&
@ -206,28 +210,31 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
if ((rai = if_indextorainfo(ifindex)) == NULL)
continue; /* non-advertising IF */
for (pp = rai->prefix.next; pp != &rai->prefix;
pp = pp->next) {
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
struct timeval now;
if (prefix_match(&pp->prefix, pp->prefixlen,
&rpm->rpm_prefix,
rpm->rpm_matchlen)) {
if (prefix_match(&pfx->pfx_prefix,
pfx->pfx_prefixlen, &rpm->rpm_prefix,
rpm->rpm_matchlen)) {
/* change parameters */
pp->validlifetime = ntohl(rpu->rpu_vltime);
pp->preflifetime = ntohl(rpu->rpu_pltime);
pfx->pfx_validlifetime =
ntohl(rpu->rpu_vltime);
pfx->pfx_preflifetime =
ntohl(rpu->rpu_pltime);
if (irr->irr_rrf_decrvalid) {
gettimeofday(&now, 0);
pp->vltimeexpire =
now.tv_sec + pp->validlifetime;
pfx->pfx_vltimeexpire =
now.tv_sec +
pfx->pfx_validlifetime;
} else
pp->vltimeexpire = 0;
pfx->pfx_vltimeexpire = 0;
if (irr->irr_rrf_decrprefd) {
gettimeofday(&now, 0);
pp->pltimeexpire =
now.tv_sec + pp->preflifetime;
pfx->pfx_pltimeexpire =
now.tv_sec +
pfx->pfx_preflifetime;
} else
pp->pltimeexpire = 0;
pfx->pfx_pltimeexpire = 0;
}
}
}
@ -245,11 +252,11 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
struct in6_rrenumreq irr;
if ((rr_pco_check(len, rpm) != 0))
return 1;
return (1);
if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "<%s> socket: %s", __func__,
strerror(errno));
strerror(errno));
exit(1);
}
@ -264,8 +271,8 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
while (if_indextoname(++ifindex, irr.irr_name)) {
/*
* if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off,
* the interface is not applied
* if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and
* IFF_UP is off, the interface is not applied
*/
if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 &&
(iflist[ifindex]->ifm_flags & IFF_UP) == 0)
@ -274,13 +281,13 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
do_use_prefix(len, rpm, &irr, ifindex);
}
if (errno == ENXIO)
return 0;
return (0);
else if (errno) {
syslog(LOG_ERR, "<%s> if_indextoname: %s", __func__,
strerror(errno));
return 1;
strerror(errno));
return (1);
}
return 0;
return (0);
}
/*
@ -305,11 +312,11 @@ do_rr(int len, struct icmp6_router_renum *rr)
int rpmlen;
rpm = (struct rr_pco_match *)cp;
if (len < sizeof(struct rr_pco_match)) {
if ((size_t)len < sizeof(struct rr_pco_match)) {
tooshort:
syslog(LOG_ERR, "<%s> pkt too short. left len = %d. "
"gabage at end of pkt?", __func__, len);
return 1;
"gabage at end of pkt?", __func__, len);
return (1);
}
rpmlen = rpm->rpm_len << 3;
if (len < rpmlen)
@ -325,7 +332,7 @@ do_rr(int len, struct icmp6_router_renum *rr)
len -= rpmlen;
}
return 0;
return (0);
}
/*
@ -334,46 +341,45 @@ do_rr(int len, struct icmp6_router_renum *rr)
*/
static int
rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from,
struct in6_addr *dst)
struct in6_addr *dst)
{
u_char ntopbuf[INET6_ADDRSTRLEN];
/* omit rr minimal length check. hope kernel have done it. */
/* rr_command length check */
if (len < (sizeof(struct icmp6_router_renum) +
sizeof(struct rr_pco_match))) {
if ((size_t)len < (sizeof(struct icmp6_router_renum) +
sizeof(struct rr_pco_match))) {
syslog(LOG_ERR, "<%s> rr_command len %d is too short",
__func__, len);
return 1;
__func__, len);
return (1);
}
/* destination check. only for multicast. omit unicast check. */
if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) &&
!IN6_IS_ADDR_MC_SITELOCAL(dst)) {
syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal",
__func__,
inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN));
return 1;
__func__,
inet_ntop(AF_INET6, dst, ntopbuf, sizeof(ntopbuf)));
return (1);
}
/* seqnum and segnum check */
if (rro.rro_seqnum > rr->rr_seqnum) {
syslog(LOG_WARNING,
"<%s> rcvd old seqnum %d from %s",
__func__, (u_int32_t)ntohl(rr->rr_seqnum),
inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN));
return 1;
"<%s> rcvd old seqnum %d from %s",
__func__, (u_int32_t)ntohl(rr->rr_seqnum),
inet_ntop(AF_INET6, from, ntopbuf, sizeof(ntopbuf)));
return (1);
}
if (rro.rro_seqnum == rr->rr_seqnum &&
(rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 &&
RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) {
if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0)
syslog(LOG_WARNING,
"<%s> rcvd duped segnum %d from %s",
__func__, rr->rr_segnum,
inet_ntop(AF_INET6, from, ntopbuf,
INET6_ADDRSTRLEN));
return 0;
"<%s> rcvd duped segnum %d from %s",
__func__, rr->rr_segnum, inet_ntop(AF_INET6, from,
ntopbuf, sizeof(ntopbuf)));
return (0);
}
/* update seqnum */
@ -382,16 +388,16 @@ rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from,
/* init rro_segnum_bits */
memset(rro.rro_segnum_bits, 0,
sizeof(rro.rro_segnum_bits));
sizeof(rro.rro_segnum_bits));
}
rro.rro_seqnum = rr->rr_seqnum;
return 0;
return (0);
}
static void
rr_command_input(int len, struct icmp6_router_renum *rr,
struct in6_addr *from, struct in6_addr *dst)
struct in6_addr *from, struct in6_addr *dst)
{
/* rr_command validity check */
if (rr_command_check(len, rr, from, dst))
@ -401,9 +407,8 @@ rr_command_input(int len, struct icmp6_router_renum *rr,
return;
/* do router renumbering */
if (do_rr(len, rr)) {
if (do_rr(len, rr))
goto failed;
}
/* update segnum */
RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum);
@ -417,27 +422,26 @@ rr_command_input(int len, struct icmp6_router_renum *rr,
void
rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
struct sockaddr_in6 *from, struct in6_addr *dst)
struct sockaddr_in6 *from, struct in6_addr *dst)
{
u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
syslog(LOG_DEBUG,
"<%s> RR received from %s to %s on %s",
__func__,
inet_ntop(AF_INET6, &from->sin6_addr,
ntopbuf[0], INET6_ADDRSTRLEN),
inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
"<%s> RR received from %s to %s on %s",
__func__,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0] ,sizeof(ntopbuf[0])),
inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
/* packet validation based on Section 4.1 of RFC2894 */
if (len < sizeof(struct icmp6_router_renum)) {
if ((size_t)len < sizeof(struct icmp6_router_renum)) {
syslog(LOG_NOTICE,
"<%s>: RR short message (size %d) from %s to %s on %s",
__func__, len,
inet_ntop(AF_INET6, &from->sin6_addr,
ntopbuf[0], INET6_ADDRSTRLEN),
inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
"<%s>: RR short message (size %d) from %s to %s on %s",
__func__, len,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0],
sizeof(ntopbuf[0])),
inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
@ -449,16 +453,16 @@ rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
* We rely on the kernel input routine for unicast addresses, and thus
* check multicast destinations only.
*/
if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) &&
!IN6_ARE_ADDR_EQUAL(&in6a_site_allrouters, &pi->ipi6_addr)) {
if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && !IN6_ARE_ADDR_EQUAL(
&sin6_sitelocal_allrouters.sin6_addr, &pi->ipi6_addr)) {
syslog(LOG_NOTICE,
"<%s>: RR message with invalid destination (%s) "
"from %s on %s",
__func__,
inet_ntop(AF_INET6, &dst, ntopbuf[0], INET6_ADDRSTRLEN),
inet_ntop(AF_INET6, &from->sin6_addr,
ntopbuf[1], INET6_ADDRSTRLEN),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
"<%s>: RR message with invalid destination (%s) "
"from %s on %s",
__func__,
inet_ntop(AF_INET6, &dst, ntopbuf[0], sizeof(ntopbuf[0])),
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[1],
sizeof(ntopbuf[1])),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
@ -477,7 +481,7 @@ rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
break;
default:
syslog(LOG_ERR, "<%s> received unknown code %d",
__func__, rr->rr_code);
__func__, rr->rr_code);
break;
}

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

View File

@ -37,9 +37,10 @@
.Nd router advertisement daemon
.Sh SYNOPSIS
.Nm
.Op Fl dDfMRs
.Op Fl dDfRs
.Op Fl c Ar configfile
.Op Fl F Ar dumpfile
.Op Fl M Ar ifname
.Op Fl p Ar pidfile
.Ar interface ...
.Sh DESCRIPTION
@ -103,7 +104,7 @@ will not watch the routing table and the whole functionality described
above will be suppressed.
.Pp
Basically, hosts MUST NOT send Router Advertisement messages at any
time (RFC 2461, Section 6.2.3).
time (RFC 4861, Section 6.2.3).
However, it would sometimes be useful to allow hosts to advertise some
parameters such as prefix information and link MTU.
Thus,
@ -176,7 +177,7 @@ In this case,
.Nm
will transmit router advertisement with router lifetime 0
to all the interfaces
.Pq in accordance with RFC2461 6.2.5 .
.Pq in accordance with RFC 4861 6.2.5 .
.Sh FILES
.Bl -tag -width Pa -compact
.It Pa /etc/rtadvd.conf
@ -193,6 +194,34 @@ dumps its internal state.
.Sh SEE ALSO
.Xr rtadvd.conf 5 ,
.Xr rtsol 8
.Rs
.%A Thomas Narten
.%A Erik Nordmark
.%A W. A. Simpson
.%A Hesham Soliman
.%T Neighbor Discovery for IP version 6 (IPv6)
.%R RFC 4861
.Re
.Rs
.%A Thomas Narten
.%A Erik Nordmark
.%A W. A. Simpson
.%T Neighbor Discovery for IP version 6 (IPv6)
.%R RFC 2461 (obsoleted by RFC 4861)
.Re
.Rs
.%A Richard Draves
.%T Default Router Preferences and More-Specific Routes
.%R draft-ietf-ipngwg-router-selection-xx.txt
.Re
.Rs
.%A J. Jeong
.%A S. Park
.%A L. Beloeil
.%A S. Madanapalli
.%T IPv6 Router Advertisement Options for DNS Configuration
.%R RFC 6106
.Re
.Sh HISTORY
The
.Nm

File diff suppressed because it is too large Load Diff

View File

@ -18,4 +18,5 @@
# this part by hand, and then invoke rtadvd with the -s option.
#ef0:\
# :addr="3ffe:501:ffff:1000::":prefixlen#64:
# :addr="2001:db8:ffff:1000::":prefixlen#64:\
# :rdnss="2001:db8:ffff:1000::1":dnssl="example.com":

View File

@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 17, 1998
.Dd June 4, 2011
.Dt RTADVD.CONF 5
.Os
.Sh NAME
@ -179,10 +179,25 @@ will automatically get appropriate prefixes from the kernel's routing table,
and advertise the prefixes with the default parameters.
Keywords other than
.Cm clockskew
and
.Cm noifprefix
can be augmented with a number, like
.Dq Li prefix2 ,
to specify multiple prefixes.
.Bl -tag -width indent
.It Cm \&noifprefix
(bool) Specifies no prefix on the network interfaces will be advertised.
By default
.Nm rtadvd
automatically gathers on-link prefixes from all of the network interfaces
and advertise them.
The
.Cm noifprefix
disables that behavior.
If this is specified and no
.Cm addr
keyword is specified, no prefix information option will be included in the
message.
.It Cm \&clockskew
(num) Time skew to adjust link propagation delays and clock skews
between routers on the link
@ -355,6 +370,66 @@ However, keywords that start with
.Dq Li rtr
have basically been obsoleted, and should not be used any more.
.Pp
The following items are for ICMPv6 Recursive DNS Server Option and
DNS Search List Option
.Pq RFC 6106 ,
which will be attached to router advertisement header.
These items are optional.
.Bl -tag -width indent
.It Cm \&rdnss
(str) The IPv6 address of one or more recursive DNS servers.
The argument must be inside double quotes.
Multiple DNS servers can be specified in a comma-separated string.
If different lifetimes are needed for different servers,
separate entries can be given by using
.Cm rdnss ,
.Cm rdnss0 ,
.Cm rdnss1 ,
.Cm rdnss2 ...
options with corresponding
.Cm rdnssltime ,
.Cm rdnssltime0 ,
.Cm rdnssltime1 ,
.Cm rdnssltime2 ...
entries.
Note that the maximum number of servers depends on the receiver side.
See also
.Xr resolver 5
manual page for resolver implementation in
.Fx .
.It Cm \&rdnssltime
The lifetime of the
.Cm rdnss
DNS server entries.
The default value is 3/2 of the interval time.
.It Cm \&dnssl
(str) One or more domain names in a comma-separated string.
These domain names will be used when making DNS queries on a
non-fully-qualified domain name.
If different lifetimes are needed for different domains, separate entries
can be given by using
.Cm dnssl ,
.Cm dnssl0 ,
.Cm dnssl1 ,
.Cm dnssl2 ...
options with corresponding
.Cm dnsslltime ,
.Cm dnsslltime0 ,
.Cm dnsslltime1 ,
.Cm dnsslltime2 ...
entries.
Note that the maximum number of names depends on the receiver side.
See also
.Xr resolver 5
manual page for resolver implementation in
.Fx .
.It Cm \&dnsslltime
The lifetime of the
.Cm dnssl
DNS search list entries.
The default value is 3/2 of the interval time.
.El
.Pp
You can also refer one line from another by using
.Cm tc
capability.
@ -388,7 +463,18 @@ option to
.Xr rtadvd 8 .
.Bd -literal -offset
ef0:\\
:addr="3ffe:501:ffff:1000::":prefixlen#64:
:addr="2001:db8:ffff:1000::":prefixlen#64:
.Ed
.Pp
The following example configures the
.Li wlan0
interface and adds two DNS servers and a DNS domain search options
using the default option lifetime values.
.Bd -literal -offset
wlan0:\\
:addr="2001:db8:ffff:1000::":prefixlen#64:\\
:rdnss="2001:db8:ffff::10,2001:db8:ffff::2:43":\\
:dnssl="example.com":
.Ed
.Pp
The following example presents the default values in an explicit manner.
@ -399,24 +485,41 @@ default:\\
:chlim#64:raflags#0:rltime#1800:rtime#0:retrans#0:\\
:pinfoflags="la":vltime#2592000:pltime#604800:mtu#0:
ef0:\\
:addr="3ffe:501:ffff:1000::":prefixlen#64:tc=default:
:addr="2001:db8:ffff:1000::":prefixlen#64:tc=default:
.Ed
.Sh SEE ALSO
.Xr termcap 5 ,
.Xr resolver 5 ,
.Xr rtadvd 8 ,
.Xr rtsol 8
.Rs
.%A Thomas Narten
.%A Erik Nordmark
.%A W. A. Simpson
.%A Hesham Soliman
.%T Neighbor Discovery for IP version 6 (IPv6)
.%R RFC 2461
.%R RFC 4861
.Re
.Rs
.%A Thomas Narten
.%A Erik Nordmark
.%A W. A. Simpson
.%T Neighbor Discovery for IP version 6 (IPv6)
.%R RFC 2461 (obsoleted by RFC 4861)
.Re
.Rs
.%A Richard Draves
.%T Default Router Preferences and More-Specific Routes
.%R draft-ietf-ipngwg-router-selection-xx.txt
.Re
.Rs
.%A J. Jeong
.%A S. Park
.%A L. Beloeil
.%A S. Madanapalli
.%T IPv6 Router Advertisement Options for DNS Configuration
.%R RFC 6106
.Re
.Sh HISTORY
The
.Xr rtadvd 8

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -30,11 +30,41 @@
* SUCH DAMAGE.
*/
#define ALLNODES "ff02::1"
#define ALLROUTERS_LINK "ff02::2"
#define ALLROUTERS_SITE "ff05::2"
#define ANY "::"
#define RTSOLLEN 8
#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
#define IN6ADDR_SITELOCAL_ALLROUTERS_INIT \
{{{ 0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
extern struct sockaddr_in6 sin6_linklocal_allnodes;
extern struct sockaddr_in6 sin6_linklocal_allrouters;
extern struct sockaddr_in6 sin6_sitelocal_allrouters;
/*
* RFC 3542 API deprecates IPV6_PKTINFO in favor of
* IPV6_RECVPKTINFO
*/
#ifndef IPV6_RECVPKTINFO
#ifdef IPV6_PKTINFO
#define IPV6_RECVPKTINFO IPV6_PKTINFO
#endif
#endif
/*
* RFC 3542 API deprecates IPV6_HOPLIMIT in favor of
* IPV6_RECVHOPLIMIT
*/
#ifndef IPV6_RECVHOPLIMIT
#ifdef IPV6_HOPLIMIT
#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
#endif
#endif
/* protocol constants and default values */
#define DEF_MAXRTRADVINTERVAL 600
@ -62,100 +92,150 @@
#define PREFIX_FROM_DYNAMIC 3
struct prefix {
struct prefix *next; /* forward link */
struct prefix *prev; /* previous link */
TAILQ_ENTRY(prefix) pfx_next;
struct rainfo *rainfo; /* back pointer to the interface */
struct rainfo *pfx_rainfo; /* back pointer to the interface */
/*
* Expiration timer. This is used when a prefix derived from
* the kernel is deleted.
*/
struct rtadvd_timer *pfx_timer;
struct rtadvd_timer *timer; /* expiration timer. used when a prefix
* derived from the kernel is deleted.
*/
u_int32_t pfx_validlifetime; /* AdvValidLifetime */
long pfx_vltimeexpire; /* Expiration of vltime */
u_int32_t pfx_preflifetime; /* AdvPreferredLifetime */
long pfx_pltimeexpire; /* Expiration of pltime */
u_int pfx_onlinkflg; /* bool: AdvOnLinkFlag */
u_int pfx_autoconfflg; /* bool: AdvAutonomousFlag */
int pfx_prefixlen;
int pfx_origin; /* From kernel or config */
u_int32_t validlifetime; /* AdvValidLifetime */
long vltimeexpire; /* expiration of vltime; decrement case only */
u_int32_t preflifetime; /* AdvPreferredLifetime */
long pltimeexpire; /* expiration of pltime; decrement case only */
u_int onlinkflg; /* bool: AdvOnLinkFlag */
u_int autoconfflg; /* bool: AdvAutonomousFlag */
int prefixlen;
int origin; /* from kernel or config */
struct in6_addr prefix;
struct in6_addr pfx_prefix;
};
#ifdef ROUTEINFO
struct rtinfo {
struct rtinfo *prev; /* previous link */
struct rtinfo *next; /* forward link */
TAILQ_ENTRY(rtinfo) rti_next;
u_int32_t ltime; /* route lifetime */
u_int rtpref; /* route preference */
int prefixlen;
struct in6_addr prefix;
u_int32_t rti_ltime; /* route lifetime */
u_int rti_rtpref; /* route preference */
int rti_prefixlen;
struct in6_addr rti_prefix;
};
#endif
struct rdnss_addr {
TAILQ_ENTRY(rdnss_addr) ra_next;
struct in6_addr ra_dns; /* DNS server entry */
};
struct rdnss {
TAILQ_ENTRY(rdnss) rd_next;
TAILQ_HEAD(, rdnss_addr) rd_list; /* list of DNS servers */
int rd_cnt; /* number of DNS servers */
u_int32_t rd_ltime; /* number of seconds valid */
};
/*
* The maximum length of a domain name in a DNS search list is calculated
* by a domain name + length fields per 63 octets + a zero octet at
* the tail and adding 8 octet boundary padding.
*/
#define _DNAME_LABELENC_MAXLEN \
(NI_MAXHOST + (NI_MAXHOST / 64 + 1) + 1)
#define DNAME_LABELENC_MAXLEN \
(_DNAME_LABELENC_MAXLEN + 8 - _DNAME_LABELENC_MAXLEN % 8)
struct dnssl_addr {
TAILQ_ENTRY(dnssl_addr) da_next;
int da_len; /* length of entry */
char da_dom[DNAME_LABELENC_MAXLEN]; /* search domain name entry */
};
struct dnssl {
TAILQ_ENTRY(dnssl) dn_next;
TAILQ_HEAD(, dnssl_addr) dn_list; /* list of search domains */
u_int32_t dn_ltime; /* number of seconds valid */
};
struct soliciter {
struct soliciter *next;
struct sockaddr_in6 addr;
TAILQ_ENTRY(soliciter) sol_next;
struct sockaddr_in6 sol_addr;
};
struct rainfo {
/* pointer for list */
struct rainfo *next;
TAILQ_ENTRY(rainfo) rai_next;
/* timer related parameters */
struct rtadvd_timer *timer;
int initcounter; /* counter for the first few advertisements */
struct timeval lastsent; /* timestamp when the latest RA was sent */
int waiting; /* number of RS waiting for RA */
struct rtadvd_timer *rai_timer;
/* counter for the first few advertisements */
int rai_initcounter;
/* timestamp when the latest RA was sent */
struct timeval rai_lastsent;
/* number of RS waiting for RA */
int rai_waiting;
/* interface information */
int ifindex;
int advlinkopt; /* bool: whether include link-layer addr opt */
struct sockaddr_dl *sdl;
char ifname[16];
int phymtu; /* mtu of the physical interface */
int rai_ifindex;
int rai_advlinkopt; /* bool: whether include link-layer addr opt */
int rai_advifprefix; /* bool: gather IF prefixes? */
struct sockaddr_dl *rai_sdl;
char rai_ifname[IFNAMSIZ];
u_int32_t rai_phymtu; /* mtu of the physical interface */
/* Router configuration variables */
u_short lifetime; /* AdvDefaultLifetime */
u_int maxinterval; /* MaxRtrAdvInterval */
u_int mininterval; /* MinRtrAdvInterval */
int managedflg; /* AdvManagedFlag */
int otherflg; /* AdvOtherConfigFlag */
u_short rai_lifetime; /* AdvDefaultLifetime */
u_int rai_maxinterval; /* MaxRtrAdvInterval */
u_int rai_mininterval; /* MinRtrAdvInterval */
int rai_managedflg; /* AdvManagedFlag */
int rai_otherflg; /* AdvOtherConfigFlag */
int rtpref; /* router preference */
u_int32_t linkmtu; /* AdvLinkMTU */
u_int32_t reachabletime; /* AdvReachableTime */
u_int32_t retranstimer; /* AdvRetransTimer */
u_int hoplimit; /* AdvCurHopLimit */
struct prefix prefix; /* AdvPrefixList(link head) */
int pfxs; /* number of prefixes */
long clockskew; /* used for consisitency check of lifetimes */
int rai_rtpref; /* router preference */
u_int32_t rai_linkmtu; /* AdvLinkMTU */
u_int32_t rai_reachabletime; /* AdvReachableTime */
u_int32_t rai_retranstimer; /* AdvRetransTimer */
u_int rai_hoplimit; /* AdvCurHopLimit */
TAILQ_HEAD(, prefix) rai_prefix;/* AdvPrefixList(link head) */
int rai_pfxs; /* number of prefixes */
long rai_clockskew; /* used for consisitency check of lifetimes */
TAILQ_HEAD(, rdnss) rai_rdnss; /* DNS server list */
TAILQ_HEAD(, dnssl) rai_dnssl; /* search domain list */
#ifdef ROUTEINFO
struct rtinfo route; /* route information option (link head) */
int routes; /* number of route information options */
TAILQ_HEAD(, rtinfo) rai_route; /* route information option (link head) */
int rai_routes; /* number of route information options */
#endif
/* actual RA packet data and its length */
size_t ra_datalen;
u_char *ra_data;
size_t rai_ra_datalen;
u_char *rai_ra_data;
/* statistics */
u_quad_t raoutput; /* number of RAs sent */
u_quad_t rainput; /* number of RAs received */
u_quad_t rainconsistent; /* number of RAs inconsistent with ours */
u_quad_t rsinput; /* number of RSs received */
u_quad_t rai_raoutput; /* # of RAs sent */
u_quad_t rai_rainput; /* # of RAs received */
u_quad_t rai_rainconsistent; /* # of RAs inconsistent with ours */
u_quad_t rai_rsinput; /* # of RSs received */
/* info about soliciter */
struct soliciter *soliciter; /* recent solication source */
TAILQ_HEAD(, soliciter) rai_soliciter; /* recent solication source */
};
struct rtadvd_timer *ra_timeout(void *);
void ra_timer_update(void *, struct timeval *);
/* Interface list including RA information */
extern TAILQ_HEAD(railist_head_t, rainfo) railist;
int prefix_match(struct in6_addr *, int, struct in6_addr *, int);
struct rainfo *if_indextorainfo(int);
struct prefix *find_prefix(struct rainfo *, struct in6_addr *, int);
struct rtadvd_timer *ra_timeout(void *);
void ra_timer_update(void *, struct timeval *);
extern struct in6_addr in6a_site_allrouters;
int prefix_match(struct in6_addr *, int,
struct in6_addr *, int);
struct rainfo *if_indextorainfo(int);
struct prefix *find_prefix(struct rainfo *,
struct in6_addr *, int);

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -31,6 +31,7 @@
*/
#include <sys/time.h>
#include <sys/queue.h>
#include <unistd.h>
#include <syslog.h>
@ -39,21 +40,19 @@
#include <search.h>
#include "timer.h"
static struct rtadvd_timer timer_head;
#define MILLION 1000000
#define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\
(t1)->tv_usec == (t2)->tv_usec)
static struct timeval tm_max = {0x7fffffff, 0x7fffffff};
struct rtadvd_timer_head_t ra_timer =
TAILQ_HEAD_INITIALIZER(ra_timer);
static struct timeval tm_limit = {0x7fffffff, 0x7fffffff};
static struct timeval tm_max;
void
rtadvd_timer_init()
rtadvd_timer_init(void)
{
memset(&timer_head, 0, sizeof(timer_head));
timer_head.next = timer_head.prev = &timer_head;
timer_head.tm = tm_max;
tm_max = tm_limit;
TAILQ_INIT(&ra_timer);
}
struct rtadvd_timer *
@ -61,54 +60,57 @@ rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *),
void (*update)(void *, struct timeval *),
void *timeodata, void *updatedata)
{
struct rtadvd_timer *newtimer;
if ((newtimer = malloc(sizeof(*newtimer))) == NULL) {
syslog(LOG_ERR,
"<%s> can't allocate memory", __func__);
exit(1);
}
memset(newtimer, 0, sizeof(*newtimer));
struct rtadvd_timer *rat;
if (timeout == NULL) {
syslog(LOG_ERR,
"<%s> timeout function unspecified", __func__);
"<%s> timeout function unspecified", __func__);
exit(1);
}
newtimer->expire = timeout;
newtimer->update = update;
newtimer->expire_data = timeodata;
newtimer->update_data = updatedata;
newtimer->tm = tm_max;
rat = malloc(sizeof(*rat));
if (rat == NULL) {
syslog(LOG_ERR,
"<%s> can't allocate memory", __func__);
exit(1);
}
memset(rat, 0, sizeof(*rat));
rat->rat_expire = timeout;
rat->rat_update = update;
rat->rat_expire_data = timeodata;
rat->rat_update_data = updatedata;
rat->rat_tm = tm_max;
/* link into chain */
insque(newtimer, &timer_head);
TAILQ_INSERT_TAIL(&ra_timer, rat, rat_next);
return(newtimer);
return (rat);
}
void
rtadvd_remove_timer(struct rtadvd_timer **timer)
rtadvd_remove_timer(struct rtadvd_timer *rat)
{
remque(*timer);
free(*timer);
*timer = NULL;
if (rat == NULL)
return;
TAILQ_REMOVE(&ra_timer, rat, rat_next);
free(rat);
}
void
rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *rat)
{
struct timeval now;
/* reset the timer */
gettimeofday(&now, NULL);
TIMEVAL_ADD(&now, tm, &timer->tm);
TIMEVAL_ADD(&now, tm, &rat->rat_tm);
/* update the next expiration time */
if (TIMEVAL_LT(timer->tm, timer_head.tm))
timer_head.tm = timer->tm;
if (TIMEVAL_LT(&rat->rat_tm, &tm_max))
tm_max = rat->rat_tm;
return;
}
@ -119,58 +121,52 @@ rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
* Return the next interval for select() call.
*/
struct timeval *
rtadvd_check_timer()
rtadvd_check_timer(void)
{
static struct timeval returnval;
struct timeval now;
struct rtadvd_timer *tm = timer_head.next, *tm_next;
struct rtadvd_timer *rat;
gettimeofday(&now, NULL);
timer_head.tm = tm_max;
for (tm = timer_head.next; tm != &timer_head; tm = tm_next) {
tm_next = tm->next;
if (TIMEVAL_LEQ(tm->tm, now)) {
if (((*tm->expire)(tm->expire_data) == NULL))
tm_max = tm_limit;
TAILQ_FOREACH(rat, &ra_timer, rat_next) {
if (TIMEVAL_LEQ(&rat->rat_tm, &now)) {
if (((*rat->rat_expire)(rat->rat_expire_data) == NULL))
continue; /* the timer was removed */
if (tm->update)
(*tm->update)(tm->update_data, &tm->tm);
TIMEVAL_ADD(&tm->tm, &now, &tm->tm);
if (rat->rat_update)
(*rat->rat_update)(rat->rat_update_data, &rat->rat_tm);
TIMEVAL_ADD(&rat->rat_tm, &now, &rat->rat_tm);
}
if (TIMEVAL_LT(tm->tm, timer_head.tm))
timer_head.tm = tm->tm;
if (TIMEVAL_LT(&rat->rat_tm, &tm_max))
tm_max = rat->rat_tm;
}
if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) {
if (TIMEVAL_EQUAL(&tm_max, &tm_limit)) {
/* no need to timeout */
return(NULL);
} else if (TIMEVAL_LT(timer_head.tm, now)) {
return (NULL);
} else if (TIMEVAL_LT(&tm_max, &now)) {
/* this may occur when the interval is too small */
returnval.tv_sec = returnval.tv_usec = 0;
} else
TIMEVAL_SUB(&timer_head.tm, &now, &returnval);
return(&returnval);
TIMEVAL_SUB(&tm_max, &now, &returnval);
return (&returnval);
}
struct timeval *
rtadvd_timer_rest(struct rtadvd_timer *timer)
rtadvd_timer_rest(struct rtadvd_timer *rat)
{
static struct timeval returnval, now;
gettimeofday(&now, NULL);
if (TIMEVAL_LEQ(timer->tm, now)) {
if (TIMEVAL_LEQ(&rat->rat_tm, &now)) {
syslog(LOG_DEBUG,
"<%s> a timer must be expired, but not yet",
__func__);
"<%s> a timer must be expired, but not yet",
__func__);
returnval.tv_sec = returnval.tv_usec = 0;
}
else
TIMEVAL_SUB(&timer->tm, &now, &returnval);
TIMEVAL_SUB(&rat->rat_tm, &now, &returnval);
return(&returnval);
return (&returnval);
}
/* result = a + b */

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 1998 WIDE Project.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -31,35 +31,42 @@
*/
/* a < b */
#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\
(((a).tv_sec == (b).tv_sec) && \
((a).tv_usec < (b).tv_usec)))
#define TIMEVAL_LT(a, b) \
(((a)->tv_sec < (b)->tv_sec) || \
(((a)->tv_sec == (b)->tv_sec) && \
((a)->tv_usec < (b)->tv_usec)))
/* a <= b */
#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\
(((a).tv_sec == (b).tv_sec) &&\
((a).tv_usec <= (b).tv_usec)))
#define TIMEVAL_LEQ(a, b) \
(((a)->tv_sec < (b)->tv_sec) || \
(((a)->tv_sec == (b)->tv_sec) && \
((a)->tv_usec <= (b)->tv_usec)))
#define TIMEVAL_EQUAL(a,b) \
(((a)->tv_sec == (b)->tv_sec) && \
((a)->tv_usec == (b)->tv_usec))
extern TAILQ_HEAD(rtadvd_timer_head_t, rtadvd_timer) ra_timer;
struct rtadvd_timer {
struct rtadvd_timer *next;
struct rtadvd_timer *prev;
struct rainfo *rai;
struct timeval tm;
TAILQ_ENTRY(rtadvd_timer) rat_next;
struct rtadvd_timer *(*expire)(void *); /* expiration function */
void *expire_data;
void (*update)(void *, struct timeval *); /* update function */
void *update_data;
struct rainfo *rat_rai;
struct timeval rat_tm;
struct rtadvd_timer *(*rat_expire)(void *);
void *rat_expire_data;
void (*rat_update)(void *, struct timeval *);
void *rat_update_data;
};
void rtadvd_timer_init(void);
struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *),
void (*)(void *, struct timeval *), void *, void *);
void rtadvd_set_timer(struct timeval *, struct rtadvd_timer *);
void rtadvd_remove_timer(struct rtadvd_timer **);
struct timeval * rtadvd_check_timer(void);
struct timeval * rtadvd_timer_rest(struct rtadvd_timer *);
void TIMEVAL_ADD(struct timeval *, struct timeval *,
struct timeval *);
void TIMEVAL_SUB(struct timeval *, struct timeval *,
struct timeval *);
void rtadvd_timer_init(void);
struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *),
void (*)(void *, struct timeval *), void *, void *);
void rtadvd_set_timer(struct timeval *,
struct rtadvd_timer *);
void rtadvd_remove_timer(struct rtadvd_timer *);
struct timeval *rtadvd_check_timer(void);
struct timeval *rtadvd_timer_rest(struct rtadvd_timer *);
void TIMEVAL_ADD(struct timeval *, struct timeval *,
struct timeval *);
void TIMEVAL_SUB(struct timeval *, struct timeval *,
struct timeval *);

View File

@ -19,7 +19,6 @@ MAN= rtsold.8
MLINKS= rtsold.8 rtsol.8
SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c
WARNS?= 3
CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H
DPADD= ${LIBKVM}
LDADD= -lkvm

View File

@ -34,6 +34,7 @@
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <net/if.h>
#include <netinet/in.h>
@ -58,41 +59,41 @@ static const char * const ifstatstr[] = {"IDLE", "DELAY", "PROBE", "DOWN", "TENT
static void
dump_interface_status(void)
{
struct ifinfo *ifinfo;
struct ifinfo *ifi;
struct timeval now;
gettimeofday(&now, NULL);
for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
fprintf(fp, "Interface %s\n", ifinfo->ifname);
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
fprintf(fp, "Interface %s\n", ifi->ifname);
fprintf(fp, " probe interval: ");
if (ifinfo->probeinterval) {
fprintf(fp, "%d\n", ifinfo->probeinterval);
fprintf(fp, " probe timer: %d\n", ifinfo->probetimer);
if (ifi->probeinterval) {
fprintf(fp, "%d\n", ifi->probeinterval);
fprintf(fp, " probe timer: %d\n", ifi->probetimer);
} else {
fprintf(fp, "infinity\n");
fprintf(fp, " no probe timer\n");
}
fprintf(fp, " interface status: %s\n",
ifinfo->active > 0 ? "active" : "inactive");
ifi->active > 0 ? "active" : "inactive");
fprintf(fp, " other config: %s\n",
ifinfo->otherconfig ? "on" : "off");
fprintf(fp, " rtsold status: %s\n", ifstatstr[ifinfo->state]);
ifi->otherconfig ? "on" : "off");
fprintf(fp, " rtsold status: %s\n", ifstatstr[ifi->state]);
fprintf(fp, " carrier detection: %s\n",
ifinfo->mediareqok ? "available" : "unavailable");
ifi->mediareqok ? "available" : "unavailable");
fprintf(fp, " probes: %d, dadcount = %d\n",
ifinfo->probes, ifinfo->dadcount);
if (ifinfo->timer.tv_sec == tm_max.tv_sec &&
ifinfo->timer.tv_usec == tm_max.tv_usec)
ifi->probes, ifi->dadcount);
if (ifi->timer.tv_sec == tm_max.tv_sec &&
ifi->timer.tv_usec == tm_max.tv_usec)
fprintf(fp, " no timer\n");
else {
fprintf(fp, " timer: interval=%d:%d, expire=%s\n",
(int)ifinfo->timer.tv_sec,
(int)ifinfo->timer.tv_usec,
(ifinfo->expire.tv_sec < now.tv_sec) ? "expired"
: sec2str(ifinfo->expire.tv_sec - now.tv_sec));
(int)ifi->timer.tv_sec,
(int)ifi->timer.tv_usec,
(ifi->expire.tv_sec < now.tv_sec) ? "expired"
: sec2str(ifi->expire.tv_sec - now.tv_sec));
}
fprintf(fp, " number of valid RAs: %d\n", ifinfo->racnt);
fprintf(fp, " number of valid RAs: %d\n", ifi->racnt);
}
}
@ -145,5 +146,6 @@ sec2str(time_t total)
p += n;
}
snprintf(p, ep - p, "%ds", secs);
return(result);
return (result);
}

View File

@ -91,25 +91,25 @@ interface_up(char *name)
if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s",
strerror(errno));
return(-1);
return (-1);
}
if (!(ifr.ifr_flags & IFF_UP)) {
ifr.ifr_flags |= IFF_UP;
if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
warnmsg(LOG_ERR, __func__,
"ioctl(SIOCSIFFLAGS): %s", strerror(errno));
return(-1);
return (-1);
}
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
warnmsg(LOG_WARNING, __func__, "socket(AF_INET6, SOCK_DGRAM): %s",
strerror(errno));
return(-1);
return (-1);
}
if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFINFO_IN6): %s",
strerror(errno));
close(s);
return(-1);
return (-1);
}
warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name);
@ -122,13 +122,13 @@ interface_up(char *name)
"ioctl(SIOCSIFINFO_IN6): %s",
strerror(errno));
close(s);
return(-1);
return (-1);
}
} else {
warnmsg(LOG_WARNING, __func__,
"%s is disabled.", name);
close(s);
return(-1);
return (-1);
}
}
if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) {
@ -139,13 +139,13 @@ interface_up(char *name)
"ioctl(SIOCSIFINFO_IN6): %s",
strerror(errno));
close(s);
return(-1);
return (-1);
}
} else {
warnmsg(LOG_WARNING, __func__,
"%s does not accept Router Advertisement.", name);
close(s);
return(-1);
return (-1);
}
}
close(s);
@ -154,22 +154,22 @@ interface_up(char *name)
if (llflag < 0) {
warnmsg(LOG_WARNING, __func__,
"get_llflag() failed, anyway I'll try");
return 0;
return (0);
}
if (!(llflag & IN6_IFF_NOTREADY)) {
warnmsg(LOG_DEBUG, __func__, "%s is ready", name);
return(0);
return (0);
} else {
if (llflag & IN6_IFF_TENTATIVE) {
warnmsg(LOG_DEBUG, __func__, "%s is tentative",
name);
return IFS_TENTATIVE;
return (IFS_TENTATIVE);
}
if (llflag & IN6_IFF_DUPLICATED)
warnmsg(LOG_DEBUG, __func__, "%s is duplicated",
name);
return -1;
return (-1);
}
}
@ -186,16 +186,14 @@ interface_status(struct ifinfo *ifinfo)
if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s",
ifname, strerror(errno));
return(-1);
return (-1);
}
/*
* if one of UP and RUNNING flags is dropped,
* the interface is not active.
*/
if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
goto inactive;
}
/* Next, check carrier on the interface, if possible */
if (!ifinfo->mediareqok)
goto active;
@ -232,10 +230,10 @@ interface_status(struct ifinfo *ifinfo)
}
inactive:
return(0);
return (0);
active:
return(1);
return (1);
}
#define ROUNDUP(a, size) \
@ -254,9 +252,9 @@ lladdropt_length(struct sockaddr_dl *sdl)
#ifdef IFT_IEEE80211
case IFT_IEEE80211:
#endif
return(ROUNDUP8(ETHER_ADDR_LEN + 2));
return (ROUNDUP8(ETHER_ADDR_LEN + 2));
default:
return(0);
return (0);
}
}
@ -301,7 +299,7 @@ if_nametosdl(char *name)
return(NULL);
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
free(buf);
return(NULL);
return (NULL);
}
lim = buf + len;
@ -327,17 +325,17 @@ if_nametosdl(char *name)
if (next == lim) {
/* search failed */
free(buf);
return(NULL);
return (NULL);
}
if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) {
free(buf);
return(NULL);
return (NULL);
}
memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len);
free(buf);
return(ret_sdl);
return (ret_sdl);
}
int
@ -350,9 +348,9 @@ getinet6sysctl(int code)
mib[3] = code;
size = sizeof(value);
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0)
return -1;
return (-1);
else
return value;
return (value);
}
int
@ -366,9 +364,9 @@ setinet6sysctl(int code, int newval)
size = sizeof(value);
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size,
&newval, sizeof(newval)) < 0)
return -1;
return (-1);
else
return value;
return (value);
}
/*------------------------------------------------------------*/
@ -414,12 +412,12 @@ get_llflag(const char *name)
freeifaddrs(ifap);
close(s);
return ifr6.ifr_ifru.ifru_flags6;
return (ifr6.ifr_ifru.ifru_flags6);
}
freeifaddrs(ifap);
close(s);
return -1;
return (-1);
}

View File

@ -72,18 +72,18 @@ probe_init(void)
if (sndcmsgbuf == NULL &&
(sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) {
warnmsg(LOG_ERR, __func__, "malloc failed");
return(-1);
return (-1);
}
if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
return(-1);
return (-1);
}
/* make the socket send-only */
if (shutdown(probesock, 0)) {
warnmsg(LOG_ERR, __func__, "shutdown: %s", strerror(errno));
return(-1);
return (-1);
}
/* initialize msghdr for sending packets */
@ -92,7 +92,8 @@ probe_init(void)
sndmhdr.msg_iovlen = 1;
sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
sndmhdr.msg_controllen = scmsglen;
return(0);
return (0);
}
/*

View File

@ -83,7 +83,7 @@ int
rtsock_open(void)
{
return socket(PF_ROUTE, SOCK_RAW, 0);
return (socket(PF_ROUTE, SOCK_RAW, 0));
}
int
@ -130,7 +130,7 @@ rtsock_input(int s)
}
}
return ret;
return (ret);
}
#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
@ -142,7 +142,7 @@ rtsock_input_ifannounce(int s __unused, struct rt_msghdr *rtm, char *lim)
ifan = (struct if_announcemsghdr *)rtm;
if ((char *)(ifan + 1) > lim)
return -1;
return (-1);
switch (ifan->ifan_what) {
case IFAN_ARRIVAL:
@ -170,6 +170,6 @@ rtsock_input_ifannounce(int s __unused, struct rt_msghdr *rtm, char *lim)
break;
}
return 0;
return (0);
}
#endif

View File

@ -2,6 +2,7 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* Copyright (C) 2011 Hiroki Sato
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -43,13 +44,16 @@
#include <net/route.h>
#include <net/if_dl.h>
#define __BSD_VISIBLE 1 /* IN6ADDR_LINKLOCAL_ALLROUTERS_INIT */
#include <netinet/in.h>
#undef __BSD_VISIBLE
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
@ -61,8 +65,6 @@
#include <syslog.h>
#include "rtsold.h"
#define ALLROUTER "ff02::2"
static struct msghdr rcvmhdr;
static struct msghdr sndmhdr;
static struct iovec rcviov[2];
@ -71,15 +73,40 @@ static struct sockaddr_in6 from;
static int rcvcmsglen;
int rssock;
struct ifinfo_head_t ifinfo_head =
TAILQ_HEAD_INITIALIZER(ifinfo_head);
static struct sockaddr_in6 sin6_allrouters = {
static const struct sockaddr_in6 sin6_allrouters = {
.sin6_len = sizeof(sin6_allrouters),
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
};
static void call_script(char *, char *);
static void call_script(const int, const char *const *, void *);
static size_t dname_labeldec(char *, size_t, const char *);
static int safefile(const char *);
#define _ARGS_OTHER otherconf_script, ifi->ifname
#define _ARGS_RESADD resolvconf_script, "-a", ifi->ifname
#define _ARGS_RESDEL resolvconf_script, "-d", ifi->ifname
#define CALL_SCRIPT(name, sm_head) \
do { \
const char *const sarg[] = { _ARGS_##name, NULL }; \
call_script(sizeof(sarg), sarg, sm_head); \
} while(0)
#define ELM_MALLOC(p,error_action) \
do { \
p = malloc(sizeof(*p)); \
if (p == NULL) { \
warnmsg(LOG_ERR, __func__, "malloc failed: %s", \
strerror(errno)); \
error_action; \
} \
memset(p, 0, sizeof(*p)); \
} while(0)
int
sockopen(void)
{
@ -93,63 +120,35 @@ sockopen(void)
if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
warnmsg(LOG_ERR, __func__,
"malloc for receive msghdr failed");
return(-1);
return (-1);
}
if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) {
warnmsg(LOG_ERR, __func__,
"malloc for send msghdr failed");
return(-1);
return (-1);
}
memset(&sin6_allrouters, 0, sizeof(struct sockaddr_in6));
sin6_allrouters.sin6_family = AF_INET6;
sin6_allrouters.sin6_len = sizeof(sin6_allrouters);
if (inet_pton(AF_INET6, ALLROUTER,
&sin6_allrouters.sin6_addr.s6_addr) != 1) {
warnmsg(LOG_ERR, __func__, "inet_pton failed for %s",
ALLROUTER);
return(-1);
}
if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
return(-1);
return (-1);
}
/* specify to tell receiving interface */
on = 1;
#ifdef IPV6_RECVPKTINFO
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
sizeof(on)) < 0) {
warnmsg(LOG_ERR, __func__, "IPV6_RECVPKTINFO: %s",
strerror(errno));
exit(1);
}
#else /* old adv. API */
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
sizeof(on)) < 0) {
warnmsg(LOG_ERR, __func__, "IPV6_PKTINFO: %s",
strerror(errno));
exit(1);
}
#endif
on = 1;
/* specify to tell value of hoplimit field of received IP6 hdr */
#ifdef IPV6_RECVHOPLIMIT
on = 1;
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
sizeof(on)) < 0) {
warnmsg(LOG_ERR, __func__, "IPV6_RECVHOPLIMIT: %s",
strerror(errno));
exit(1);
}
#else /* old adv. API */
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
sizeof(on)) < 0) {
warnmsg(LOG_ERR, __func__, "IPV6_HOPLIMIT: %s",
strerror(errno));
exit(1);
}
#endif
/* specfiy to accept only router advertisements on the socket */
ICMP6_FILTER_SETBLOCKALL(&filt);
@ -176,11 +175,11 @@ sockopen(void)
sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
sndmhdr.msg_controllen = sndcmsglen;
return(rssock);
return (rssock);
}
void
sendpacket(struct ifinfo *ifinfo)
sendpacket(struct ifinfo *ifi)
{
struct in6_pktinfo *pi;
struct cmsghdr *cm;
@ -189,11 +188,11 @@ sendpacket(struct ifinfo *ifinfo)
struct sockaddr_in6 dst;
dst = sin6_allrouters;
dst.sin6_scope_id = ifinfo->linkid;
dst.sin6_scope_id = ifi->linkid;
sndmhdr.msg_name = (caddr_t)&dst;
sndmhdr.msg_iov[0].iov_base = (caddr_t)ifinfo->rs_data;
sndmhdr.msg_iov[0].iov_len = ifinfo->rs_datalen;
sndmhdr.msg_iov[0].iov_base = (caddr_t)ifi->rs_data;
sndmhdr.msg_iov[0].iov_len = ifi->rs_datalen;
cm = CMSG_FIRSTHDR(&sndmhdr);
/* specify the outgoing interface */
@ -202,7 +201,7 @@ sendpacket(struct ifinfo *ifinfo)
cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
pi = (struct in6_pktinfo *)CMSG_DATA(cm);
memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
pi->ipi6_ifindex = ifinfo->sdl->sdl_index;
pi->ipi6_ifindex = ifi->sdl->sdl_index;
/* specify the hop limit of the packet */
cm = CMSG_NXTHDR(&sndmhdr, cm);
@ -213,38 +212,50 @@ sendpacket(struct ifinfo *ifinfo)
warnmsg(LOG_DEBUG, __func__,
"send RS on %s, whose state is %d",
ifinfo->ifname, ifinfo->state);
ifi->ifname, ifi->state);
i = sendmsg(rssock, &sndmhdr, 0);
if (i < 0 || (size_t)i != ifinfo->rs_datalen) {
if (i < 0 || (size_t)i != ifi->rs_datalen) {
/*
* ENETDOWN is not so serious, especially when using several
* network cards on a mobile node. We ignore it.
*/
if (errno != ENETDOWN || dflag > 0)
warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s",
ifinfo->ifname, strerror(errno));
ifi->ifname, strerror(errno));
}
/* update counter */
ifinfo->probes++;
ifi->probes++;
}
void
rtsol_input(int s)
{
u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
int ifindex = 0, *hlimp = NULL;
ssize_t i;
int l, ifindex = 0, *hlimp = NULL;
ssize_t msglen;
struct in6_pktinfo *pi = NULL;
struct ifinfo *ifi = NULL;
struct ra_opt *rao = NULL;
struct icmp6_hdr *icp;
struct nd_router_advert *nd_ra;
struct cmsghdr *cm;
char *raoptp;
char *p;
struct in6_addr *addr;
struct nd_opt_hdr *ndo;
struct nd_opt_rdnss *rdnss;
struct nd_opt_dnssl *dnssl;
size_t len;
char nsbuf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ + 1];
char dname[NI_MAXHOST];
struct timeval now;
struct timeval lifetime;
/* get message. namelen and controllen must always be initialized. */
rcvmhdr.msg_namelen = sizeof(from);
rcvmhdr.msg_controllen = rcvcmsglen;
if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) {
if ((msglen = recvmsg(s, &rcvmhdr, 0)) < 0) {
warnmsg(LOG_ERR, __func__, "recvmsg: %s", strerror(errno));
return;
}
@ -275,9 +286,9 @@ rtsol_input(int s)
return;
}
if ((size_t)i < sizeof(struct nd_router_advert)) {
if ((size_t)msglen < sizeof(struct nd_router_advert)) {
warnmsg(LOG_INFO, __func__,
"packet size(%zd) is too short", i);
"packet size(%zd) is too short", msglen);
return;
}
@ -354,9 +365,157 @@ rtsol_input(int s)
warnmsg(LOG_DEBUG, __func__,
"OtherConfigFlag on %s is turned on", ifi->ifname);
ifi->otherconfig = 1;
call_script(otherconf_script, ifi->ifname);
CALL_SCRIPT(OTHER, NULL);
}
/* Initialize ra_opt per-interface structure. */
gettimeofday(&now, NULL);
if (!TAILQ_EMPTY(&ifi->ifi_ra_opt))
while ((rao = TAILQ_FIRST(&ifi->ifi_ra_opt)) != NULL) {
if (rao->rao_msg != NULL)
free(rao->rao_msg);
TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
free(rao);
}
else
TAILQ_INIT(&ifi->ifi_ra_opt);
#define RA_OPT_NEXT_HDR(x) (struct nd_opt_hdr *)((char *)x + \
(((struct nd_opt_hdr *)x)->nd_opt_len * 8))
/* Process RA options. */
warnmsg(LOG_DEBUG, __func__, "Processing RA");
raoptp = (char *)icp + sizeof(struct nd_router_advert);
while (raoptp < (char *)icp + msglen) {
ndo = (struct nd_opt_hdr *)raoptp;
warnmsg(LOG_DEBUG, __func__, "ndo = %p", raoptp);
warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_type = %d",
ndo->nd_opt_type);
warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_len = %d",
ndo->nd_opt_len);
switch (ndo->nd_opt_type) {
case ND_OPT_RDNSS:
rdnss = (struct nd_opt_rdnss *)raoptp;
/* Optlen sanity check (Section 5.3.1 in RFC 6106) */
if (rdnss->nd_opt_rdnss_len < 3) {
warnmsg(LOG_INFO, __func__,
"too short RDNSS option"
"in RA from %s was ignored.",
inet_ntop(AF_INET6, &from.sin6_addr,
ntopbuf, INET6_ADDRSTRLEN));
break;
}
addr = (struct in6_addr *)(raoptp + sizeof(*rdnss));
while ((char *)addr < (char *)RA_OPT_NEXT_HDR(raoptp)) {
if (inet_ntop(AF_INET6, addr, ntopbuf,
INET6_ADDRSTRLEN) == NULL) {
warnmsg(LOG_INFO, __func__,
"an invalid address in RDNSS option"
" in RA from %s was ignored.",
inet_ntop(AF_INET6, &from.sin6_addr,
ntopbuf, INET6_ADDRSTRLEN));
addr++;
continue;
}
if (IN6_IS_ADDR_LINKLOCAL(addr))
/* XXX: % has to be escaped here */
l = snprintf(nsbuf, sizeof(nsbuf),
"%s%c%s", ntopbuf,
SCOPE_DELIMITER,
ifi->ifname);
else
l = snprintf(nsbuf, sizeof(nsbuf),
"%s", ntopbuf);
if (l < 0 || (size_t)l >= sizeof(nsbuf)) {
warnmsg(LOG_ERR, __func__,
"address copying error in "
"RDNSS option: %d.", l);
addr++;
continue;
}
warnmsg(LOG_DEBUG, __func__, "nsbuf = %s",
nsbuf);
ELM_MALLOC(rao, break);
rao->rao_type = ndo->nd_opt_type;
rao->rao_len = strlen(nsbuf);
rao->rao_msg = strdup(nsbuf);
if (rao->rao_msg == NULL) {
warnmsg(LOG_ERR, __func__,
"strdup failed: %s",
strerror(errno));
free(rao);
addr++;
continue;
}
/* Set expiration timer */
memset(&rao->rao_expire, 0, sizeof(rao->rao_expire));
memset(&lifetime, 0, sizeof(lifetime));
lifetime.tv_sec = ntohl(rdnss->nd_opt_rdnss_lifetime);
timeradd(&now, &lifetime, &rao->rao_expire);
TAILQ_INSERT_TAIL(&ifi->ifi_ra_opt, rao, rao_next);
addr++;
}
break;
case ND_OPT_DNSSL:
dnssl = (struct nd_opt_dnssl *)raoptp;
/* Optlen sanity check (Section 5.3.1 in RFC 6106) */
if (dnssl->nd_opt_dnssl_len < 2) {
warnmsg(LOG_INFO, __func__,
"too short DNSSL option"
"in RA from %s was ignored.",
inet_ntop(AF_INET6, &from.sin6_addr,
ntopbuf, INET6_ADDRSTRLEN));
break;
}
/*
* Ensure NUL-termination in DNSSL in case of
* malformed field.
*/
p = (char *)RA_OPT_NEXT_HDR(raoptp);
*(p - 1) = '\0';
p = raoptp + sizeof(*dnssl);
while (1 < (len = dname_labeldec(dname, sizeof(dname),
p))) {
/* length == 1 means empty string */
warnmsg(LOG_DEBUG, __func__, "dname = %s",
dname);
ELM_MALLOC(rao, break);
rao->rao_type = ndo->nd_opt_type;
rao->rao_len = strlen(dname);
rao->rao_msg = strdup(dname);
if (rao->rao_msg == NULL) {
warnmsg(LOG_ERR, __func__,
"strdup failed: %s",
strerror(errno));
free(rao);
break;
}
/* Set expiration timer */
memset(&rao->rao_expire, 0, sizeof(rao->rao_expire));
memset(&lifetime, 0, sizeof(lifetime));
lifetime.tv_sec = ntohl(dnssl->nd_opt_dnssl_lifetime);
timeradd(&now, &lifetime, &rao->rao_expire);
TAILQ_INSERT_TAIL(&ifi->ifi_ra_opt, rao, rao_next);
p += len;
}
break;
default:
/* nothing to do for other options */
break;
}
raoptp = (char *)RA_OPT_NEXT_HDR(raoptp);
}
ra_opt_handler(ifi);
ifi->racnt++;
switch (ifi->state) {
@ -371,23 +530,166 @@ rtsol_input(int s)
}
}
static void
call_script(char *scriptpath, char *ifname)
{
pid_t pid, wpid;
static char resstr_ns_prefix[] = "nameserver ";
static char resstr_sh_prefix[] = "search ";
static char resstr_nl[] = "\n";
static char resstr_sp[] = " ";
if (scriptpath == NULL)
int
ra_opt_handler(struct ifinfo *ifi)
{
struct ra_opt *rao;
struct script_msg *smp1, *smp2, *smp3;
struct timeval now;
TAILQ_HEAD(, script_msg) sm_rdnss_head =
TAILQ_HEAD_INITIALIZER(sm_rdnss_head);
TAILQ_HEAD(, script_msg) sm_dnssl_head =
TAILQ_HEAD_INITIALIZER(sm_dnssl_head);
int dcount, dlen;
dcount = 0;
dlen = strlen(resstr_sh_prefix) + strlen(resstr_nl);
gettimeofday(&now, NULL);
TAILQ_FOREACH(rao, &ifi->ifi_ra_opt, rao_next) {
switch (rao->rao_type) {
case ND_OPT_RDNSS:
if (timercmp(&now, &rao->rao_expire, >)) {
warnmsg(LOG_INFO, __func__,
"expired rdnss entry: %s",
(char *)rao->rao_msg);
break;
}
ELM_MALLOC(smp1, continue);
ELM_MALLOC(smp2, goto free1);
ELM_MALLOC(smp3, goto free2);
smp1->sm_msg = resstr_ns_prefix;
TAILQ_INSERT_TAIL(&sm_rdnss_head, smp1, sm_next);
smp2->sm_msg = rao->rao_msg;
TAILQ_INSERT_TAIL(&sm_rdnss_head, smp2, sm_next);
smp3->sm_msg = resstr_nl;
TAILQ_INSERT_TAIL(&sm_rdnss_head, smp3, sm_next);
break;
case ND_OPT_DNSSL:
if (timercmp(&now, &rao->rao_expire, >)) {
warnmsg(LOG_INFO, __func__,
"expired dnssl entry: %s",
(char *)rao->rao_msg);
break;
}
dcount++;
/* Check resolv.conf(5) restrictions. */
if (dcount > 6) {
warnmsg(LOG_INFO, __func__,
"dnssl entry exceeding maximum count (%d>6)"
": %s", dcount, (char *)rao->rao_msg);
break;
}
if (256 < dlen + strlen(rao->rao_msg) +
strlen(resstr_sp)) {
warnmsg(LOG_INFO, __func__,
"dnssl entry exceeding maximum length "
"(>256): %s", (char *)rao->rao_msg);
break;
}
ELM_MALLOC(smp1, continue);
ELM_MALLOC(smp2, goto free1);
if (TAILQ_EMPTY(&sm_dnssl_head)) {
ELM_MALLOC(smp3, goto free2);
smp3->sm_msg = resstr_sh_prefix;
TAILQ_INSERT_TAIL(&sm_dnssl_head, smp3,
sm_next);
}
smp1->sm_msg = rao->rao_msg;
TAILQ_INSERT_TAIL(&sm_dnssl_head, smp1, sm_next);
smp2->sm_msg = resstr_sp;
TAILQ_INSERT_TAIL(&sm_dnssl_head, smp2, sm_next);
dlen += strlen(rao->rao_msg) + strlen(resstr_sp);
break;
default:
break;
}
continue;
free2:
free(smp2);
free1:
free(smp1);
}
/* Add \n for DNSSL list. */
if (!TAILQ_EMPTY(&sm_dnssl_head)) {
ELM_MALLOC(smp1, goto ra_opt_handler_freeit);
smp1->sm_msg = resstr_nl;
TAILQ_INSERT_TAIL(&sm_dnssl_head, smp1, sm_next);
}
TAILQ_CONCAT(&sm_rdnss_head, &sm_dnssl_head, sm_next);
if (!TAILQ_EMPTY(&sm_rdnss_head))
CALL_SCRIPT(RESADD, &sm_rdnss_head);
else
CALL_SCRIPT(RESDEL, NULL);
ra_opt_handler_freeit:
/* Clear script message queue. */
if (!TAILQ_EMPTY(&sm_rdnss_head)) {
while ((smp1 = TAILQ_FIRST(&sm_rdnss_head)) != NULL) {
TAILQ_REMOVE(&sm_rdnss_head, smp1, sm_next);
free(smp1);
}
}
return (0);
}
static void
call_script(const int argc, const char *const argv[], void *head)
{
const char *scriptpath;
int fd[2];
int error;
pid_t pid, wpid;
TAILQ_HEAD(, script_msg) *sm_head;
if ((scriptpath = argv[0]) == NULL)
return;
fd[0] = fd[1] = -1;
sm_head = head;
if (sm_head != NULL && !TAILQ_EMPTY(sm_head)) {
error = pipe(fd);
if (error) {
warnmsg(LOG_ERR, __func__,
"failed to create a pipe: %s", strerror(errno));
return;
}
}
/* launch the script */
pid = fork();
if (pid < 0) {
warnmsg(LOG_ERR, __func__,
"failed to fork: %s", strerror(errno));
return;
} else if (pid) {
} else if (pid) { /* parent */
int wstatus;
if (fd[0] != -1) { /* Send message to the child if any. */
ssize_t len;
struct script_msg *smp;
close(fd[0]);
TAILQ_FOREACH(smp, sm_head, sm_next) {
len = strlen(smp->sm_msg);
warnmsg(LOG_DEBUG, __func__,
"write to child = %s(%zd)",
smp->sm_msg, len);
if (write(fd[1], smp->sm_msg, len) != len) {
warnmsg(LOG_ERR, __func__,
"write to child failed: %s",
strerror(errno));
break;
}
}
close(fd[1]);
}
do {
wpid = wait(&wstatus);
} while (wpid != pid && wpid > 0);
@ -395,17 +697,12 @@ call_script(char *scriptpath, char *ifname)
if (wpid < 0)
warnmsg(LOG_ERR, __func__,
"wait: %s", strerror(errno));
else {
else
warnmsg(LOG_DEBUG, __func__,
"script \"%s\" terminated", scriptpath);
}
} else {
char *argv[3];
int fd;
argv[0] = scriptpath;
argv[1] = ifname;
argv[2] = NULL;
} else { /* child */
int nullfd;
char **_argv;
if (safefile(scriptpath)) {
warnmsg(LOG_ERR, __func__,
@ -413,20 +710,42 @@ call_script(char *scriptpath, char *ifname)
scriptpath);
exit(1);
}
if ((fd = open("/dev/null", O_RDWR)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO)
close(fd);
nullfd = open("/dev/null", O_RDWR);
if (nullfd < 0) {
warnmsg(LOG_ERR, __func__,
"open /dev/null: %s", strerror(errno));
exit(1);
}
if (fd[0] != -1) { /* Receive message from STDIN if any. */
close(fd[1]);
if (fd[0] != STDIN_FILENO) {
/* Connect a pipe read-end to child's STDIN. */
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
warnmsg(LOG_ERR, __func__,
"dup2 STDIN: %s", strerror(errno));
exit(1);
}
close(fd[0]);
}
} else
dup2(nullfd, STDIN_FILENO);
dup2(nullfd, STDOUT_FILENO);
dup2(nullfd, STDERR_FILENO);
if (nullfd > STDERR_FILENO)
close(nullfd);
execv(scriptpath, argv);
_argv = malloc(sizeof(*_argv) * argc);
if (_argv == NULL) {
warnmsg(LOG_ERR, __func__,
"malloc: %s", strerror(errno));
exit(1);
}
memcpy(_argv, argv, (size_t)argc);
execv(scriptpath, (char *const *)_argv);
warnmsg(LOG_ERR, __func__, "child: exec failed: %s",
strerror(errno));
exit(0);
exit(1);
}
return;
@ -471,3 +790,37 @@ safefile(const char *path)
return (0);
}
/* Decode domain name label encoding in RFC 1035 Section 3.1 */
static size_t
dname_labeldec(char *dst, size_t dlen, const char *src)
{
size_t len;
const char *src_origin;
const char *src_last;
const char *dst_origin;
src_origin = src;
src_last = strchr(src, '\0');
dst_origin = dst;
memset(dst, '\0', dlen);
while (src && (len = (uint8_t)(*src++) & 0x3f) &&
(src + len) <= src_last) {
if (dst != dst_origin)
*dst++ = '.';
warnmsg(LOG_DEBUG, __func__, "labellen = %zd", len);
memcpy(dst, src, len);
src += len;
dst += len;
}
*dst = '\0';
/*
* XXX validate that domain name only contains valid characters
* for two reasons: 1) correctness, 2) we do not want to pass
* possible malicious, unescaped characters like `` to a script
* or program that could be exploited that way.
*/
return (src - src_origin);
}

View File

@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd September 2, 2009
.Dd May 28, 2011
.Dt RTSOLD 8
.Os
.\"
@ -41,18 +41,24 @@
.Nm
.Op Fl dDfFm1
.Op Fl O Ar script-name
.Op Fl P Ar pidfile
.Op Fl R Ar script-name
.Ar interface ...
.Nm
.Op Fl dDfFm1
.Op Fl O Ar script-name
.Op Fl P Ar pidfile
.Op Fl R Ar script-name
.Fl a
.Nm rtsol
.Op Fl dDF
.Op Fl dD
.Op Fl O Ar script-name
.Op Fl R Ar script-name
.Ar interface ...
.Nm rtsol
.Op Fl dD
.Op Fl O Ar script-name
.Op Fl R Ar script-name
.Fl a
.\"
.Sh DESCRIPTION
@ -221,6 +227,24 @@ configuration.
must be the absolute path from root to the script file, be a regular
file, and be created by the same owner who runs
.Nm .
.It Fl P Ar pidfile
Writes the process ID of
.Nm
to
.Pa pidfile
instead of the default PID file
.Pa /var/run/rtsold.pid .
.It Fl R Ar script-name
Specifies a script to run when router advertisment options
.Dv RDNSS Pq Recursive DNS Server
or
.Dv DNSSL Pq DNS Search List
are encountered.
The information of DNS servers and DNS search domains will be sent to
standard input of this script.
The
.Xr resolvconf 8
script is used by default.
.El
.Sh FILES
.Bl -tag -width /var/run/rtsold.dump -compact
@ -235,6 +259,7 @@ dumps internal state on.
.Ex -std
.\"
.Sh SEE ALSO
.Xr resolvconf 8 ,
.Xr rtadvd 8 ,
.Xr sysctl 8
.\"

View File

@ -63,6 +63,9 @@
#include "rtsold.h"
#define RTSOL_DUMPFILE "/var/run/rtsold.dump";
#define RTSOL_PIDFILE "/var/run/rtsold.pid";
struct ifinfo *iflist;
struct timeval tm_max = {0x7fffffff, 0x7fffffff};
static int log_upto = 999;
@ -72,7 +75,8 @@ int Fflag = 0; /* force setting sysctl parameters */
int aflag = 0;
int dflag = 0;
char *otherconf_script;
const char *otherconf_script;
const char *resolvconf_script = "/sbin/resolvconf";
/* protocol constants */
#define MAX_RTR_SOLICITATION_DELAY 1 /* second */
@ -85,35 +89,32 @@ char *otherconf_script;
*/
#define PROBE_INTERVAL 60
int main(int, char **);
/* static variables and functions */
static int mobile_node = 0;
static const char *pidfilename = RTSOL_PIDFILE;
#ifndef SMALL
static int do_dump;
static const char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */
#endif
#if 1
static const char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */
static const char *dumpfilename = RTSOL_DUMPFILE;
#endif
#if 0
static int ifreconfig(char *);
#endif
static int make_packet(struct ifinfo *);
static struct timeval *rtsol_check_timer(void);
#ifndef SMALL
static void rtsold_set_dump_file(int);
#endif
static void usage(char *);
static void usage(void);
int
main(int argc, char **argv)
{
int s, ch, once = 0;
struct timeval *timeout;
char *argv0;
const char *opts;
#ifdef HAVE_POLL_H
struct pollfd set[2];
@ -124,19 +125,15 @@ main(int argc, char **argv)
#endif
int rtsock;
/*
* Initialization
*/
argv0 = argv[0];
/* get option */
if (argv0 && argv0[strlen(argv0) - 1] != 'd') {
fflag = 1;
once = 1;
opts = "adDFO:";
} else
opts = "adDfFm1O:";
#ifndef SMALL
/* rtsold */
opts = "adDfFm1O:P:R:";
#else
/* rtsol */
opts = "adDFO:P:R:";
fflag = 1;
once = 1;
#endif
while ((ch = getopt(argc, argv, opts)) != -1) {
switch (ch) {
case 'a':
@ -163,17 +160,23 @@ main(int argc, char **argv)
case 'O':
otherconf_script = optarg;
break;
case 'P':
pidfilename = optarg;
break;
case 'R':
resolvconf_script = optarg;
break;
default:
usage(argv0);
/*NOTREACHED*/
usage();
exit(1);
}
}
argc -= optind;
argv += optind;
if ((!aflag && argc == 0) || (aflag && argc != 0)) {
usage(argv0);
/*NOTREACHED*/
usage();
exit(1);
}
/* set log level */
@ -182,9 +185,9 @@ main(int argc, char **argv)
if (!fflag) {
char *ident;
ident = strrchr(argv0, '/');
ident = strrchr(argv[0], '/');
if (!ident)
ident = argv0;
ident = argv[0];
else
ident++;
openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON);
@ -196,7 +199,14 @@ main(int argc, char **argv)
errx(1, "configuration script (%s) must be an absolute path",
otherconf_script);
}
if (resolvconf_script && *resolvconf_script != '/') {
errx(1, "configuration script (%s) must be an absolute path",
resolvconf_script);
}
if (pidfilename && *pidfilename != '/') {
errx(1, "pid filename (%s) must be an absolute path",
pidfilename);
}
#ifndef HAVE_ARC4RANDOM
/* random value initialization */
srandom((u_long)time(NULL));
@ -226,7 +236,6 @@ main(int argc, char **argv)
if ((s = sockopen()) < 0) {
warnmsg(LOG_ERR, __func__, "failed to open a socket");
exit(1);
/*NOTREACHED*/
}
#ifdef HAVE_POLL_H
set[0].fd = s;
@ -242,7 +251,6 @@ main(int argc, char **argv)
if ((rtsock = rtsock_open()) < 0) {
warnmsg(LOG_ERR, __func__, "failed to open a socket");
exit(1);
/*NOTREACHED*/
}
#ifdef HAVE_POLL_H
set[1].fd = rtsock;
@ -255,12 +263,12 @@ main(int argc, char **argv)
#ifndef HAVE_POLL_H
fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
if ((fdsetp = malloc(fdmasks)) == NULL) {
err(1, "malloc");
/*NOTREACHED*/
warnmsg(LOG_ERR, __func__, "malloc");
exit(1);
}
if ((selectfdp = malloc(fdmasks)) == NULL) {
err(1, "malloc");
/*NOTREACHED*/
warnmsg(LOG_ERR, __func__, "malloc");
exit(1);
}
#endif
@ -269,7 +277,6 @@ main(int argc, char **argv)
warnmsg(LOG_ERR, __func__,
"failed to initialize interfaces");
exit(1);
/*NOTREACHED*/
}
if (aflag)
argv = autoifprobe();
@ -278,7 +285,6 @@ main(int argc, char **argv)
warnmsg(LOG_ERR, __func__,
"failed to initialize %s", *argv);
exit(1);
/*NOTREACHED*/
}
argv++;
}
@ -291,7 +297,6 @@ main(int argc, char **argv)
/*NOTREACHED*/
}
#if 1
/* dump the current pid */
if (!once) {
pid_t pid = getpid();
@ -306,8 +311,6 @@ main(int argc, char **argv)
fclose(fp);
}
}
#endif
#ifndef HAVE_POLL_H
memset(fdsetp, 0, fdmasks);
FD_SET(s, fdsetp);
@ -337,7 +340,7 @@ main(int argc, char **argv)
break;
/* if all interfaces have got RA packet, we are done */
for (ifi = iflist; ifi; ifi = ifi->next) {
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (ifi->state != IFS_DOWN && ifi->racnt == 0)
break;
}
@ -373,102 +376,97 @@ main(int argc, char **argv)
}
/* NOTREACHED */
return 0;
return (0);
}
int
ifconfig(char *ifname)
{
struct ifinfo *ifinfo;
struct ifinfo *ifi;
struct sockaddr_dl *sdl;
int flags;
if ((sdl = if_nametosdl(ifname)) == NULL) {
warnmsg(LOG_ERR, __func__,
"failed to get link layer information for %s", ifname);
return(-1);
return (-1);
}
if (find_ifinfo(sdl->sdl_index)) {
warnmsg(LOG_ERR, __func__,
"interface %s was already configured", ifname);
free(sdl);
return(-1);
return (-1);
}
if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) {
if ((ifi = malloc(sizeof(*ifi))) == NULL) {
warnmsg(LOG_ERR, __func__, "memory allocation failed");
free(sdl);
return(-1);
return (-1);
}
memset(ifinfo, 0, sizeof(*ifinfo));
ifinfo->sdl = sdl;
memset(ifi, 0, sizeof(*ifi));
ifi->sdl = sdl;
strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname));
strlcpy(ifi->ifname, ifname, sizeof(ifi->ifname));
/* construct a router solicitation message */
if (make_packet(ifinfo))
if (make_packet(ifi))
goto bad;
/* set link ID of this interface. */
#ifdef HAVE_SCOPELIB
if (inet_zoneid(AF_INET6, 2, ifname, &ifinfo->linkid))
if (inet_zoneid(AF_INET6, 2, ifname, &ifi->linkid))
goto bad;
#else
/* XXX: assume interface IDs as link IDs */
ifinfo->linkid = ifinfo->sdl->sdl_index;
ifi->linkid = ifi->sdl->sdl_index;
#endif
/*
* check if the interface is available.
* also check if SIOCGIFMEDIA ioctl is OK on the interface.
*/
ifinfo->mediareqok = 1;
ifinfo->active = interface_status(ifinfo);
if (!ifinfo->mediareqok) {
ifi->mediareqok = 1;
ifi->active = interface_status(ifi);
if (!ifi->mediareqok) {
/*
* probe routers periodically even if the link status
* does not change.
*/
ifinfo->probeinterval = PROBE_INTERVAL;
ifi->probeinterval = PROBE_INTERVAL;
}
/* activate interface: interface_up returns 0 on success */
flags = interface_up(ifinfo->ifname);
flags = interface_up(ifi->ifname);
if (flags == 0)
ifinfo->state = IFS_DELAY;
ifi->state = IFS_DELAY;
else if (flags == IFS_TENTATIVE)
ifinfo->state = IFS_TENTATIVE;
ifi->state = IFS_TENTATIVE;
else
ifinfo->state = IFS_DOWN;
ifi->state = IFS_DOWN;
rtsol_timer_update(ifinfo);
rtsol_timer_update(ifi);
/* link into chain */
if (iflist)
ifinfo->next = iflist;
iflist = ifinfo;
return(0);
TAILQ_INSERT_TAIL(&ifinfo_head, ifi, ifi_next);
return (0);
bad:
free(ifinfo->sdl);
free(ifinfo);
return(-1);
free(ifi->sdl);
free(ifi);
return (-1);
}
void
iflist_init(void)
{
struct ifinfo *ifi, *next;
struct ifinfo *ifi;
for (ifi = iflist; ifi; ifi = next) {
next = ifi->next;
if (ifi->sdl)
while ((ifi = TAILQ_FIRST(&ifinfo_head)) != NULL) {
TAILQ_REMOVE(&ifinfo_head, ifi, ifi_next);
if (ifi->sdl != NULL)
free(ifi->sdl);
if (ifi->rs_data)
if (ifi->rs_data != NULL)
free(ifi->rs_data);
free(ifi);
iflist = NULL;
}
}
@ -480,7 +478,7 @@ ifreconfig(char *ifname)
int rv;
prev = NULL;
for (ifi = iflist; ifi; ifi = ifi->next) {
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0)
break;
prev = ifi;
@ -494,7 +492,8 @@ ifreconfig(char *ifname)
free(ifi->rs_data);
free(ifi->sdl);
free(ifi);
return rv;
return (rv);
}
#endif
@ -503,34 +502,35 @@ find_ifinfo(int ifindex)
{
struct ifinfo *ifi;
for (ifi = iflist; ifi; ifi = ifi->next)
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (ifi->sdl->sdl_index == ifindex)
return(ifi);
return(NULL);
return (ifi);
}
return (NULL);
}
static int
make_packet(struct ifinfo *ifinfo)
make_packet(struct ifinfo *ifi)
{
size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0;
struct nd_router_solicit *rs;
char *buf;
if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) {
if ((lladdroptlen = lladdropt_length(ifi->sdl)) == 0) {
warnmsg(LOG_INFO, __func__,
"link-layer address option has null length"
" on %s. Treat as not included.", ifinfo->ifname);
" on %s. Treat as not included.", ifi->ifname);
}
packlen += lladdroptlen;
ifinfo->rs_datalen = packlen;
ifi->rs_datalen = packlen;
/* allocate buffer */
if ((buf = malloc(packlen)) == NULL) {
warnmsg(LOG_ERR, __func__,
"memory allocation failed for %s", ifinfo->ifname);
return(-1);
"memory allocation failed for %s", ifi->ifname);
return (-1);
}
ifinfo->rs_data = buf;
ifi->rs_data = buf;
/* fill in the message */
rs = (struct nd_router_solicit *)buf;
@ -542,9 +542,9 @@ make_packet(struct ifinfo *ifinfo)
/* fill in source link-layer address option */
if (lladdroptlen)
lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf);
lladdropt_fill(ifi->sdl, (struct nd_opt_hdr *)buf);
return(0);
return (0);
}
static struct timeval *
@ -552,56 +552,64 @@ rtsol_check_timer(void)
{
static struct timeval returnval;
struct timeval now, rtsol_timer;
struct ifinfo *ifinfo;
struct ifinfo *ifi;
struct ra_opt *rao;
int flags;
gettimeofday(&now, NULL);
rtsol_timer = tm_max;
for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
if (timercmp(&ifinfo->expire, &now, <=)) {
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (timercmp(&ifi->expire, &now, <=)) {
if (dflag > 1)
warnmsg(LOG_DEBUG, __func__,
"timer expiration on %s, "
"state = %d", ifinfo->ifname,
ifinfo->state);
"state = %d", ifi->ifname,
ifi->state);
switch (ifinfo->state) {
/* Remove all RA options. */
while ((rao = TAILQ_FIRST(&ifi->ifi_ra_opt)) != NULL) {
if (rao->rao_msg != NULL)
free(rao->rao_msg);
TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
free(rao);
}
switch (ifi->state) {
case IFS_DOWN:
case IFS_TENTATIVE:
/* interface_up returns 0 on success */
flags = interface_up(ifinfo->ifname);
flags = interface_up(ifi->ifname);
if (flags == 0)
ifinfo->state = IFS_DELAY;
ifi->state = IFS_DELAY;
else if (flags == IFS_TENTATIVE)
ifinfo->state = IFS_TENTATIVE;
ifi->state = IFS_TENTATIVE;
else
ifinfo->state = IFS_DOWN;
ifi->state = IFS_DOWN;
break;
case IFS_IDLE:
{
int oldstatus = ifinfo->active;
int oldstatus = ifi->active;
int probe = 0;
ifinfo->active = interface_status(ifinfo);
ifi->active = interface_status(ifi);
if (oldstatus != ifinfo->active) {
if (oldstatus != ifi->active) {
warnmsg(LOG_DEBUG, __func__,
"%s status is changed"
" from %d to %d",
ifinfo->ifname,
oldstatus, ifinfo->active);
ifi->ifname,
oldstatus, ifi->active);
probe = 1;
ifinfo->state = IFS_DELAY;
} else if (ifinfo->probeinterval &&
(ifinfo->probetimer -=
ifinfo->timer.tv_sec) <= 0) {
ifi->state = IFS_DELAY;
} else if (ifi->probeinterval &&
(ifi->probetimer -=
ifi->timer.tv_sec) <= 0) {
/* probe timer expired */
ifinfo->probetimer =
ifinfo->probeinterval;
ifi->probetimer =
ifi->probeinterval;
probe = 1;
ifinfo->state = IFS_PROBE;
ifi->state = IFS_PROBE;
}
/*
@ -609,38 +617,58 @@ rtsol_check_timer(void)
* status wrt the "other" configuration.
*/
if (probe)
ifinfo->otherconfig = 0;
ifi->otherconfig = 0;
if (probe && mobile_node)
defrouter_probe(ifinfo);
defrouter_probe(ifi);
break;
}
case IFS_DELAY:
ifinfo->state = IFS_PROBE;
sendpacket(ifinfo);
ifi->state = IFS_PROBE;
sendpacket(ifi);
break;
case IFS_PROBE:
if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
sendpacket(ifinfo);
if (ifi->probes < MAX_RTR_SOLICITATIONS)
sendpacket(ifi);
else {
warnmsg(LOG_INFO, __func__,
"No answer after sending %d RSs",
ifinfo->probes);
ifinfo->probes = 0;
ifinfo->state = IFS_IDLE;
ifi->probes);
ifi->probes = 0;
ifi->state = IFS_IDLE;
}
break;
}
rtsol_timer_update(ifinfo);
}
rtsol_timer_update(ifi);
} else {
/* Expiration check for RA options. */
struct ra_opt *rao_tmp;
int expire = 0;
if (timercmp(&ifinfo->expire, &rtsol_timer, <))
rtsol_timer = ifinfo->expire;
TAILQ_FOREACH_SAFE(rao, &ifi->ifi_ra_opt, rao_next, rao_tmp) {
warnmsg(LOG_DEBUG, __func__,
"RA expiration timer: "
"type=%d, msg=%s, timer=%ld:%08ld",
rao->rao_type, (char *)rao->rao_msg,
(long)rao->rao_expire.tv_sec,
(long)rao->rao_expire.tv_usec);
if (timercmp(&now, &rao->rao_expire, >=)) {
warnmsg(LOG_DEBUG, __func__,
"RA expiration timer: expired.");
TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
expire = 1;
}
}
if (expire)
ra_opt_handler(ifi);
}
if (timercmp(&ifi->expire, &rtsol_timer, <))
rtsol_timer = ifi->expire;
}
if (timercmp(&rtsol_timer, &tm_max, ==)) {
warnmsg(LOG_DEBUG, __func__, "there is no timer");
return(NULL);
return (NULL);
} else if (timercmp(&rtsol_timer, &now, <))
/* this may occur when the interval is too small */
returnval.tv_sec = returnval.tv_usec = 0;
@ -651,35 +679,35 @@ rtsol_check_timer(void)
warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld",
(long)returnval.tv_sec, (long)returnval.tv_usec);
return(&returnval);
return (&returnval);
}
void
rtsol_timer_update(struct ifinfo *ifinfo)
rtsol_timer_update(struct ifinfo *ifi)
{
#define MILLION 1000000
#define DADRETRY 10 /* XXX: adhoc */
long interval;
struct timeval now;
bzero(&ifinfo->timer, sizeof(ifinfo->timer));
bzero(&ifi->timer, sizeof(ifi->timer));
switch (ifinfo->state) {
switch (ifi->state) {
case IFS_DOWN:
case IFS_TENTATIVE:
if (++ifinfo->dadcount > DADRETRY) {
ifinfo->dadcount = 0;
ifinfo->timer.tv_sec = PROBE_INTERVAL;
if (++ifi->dadcount > DADRETRY) {
ifi->dadcount = 0;
ifi->timer.tv_sec = PROBE_INTERVAL;
} else
ifinfo->timer.tv_sec = 1;
ifi->timer.tv_sec = 1;
break;
case IFS_IDLE:
if (mobile_node) {
/* XXX should be configurable */
ifinfo->timer.tv_sec = 3;
ifi->timer.tv_sec = 3;
}
else
ifinfo->timer = tm_max; /* stop timer(valid?) */
ifi->timer = tm_max; /* stop timer(valid?) */
break;
case IFS_DELAY:
#ifndef HAVE_ARC4RANDOM
@ -687,12 +715,12 @@ rtsol_timer_update(struct ifinfo *ifinfo)
#else
interval = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MILLION);
#endif
ifinfo->timer.tv_sec = interval / MILLION;
ifinfo->timer.tv_usec = interval % MILLION;
ifi->timer.tv_sec = interval / MILLION;
ifi->timer.tv_usec = interval % MILLION;
break;
case IFS_PROBE:
if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
if (ifi->probes < MAX_RTR_SOLICITATIONS)
ifi->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
else {
/*
* After sending MAX_RTR_SOLICITATIONS solicitations,
@ -701,30 +729,30 @@ rtsol_timer_update(struct ifinfo *ifinfo)
* the timer value to MAX_RTR_SOLICITATION_DELAY based
* on RFC 2461, Section 6.3.7.
*/
ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
ifi->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
}
break;
default:
warnmsg(LOG_ERR, __func__,
"illegal interface state(%d) on %s",
ifinfo->state, ifinfo->ifname);
ifi->state, ifi->ifname);
return;
}
/* reset the timer */
if (timercmp(&ifinfo->timer, &tm_max, ==)) {
ifinfo->expire = tm_max;
if (timercmp(&ifi->timer, &tm_max, ==)) {
ifi->expire = tm_max;
warnmsg(LOG_DEBUG, __func__,
"stop timer for %s", ifinfo->ifname);
"stop timer for %s", ifi->ifname);
} else {
gettimeofday(&now, NULL);
timeradd(&now, &ifinfo->timer, &ifinfo->expire);
timeradd(&now, &ifi->timer, &ifi->expire);
if (dflag > 1)
warnmsg(LOG_DEBUG, __func__,
"set timer for %s to %d:%d", ifinfo->ifname,
(int)ifinfo->timer.tv_sec,
(int)ifinfo->timer.tv_usec);
"set timer for %s to %d:%d", ifi->ifname,
(int)ifi->timer.tv_sec,
(int)ifi->timer.tv_usec);
}
#undef MILLION
@ -742,28 +770,23 @@ rtsold_set_dump_file(int sig __unused)
#endif
static void
usage(char *progname)
usage(void)
{
if (progname && progname[strlen(progname) - 1] != 'd') {
fprintf(stderr, "usage: rtsol [-dDF] interfaces...\n");
fprintf(stderr, "usage: rtsol [-dDF] -a\n");
} else {
fprintf(stderr, "usage: rtsold [-adDfFm1] interfaces...\n");
fprintf(stderr, "usage: rtsold [-dDfFm1] -a\n");
}
exit(1);
#ifndef SMALL
fprintf(stderr, "usage: rtsold [-adDfFm1] [-O script-name] "
"[-P pidfile] [-R script-name] interfaces...\n");
fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
"[-P pidfile] [-R script-name] -a\n");
#else
fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
"[-P pidfile] [-R script-name] interfaces...\n");
fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
"[-P pidfile] [-R script-name] -a\n");
#endif
}
void
#if __STDC__
warnmsg(int priority, const char *func, const char *msg, ...)
#else
warnmsg(priority, func, msg, va_alist)
int priority;
const char *func;
const char *msg;
va_dcl
#endif
{
va_list ap;
char buf[BUFSIZ];
@ -805,11 +828,11 @@ autoifprobe(void)
n = 0;
if (getifaddrs(&ifap) != 0)
return NULL;
return (NULL);
if (!Fflag && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
err(1, "socket");
/* NOTREACHED */
warnmsg(LOG_ERR, __func__, "socket");
exit(1);
}
target = NULL;
@ -845,8 +868,9 @@ autoifprobe(void)
memset(&nd, 0, sizeof(nd));
strlcpy(nd.ifname, ifa->ifa_name, sizeof(nd.ifname));
if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
err(1, "ioctl(SIOCGIFINFO_IN6)");
/* NOTREACHED */
warnmsg(LOG_ERR, __func__,
"ioctl(SIOCGIFINFO_IN6)");
exit(1);
}
if ((nd.ndi.flags & ND6_IFF_IFDISABLED))
continue;
@ -856,32 +880,40 @@ autoifprobe(void)
/* if we find multiple candidates, just warn. */
if (n != 0 && dflag > 1)
warnx("multiple interfaces found");
warnmsg(LOG_WARNING, __func__,
"multiple interfaces found");
a = (char **)realloc(argv, (n + 1) * sizeof(char **));
if (a == NULL)
err(1, "realloc");
if (a == NULL) {
warnmsg(LOG_ERR, __func__, "realloc");
exit(1);
}
argv = a;
argv[n] = strdup(ifa->ifa_name);
if (!argv[n])
err(1, "malloc");
if (!argv[n]) {
warnmsg(LOG_ERR, __func__, "malloc");
exit(1);
}
n++;
}
if (n) {
a = (char **)realloc(argv, (n + 1) * sizeof(char **));
if (a == NULL)
err(1, "realloc");
if (a == NULL) {
warnmsg(LOG_ERR, __func__, "realloc");
exit(1);
}
argv = a;
argv[n] = NULL;
if (dflag > 0) {
for (i = 0; i < n; i++)
warnx("probing %s", argv[i]);
warnmsg(LOG_WARNING, __func__, "probing %s",
argv[i]);
}
}
if (!Fflag)
close(s);
freeifaddrs(ifap);
return argv;
return (argv);
}

View File

@ -31,8 +31,23 @@
* $FreeBSD$
*/
struct script_msg {
TAILQ_ENTRY(script_msg) sm_next;
char *sm_msg;
};
struct ra_opt {
TAILQ_ENTRY(ra_opt) rao_next;
u_int8_t rao_type;
struct timeval rao_expire;
size_t rao_len;
void *rao_msg;
};
struct ifinfo {
struct ifinfo *next; /* pointer to the next interface */
TAILQ_ENTRY(ifinfo) ifi_next; /* pointer to the next interface */
struct sockaddr_dl *sdl; /* link-layer address */
char ifname[IF_NAMESIZE]; /* interface name */
@ -54,6 +69,8 @@ struct ifinfo {
size_t rs_datalen;
u_char *rs_data;
TAILQ_HEAD(, ra_opt) ifi_ra_opt;
};
/* per interface status */
@ -63,12 +80,41 @@ struct ifinfo {
#define IFS_DOWN 3
#define IFS_TENTATIVE 4
/* Interface list */
extern TAILQ_HEAD(ifinfo_head_t, ifinfo) ifinfo_head;
/*
* RFC 3542 API deprecates IPV6_PKTINFO in favor of
* IPV6_RECVPKTINFO
*/
#ifndef IPV6_RECVPKTINFO
#ifdef IPV6_PKTINFO
#define IPV6_RECVPKTINFO IPV6_PKTINFO
#endif
#endif
/*
* RFC 3542 API deprecates IPV6_HOPLIMIT in favor of
* IPV6_RECVHOPLIMIT
*/
#ifndef IPV6_RECVHOPLIMIT
#ifdef IPV6_HOPLIMIT
#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
#endif
#endif
#ifndef IN6ADDR_LINKLOCAL_ALLROUTERS_INIT
#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
#endif
/* rtsold.c */
extern struct timeval tm_max;
extern int dflag;
extern int aflag;
extern int Fflag;
extern char *otherconf_script;
extern const char *otherconf_script;
extern const char *resolvconf_script;
extern int ifconfig(char *);
extern void iflist_init(void);
struct ifinfo *find_ifinfo(int);
@ -76,6 +122,7 @@ void rtsol_timer_update(struct ifinfo *);
extern void warnmsg(int, const char *, const char *, ...)
__attribute__((__format__(__printf__, 3, 4)));
extern char **autoifprobe(void);
extern int ra_opt_handler(struct ifinfo *);
/* if.c */
extern int ifinit(void);

Some files were not shown because too many files have changed in this diff Show More