MFC
This commit is contained in:
commit
81c02539f1
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -5,6 +5,4 @@
|
||||
|
||||
GEOM_CLASS= sched
|
||||
|
||||
WARNS?= 6
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 .
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 "
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
@ -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);
|
||||
|
@ -3459,7 +3459,7 @@ nfsmout:
|
||||
*/
|
||||
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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 *
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
457
sys/netinet/in_pcbgroup.c
Normal 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);
|
||||
}
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
103
sys/netinet6/in6_pcbgroup.c
Normal 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));
|
||||
}
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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) */
|
||||
|
@ -420,13 +420,13 @@ nospace:
|
||||
*/
|
||||
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]
|
||||
|
25
tools/regression/bin/sh/expansion/heredoc1.0
Normal file
25
tools/regression/bin/sh/expansion/heredoc1.0
Normal 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
|
15
tools/regression/bin/sh/expansion/heredoc2.0
Normal file
15
tools/regression/bin/sh/expansion/heredoc2.0
Normal 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
|
@ -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);
|
||||
|
||||
|
@ -28,8 +28,6 @@ MLINKS= grep.1 egrep.1 \
|
||||
bsdgrep.1: grep.1
|
||||
cp ${.ALLSRC} ${.TARGET}
|
||||
|
||||
WARNS?= 6
|
||||
|
||||
LDADD= -lz -lbz2
|
||||
DPADD= ${LIBZ} ${LIBBZ2}
|
||||
|
||||
|
@ -7,8 +7,6 @@ PROG= iconv
|
||||
#SRCS= iconv.c
|
||||
MAN= iconv.1
|
||||
|
||||
WARNS?= 6
|
||||
|
||||
LDADD+= -lcrypt
|
||||
DPADD+= ${LIBCRYPT}
|
||||
|
||||
|
@ -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_
|
||||
/*
|
||||
|
@ -6,6 +6,4 @@ MAN= rctl.8
|
||||
DPADD= ${LIBUTIL}
|
||||
LDADD= -lutil
|
||||
|
||||
WARNS?= 6
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -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
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
PROG= ath3kfw
|
||||
MAN= ath3kfw.8
|
||||
WARNS?= 6
|
||||
DPADD+= ${LIBUSB}
|
||||
LDADD+= -lusb
|
||||
|
||||
|
@ -33,7 +33,6 @@
|
||||
|
||||
#
|
||||
# TODO:
|
||||
# - Add -R /sbin/resolvconf to rtsol once support is in tree.
|
||||
# - Add DHCPv6 support once FreeBSD ships with it.
|
||||
#
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 @@ breakbreak:
|
||||
* 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
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
@ -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":
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
.\"
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user