MFC
This commit is contained in:
commit
5b6ea0b538
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/largeSMP/; revision=222526
@ -210,7 +210,7 @@ icmp_log_redirect="NO" # Set to YES to log ICMP REDIRECT packets
|
||||
network_interfaces="auto" # List of network interfaces (or "auto").
|
||||
cloned_interfaces="" # List of cloned network interfaces to create.
|
||||
#cloned_interfaces="gif0 gif1 gif2 gif3" # Pre-cloning GENERIC config.
|
||||
ifconfig_lo0="inet 127.0.0.1" # default loopback device configuration.
|
||||
#ifconfig_lo0="inet 127.0.0.1" # default loopback device configuration.
|
||||
#ifconfig_lo0_alias0="inet 127.0.0.254 netmask 0xffffffff" # Sample alias entry.
|
||||
#ifconfig_ed0_ipx="ipx 0x00010010" # Sample IPX address family entry.
|
||||
#ifconfig_ed0_ipv6="inet6 2001:db8:1::1 prefixlen 64" # Sample IPv6 addr entry
|
||||
|
@ -44,9 +44,9 @@ ifn_start()
|
||||
|
||||
ifscript_up ${ifn} && cfg=0
|
||||
ifconfig_up ${ifn} && cfg=0
|
||||
ipv4_up ${ifn} && cfg=0
|
||||
ipv6_up ${ifn} && cfg=0
|
||||
ipx_up ${ifn} && cfg=0
|
||||
afexists inet && ipv4_up ${ifn} && cfg=0
|
||||
afexists inet6 && ipv6_up ${ifn} && cfg=0
|
||||
afexists ipx && ipx_up ${ifn} && cfg=0
|
||||
childif_create ${ifn} && cfg=0
|
||||
|
||||
return $cfg
|
||||
@ -64,9 +64,9 @@ ifn_stop()
|
||||
|
||||
[ -z "$ifn" ] && err 1 "ifn_stop called without an interface"
|
||||
|
||||
ipx_down ${ifn} && cfg=0
|
||||
ipv6_down ${ifn} && cfg=0
|
||||
ipv4_down ${ifn} && cfg=0
|
||||
afexists ipx && ipx_down ${ifn} && cfg=0
|
||||
afexists inet6 && ipv6_down ${ifn} && cfg=0
|
||||
afexists inet && ipv4_down ${ifn} && cfg=0
|
||||
ifconfig_down ${ifn} && cfg=0
|
||||
ifscript_down ${ifn} && cfg=0
|
||||
childif_destroy ${ifn} && cfg=0
|
||||
@ -86,6 +86,11 @@ ifconfig_up()
|
||||
local _cfg _ipv6_opts ifconfig_args
|
||||
_cfg=1
|
||||
|
||||
# Make sure lo0 always comes up.
|
||||
if [ "$1" = "lo0" ]; then
|
||||
_cfg=0
|
||||
fi
|
||||
|
||||
# ifconfig_IF
|
||||
ifconfig_args=`ifconfig_getargs $1`
|
||||
if [ -n "${ifconfig_args}" ]; then
|
||||
@ -351,10 +356,10 @@ afexists()
|
||||
|
||||
case ${_af} in
|
||||
inet)
|
||||
${SYSCTL_N} net.inet > /dev/null 2>&1
|
||||
${SYSCTL_N} kern.features.inet > /dev/null 2>&1
|
||||
;;
|
||||
inet6)
|
||||
${SYSCTL_N} net.inet6 > /dev/null 2>&1
|
||||
${SYSCTL_N} kern.features.inet6 > /dev/null 2>&1
|
||||
;;
|
||||
ipx)
|
||||
${SYSCTL_N} net.ipx > /dev/null 2>&1
|
||||
@ -512,6 +517,13 @@ ipv4_up()
|
||||
_if=$1
|
||||
_ret=1
|
||||
|
||||
# Add 127.0.0.1/8 to lo0 unless otherwise specified.
|
||||
if [ "${_if}" = "lo0" ]; then
|
||||
ifconfig_args=`ifconfig_getargs ${_if}`
|
||||
if [ -z "${ifconfig_args}" ]; then
|
||||
ifconfig ${_if} inet 127.0.0.1/8 alias
|
||||
fi
|
||||
fi
|
||||
ifalias_up ${_if} inet && _ret=0
|
||||
ipv4_addrs_common ${_if} alias && _ret=0
|
||||
|
||||
|
@ -163,11 +163,8 @@ process_file_actions_entry(posix_spawn_file_actions_entry_t *fae)
|
||||
return (errno);
|
||||
break;
|
||||
case FAE_CLOSE:
|
||||
/* Perform a close() */
|
||||
if (_close(fae->fae_fildes) != 0) {
|
||||
if (errno == EBADF)
|
||||
return (EBADF);
|
||||
}
|
||||
/* Perform a close(), do not fail if already closed */
|
||||
(void)_close(fae->fae_fildes);
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
|
@ -58,10 +58,7 @@ pio2_2t = 2.0670321098263988236496903051604844e-43L, /* 0x127044533e63a0105df5
|
||||
pio2_3 = 2.0670321098263988236499468110329591e-43L, /* 0x127044533e63a0105e00000000000.0p-254 */
|
||||
pio2_3t = -2.5650587247459238361625433492959285e-65L; /* -0x159c4ec64ddaeb5f78671cbfb2210.0p-327 */
|
||||
|
||||
#ifdef INLINE_REM_PIO2L
|
||||
static inline __always_inline
|
||||
#endif
|
||||
int
|
||||
static inline __always_inline int
|
||||
__ieee754_rem_pio2l(long double x, long double *y)
|
||||
{
|
||||
union IEEEl2bits u,u1;
|
||||
|
@ -70,10 +70,7 @@ pio2_2t = 6.36831716351095013979e-25L, /* 0xc51701b839a25205.0p-144 */
|
||||
pio2_3t = -2.75299651904407171810e-37L; /* -0xbb5bf6c7ddd660ce.0p-185 */
|
||||
#endif
|
||||
|
||||
#ifdef INLINE_REM_PIO2L
|
||||
static inline __always_inline
|
||||
#endif
|
||||
int
|
||||
static inline __always_inline int
|
||||
__ieee754_rem_pio2l(long double x, long double *y)
|
||||
{
|
||||
union IEEEl2bits u,u1;
|
||||
|
@ -35,7 +35,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <float.h>
|
||||
|
||||
#include "math.h"
|
||||
#define INLINE_REM_PIO2L
|
||||
#include "math_private.h"
|
||||
#if LDBL_MANT_DIG == 64
|
||||
#include "../ld80/e_rem_pio2l.h"
|
||||
|
@ -30,7 +30,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <float.h>
|
||||
|
||||
#include "math.h"
|
||||
#define INLINE_REM_PIO2L
|
||||
#include "math_private.h"
|
||||
#if LDBL_MANT_DIG == 64
|
||||
#include "../ld80/e_rem_pio2l.h"
|
||||
|
@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <float.h>
|
||||
|
||||
#include "math.h"
|
||||
#define INLINE_REM_PIO2L
|
||||
#include "math_private.h"
|
||||
#if LDBL_MANT_DIG == 64
|
||||
#include "../ld80/e_rem_pio2l.h"
|
||||
|
@ -24,7 +24,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 27, 2011
|
||||
.Dd May 30, 2011
|
||||
.Dt GPART 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -802,6 +802,22 @@ providers and some of them will be marked as corrupt.
|
||||
Be careful when choosing a provider for recovering.
|
||||
If you choose incorrectly you can destroy the metadata of another GEOM class,
|
||||
e.g. GEOM MIRROR or GEOM LABEL.
|
||||
.Sh SYSCTL VARIABLES
|
||||
The following
|
||||
.Xr sysctl 8
|
||||
variables can be used to control the behavior of the
|
||||
.Nm PART
|
||||
GEOM class.
|
||||
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
|
||||
.Nm PART
|
||||
GEOM class verifies all generic partition parameters that it gets from the
|
||||
disk metadata. If some inconsistency is detected, partition table will be
|
||||
rejected with a diagnostic message:
|
||||
.Pa GEOM_PART: Integrity check failed (provider, scheme) .
|
||||
.Sh EXIT STATUS
|
||||
Exit status is 0 on success, and 1 if the command fails.
|
||||
.Sh EXAMPLES
|
||||
|
@ -1243,7 +1243,7 @@ local_send_thread(void *arg)
|
||||
ggio->gctl_offset + res->hr_localoff);
|
||||
if (ret == ggio->gctl_length)
|
||||
hio->hio_errors[ncomp] = 0;
|
||||
else {
|
||||
else if (!ISSYNCREQ(hio)) {
|
||||
/*
|
||||
* If READ failed, try to read from remote node.
|
||||
*/
|
||||
|
@ -1,7 +1,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 27, 2010
|
||||
.Dd May 30, 2011
|
||||
.Dt IPFW 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -871,13 +871,16 @@ for more information on
|
||||
and
|
||||
.Cm ngtee
|
||||
actions.
|
||||
.It Cm setfib Ar fibnum
|
||||
.It Cm setfib Ar fibnum | tablearg
|
||||
The packet is tagged so as to use the FIB (routing table)
|
||||
.Ar fibnum
|
||||
in any subsequent forwarding decisions.
|
||||
Initially this is limited to the values 0 through 15, see
|
||||
.Xr setfib 1 .
|
||||
Processing continues at the next rule.
|
||||
It is possible to use the
|
||||
.Cm tablearg
|
||||
keyword with a setfib. If tablearg value is not within compiled FIB range packet fib is set to 0.
|
||||
.It Cm reass
|
||||
Queue and reassemble ip fragments.
|
||||
If the packet is not fragmented, counters are updated and processing continues with the next rule.
|
||||
@ -1711,7 +1714,7 @@ is used.
|
||||
The
|
||||
.Cm tablearg
|
||||
argument can be used with the following actions:
|
||||
.Cm nat, pipe , queue, divert, tee, netgraph, ngtee, fwd, skipto
|
||||
.Cm nat, pipe , queue, divert, tee, netgraph, ngtee, fwd, skipto, setfib,
|
||||
action parameters:
|
||||
.Cm tag, untag,
|
||||
rule options:
|
||||
|
@ -2835,14 +2835,19 @@ ipfw_add(char *av[])
|
||||
size_t intsize = sizeof(int);
|
||||
|
||||
action->opcode = O_SETFIB;
|
||||
NEED1("missing fib number");
|
||||
action->arg1 = strtoul(*av, NULL, 10);
|
||||
if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1)
|
||||
errx(EX_DATAERR, "fibs not suported.\n");
|
||||
if (action->arg1 >= numfibs) /* Temporary */
|
||||
errx(EX_DATAERR, "fib too large.\n");
|
||||
av++;
|
||||
break;
|
||||
NEED1("missing fib number");
|
||||
if (_substrcmp(*av, "tablearg") == 0) {
|
||||
action->arg1 = IP_FW_TABLEARG;
|
||||
} else {
|
||||
action->arg1 = strtoul(*av, NULL, 10);
|
||||
if (sysctlbyname("net.fibs", &numfibs, &intsize,
|
||||
NULL, 0) == -1)
|
||||
errx(EX_DATAERR, "fibs not suported.\n");
|
||||
if (action->arg1 >= numfibs) /* Temporary */
|
||||
errx(EX_DATAERR, "fib too large.\n");
|
||||
}
|
||||
av++;
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_REASS:
|
||||
|
@ -90,9 +90,6 @@ main(int argc, char *argv[])
|
||||
struct statfs *mntbuf, *sfs;
|
||||
struct addrinfo hints;
|
||||
|
||||
/* Start disks transferring immediately. */
|
||||
sync();
|
||||
|
||||
all = errs = 0;
|
||||
while ((ch = getopt(argc, argv, "AaF:fh:t:v")) != -1)
|
||||
switch (ch) {
|
||||
@ -127,6 +124,10 @@ main(int argc, char *argv[])
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/* Start disks transferring immediately. */
|
||||
if ((fflag & MNT_FORCE) == 0)
|
||||
sync();
|
||||
|
||||
if ((argc == 0 && !all) || (argc != 0 && all))
|
||||
usage();
|
||||
|
||||
|
@ -46,7 +46,9 @@ MAN= aac.4 \
|
||||
atapicam.4 \
|
||||
ataraid.4 \
|
||||
ath.4 \
|
||||
ath_ahb.4 \
|
||||
ath_hal.4 \
|
||||
ath_pci.4 \
|
||||
atkbd.4 \
|
||||
atkbdc.4 \
|
||||
${_atp.4} \
|
||||
|
@ -40,6 +40,7 @@ place the following lines in your
|
||||
kernel configuration file:
|
||||
.Bd -ragged -offset indent
|
||||
.Cd "device ath"
|
||||
.Cd "device ath_pci"
|
||||
.Cd "device ath_hal"
|
||||
.Cd "options AH_SUPPORT_AR5416"
|
||||
.Cd "device ath_rate_sample"
|
||||
@ -51,6 +52,7 @@ module at boot time, place the following line in
|
||||
.Xr loader.conf 5 :
|
||||
.Bd -literal -offset indent
|
||||
if_ath_load="YES"
|
||||
if_ath_pci_load="YES"
|
||||
.Ed
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
@ -64,6 +66,19 @@ Supported features include 802.11 and 802.3 frames, power management, BSS,
|
||||
IBSS, MBSS, TDMA, and host-based access point operation modes.
|
||||
All host/device interaction is via DMA.
|
||||
.Pp
|
||||
Please note that from FreeBSD-9.0, the
|
||||
.Nm
|
||||
driver does not include the PCI/PCIe bus glue.
|
||||
The same driver supports multiple underlying bus types, including PCI/PCIe,
|
||||
but also embedded (AHB) and USB in the future.
|
||||
.Pp
|
||||
To enable use for PCI/PCIe systems, see the
|
||||
.Xr ath_pci 4
|
||||
driver.
|
||||
For embedded systems which use the AHB to connect the wireless MAC, see the
|
||||
.Xr ath_ahb 4
|
||||
driver.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
driver encapsulates all IP and ARP traffic as 802.11 frames, however
|
||||
|
60
share/man/man4/ath_ahb.4
Normal file
60
share/man/man4/ath_ahb.4
Normal file
@ -0,0 +1,60 @@
|
||||
.\"-
|
||||
.\" Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd
|
||||
.\" All rights reserved.
|
||||
.\""
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer,
|
||||
.\" without modification.
|
||||
.\" 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
.\" similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
.\" redistribution must be conditioned upon including a substantially
|
||||
.\" similar Disclaimer requirement for further binary redistribution.
|
||||
.\"
|
||||
.\" NO WARRANTY
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
.\" LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
.\" THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"/
|
||||
.Dd May 30, 2011
|
||||
.Dt ATH_AHB 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ath_ahb
|
||||
.Nd "Atheros AHB device glue"
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device ath_ahb"
|
||||
.Sh DESCRIPTION
|
||||
This module provides the AHB bus glue needed for the devices supported
|
||||
by the
|
||||
.Xr ath 4
|
||||
and
|
||||
.Xr ath_hal 4
|
||||
drivers.
|
||||
.Pp
|
||||
This is only relevant for embedded System-on-Chip (SoC) devices such as
|
||||
the Atheros AR913x series, which include an Atheros wireless MAC on-die.
|
||||
.Sh SEE ALSO
|
||||
.Xr ath 4
|
||||
.Xr ath_hal 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
module first appeared in
|
||||
.Fx 9.0 .
|
||||
.Sh BUGS
|
||||
See
|
||||
.Xr ath 4
|
||||
for known bugs.
|
@ -51,14 +51,17 @@ or
|
||||
.\".Cd "device ath_ar5312"
|
||||
.\".Cd "device ath_rf2136"
|
||||
.\".Cd "device ath_rf2137"
|
||||
.Cd "device ath_ar9130"
|
||||
.Cd "device ath_ar9160"
|
||||
.Cd "device ath_ar9280"
|
||||
.Cd "device ath_ar9285"
|
||||
.Cd "device ath_ar9287"
|
||||
.Cd "options AH_SUPPORT_AR5416"
|
||||
.Sh DESCRIPTION
|
||||
The hal provides hardware support for wireless network adapters based on
|
||||
the Atheros AR5210, AR5211, AR5212, AR5213, AR2413, AR2417, AR2425,
|
||||
AR5413, AR5416, AR5418, AR5424, AR9160, AR9220, AR9280, and AR9285 chips
|
||||
(and companion RF/baseband parts).
|
||||
AR5413, AR5416, AR5418, AR5424, AR9160, AR9220, AR9280, AR9285 and AR9287
|
||||
chips (and companion RF/baseband parts).
|
||||
This code is part of the
|
||||
.Xr ath 4
|
||||
driver but configured separately to allow fine-grained control
|
||||
@ -66,14 +69,15 @@ over the set of chips supported.
|
||||
Selecting
|
||||
.Nm
|
||||
enables support for all PCI and Cardbus devices.
|
||||
Note this includes AR5416, AR9160, AR9220, AR9280 and AR9285 devices
|
||||
and must be accompanied by the
|
||||
Note this includes AR5416, AR5418, AR9130, AR9160, AR9220, AR9280, AR9285
|
||||
and AR9287 devices and must be accompanied by the
|
||||
AH_SUPPORT_AR5416
|
||||
option to enable the extended hardware descriptor format used by
|
||||
AR5416 and later devices.
|
||||
.Pp
|
||||
Some devices come in Cardbus/MiniPCI/PCI format.
|
||||
Others (AR9280, AR9285) come in PCIe, Mini-PCIe or ExpressCard format.
|
||||
Others (for example AR2413, AR2427, AR5418, AR9280, AR9285, AR9287) come in
|
||||
PCIe, Mini-PCIe or ExpressCard format.
|
||||
.Pp
|
||||
Historically this code has been released in a binary-only form
|
||||
and packaged as a separate module.
|
||||
|
57
share/man/man4/ath_pci.4
Normal file
57
share/man/man4/ath_pci.4
Normal file
@ -0,0 +1,57 @@
|
||||
.\"-
|
||||
.\" Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd
|
||||
.\" All rights reserved.
|
||||
.\""
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer,
|
||||
.\" without modification.
|
||||
.\" 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
.\" similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
.\" redistribution must be conditioned upon including a substantially
|
||||
.\" similar Disclaimer requirement for further binary redistribution.
|
||||
.\"
|
||||
.\" NO WARRANTY
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
.\" LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
.\" THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"/
|
||||
.Dd May 30, 2011
|
||||
.Dt ATH_PCI 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ath_pci
|
||||
.Nd "Atheros PCI device glue"
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device ath_pci"
|
||||
.Sh DESCRIPTION
|
||||
This module provides the PCI/PCIe bus glue needed for the devices supported
|
||||
by the
|
||||
.Xr ath 4
|
||||
and
|
||||
.Xr ath_hal 4
|
||||
drivers.
|
||||
.Sh SEE ALSO
|
||||
.Xr ath 4
|
||||
.Xr ath_hal 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
module first appeared in
|
||||
.Fx 9.0 .
|
||||
.Sh BUGS
|
||||
See
|
||||
.Xr ath 4
|
||||
for known bugs.
|
@ -23,7 +23,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd June 17, 2010
|
||||
.Dd May 30, 2011
|
||||
.Dt C 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -122,7 +122,7 @@ Support for variable length arrays
|
||||
New high-precision integer type named long long int, and other integer types
|
||||
defined in stdint.h
|
||||
.It
|
||||
New boolen data type implemented in stdbool.h
|
||||
New boolean data type implemented in stdbool.h
|
||||
.It
|
||||
One line comments taken from the C++ language
|
||||
.It
|
||||
|
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 25, 2011
|
||||
.Dd May 30, 2011
|
||||
.Dt PORTS 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -479,6 +479,8 @@ Of course, these ports may not work as expected, but if you really know
|
||||
what you are doing and are sure about installing a forbidden port, then
|
||||
.Va NO_IGNORE
|
||||
lets you do it.
|
||||
.It Va NO_CHECKSUM
|
||||
If defined, skip verifying the port's checksum.
|
||||
.It Va TRYBROKEN
|
||||
If defined, attempt to build a port even if it is marked as
|
||||
.Aq Va BROKEN .
|
||||
|
@ -65,7 +65,9 @@ and should have experience upgrading systems from source.
|
||||
The release build process requires that
|
||||
.Pa /usr/obj
|
||||
be populated with the output of
|
||||
.Dq Li "make buildworld" .
|
||||
.Dq Li "make buildworld"
|
||||
and
|
||||
.Dq Li "make buildkernel" .
|
||||
This is necessary to provide the object files for the release or, when
|
||||
using
|
||||
.Pa generate-release.sh ,
|
||||
@ -294,7 +296,7 @@ The following sequence of commands can be used to build a
|
||||
cd /usr
|
||||
svn co svn://svn.freebsd.org/base/head src
|
||||
cd src
|
||||
make buildworld
|
||||
make buildworld buildkernel
|
||||
cd release
|
||||
make release
|
||||
make install DESTDIR=/var/freebsd-snapshot
|
||||
|
@ -33,6 +33,7 @@ loader.help: help.common
|
||||
|
||||
.PATH: ${.CURDIR}/../../forth
|
||||
FILES+= loader.4th support.4th loader.conf
|
||||
FILES+= screen.4th frames.4th
|
||||
FILES+= beastie.4th brand.4th check-password.4th color.4th delay.4th
|
||||
FILES+= menu.4th menu-commands.4th shortcuts.4th version.4th
|
||||
.if !exists(${DESTDIR}/boot/loader.rc)
|
||||
|
@ -113,8 +113,9 @@ loader.help: help.common help.ps3
|
||||
|
||||
.PATH: ${.CURDIR}/../../forth
|
||||
FILES= loader.help loader.4th support.4th loader.conf
|
||||
FILES+= screen.4th frames.4th
|
||||
FILES+= beastie.4th brand.4th check-password.4th color.4th delay.4th
|
||||
FILES+= menu.4th menu-commands.4th shortcuts.4th version.4th
|
||||
FILES+= menu.4th menu-commands.4th shortcuts.4th version.4th
|
||||
FILESDIR_loader.conf= /boot/defaults
|
||||
|
||||
.if !exists(${DESTDIR}/boot/loader.rc)
|
||||
|
@ -84,8 +84,9 @@ loader.help: help.common help.sparc64
|
||||
|
||||
.PATH: ${.CURDIR}/../../forth
|
||||
FILES= loader.help loader.4th support.4th loader.conf
|
||||
FILES+= screen.4th frames.4th
|
||||
FILES+= beastie.4th brand.4th check-password.4th color.4th delay.4th
|
||||
FILES+= menu.4th menu-commands.4th shortcuts.4th version.4th
|
||||
FILES+= menu.4th menu-commands.4th shortcuts.4th version.4th
|
||||
FILESDIR_loader.conf= /boot/defaults
|
||||
|
||||
.if !exists(${DESTDIR}/boot/loader.rc)
|
||||
|
@ -89,7 +89,8 @@ typedef enum {
|
||||
} ada_flags;
|
||||
|
||||
typedef enum {
|
||||
ADA_Q_NONE = 0x00
|
||||
ADA_Q_NONE = 0x00,
|
||||
ADA_Q_4K = 0x01,
|
||||
} ada_quirks;
|
||||
|
||||
typedef enum {
|
||||
@ -153,6 +154,86 @@ struct ada_quirk_entry {
|
||||
|
||||
static struct ada_quirk_entry ada_quirk_table[] =
|
||||
{
|
||||
{
|
||||
/* Hitachi Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* Samsung Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* Seagate Barracuda Green Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* Seagate Momentus Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* Seagate Momentus Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* Seagate Momentus Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* Seagate Momentus Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* Seagate Momentus Thin Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* WDC Caviar Green Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* WDC Caviar Green Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* WDC Caviar Green Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* WDC Caviar Green Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* WDC Scorpio Black Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* WDC Scorpio Black Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* WDC Scorpio Blue Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* WDC Scorpio Blue Advanced Format (4k) drives */
|
||||
{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" },
|
||||
/*quirks*/ADA_Q_4K
|
||||
},
|
||||
{
|
||||
/* Default */
|
||||
{
|
||||
@ -740,7 +821,7 @@ adaregister(struct cam_periph *periph, void *arg)
|
||||
struct disk_params *dp;
|
||||
caddr_t match;
|
||||
u_int maxio;
|
||||
int legacy_id;
|
||||
int legacy_id, quirks;
|
||||
|
||||
cgd = (struct ccb_getdev *)arg;
|
||||
if (periph == NULL) {
|
||||
@ -815,6 +896,11 @@ adaregister(struct cam_periph *periph, void *arg)
|
||||
*/
|
||||
(void)cam_periph_hold(periph, PRIBIO);
|
||||
mtx_unlock(periph->sim->mtx);
|
||||
snprintf(announce_buf, sizeof(announce_buf),
|
||||
"kern.cam.ada.%d.quirks", periph->unit_number);
|
||||
quirks = softc->quirks;
|
||||
TUNABLE_INT_FETCH(announce_buf, &quirks);
|
||||
softc->quirks = quirks;
|
||||
softc->write_cache = -1;
|
||||
snprintf(announce_buf, sizeof(announce_buf),
|
||||
"kern.cam.ada.%d.write_cache", periph->unit_number);
|
||||
@ -870,6 +956,9 @@ adaregister(struct cam_periph *periph, void *arg)
|
||||
softc->disk->d_stripeoffset = (softc->disk->d_stripesize -
|
||||
ata_logical_sector_offset(&cgd->ident_data)) %
|
||||
softc->disk->d_stripesize;
|
||||
} else if (softc->quirks & ADA_Q_4K) {
|
||||
softc->disk->d_stripesize = 4096;
|
||||
softc->disk->d_stripeoffset = 0;
|
||||
}
|
||||
softc->disk->d_fwsectors = softc->params.secs_per_track;
|
||||
softc->disk->d_fwheads = softc->params.heads;
|
||||
|
@ -171,6 +171,11 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath,
|
||||
* Snapshots are always read-only.
|
||||
*/
|
||||
mp->mnt_flag |= MNT_RDONLY;
|
||||
/*
|
||||
* We don't want snapshots to allow access to vulnerable setuid
|
||||
* programs, so we turn off setuid when mounting snapshots.
|
||||
*/
|
||||
mp->mnt_flag |= MNT_NOSUID;
|
||||
/*
|
||||
* We don't want snapshots to be visible in regular
|
||||
* mount(8) and df(1) output.
|
||||
|
@ -432,7 +432,10 @@ options KTRACE_REQUEST_POOL=101
|
||||
# defined by the KTR_* constants in <sys/ktr.h>. KTR_MASK defines the
|
||||
# initial value of the ktr_mask variable which determines at runtime
|
||||
# what events to trace. KTR_CPUMASK determines which CPU's log
|
||||
# events, with bit X corresponding to CPU X. KTR_VERBOSE enables
|
||||
# events, with bit X corresponding to CPU X. The layout of the string
|
||||
# passed as KTR_CPUMASK must match a serie of bitmasks each of them
|
||||
# separated by the ", " characters (ie:
|
||||
# KTR_CPUMASK=("0xAF, 0xFFFFFFFFFFFFFFFF")). KTR_VERBOSE enables
|
||||
# dumping of KTR events to the console by default. This functionality
|
||||
# can be toggled via the debug.ktr_verbose sysctl and defaults to off
|
||||
# if KTR_VERBOSE is not defined. See ktr(4) and ktrdump(8) for details.
|
||||
@ -441,7 +444,7 @@ options KTR
|
||||
options KTR_ENTRIES=1024
|
||||
options KTR_COMPILE=(KTR_INTR|KTR_PROC)
|
||||
options KTR_MASK=KTR_INTR
|
||||
options KTR_CPUMASK=0x3
|
||||
options KTR_CPUMASK=("0x3")
|
||||
options KTR_VERBOSE
|
||||
|
||||
#
|
||||
|
@ -917,6 +917,8 @@ dev/cxgbe/t4_main.c optional cxgbe pci \
|
||||
compile-with "${NORMAL_C} -I$S/dev/cxgbe"
|
||||
dev/cxgbe/t4_sge.c optional cxgbe pci \
|
||||
compile-with "${NORMAL_C} -I$S/dev/cxgbe"
|
||||
dev/cxgbe/t4_l2t.c optional cxgbe pci \
|
||||
compile-with "${NORMAL_C} -I$S/dev/cxgbe"
|
||||
dev/cxgbe/common/t4_hw.c optional cxgbe pci \
|
||||
compile-with "${NORMAL_C} -I$S/dev/cxgbe"
|
||||
dev/cy/cy.c optional cy
|
||||
|
@ -3034,16 +3034,14 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd)
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
#ifdef __FreeBSD__
|
||||
INP_INFO_RLOCK(pi); /* XXX LOR */
|
||||
inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4,
|
||||
dport, 0, NULL);
|
||||
inp = in_pcblookup(pi, saddr->v4, sport, daddr->v4,
|
||||
dport, INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp == NULL) {
|
||||
inp = in_pcblookup_hash(pi, saddr->v4, sport,
|
||||
daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
|
||||
if(inp == NULL) {
|
||||
INP_INFO_RUNLOCK(pi);
|
||||
inp = in_pcblookup(pi, saddr->v4, sport,
|
||||
daddr->v4, dport, INPLOOKUP_WILDCARD |
|
||||
INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp == NULL)
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
|
||||
@ -3058,16 +3056,14 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd)
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
#ifdef __FreeBSD__
|
||||
INP_INFO_RLOCK(pi);
|
||||
inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
|
||||
&daddr->v6, dport, 0, NULL);
|
||||
inp = in6_pcblookup(pi, &saddr->v6, sport,
|
||||
&daddr->v6, dport, INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp == NULL) {
|
||||
inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
|
||||
&daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
|
||||
if (inp == NULL) {
|
||||
INP_INFO_RUNLOCK(pi);
|
||||
inp = in6_pcblookup(pi, &saddr->v6, sport,
|
||||
&daddr->v6, dport, INPLOOKUP_WILDCARD |
|
||||
INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp == NULL)
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
|
||||
@ -3085,9 +3081,10 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd)
|
||||
return (-1);
|
||||
}
|
||||
#ifdef __FreeBSD__
|
||||
INP_RLOCK_ASSERT(inp);
|
||||
pd->lookup.uid = inp->inp_cred->cr_uid;
|
||||
pd->lookup.gid = inp->inp_cred->cr_groups[0];
|
||||
INP_INFO_RUNLOCK(pi);
|
||||
INP_RUNLOCK(inp);
|
||||
#else
|
||||
pd->lookup.uid = inp->inp_socket->so_euid;
|
||||
pd->lookup.gid = inp->inp_socket->so_egid;
|
||||
|
@ -984,6 +984,21 @@ ath_vap_create(struct ieee80211com *ic,
|
||||
avp->av_bmiss = vap->iv_bmiss;
|
||||
vap->iv_bmiss = ath_bmiss_vap;
|
||||
|
||||
/* Set default parameters */
|
||||
|
||||
/*
|
||||
* Anything earlier than some AR9300 series MACs don't
|
||||
* support a smaller MPDU density.
|
||||
*/
|
||||
vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_8;
|
||||
/*
|
||||
* All NICs can handle the maximum size, however
|
||||
* AR5416 based MACs can only TX aggregates w/ RTS
|
||||
* protection when the total aggregate size is <= 8k.
|
||||
* However, for now that's enforced by the TX path.
|
||||
*/
|
||||
vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K;
|
||||
|
||||
avp->av_bslot = -1;
|
||||
if (needbeacon) {
|
||||
/*
|
||||
|
@ -136,15 +136,23 @@ ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni,
|
||||
*/
|
||||
if (ni->ni_chw == 40)
|
||||
series[i].RateFlags |= HAL_RATESERIES_2040;
|
||||
#if 0
|
||||
|
||||
/*
|
||||
* The hardware only supports short-gi in 40mhz mode -
|
||||
* if later hardware supports it in 20mhz mode, be sure
|
||||
* to add the relevant check here.
|
||||
* Set short-GI only if the node has advertised it
|
||||
* the channel width is suitable, and we support it.
|
||||
* We don't currently have a "negotiated" set of bits -
|
||||
* ni_htcap is what the remote end sends, not what this
|
||||
* node is capable of.
|
||||
*/
|
||||
if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
|
||||
if (ni->ni_chw == 40 &&
|
||||
ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 &&
|
||||
ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
|
||||
series[i].RateFlags |= HAL_RATESERIES_HALFGI;
|
||||
|
||||
if (ni->ni_chw == 20 &&
|
||||
ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 &&
|
||||
ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)
|
||||
series[i].RateFlags |= HAL_RATESERIES_HALFGI;
|
||||
#endif
|
||||
|
||||
series[i].Rate = rt->info[rix[i]].rateCode;
|
||||
|
||||
|
@ -110,6 +110,9 @@ enum {
|
||||
FW_IQ_QSIZE = 256,
|
||||
FW_IQ_ESIZE = 64, /* At least 64 mandated by the firmware spec */
|
||||
|
||||
INTR_IQ_QSIZE = 64,
|
||||
INTR_IQ_ESIZE = 64, /* Handles some CPLs too, do not reduce */
|
||||
|
||||
CTRL_EQ_QSIZE = 128,
|
||||
CTRL_EQ_ESIZE = 64,
|
||||
|
||||
@ -141,7 +144,7 @@ enum {
|
||||
/* adapter flags */
|
||||
FULL_INIT_DONE = (1 << 0),
|
||||
FW_OK = (1 << 1),
|
||||
INTR_FWD = (1 << 2),
|
||||
INTR_SHARED = (1 << 2), /* one set of intrq's for all ports */
|
||||
|
||||
CXGBE_BUSY = (1 << 9),
|
||||
|
||||
@ -384,12 +387,10 @@ struct sge_ctrlq {
|
||||
|
||||
/* stats for common events first */
|
||||
|
||||
uint64_t total_wrs; /* # of work requests sent down this queue */
|
||||
|
||||
/* stats for not-that-common events */
|
||||
|
||||
uint32_t no_desc; /* out of hardware descriptors */
|
||||
uint32_t too_long; /* WR longer than hardware max */
|
||||
} __aligned(CACHE_LINE_SIZE);
|
||||
|
||||
struct sge {
|
||||
@ -403,7 +404,7 @@ struct sge {
|
||||
|
||||
struct sge_iq fwq; /* Firmware event queue */
|
||||
struct sge_ctrlq *ctrlq;/* Control queues */
|
||||
struct sge_iq *fiq; /* Forwarded interrupt queues (INTR_FWD) */
|
||||
struct sge_iq *intrq; /* Interrupt queues */
|
||||
struct sge_txq *txq; /* NIC tx queues */
|
||||
struct sge_rxq *rxq; /* NIC rx queues */
|
||||
|
||||
@ -445,6 +446,7 @@ struct adapter {
|
||||
struct port_info *port[MAX_NPORTS];
|
||||
uint8_t chan_map[NCHAN];
|
||||
|
||||
struct l2t_data *l2t; /* L2 table */
|
||||
struct tid_info tids;
|
||||
|
||||
int registered_device_map;
|
||||
@ -456,7 +458,9 @@ struct adapter {
|
||||
struct t4_virt_res vres;
|
||||
|
||||
struct sysctl_ctx_list ctx; /* from first_port_up to last_port_down */
|
||||
struct sysctl_oid *oid_fwq;
|
||||
struct sysctl_oid *oid_ctrlq;
|
||||
struct sysctl_oid *oid_intrq;
|
||||
|
||||
struct mtx sc_lock;
|
||||
char lockname[16];
|
||||
@ -502,7 +506,10 @@ struct adapter {
|
||||
rxq = &pi->adapter->sge.rxq[pi->first_rxq]; \
|
||||
for (iter = 0; iter < pi->nrxq; ++iter, ++rxq)
|
||||
|
||||
#define NFIQ(sc) ((sc)->intr_count > 1 ? (sc)->intr_count - 1 : 1)
|
||||
/* One for errors, one for firmware events */
|
||||
#define T4_EXTRA_INTR 2
|
||||
#define NINTRQ(sc) ((sc)->intr_count > T4_EXTRA_INTR ? \
|
||||
(sc)->intr_count - T4_EXTRA_INTR : 1)
|
||||
|
||||
static inline uint32_t
|
||||
t4_read_reg(struct adapter *sc, uint32_t reg)
|
||||
@ -599,12 +606,9 @@ int t4_teardown_adapter_queues(struct adapter *);
|
||||
int t4_setup_eth_queues(struct port_info *);
|
||||
int t4_teardown_eth_queues(struct port_info *);
|
||||
void t4_intr_all(void *);
|
||||
void t4_intr_fwd(void *);
|
||||
void t4_intr(void *);
|
||||
void t4_intr_err(void *);
|
||||
void t4_intr_evt(void *);
|
||||
void t4_intr_data(void *);
|
||||
void t4_evt_rx(void *);
|
||||
void t4_eth_rx(void *);
|
||||
int t4_mgmt_tx(struct adapter *, struct mbuf *);
|
||||
int t4_eth_tx(struct ifnet *, struct sge_txq *, struct mbuf *);
|
||||
void t4_update_fl_bufsize(struct ifnet *);
|
||||
|
@ -54,7 +54,7 @@ enum {
|
||||
|
||||
#define FW_VERSION_MAJOR 1
|
||||
#define FW_VERSION_MINOR 3
|
||||
#define FW_VERSION_MICRO 8
|
||||
#define FW_VERSION_MICRO 10
|
||||
|
||||
struct port_stats {
|
||||
u64 tx_octets; /* total # of octets in good frames */
|
||||
|
140
sys/dev/cxgbe/common/jhash.h
Normal file
140
sys/dev/cxgbe/common/jhash.h
Normal file
@ -0,0 +1,140 @@
|
||||
#ifndef _JHASH_H
|
||||
#define _JHASH_H
|
||||
|
||||
/* jhash.h: Jenkins hash support.
|
||||
*
|
||||
* Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
|
||||
*
|
||||
* http://burtleburtle.net/bob/hash/
|
||||
*
|
||||
* These are the credits from Bob's sources:
|
||||
*
|
||||
* lookup2.c, by Bob Jenkins, December 1996, Public Domain.
|
||||
* hash(), hash2(), hash3, and mix() are externally useful functions.
|
||||
* Routines to test the hash are included if SELF_TEST is defined.
|
||||
* You can use this free for any purpose. It has no warranty.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/* NOTE: Arguments are modified. */
|
||||
#define __jhash_mix(a, b, c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>13); \
|
||||
b -= c; b -= a; b ^= (a<<8); \
|
||||
c -= a; c -= b; c ^= (b>>13); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<16); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>3); \
|
||||
b -= c; b -= a; b ^= (a<<10); \
|
||||
c -= a; c -= b; c ^= (b>>15); \
|
||||
}
|
||||
|
||||
/* The golden ration: an arbitrary value */
|
||||
#define JHASH_GOLDEN_RATIO 0x9e3779b9
|
||||
|
||||
/* The most generic version, hashes an arbitrary sequence
|
||||
* of bytes. No alignment or length assumptions are made about
|
||||
* the input key.
|
||||
*/
|
||||
static inline u32 jhash(const void *key, u32 length, u32 initval)
|
||||
{
|
||||
u32 a, b, c, len;
|
||||
const u8 *k = key;
|
||||
|
||||
len = length;
|
||||
a = b = JHASH_GOLDEN_RATIO;
|
||||
c = initval;
|
||||
|
||||
while (len >= 12) {
|
||||
a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
|
||||
b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
|
||||
c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
|
||||
|
||||
__jhash_mix(a,b,c);
|
||||
|
||||
k += 12;
|
||||
len -= 12;
|
||||
}
|
||||
|
||||
c += length;
|
||||
switch (len) {
|
||||
case 11: c += ((u32)k[10]<<24);
|
||||
case 10: c += ((u32)k[9]<<16);
|
||||
case 9 : c += ((u32)k[8]<<8);
|
||||
case 8 : b += ((u32)k[7]<<24);
|
||||
case 7 : b += ((u32)k[6]<<16);
|
||||
case 6 : b += ((u32)k[5]<<8);
|
||||
case 5 : b += k[4];
|
||||
case 4 : a += ((u32)k[3]<<24);
|
||||
case 3 : a += ((u32)k[2]<<16);
|
||||
case 2 : a += ((u32)k[1]<<8);
|
||||
case 1 : a += k[0];
|
||||
};
|
||||
|
||||
__jhash_mix(a,b,c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* A special optimized version that handles 1 or more of u32s.
|
||||
* The length parameter here is the number of u32s in the key.
|
||||
*/
|
||||
static inline u32 jhash2(u32 *k, u32 length, u32 initval)
|
||||
{
|
||||
u32 a, b, c, len;
|
||||
|
||||
a = b = JHASH_GOLDEN_RATIO;
|
||||
c = initval;
|
||||
len = length;
|
||||
|
||||
while (len >= 3) {
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
__jhash_mix(a, b, c);
|
||||
k += 3; len -= 3;
|
||||
}
|
||||
|
||||
c += length * 4;
|
||||
|
||||
switch (len) {
|
||||
case 2 : b += k[1];
|
||||
case 1 : a += k[0];
|
||||
};
|
||||
|
||||
__jhash_mix(a,b,c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/* A special ultra-optimized versions that knows they are hashing exactly
|
||||
* 3, 2 or 1 word(s).
|
||||
*
|
||||
* NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
|
||||
* done at the end is not done here.
|
||||
*/
|
||||
static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
|
||||
{
|
||||
a += JHASH_GOLDEN_RATIO;
|
||||
b += JHASH_GOLDEN_RATIO;
|
||||
c += initval;
|
||||
|
||||
__jhash_mix(a, b, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
|
||||
{
|
||||
return jhash_3words(a, b, 0, initval);
|
||||
}
|
||||
|
||||
static inline u32 jhash_1word(u32 a, u32 initval)
|
||||
{
|
||||
return jhash_3words(a, 0, 0, initval);
|
||||
}
|
||||
|
||||
#endif /* _JHASH_H */
|
@ -43,6 +43,7 @@ enum fw_retval {
|
||||
FW_ENOMEM = 12, /* out of memory */
|
||||
FW_EFAULT = 14, /* bad address; fw bad */
|
||||
FW_EBUSY = 16, /* resource busy */
|
||||
FW_EEXIST = 17, /* File exists */
|
||||
FW_EINVAL = 22, /* invalid argument */
|
||||
FW_ENOSYS = 38, /* functionality not implemented */
|
||||
FW_EPROTO = 71, /* protocol error */
|
||||
@ -59,6 +60,8 @@ enum fw_retval {
|
||||
FW_FCOE_NO_XCHG = 136, /* */
|
||||
FW_SCSI_RSP_ERR = 137, /* */
|
||||
FW_ERR_RDEV_IMPL_LOGO = 138, /* */
|
||||
FW_SCSI_UNDER_FLOW_ERR = 139, /* */
|
||||
FW_SCSI_OVER_FLOW_ERR = 140, /* */
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
@ -85,7 +88,8 @@ enum fw_wr_opcodes {
|
||||
FW_RI_FR_NSMR_WR = 0x19,
|
||||
FW_RI_INV_LSTAG_WR = 0x1a,
|
||||
FW_RI_WR = 0x0d,
|
||||
FW_LASTC2E_WR = 0x4a
|
||||
FW_ISCSI_NODE_WR = 0x4a,
|
||||
FW_LASTC2E_WR = 0x4b
|
||||
};
|
||||
|
||||
/*
|
||||
@ -514,7 +518,7 @@ struct fw_eth_tx_pkts_wr {
|
||||
__be32 r3;
|
||||
__be16 plen;
|
||||
__u8 npkt;
|
||||
__u8 r4;
|
||||
__u8 type;
|
||||
};
|
||||
|
||||
struct fw_eq_flush_wr {
|
||||
@ -1465,6 +1469,65 @@ struct fw_ri_wr {
|
||||
#define G_FW_RI_WR_P2PTYPE(x) \
|
||||
(((x) >> S_FW_RI_WR_P2PTYPE) & M_FW_RI_WR_P2PTYPE)
|
||||
|
||||
#ifdef FOISCSI
|
||||
struct fw_iscsi_node_wr {
|
||||
__u8 opcode;
|
||||
__u8 subop;
|
||||
__u8 node_attr_to_compl;
|
||||
__u8 len16;
|
||||
__u8 status;
|
||||
__u8 r2;
|
||||
__be16 immd_len;
|
||||
__be64 cookie;
|
||||
__be32 node_id;
|
||||
__be32 ctrl_handle;
|
||||
__be32 io_handle;
|
||||
__be32 r3;
|
||||
};
|
||||
|
||||
#define S_FW_ISCSI_NODE_WR_NODE_ATTR 7
|
||||
#define M_FW_ISCSI_NODE_WR_NODE_ATTR 0x1
|
||||
#define V_FW_ISCSI_NODE_WR_NODE_ATTR(x) ((x) << S_FW_ISCSI_NODE_WR_NODE_ATTR)
|
||||
#define G_FW_ISCSI_NODE_WR_NODE_ATTR(x) \
|
||||
(((x) >> S_FW_ISCSI_NODE_WR_NODE_ATTR) & M_FW_ISCSI_NODE_WR_NODE_ATTR)
|
||||
#define F_FW_ISCSI_NODE_WR_NODE_ATTR V_FW_ISCSI_NODE_WR_NODE_ATTR(1U)
|
||||
|
||||
#define S_FW_ISCSI_NODE_WR_SESS_ATTR 6
|
||||
#define M_FW_ISCSI_NODE_WR_SESS_ATTR 0x1
|
||||
#define V_FW_ISCSI_NODE_WR_SESS_ATTR(x) ((x) << S_FW_ISCSI_NODE_WR_SESS_ATTR)
|
||||
#define G_FW_ISCSI_NODE_WR_SESS_ATTR(x) \
|
||||
(((x) >> S_FW_ISCSI_NODE_WR_SESS_ATTR) & M_FW_ISCSI_NODE_WR_SESS_ATTR)
|
||||
#define F_FW_ISCSI_NODE_WR_SESS_ATTR V_FW_ISCSI_NODE_WR_SESS_ATTR(1U)
|
||||
|
||||
#define S_FW_ISCSI_NODE_WR_CONN_ATTR 5
|
||||
#define M_FW_ISCSI_NODE_WR_CONN_ATTR 0x1
|
||||
#define V_FW_ISCSI_NODE_WR_CONN_ATTR(x) ((x) << S_FW_ISCSI_NODE_WR_CONN_ATTR)
|
||||
#define G_FW_ISCSI_NODE_WR_CONN_ATTR(x) \
|
||||
(((x) >> S_FW_ISCSI_NODE_WR_CONN_ATTR) & M_FW_ISCSI_NODE_WR_CONN_ATTR)
|
||||
#define F_FW_ISCSI_NODE_WR_CONN_ATTR V_FW_ISCSI_NODE_WR_CONN_ATTR(1U)
|
||||
|
||||
#define S_FW_ISCSI_NODE_WR_TGT_ATTR 4
|
||||
#define M_FW_ISCSI_NODE_WR_TGT_ATTR 0x1
|
||||
#define V_FW_ISCSI_NODE_WR_TGT_ATTR(x) ((x) << S_FW_ISCSI_NODE_WR_TGT_ATTR)
|
||||
#define G_FW_ISCSI_NODE_WR_TGT_ATTR(x) \
|
||||
(((x) >> S_FW_ISCSI_NODE_WR_TGT_ATTR) & M_FW_ISCSI_NODE_WR_TGT_ATTR)
|
||||
#define F_FW_ISCSI_NODE_WR_TGT_ATTR V_FW_ISCSI_NODE_WR_TGT_ATTR(1U)
|
||||
|
||||
#define S_FW_ISCSI_NODE_WR_NODE_TYPE 3
|
||||
#define M_FW_ISCSI_NODE_WR_NODE_TYPE 0x1
|
||||
#define V_FW_ISCSI_NODE_WR_NODE_TYPE(x) ((x) << S_FW_ISCSI_NODE_WR_NODE_TYPE)
|
||||
#define G_FW_ISCSI_NODE_WR_NODE_TYPE(x) \
|
||||
(((x) >> S_FW_ISCSI_NODE_WR_NODE_TYPE) & M_FW_ISCSI_NODE_WR_NODE_TYPE)
|
||||
#define F_FW_ISCSI_NODE_WR_NODE_TYPE V_FW_ISCSI_NODE_WR_NODE_TYPE(1U)
|
||||
|
||||
#define S_FW_ISCSI_NODE_WR_COMPL 0
|
||||
#define M_FW_ISCSI_NODE_WR_COMPL 0x1
|
||||
#define V_FW_ISCSI_NODE_WR_COMPL(x) ((x) << S_FW_ISCSI_NODE_WR_COMPL)
|
||||
#define G_FW_ISCSI_NODE_WR_COMPL(x) \
|
||||
(((x) >> S_FW_ISCSI_NODE_WR_COMPL) & M_FW_ISCSI_NODE_WR_COMPL)
|
||||
#define F_FW_ISCSI_NODE_WR_COMPL V_FW_ISCSI_NODE_WR_COMPL(1U)
|
||||
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* C O M M A N D s
|
||||
@ -1511,6 +1574,7 @@ enum fw_cmd_opcodes {
|
||||
FW_RSS_VI_CONFIG_CMD = 0x23,
|
||||
FW_SCHED_CMD = 0x24,
|
||||
FW_DEVLOG_CMD = 0x25,
|
||||
FW_NETIF_CMD = 0x26,
|
||||
FW_LASTC2E_CMD = 0x40,
|
||||
FW_ERROR_CMD = 0x80,
|
||||
FW_DEBUG_CMD = 0x81,
|
||||
@ -1941,6 +2005,8 @@ enum fw_caps_config_iscsi {
|
||||
FW_CAPS_CONFIG_ISCSI_TARGET_PDU = 0x00000002,
|
||||
FW_CAPS_CONFIG_ISCSI_INITIATOR_CNXOFLD = 0x00000004,
|
||||
FW_CAPS_CONFIG_ISCSI_TARGET_CNXOFLD = 0x00000008,
|
||||
FW_CAPS_CONFIG_ISCSI_INITIATOR_SSNOFLD = 0x00000010,
|
||||
FW_CAPS_CONFIG_ISCSI_TARGET_SSNOFLD = 0x00000020,
|
||||
};
|
||||
|
||||
enum fw_caps_config_fcoe {
|
||||
@ -3941,6 +4007,39 @@ enum fw_port_cap {
|
||||
FW_PORT_CAP_TECHKX4 = 0x2000,
|
||||
};
|
||||
|
||||
#define S_FW_PORT_AUXLINFO_MDI 3
|
||||
#define M_FW_PORT_AUXLINFO_MDI 0x3
|
||||
#define V_FW_PORT_AUXLINFO_MDI(x) ((x) << S_FW_PORT_AUXLINFO_MDI)
|
||||
#define G_FW_PORT_AUXLINFO_MDI(x) \
|
||||
(((x) >> S_FW_PORT_AUXLINFO_MDI) & M_FW_PORT_AUXLINFO_MDI)
|
||||
|
||||
#define S_FW_PORT_AUXLINFO_KX4 2
|
||||
#define M_FW_PORT_AUXLINFO_KX4 0x1
|
||||
#define V_FW_PORT_AUXLINFO_KX4(x) ((x) << S_FW_PORT_AUXLINFO_KX4)
|
||||
#define G_FW_PORT_AUXLINFO_KX4(x) \
|
||||
(((x) >> S_FW_PORT_AUXLINFO_KX4) & M_FW_PORT_AUXLINFO_KX4)
|
||||
#define F_FW_PORT_AUXLINFO_KX4 V_FW_PORT_AUXLINFO_KX4(1U)
|
||||
|
||||
#define S_FW_PORT_AUXLINFO_KR 1
|
||||
#define M_FW_PORT_AUXLINFO_KR 0x1
|
||||
#define V_FW_PORT_AUXLINFO_KR(x) ((x) << S_FW_PORT_AUXLINFO_KR)
|
||||
#define G_FW_PORT_AUXLINFO_KR(x) \
|
||||
(((x) >> S_FW_PORT_AUXLINFO_KR) & M_FW_PORT_AUXLINFO_KR)
|
||||
#define F_FW_PORT_AUXLINFO_KR V_FW_PORT_AUXLINFO_KR(1U)
|
||||
|
||||
#define S_FW_PORT_AUXLINFO_FEC 0
|
||||
#define M_FW_PORT_AUXLINFO_FEC 0x1
|
||||
#define V_FW_PORT_AUXLINFO_FEC(x) ((x) << S_FW_PORT_AUXLINFO_FEC)
|
||||
#define G_FW_PORT_AUXLINFO_FEC(x) \
|
||||
(((x) >> S_FW_PORT_AUXLINFO_FEC) & M_FW_PORT_AUXLINFO_FEC)
|
||||
#define F_FW_PORT_AUXLINFO_FEC V_FW_PORT_AUXLINFO_FEC(1U)
|
||||
|
||||
#define S_FW_PORT_RCAP_AUX 11
|
||||
#define M_FW_PORT_RCAP_AUX 0x7
|
||||
#define V_FW_PORT_RCAP_AUX(x) ((x) << S_FW_PORT_RCAP_AUX)
|
||||
#define G_FW_PORT_RCAP_AUX(x) \
|
||||
(((x) >> S_FW_PORT_RCAP_AUX) & M_FW_PORT_RCAP_AUX)
|
||||
|
||||
#define S_FW_PORT_CAP_SPEED 0
|
||||
#define M_FW_PORT_CAP_SPEED 0x3f
|
||||
#define V_FW_PORT_CAP_SPEED(x) ((x) << S_FW_PORT_CAP_SPEED)
|
||||
@ -4002,11 +4101,23 @@ enum fw_port_l2cfg_ctlbf {
|
||||
FW_PORT_L2_CTLBF_MTU = 0x40
|
||||
};
|
||||
|
||||
enum fw_port_dcb_cfg {
|
||||
FW_PORT_DCB_CFG_PG = 0x01,
|
||||
FW_PORT_DCB_CFG_PFC = 0x02,
|
||||
FW_PORT_DCB_CFG_APPL = 0x04
|
||||
};
|
||||
|
||||
enum fw_port_dcb_cfg_rc {
|
||||
FW_PORT_DCB_CFG_SUCCESS = 0x0,
|
||||
FW_PORT_DCB_CFG_ERROR = 0x1
|
||||
};
|
||||
|
||||
enum fw_port_dcb_type {
|
||||
FW_PORT_DCB_TYPE_PGID = 0x00,
|
||||
FW_PORT_DCB_TYPE_PGRATE = 0x01,
|
||||
FW_PORT_DCB_TYPE_PRIORATE = 0x02,
|
||||
FW_PORT_DCB_TYPE_PFC = 0x03
|
||||
FW_PORT_DCB_TYPE_PFC = 0x03,
|
||||
FW_PORT_DCB_TYPE_APP_ID = 0x04,
|
||||
};
|
||||
|
||||
struct fw_port_cmd {
|
||||
@ -4038,7 +4149,7 @@ struct fw_port_cmd {
|
||||
__be16 acap;
|
||||
__be16 mtu;
|
||||
__u8 cbllen;
|
||||
__u8 r7;
|
||||
__u8 auxlinfo;
|
||||
__be32 r8;
|
||||
__be64 r9;
|
||||
} info;
|
||||
@ -4068,6 +4179,14 @@ struct fw_port_cmd {
|
||||
__be16 r10[3];
|
||||
__be64 r11;
|
||||
} pfc;
|
||||
struct fw_port_app_priority {
|
||||
__u8 type;
|
||||
__u8 r10_lo[3];
|
||||
__u8 prio;
|
||||
__u8 sel;
|
||||
__be16 protocolid;
|
||||
__u8 r12[8];
|
||||
} app_priority;
|
||||
} dcb;
|
||||
} u;
|
||||
};
|
||||
@ -5232,6 +5351,116 @@ struct fw_devlog_cmd {
|
||||
(((x) >> S_FW_DEVLOG_CMD_MEMADDR16_DEVLOG) & \
|
||||
M_FW_DEVLOG_CMD_MEMADDR16_DEVLOG)
|
||||
|
||||
struct fw_netif_cmd {
|
||||
__be32 op_portid;
|
||||
__be32 retval_to_len16;
|
||||
__be32 add_to_ipv4gw;
|
||||
__be32 vlanid_mtuval;
|
||||
__be32 gwaddr;
|
||||
__be32 addr;
|
||||
__be32 nmask;
|
||||
__be32 bcaddr;
|
||||
};
|
||||
|
||||
#define S_FW_NETIF_CMD_PORTID 0
|
||||
#define M_FW_NETIF_CMD_PORTID 0xf
|
||||
#define V_FW_NETIF_CMD_PORTID(x) ((x) << S_FW_NETIF_CMD_PORTID)
|
||||
#define G_FW_NETIF_CMD_PORTID(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_PORTID) & M_FW_NETIF_CMD_PORTID)
|
||||
|
||||
#define S_FW_NETIF_CMD_RETVAL 24
|
||||
#define M_FW_NETIF_CMD_RETVAL 0xff
|
||||
#define V_FW_NETIF_CMD_RETVAL(x) ((x) << S_FW_NETIF_CMD_RETVAL)
|
||||
#define G_FW_NETIF_CMD_RETVAL(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_RETVAL) & M_FW_NETIF_CMD_RETVAL)
|
||||
|
||||
#define S_FW_NETIF_CMD_IFIDX 16
|
||||
#define M_FW_NETIF_CMD_IFIDX 0xff
|
||||
#define V_FW_NETIF_CMD_IFIDX(x) ((x) << S_FW_NETIF_CMD_IFIDX)
|
||||
#define G_FW_NETIF_CMD_IFIDX(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_IFIDX) & M_FW_NETIF_CMD_IFIDX)
|
||||
|
||||
#define S_FW_NETIF_CMD_LEN16 0
|
||||
#define M_FW_NETIF_CMD_LEN16 0xff
|
||||
#define V_FW_NETIF_CMD_LEN16(x) ((x) << S_FW_NETIF_CMD_LEN16)
|
||||
#define G_FW_NETIF_CMD_LEN16(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_LEN16) & M_FW_NETIF_CMD_LEN16)
|
||||
|
||||
#define S_FW_NETIF_CMD_ADD 31
|
||||
#define M_FW_NETIF_CMD_ADD 0x1
|
||||
#define V_FW_NETIF_CMD_ADD(x) ((x) << S_FW_NETIF_CMD_ADD)
|
||||
#define G_FW_NETIF_CMD_ADD(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_ADD) & M_FW_NETIF_CMD_ADD)
|
||||
#define F_FW_NETIF_CMD_ADD V_FW_NETIF_CMD_ADD(1U)
|
||||
|
||||
#define S_FW_NETIF_CMD_LINK 30
|
||||
#define M_FW_NETIF_CMD_LINK 0x1
|
||||
#define V_FW_NETIF_CMD_LINK(x) ((x) << S_FW_NETIF_CMD_LINK)
|
||||
#define G_FW_NETIF_CMD_LINK(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_LINK) & M_FW_NETIF_CMD_LINK)
|
||||
#define F_FW_NETIF_CMD_LINK V_FW_NETIF_CMD_LINK(1U)
|
||||
|
||||
#define S_FW_NETIF_CMD_VLAN 29
|
||||
#define M_FW_NETIF_CMD_VLAN 0x1
|
||||
#define V_FW_NETIF_CMD_VLAN(x) ((x) << S_FW_NETIF_CMD_VLAN)
|
||||
#define G_FW_NETIF_CMD_VLAN(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_VLAN) & M_FW_NETIF_CMD_VLAN)
|
||||
#define F_FW_NETIF_CMD_VLAN V_FW_NETIF_CMD_VLAN(1U)
|
||||
|
||||
#define S_FW_NETIF_CMD_MTU 28
|
||||
#define M_FW_NETIF_CMD_MTU 0x1
|
||||
#define V_FW_NETIF_CMD_MTU(x) ((x) << S_FW_NETIF_CMD_MTU)
|
||||
#define G_FW_NETIF_CMD_MTU(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_MTU) & M_FW_NETIF_CMD_MTU)
|
||||
#define F_FW_NETIF_CMD_MTU V_FW_NETIF_CMD_MTU(1U)
|
||||
|
||||
#define S_FW_NETIF_CMD_DHCP 27
|
||||
#define M_FW_NETIF_CMD_DHCP 0x1
|
||||
#define V_FW_NETIF_CMD_DHCP(x) ((x) << S_FW_NETIF_CMD_DHCP)
|
||||
#define G_FW_NETIF_CMD_DHCP(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_DHCP) & M_FW_NETIF_CMD_DHCP)
|
||||
#define F_FW_NETIF_CMD_DHCP V_FW_NETIF_CMD_DHCP(1U)
|
||||
|
||||
#define S_FW_NETIF_CMD_IPV4BCADDR 3
|
||||
#define M_FW_NETIF_CMD_IPV4BCADDR 0x1
|
||||
#define V_FW_NETIF_CMD_IPV4BCADDR(x) ((x) << S_FW_NETIF_CMD_IPV4BCADDR)
|
||||
#define G_FW_NETIF_CMD_IPV4BCADDR(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_IPV4BCADDR) & M_FW_NETIF_CMD_IPV4BCADDR)
|
||||
#define F_FW_NETIF_CMD_IPV4BCADDR V_FW_NETIF_CMD_IPV4BCADDR(1U)
|
||||
|
||||
#define S_FW_NETIF_CMD_IPV4NMASK 2
|
||||
#define M_FW_NETIF_CMD_IPV4NMASK 0x1
|
||||
#define V_FW_NETIF_CMD_IPV4NMASK(x) ((x) << S_FW_NETIF_CMD_IPV4NMASK)
|
||||
#define G_FW_NETIF_CMD_IPV4NMASK(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_IPV4NMASK) & M_FW_NETIF_CMD_IPV4NMASK)
|
||||
#define F_FW_NETIF_CMD_IPV4NMASK V_FW_NETIF_CMD_IPV4NMASK(1U)
|
||||
|
||||
#define S_FW_NETIF_CMD_IPV4ADDR 1
|
||||
#define M_FW_NETIF_CMD_IPV4ADDR 0x1
|
||||
#define V_FW_NETIF_CMD_IPV4ADDR(x) ((x) << S_FW_NETIF_CMD_IPV4ADDR)
|
||||
#define G_FW_NETIF_CMD_IPV4ADDR(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_IPV4ADDR) & M_FW_NETIF_CMD_IPV4ADDR)
|
||||
#define F_FW_NETIF_CMD_IPV4ADDR V_FW_NETIF_CMD_IPV4ADDR(1U)
|
||||
|
||||
#define S_FW_NETIF_CMD_IPV4GW 0
|
||||
#define M_FW_NETIF_CMD_IPV4GW 0x1
|
||||
#define V_FW_NETIF_CMD_IPV4GW(x) ((x) << S_FW_NETIF_CMD_IPV4GW)
|
||||
#define G_FW_NETIF_CMD_IPV4GW(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_IPV4GW) & M_FW_NETIF_CMD_IPV4GW)
|
||||
#define F_FW_NETIF_CMD_IPV4GW V_FW_NETIF_CMD_IPV4GW(1U)
|
||||
|
||||
#define S_FW_NETIF_CMD_VLANID 16
|
||||
#define M_FW_NETIF_CMD_VLANID 0xfff
|
||||
#define V_FW_NETIF_CMD_VLANID(x) ((x) << S_FW_NETIF_CMD_VLANID)
|
||||
#define G_FW_NETIF_CMD_VLANID(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_VLANID) & M_FW_NETIF_CMD_VLANID)
|
||||
|
||||
#define S_FW_NETIF_CMD_MTUVAL 0
|
||||
#define M_FW_NETIF_CMD_MTUVAL 0xffff
|
||||
#define V_FW_NETIF_CMD_MTUVAL(x) ((x) << S_FW_NETIF_CMD_MTUVAL)
|
||||
#define G_FW_NETIF_CMD_MTUVAL(x) \
|
||||
(((x) >> S_FW_NETIF_CMD_MTUVAL) & M_FW_NETIF_CMD_MTUVAL)
|
||||
|
||||
enum fw_error_type {
|
||||
FW_ERROR_TYPE_EXCEPTION = 0x0,
|
||||
FW_ERROR_TYPE_HWMODULE = 0x1,
|
||||
|
@ -31,6 +31,24 @@
|
||||
#ifndef __T4_OFFLOAD_H__
|
||||
#define __T4_OFFLOAD_H__
|
||||
|
||||
/* CPL message priority levels */
|
||||
enum {
|
||||
CPL_PRIORITY_DATA = 0, /* data messages */
|
||||
CPL_PRIORITY_SETUP = 1, /* connection setup messages */
|
||||
CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */
|
||||
CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */
|
||||
CPL_PRIORITY_ACK = 1, /* RX ACK messages */
|
||||
CPL_PRIORITY_CONTROL = 1 /* control messages */
|
||||
};
|
||||
|
||||
#define INIT_TP_WR(w, tid) do { \
|
||||
(w)->wr.wr_hi = htonl(V_FW_WR_OP(FW_TP_WR) | \
|
||||
V_FW_WR_IMMDLEN(sizeof(*w) - sizeof(w->wr))); \
|
||||
(w)->wr.wr_mid = htonl(V_FW_WR_LEN16(DIV_ROUND_UP(sizeof(*w), 16)) | \
|
||||
V_FW_WR_FLOWID(tid)); \
|
||||
(w)->wr.wr_lo = cpu_to_be64(0); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Max # of ATIDs. The absolute HW max is 16K but we keep it lower.
|
||||
*/
|
||||
|
@ -82,6 +82,7 @@ typedef boolean_t bool;
|
||||
#define DIV_ROUND_UP(x, y) howmany(x, y)
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define container_of(p, s, f) ((s *)(((uint8_t *)(p)) - offsetof(s, f)))
|
||||
|
||||
#define swab16(x) bswap16(x)
|
||||
#define swab32(x) bswap32(x)
|
||||
|
@ -178,6 +178,8 @@ struct t4_filter_specification {
|
||||
|
||||
struct t4_filter {
|
||||
uint32_t idx;
|
||||
uint16_t l2tidx;
|
||||
uint16_t smtidx;
|
||||
uint64_t hits;
|
||||
struct t4_filter_specification fs;
|
||||
};
|
||||
|
361
sys/dev/cxgbe/t4_l2t.c
Normal file
361
sys/dev/cxgbe/t4_l2t.c
Normal file
@ -0,0 +1,361 @@
|
||||
/*-
|
||||
* Copyright (c) 2011 Chelsio Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 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_inet.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_vlan_var.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_llatbl.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/jhash.h"
|
||||
#include "common/t4_msg.h"
|
||||
#include "offload.h"
|
||||
#include "t4_l2t.h"
|
||||
|
||||
/* identifies sync vs async L2T_WRITE_REQs */
|
||||
#define S_SYNC_WR 12
|
||||
#define V_SYNC_WR(x) ((x) << S_SYNC_WR)
|
||||
#define F_SYNC_WR V_SYNC_WR(1)
|
||||
|
||||
enum {
|
||||
L2T_STATE_VALID, /* entry is up to date */
|
||||
L2T_STATE_STALE, /* entry may be used but needs revalidation */
|
||||
L2T_STATE_RESOLVING, /* entry needs address resolution */
|
||||
L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */
|
||||
|
||||
/* when state is one of the below the entry is not hashed */
|
||||
L2T_STATE_SWITCHING, /* entry is being used by a switching filter */
|
||||
L2T_STATE_UNUSED /* entry not in use */
|
||||
};
|
||||
|
||||
struct l2t_data {
|
||||
struct rwlock lock;
|
||||
volatile int nfree; /* number of free entries */
|
||||
struct l2t_entry *rover;/* starting point for next allocation */
|
||||
struct l2t_entry l2tab[L2T_SIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
* Module locking notes: There is a RW lock protecting the L2 table as a
|
||||
* whole plus a spinlock per L2T entry. Entry lookups and allocations happen
|
||||
* under the protection of the table lock, individual entry changes happen
|
||||
* while holding that entry's spinlock. The table lock nests outside the
|
||||
* entry locks. Allocations of new entries take the table lock as writers so
|
||||
* no other lookups can happen while allocating new entries. Entry updates
|
||||
* take the table lock as readers so multiple entries can be updated in
|
||||
* parallel. An L2T entry can be dropped by decrementing its reference count
|
||||
* and therefore can happen in parallel with entry allocation but no entry
|
||||
* can change state or increment its ref count during allocation as both of
|
||||
* these perform lookups.
|
||||
*
|
||||
* Note: We do not take refereces to ifnets in this module because both
|
||||
* the TOE and the sockets already hold references to the interfaces and the
|
||||
* lifetime of an L2T entry is fully contained in the lifetime of the TOE.
|
||||
*/
|
||||
static inline unsigned int
|
||||
vlan_prio(const struct l2t_entry *e)
|
||||
{
|
||||
return e->vlan >> 13;
|
||||
}
|
||||
|
||||
static inline void
|
||||
l2t_hold(struct l2t_data *d, struct l2t_entry *e)
|
||||
{
|
||||
if (atomic_fetchadd_int(&e->refcnt, 1) == 0) /* 0 -> 1 transition */
|
||||
atomic_add_int(&d->nfree, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* To avoid having to check address families we do not allow v4 and v6
|
||||
* neighbors to be on the same hash chain. We keep v4 entries in the first
|
||||
* half of available hash buckets and v6 in the second.
|
||||
*/
|
||||
enum {
|
||||
L2T_SZ_HALF = L2T_SIZE / 2,
|
||||
L2T_HASH_MASK = L2T_SZ_HALF - 1
|
||||
};
|
||||
|
||||
static inline unsigned int
|
||||
arp_hash(const uint32_t *key, int ifindex)
|
||||
{
|
||||
return jhash_2words(*key, ifindex, 0) & L2T_HASH_MASK;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
ipv6_hash(const uint32_t *key, int ifindex)
|
||||
{
|
||||
uint32_t xor = key[0] ^ key[1] ^ key[2] ^ key[3];
|
||||
|
||||
return L2T_SZ_HALF + (jhash_2words(xor, ifindex, 0) & L2T_HASH_MASK);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
addr_hash(const uint32_t *addr, int addr_len, int ifindex)
|
||||
{
|
||||
return addr_len == 4 ? arp_hash(addr, ifindex) :
|
||||
ipv6_hash(addr, ifindex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if an L2T entry is for the given IP/IPv6 address. It does not check
|
||||
* whether the L2T entry and the address are of the same address family.
|
||||
* Callers ensure an address is only checked against L2T entries of the same
|
||||
* family, something made trivial by the separation of IP and IPv6 hash chains
|
||||
* mentioned above. Returns 0 if there's a match,
|
||||
*/
|
||||
static inline int
|
||||
addreq(const struct l2t_entry *e, const uint32_t *addr)
|
||||
{
|
||||
if (e->v6)
|
||||
return (e->addr[0] ^ addr[0]) | (e->addr[1] ^ addr[1]) |
|
||||
(e->addr[2] ^ addr[2]) | (e->addr[3] ^ addr[3]);
|
||||
return e->addr[0] ^ addr[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Write an L2T entry. Must be called with the entry locked (XXX: really?).
|
||||
* The write may be synchronous or asynchronous.
|
||||
*/
|
||||
static int
|
||||
write_l2e(struct adapter *sc, struct l2t_entry *e, int sync)
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct cpl_l2t_write_req *req;
|
||||
|
||||
if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
req = mtod(m, struct cpl_l2t_write_req *);
|
||||
m->m_pkthdr.len = m->m_len = sizeof(*req);
|
||||
|
||||
INIT_TP_WR(req, 0);
|
||||
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx |
|
||||
V_SYNC_WR(sync) | V_TID_QID(sc->sge.fwq.abs_id)));
|
||||
req->params = htons(V_L2T_W_PORT(e->lport) | V_L2T_W_NOREPLY(!sync));
|
||||
req->l2t_idx = htons(e->idx);
|
||||
req->vlan = htons(e->vlan);
|
||||
memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
|
||||
|
||||
t4_mgmt_tx(sc, m);
|
||||
|
||||
if (sync && e->state != L2T_STATE_SWITCHING)
|
||||
e->state = L2T_STATE_SYNC_WRITE;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a packet to an L2T entry's queue of packets awaiting resolution.
|
||||
* Must be called with the entry's lock held.
|
||||
*/
|
||||
static inline void
|
||||
arpq_enqueue(struct l2t_entry *e, struct mbuf *m)
|
||||
{
|
||||
mtx_assert(&e->lock, MA_OWNED);
|
||||
|
||||
m->m_next = NULL;
|
||||
if (e->arpq_head)
|
||||
e->arpq_tail->m_next = m;
|
||||
else
|
||||
e->arpq_head = m;
|
||||
e->arpq_tail = m;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a free L2T entry. Must be called with l2t_data.lock held.
|
||||
*/
|
||||
static struct l2t_entry *
|
||||
alloc_l2e(struct l2t_data *d)
|
||||
{
|
||||
struct l2t_entry *end, *e, **p;
|
||||
|
||||
rw_assert(&d->lock, RA_WLOCKED);
|
||||
|
||||
if (!atomic_load_acq_int(&d->nfree))
|
||||
return (NULL);
|
||||
|
||||
/* there's definitely a free entry */
|
||||
for (e = d->rover, end = &d->l2tab[L2T_SIZE]; e != end; ++e)
|
||||
if (atomic_load_acq_int(&e->refcnt) == 0)
|
||||
goto found;
|
||||
|
||||
for (e = d->l2tab; atomic_load_acq_int(&e->refcnt); ++e) ;
|
||||
found:
|
||||
d->rover = e + 1;
|
||||
atomic_add_int(&d->nfree, -1);
|
||||
|
||||
/*
|
||||
* The entry we found may be an inactive entry that is
|
||||
* presently in the hash table. We need to remove it.
|
||||
*/
|
||||
if (e->state < L2T_STATE_SWITCHING) {
|
||||
for (p = &d->l2tab[e->hash].first; *p; p = &(*p)->next) {
|
||||
if (*p == e) {
|
||||
*p = e->next;
|
||||
e->next = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e->state = L2T_STATE_UNUSED;
|
||||
return e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when an L2T entry has no more users. The entry is left in the hash
|
||||
* table since it is likely to be reused but we also bump nfree to indicate
|
||||
* that the entry can be reallocated for a different neighbor. We also drop
|
||||
* the existing neighbor reference in case the neighbor is going away and is
|
||||
* waiting on our reference.
|
||||
*
|
||||
* Because entries can be reallocated to other neighbors once their ref count
|
||||
* drops to 0 we need to take the entry's lock to avoid races with a new
|
||||
* incarnation.
|
||||
*/
|
||||
static void
|
||||
t4_l2e_free(struct l2t_entry *e)
|
||||
{
|
||||
struct llentry *lle = NULL;
|
||||
struct l2t_data *d;
|
||||
|
||||
mtx_lock(&e->lock);
|
||||
if (atomic_load_acq_int(&e->refcnt) == 0) { /* hasn't been recycled */
|
||||
lle = e->lle;
|
||||
e->lle = NULL;
|
||||
/*
|
||||
* Don't need to worry about the arpq, an L2T entry can't be
|
||||
* released if any packets are waiting for resolution as we
|
||||
* need to be able to communicate with the device to close a
|
||||
* connection.
|
||||
*/
|
||||
}
|
||||
mtx_unlock(&e->lock);
|
||||
|
||||
d = container_of(e, struct l2t_data, l2tab[e->idx]);
|
||||
atomic_add_int(&d->nfree, 1);
|
||||
|
||||
if (lle)
|
||||
LLE_FREE(lle);
|
||||
}
|
||||
|
||||
void
|
||||
t4_l2t_release(struct l2t_entry *e)
|
||||
{
|
||||
if (atomic_fetchadd_int(&e->refcnt, -1) == 1)
|
||||
t4_l2e_free(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate an L2T entry for use by a switching rule. Such need to be
|
||||
* explicitly freed and while busy they are not on any hash chain, so normal
|
||||
* address resolution updates do not see them.
|
||||
*/
|
||||
struct l2t_entry *
|
||||
t4_l2t_alloc_switching(struct l2t_data *d)
|
||||
{
|
||||
struct l2t_entry *e;
|
||||
|
||||
rw_rlock(&d->lock);
|
||||
e = alloc_l2e(d);
|
||||
if (e) {
|
||||
mtx_lock(&e->lock); /* avoid race with t4_l2t_free */
|
||||
e->state = L2T_STATE_SWITCHING;
|
||||
atomic_store_rel_int(&e->refcnt, 1);
|
||||
mtx_unlock(&e->lock);
|
||||
}
|
||||
rw_runlock(&d->lock);
|
||||
return e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets/updates the contents of a switching L2T entry that has been allocated
|
||||
* with an earlier call to @t4_l2t_alloc_switching.
|
||||
*/
|
||||
int
|
||||
t4_l2t_set_switching(struct adapter *sc, struct l2t_entry *e, uint16_t vlan,
|
||||
uint8_t port, uint8_t *eth_addr)
|
||||
{
|
||||
e->vlan = vlan;
|
||||
e->lport = port;
|
||||
memcpy(e->dmac, eth_addr, ETHER_ADDR_LEN);
|
||||
return write_l2e(sc, e, 0);
|
||||
}
|
||||
|
||||
struct l2t_data *
|
||||
t4_init_l2t(int flags)
|
||||
{
|
||||
int i;
|
||||
struct l2t_data *d;
|
||||
|
||||
d = malloc(sizeof(*d), M_CXGBE, M_ZERO | flags);
|
||||
if (!d)
|
||||
return (NULL);
|
||||
|
||||
d->rover = d->l2tab;
|
||||
atomic_store_rel_int(&d->nfree, L2T_SIZE);
|
||||
rw_init(&d->lock, "L2T");
|
||||
|
||||
for (i = 0; i < L2T_SIZE; i++) {
|
||||
d->l2tab[i].idx = i;
|
||||
d->l2tab[i].state = L2T_STATE_UNUSED;
|
||||
mtx_init(&d->l2tab[i].lock, "L2T_E", NULL, MTX_DEF);
|
||||
atomic_store_rel_int(&d->l2tab[i].refcnt, 0);
|
||||
}
|
||||
|
||||
return (d);
|
||||
}
|
||||
|
||||
int
|
||||
t4_free_l2t(struct l2t_data *d)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < L2T_SIZE; i++)
|
||||
mtx_destroy(&d->l2tab[i].lock);
|
||||
rw_destroy(&d->lock);
|
||||
free(d, M_CXGBE);
|
||||
|
||||
return (0);
|
||||
}
|
71
sys/dev/cxgbe/t4_l2t.h
Normal file
71
sys/dev/cxgbe/t4_l2t.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*-
|
||||
* Copyright (c) 2011 Chelsio Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __T4_L2T_H
|
||||
#define __T4_L2T_H
|
||||
|
||||
enum { L2T_SIZE = 4096 }; /* # of L2T entries */
|
||||
|
||||
/*
|
||||
* Each L2T entry plays multiple roles. First of all, it keeps state for the
|
||||
* corresponding entry of the HW L2 table and maintains a queue of offload
|
||||
* packets awaiting address resolution. Second, it is a node of a hash table
|
||||
* chain, where the nodes of the chain are linked together through their next
|
||||
* pointer. Finally, each node is a bucket of a hash table, pointing to the
|
||||
* first element in its chain through its first pointer.
|
||||
*/
|
||||
struct l2t_entry {
|
||||
uint16_t state; /* entry state */
|
||||
uint16_t idx; /* entry index */
|
||||
uint32_t addr[4]; /* next hop IP or IPv6 address */
|
||||
struct ifnet *ifp; /* outgoing interface */
|
||||
uint16_t smt_idx; /* SMT index */
|
||||
uint16_t vlan; /* VLAN TCI (id: 0-11, prio: 13-15) */
|
||||
int ifindex; /* interface index */
|
||||
struct llentry *lle; /* llentry for next hop */
|
||||
struct l2t_entry *first; /* start of hash chain */
|
||||
struct l2t_entry *next; /* next l2t_entry on chain */
|
||||
struct mbuf *arpq_head; /* list of mbufs awaiting resolution */
|
||||
struct mbuf *arpq_tail;
|
||||
struct mtx lock;
|
||||
volatile uint32_t refcnt; /* entry reference count */
|
||||
uint16_t hash; /* hash bucket the entry is on */
|
||||
uint8_t v6; /* whether entry is for IPv6 */
|
||||
uint8_t lport; /* associated offload logical port */
|
||||
uint8_t dmac[ETHER_ADDR_LEN]; /* next hop's MAC address */
|
||||
};
|
||||
|
||||
struct l2t_data *t4_init_l2t(int);
|
||||
int t4_free_l2t(struct l2t_data *);
|
||||
struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *);
|
||||
int t4_l2t_set_switching(struct adapter *, struct l2t_entry *, uint16_t,
|
||||
uint8_t, uint8_t *);
|
||||
void t4_l2t_release(struct l2t_entry *);
|
||||
|
||||
#endif /* __T4_L2T_H */
|
@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include "common/t4_regs_values.h"
|
||||
#include "common/t4fw_interface.h"
|
||||
#include "t4_ioctl.h"
|
||||
#include "t4_l2t.h"
|
||||
|
||||
/* T4 bus driver interface */
|
||||
static int t4_probe(device_t);
|
||||
@ -213,12 +214,12 @@ SYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupt_types, CTLFLAG_RDTUN, &intr_types, 0,
|
||||
"interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively)");
|
||||
|
||||
/*
|
||||
* Force the driver to use interrupt forwarding.
|
||||
* Force the driver to use the same set of interrupts for all ports.
|
||||
*/
|
||||
static int intr_fwd = 0;
|
||||
TUNABLE_INT("hw.cxgbe.interrupt_forwarding", &intr_fwd);
|
||||
SYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupt_forwarding, CTLFLAG_RDTUN,
|
||||
&intr_fwd, 0, "always use forwarded interrupts");
|
||||
static int intr_shared = 0;
|
||||
TUNABLE_INT("hw.cxgbe.interrupts_shared", &intr_shared);
|
||||
SYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupts_shared, CTLFLAG_RDTUN,
|
||||
&intr_shared, 0, "interrupts shared between all ports");
|
||||
|
||||
static unsigned int filter_mode = HW_TPL_FR_MT_PR_IV_P_FC;
|
||||
TUNABLE_INT("hw.cxgbe.filter_mode", &filter_mode);
|
||||
@ -228,7 +229,7 @@ SYSCTL_UINT(_hw_cxgbe, OID_AUTO, filter_mode, CTLFLAG_RDTUN,
|
||||
struct intrs_and_queues {
|
||||
int intr_type; /* INTx, MSI, or MSI-X */
|
||||
int nirq; /* Number of vectors */
|
||||
int intr_fwd; /* Interrupts forwarded */
|
||||
int intr_shared; /* Interrupts shared between all ports */
|
||||
int ntxq10g; /* # of NIC txq's for each 10G port */
|
||||
int nrxq10g; /* # of NIC rxq's for each 10G port */
|
||||
int ntxq1g; /* # of NIC txq's for each 1G port */
|
||||
@ -240,6 +241,7 @@ struct filter_entry {
|
||||
uint32_t locked:1; /* filter is administratively locked */
|
||||
uint32_t pending:1; /* filter action is pending firmware reply */
|
||||
uint32_t smtidx:8; /* Source MAC Table index for smac */
|
||||
struct l2t_entry *l2t; /* Layer Two Table entry for dmac */
|
||||
|
||||
struct t4_filter_specification fs;
|
||||
};
|
||||
@ -304,7 +306,7 @@ static int set_filter_mode(struct adapter *, uint32_t);
|
||||
static int get_filter(struct adapter *, struct t4_filter *);
|
||||
static int set_filter(struct adapter *, struct t4_filter *);
|
||||
static int del_filter(struct adapter *, struct t4_filter *);
|
||||
static void clear_filter(struct adapter *, struct filter_entry *);
|
||||
static void clear_filter(struct filter_entry *);
|
||||
static int set_filter_wr(struct adapter *, int);
|
||||
static int del_filter_wr(struct adapter *, int);
|
||||
void filter_rpl(struct adapter *, const struct cpl_set_tcb_rpl *);
|
||||
@ -514,8 +516,8 @@ t4_attach(device_t dev)
|
||||
device_printf(dev, "unable to initialize port %d: %d\n",
|
||||
i, rc);
|
||||
free(pi, M_CXGBE);
|
||||
sc->port[i] = NULL; /* indicates init failed */
|
||||
continue;
|
||||
sc->port[i] = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d",
|
||||
@ -582,15 +584,15 @@ t4_attach(device_t dev)
|
||||
s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g;
|
||||
s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g;
|
||||
s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */
|
||||
s->neq += NCHAN; /* control queues, 1 per hw channel */
|
||||
s->neq += sc->params.nports; /* control queues, 1 per port */
|
||||
s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */
|
||||
if (iaq.intr_fwd) {
|
||||
sc->flags |= INTR_FWD;
|
||||
s->niq += NFIQ(sc); /* forwarded interrupt queues */
|
||||
s->fiq = malloc(NFIQ(sc) * sizeof(struct sge_iq), M_CXGBE,
|
||||
M_ZERO | M_WAITOK);
|
||||
}
|
||||
s->ctrlq = malloc(NCHAN * sizeof(struct sge_ctrlq), M_CXGBE,
|
||||
if (iaq.intr_shared)
|
||||
sc->flags |= INTR_SHARED;
|
||||
s->niq += NINTRQ(sc); /* interrupt queues */
|
||||
|
||||
s->intrq = malloc(NINTRQ(sc) * sizeof(struct sge_iq), M_CXGBE,
|
||||
M_ZERO | M_WAITOK);
|
||||
s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_ctrlq), M_CXGBE,
|
||||
M_ZERO | M_WAITOK);
|
||||
s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE,
|
||||
M_ZERO | M_WAITOK);
|
||||
@ -604,6 +606,8 @@ t4_attach(device_t dev)
|
||||
sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE,
|
||||
M_ZERO | M_WAITOK);
|
||||
|
||||
sc->l2t = t4_init_l2t(M_WAITOK);
|
||||
|
||||
t4_sysctls(sc);
|
||||
|
||||
/*
|
||||
@ -691,11 +695,14 @@ t4_detach(device_t dev)
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid,
|
||||
sc->msix_res);
|
||||
|
||||
if (sc->l2t)
|
||||
t4_free_l2t(sc->l2t);
|
||||
|
||||
free(sc->irq, M_CXGBE);
|
||||
free(sc->sge.rxq, M_CXGBE);
|
||||
free(sc->sge.txq, M_CXGBE);
|
||||
free(sc->sge.ctrlq, M_CXGBE);
|
||||
free(sc->sge.fiq, M_CXGBE);
|
||||
free(sc->sge.intrq, M_CXGBE);
|
||||
free(sc->sge.iqmap, M_CXGBE);
|
||||
free(sc->sge.eqmap, M_CXGBE);
|
||||
free(sc->tids.ftid_tab, M_CXGBE);
|
||||
@ -1231,33 +1238,32 @@ cfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g,
|
||||
nrxq10g = min(nc, max_nrxq_10g);
|
||||
nrxq1g = min(nc, max_nrxq_1g);
|
||||
|
||||
/* Extra 2 is for a) error interrupt b) firmware event */
|
||||
iaq->nirq = n10g * nrxq10g + n1g * nrxq1g + 2;
|
||||
if (iaq->nirq <= navail && intr_fwd == 0) {
|
||||
iaq->nirq = n10g * nrxq10g + n1g * nrxq1g + T4_EXTRA_INTR;
|
||||
if (iaq->nirq <= navail && intr_shared == 0) {
|
||||
|
||||
if (itype == INTR_MSI && !powerof2(iaq->nirq))
|
||||
goto fwd;
|
||||
goto share;
|
||||
|
||||
/* One for err, one for fwq, and one for each rxq */
|
||||
|
||||
iaq->intr_fwd = 0;
|
||||
iaq->intr_shared = 0;
|
||||
iaq->nrxq10g = nrxq10g;
|
||||
iaq->nrxq1g = nrxq1g;
|
||||
|
||||
} else {
|
||||
fwd:
|
||||
iaq->intr_fwd = 1;
|
||||
share:
|
||||
iaq->intr_shared = 1;
|
||||
|
||||
if (navail > nc) {
|
||||
if (navail >= nc + T4_EXTRA_INTR) {
|
||||
if (itype == INTR_MSIX)
|
||||
navail = nc + 1;
|
||||
navail = nc + T4_EXTRA_INTR;
|
||||
|
||||
/* navail is and must remain a pow2 for MSI */
|
||||
if (itype == INTR_MSI) {
|
||||
KASSERT(powerof2(navail),
|
||||
("%d not power of 2", navail));
|
||||
|
||||
while (navail / 2 > nc)
|
||||
while (navail / 2 >= nc + T4_EXTRA_INTR)
|
||||
navail /= 2;
|
||||
}
|
||||
}
|
||||
@ -1290,7 +1296,7 @@ cfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g,
|
||||
* the kernel is willing to allocate (it's in navail).
|
||||
*/
|
||||
pci_release_msi(sc->dev);
|
||||
goto fwd;
|
||||
goto share;
|
||||
}
|
||||
|
||||
device_printf(sc->dev,
|
||||
@ -1923,16 +1929,18 @@ cxgbe_uninit_synchronized(struct port_info *pi)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define T4_ALLOC_IRQ(sc, irqid, rid, handler, arg, name) do { \
|
||||
rc = t4_alloc_irq(sc, &sc->irq[irqid], rid, handler, arg, name); \
|
||||
#define T4_ALLOC_IRQ(sc, irq, rid, handler, arg, name) do { \
|
||||
rc = t4_alloc_irq(sc, irq, rid, handler, arg, name); \
|
||||
if (rc != 0) \
|
||||
goto done; \
|
||||
} while (0)
|
||||
static int
|
||||
first_port_up(struct adapter *sc)
|
||||
{
|
||||
int rc, i;
|
||||
char name[8];
|
||||
int rc, i, rid, p, q;
|
||||
char s[8];
|
||||
struct irq *irq;
|
||||
struct sge_iq *intrq;
|
||||
|
||||
ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
|
||||
|
||||
@ -1946,39 +1954,52 @@ first_port_up(struct adapter *sc)
|
||||
/*
|
||||
* Setup interrupts.
|
||||
*/
|
||||
irq = &sc->irq[0];
|
||||
rid = sc->intr_type == INTR_INTX ? 0 : 1;
|
||||
if (sc->intr_count == 1) {
|
||||
KASSERT(sc->flags & INTR_FWD,
|
||||
("%s: single interrupt but not forwarded?", __func__));
|
||||
T4_ALLOC_IRQ(sc, 0, 0, t4_intr_all, sc, "all");
|
||||
KASSERT(sc->flags & INTR_SHARED,
|
||||
("%s: single interrupt but not shared?", __func__));
|
||||
|
||||
T4_ALLOC_IRQ(sc, irq, rid, t4_intr_all, sc, "all");
|
||||
} else {
|
||||
/* Multiple interrupts. The first one is always error intr */
|
||||
T4_ALLOC_IRQ(sc, 0, 1, t4_intr_err, sc, "err");
|
||||
T4_ALLOC_IRQ(sc, irq, rid, t4_intr_err, sc, "err");
|
||||
irq++;
|
||||
rid++;
|
||||
|
||||
if (sc->flags & INTR_FWD) {
|
||||
/* The rest are shared by the fwq and all data intr */
|
||||
for (i = 1; i < sc->intr_count; i++) {
|
||||
snprintf(name, sizeof(name), "mux%d", i - 1);
|
||||
T4_ALLOC_IRQ(sc, i, i + 1, t4_intr_fwd,
|
||||
&sc->sge.fiq[i - 1], name);
|
||||
/* Firmware event queue normally has an interrupt of its own */
|
||||
if (sc->intr_count > T4_EXTRA_INTR) {
|
||||
T4_ALLOC_IRQ(sc, irq, rid, t4_intr_evt, &sc->sge.fwq,
|
||||
"evt");
|
||||
irq++;
|
||||
rid++;
|
||||
}
|
||||
|
||||
intrq = &sc->sge.intrq[0];
|
||||
if (sc->flags & INTR_SHARED) {
|
||||
|
||||
/* All ports share these interrupt queues */
|
||||
|
||||
for (i = 0; i < NINTRQ(sc); i++) {
|
||||
snprintf(s, sizeof(s), "*.%d", i);
|
||||
T4_ALLOC_IRQ(sc, irq, rid, t4_intr, intrq, s);
|
||||
irq++;
|
||||
rid++;
|
||||
intrq++;
|
||||
}
|
||||
} else {
|
||||
struct port_info *pi;
|
||||
int p, q;
|
||||
|
||||
T4_ALLOC_IRQ(sc, 1, 2, t4_intr_evt, &sc->sge.fwq,
|
||||
"evt");
|
||||
/* Each port has its own set of interrupt queues */
|
||||
|
||||
p = q = 0;
|
||||
pi = sc->port[p];
|
||||
for (i = 2; i < sc->intr_count; i++) {
|
||||
snprintf(name, sizeof(name), "p%dq%d", p, q);
|
||||
if (++q >= pi->nrxq) {
|
||||
p++;
|
||||
q = 0;
|
||||
pi = sc->port[p];
|
||||
for (p = 0; p < sc->params.nports; p++) {
|
||||
for (q = 0; q < sc->port[p]->nrxq; q++) {
|
||||
snprintf(s, sizeof(s), "%d.%d", p, q);
|
||||
T4_ALLOC_IRQ(sc, irq, rid, t4_intr,
|
||||
intrq, s);
|
||||
irq++;
|
||||
rid++;
|
||||
intrq++;
|
||||
}
|
||||
T4_ALLOC_IRQ(sc, i, i + 1, t4_intr_data,
|
||||
&sc->sge.rxq[i - 2], name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2913,8 +2934,10 @@ get_filter(struct adapter *sc, struct t4_filter *t)
|
||||
for (i = t->idx; i < nfilters; i++, f++) {
|
||||
if (f->valid) {
|
||||
t->idx = i;
|
||||
t->fs = f->fs;
|
||||
t->l2tidx = f->l2t ? f->l2t->idx : 0;
|
||||
t->smtidx = f->smtidx;
|
||||
t->hits = 0; /* XXX implement */
|
||||
t->fs = f->fs;
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -3034,11 +3057,12 @@ del_filter(struct adapter *sc, struct t4_filter *t)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* XXX: L2T */
|
||||
static void
|
||||
clear_filter(struct adapter *sc, struct filter_entry *f)
|
||||
clear_filter(struct filter_entry *f)
|
||||
{
|
||||
(void) sc;
|
||||
if (f->l2t)
|
||||
t4_l2t_release(f->l2t);
|
||||
|
||||
bzero(f, sizeof (*f));
|
||||
}
|
||||
|
||||
@ -3053,8 +3077,18 @@ set_filter_wr(struct adapter *sc, int fidx)
|
||||
|
||||
ADAPTER_LOCK_ASSERT_OWNED(sc);
|
||||
|
||||
if (f->fs.newdmac || f->fs.newvlan)
|
||||
return (ENOTSUP); /* XXX: fix after L2T code */
|
||||
if (f->fs.newdmac || f->fs.newvlan) {
|
||||
/* This filter needs an L2T entry; allocate one. */
|
||||
f->l2t = t4_l2t_alloc_switching(sc->l2t);
|
||||
if (f->l2t == NULL)
|
||||
return (EAGAIN);
|
||||
if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport,
|
||||
f->fs.dmac)) {
|
||||
t4_l2t_release(f->l2t);
|
||||
f->l2t = NULL;
|
||||
return (ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
ftid = sc->tids.ftid_base + fidx;
|
||||
|
||||
@ -3089,7 +3123,7 @@ set_filter_wr(struct adapter *sc, int fidx)
|
||||
V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) |
|
||||
V_FW_FILTER_WR_TXCHAN(f->fs.eport) |
|
||||
V_FW_FILTER_WR_PRIO(f->fs.prio) |
|
||||
V_FW_FILTER_WR_L2TIX(0)); /* XXX: L2T */
|
||||
V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0));
|
||||
fwr->ethtype = htobe16(f->fs.val.ethtype);
|
||||
fwr->ethtypem = htobe16(f->fs.mask.ethtype);
|
||||
fwr->frag_to_ovlan_vldm =
|
||||
@ -3101,7 +3135,7 @@ set_filter_wr(struct adapter *sc, int fidx)
|
||||
V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.ovlan_vld));
|
||||
fwr->smac_sel = 0;
|
||||
fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) |
|
||||
V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id));
|
||||
V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.intrq[0].abs_id));
|
||||
fwr->maci_to_matchtypem =
|
||||
htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) |
|
||||
V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) |
|
||||
@ -3136,7 +3170,7 @@ set_filter_wr(struct adapter *sc, int fidx)
|
||||
if (rc != 0) {
|
||||
sc->tids.ftids_in_use--;
|
||||
m_freem(m);
|
||||
clear_filter(sc, f);
|
||||
clear_filter(f);
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
@ -3161,7 +3195,7 @@ del_filter_wr(struct adapter *sc, int fidx)
|
||||
m->m_len = m->m_pkthdr.len = sizeof(*fwr);
|
||||
bzero(fwr, sizeof (*fwr));
|
||||
|
||||
t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id);
|
||||
t4_mk_filtdelwr(ftid, fwr, sc->sge.intrq[0].abs_id);
|
||||
|
||||
f->pending = 1;
|
||||
rc = t4_mgmt_tx(sc, m);
|
||||
@ -3188,12 +3222,12 @@ filter_rpl(struct adapter *sc, const struct cpl_set_tcb_rpl *rpl)
|
||||
* Clear the filter when we get confirmation from the
|
||||
* hardware that the filter has been deleted.
|
||||
*/
|
||||
clear_filter(sc, f);
|
||||
clear_filter(f);
|
||||
sc->tids.ftids_in_use--;
|
||||
} else if (rc == FW_FILTER_WR_SMT_TBL_FULL) {
|
||||
device_printf(sc->dev,
|
||||
"filter %u setup failed due to full SMT\n", idx);
|
||||
clear_filter(sc, f);
|
||||
clear_filter(f);
|
||||
sc->tids.ftids_in_use--;
|
||||
} else if (rc == FW_FILTER_WR_FLT_ADDED) {
|
||||
f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff;
|
||||
@ -3206,7 +3240,7 @@ filter_rpl(struct adapter *sc, const struct cpl_set_tcb_rpl *rpl)
|
||||
*/
|
||||
device_printf(sc->dev,
|
||||
"filter %u setup failed with error %u\n", idx, rc);
|
||||
clear_filter(sc, f);
|
||||
clear_filter(f);
|
||||
sc->tids.ftids_in_use--;
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +91,8 @@ struct sgl {
|
||||
bus_dma_segment_t seg[TX_SGL_SEGS];
|
||||
};
|
||||
|
||||
static void t4_evt_rx(void *);
|
||||
static void t4_eth_rx(void *);
|
||||
static inline void init_iq(struct sge_iq *, struct adapter *, int, int, int,
|
||||
int, iq_intr_handler_t *, char *);
|
||||
static inline void init_fl(struct sge_fl *, int, char *);
|
||||
@ -102,8 +104,10 @@ static int free_ring(struct adapter *, bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
|
||||
static int alloc_iq_fl(struct port_info *, struct sge_iq *, struct sge_fl *,
|
||||
int, int);
|
||||
static int free_iq_fl(struct port_info *, struct sge_iq *, struct sge_fl *);
|
||||
static int alloc_iq(struct sge_iq *, int);
|
||||
static int free_iq(struct sge_iq *);
|
||||
static int alloc_intrq(struct adapter *, int, int, int);
|
||||
static int free_intrq(struct sge_iq *);
|
||||
static int alloc_fwq(struct adapter *, int);
|
||||
static int free_fwq(struct sge_iq *);
|
||||
static int alloc_rxq(struct port_info *, struct sge_rxq *, int, int);
|
||||
static int free_rxq(struct port_info *, struct sge_rxq *);
|
||||
static int alloc_ctrlq(struct adapter *, struct sge_ctrlq *, int);
|
||||
@ -139,9 +143,10 @@ static void write_eqflush_wr(struct sge_eq *);
|
||||
static __be64 get_flit(bus_dma_segment_t *, int, int);
|
||||
static int handle_sge_egr_update(struct adapter *,
|
||||
const struct cpl_sge_egr_update *);
|
||||
static void handle_cpl(struct adapter *, struct sge_iq *);
|
||||
|
||||
static int ctrl_tx(struct adapter *, struct sge_ctrlq *, struct mbuf *);
|
||||
static int sysctl_abs_id(SYSCTL_HANDLER_ARGS);
|
||||
static int sysctl_uint16(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
extern void filter_rpl(struct adapter *, const struct cpl_set_tcb_rpl *);
|
||||
|
||||
@ -243,8 +248,7 @@ t4_destroy_dma_tag(struct adapter *sc)
|
||||
|
||||
/*
|
||||
* Allocate and initialize the firmware event queue, control queues, and the
|
||||
* forwarded interrupt queues (if any). The adapter owns all these queues as
|
||||
* they are not associated with any particular port.
|
||||
* interrupt queues. The adapter owns all of these queues.
|
||||
*
|
||||
* Returns errno on failure. Resources allocated up to that point may still be
|
||||
* allocated. Caller is responsible for cleanup in case this function fails.
|
||||
@ -252,8 +256,8 @@ t4_destroy_dma_tag(struct adapter *sc)
|
||||
int
|
||||
t4_setup_adapter_queues(struct adapter *sc)
|
||||
{
|
||||
int i, rc;
|
||||
struct sge_iq *iq, *fwq;
|
||||
int i, j, rc, intr_idx, qsize;
|
||||
struct sge_iq *iq;
|
||||
struct sge_ctrlq *ctrlq;
|
||||
iq_intr_handler_t *handler;
|
||||
char name[16];
|
||||
@ -264,47 +268,76 @@ t4_setup_adapter_queues(struct adapter *sc)
|
||||
struct sysctl_oid *oid = device_get_sysctl_tree(sc->dev);
|
||||
struct sysctl_oid_list *children = SYSCTL_CHILDREN(oid);
|
||||
|
||||
sc->oid_fwq = SYSCTL_ADD_NODE(&sc->ctx, children, OID_AUTO,
|
||||
"fwq", CTLFLAG_RD, NULL, "firmware event queue");
|
||||
sc->oid_ctrlq = SYSCTL_ADD_NODE(&sc->ctx, children, OID_AUTO,
|
||||
"ctrlq", CTLFLAG_RD, NULL, "ctrl queues");
|
||||
sc->oid_intrq = SYSCTL_ADD_NODE(&sc->ctx, children, OID_AUTO,
|
||||
"intrq", CTLFLAG_RD, NULL, "interrupt queues");
|
||||
}
|
||||
|
||||
fwq = &sc->sge.fwq;
|
||||
if (sc->flags & INTR_FWD) {
|
||||
iq = &sc->sge.fiq[0];
|
||||
|
||||
/*
|
||||
* Forwarded interrupt queues - allocate 1 if there's only 1
|
||||
* vector available, one less than the number of vectors
|
||||
* otherwise (the first vector is reserved for the error
|
||||
* interrupt in that case).
|
||||
*/
|
||||
i = sc->intr_count > 1 ? 1 : 0;
|
||||
for (; i < sc->intr_count; i++, iq++) {
|
||||
|
||||
snprintf(name, sizeof(name), "%s fiq%d",
|
||||
/*
|
||||
* Interrupt queues
|
||||
*/
|
||||
intr_idx = sc->intr_count - NINTRQ(sc);
|
||||
if (sc->flags & INTR_SHARED) {
|
||||
qsize = max((sc->sge.nrxq + 1) * 2, INTR_IQ_QSIZE);
|
||||
for (i = 0; i < NINTRQ(sc); i++, intr_idx++) {
|
||||
snprintf(name, sizeof(name), "%s intrq%d",
|
||||
device_get_nameunit(sc->dev), i);
|
||||
init_iq(iq, sc, 0, 0, (sc->sge.nrxq + 1) * 2, 16, NULL,
|
||||
name);
|
||||
|
||||
rc = alloc_iq(iq, i);
|
||||
iq = &sc->sge.intrq[i];
|
||||
init_iq(iq, sc, 0, 0, qsize, INTR_IQ_ESIZE, NULL, name);
|
||||
rc = alloc_intrq(sc, i % sc->params.nports, i,
|
||||
intr_idx);
|
||||
|
||||
if (rc != 0) {
|
||||
device_printf(sc->dev,
|
||||
"failed to create fwd intr queue %d: %d\n",
|
||||
i, rc);
|
||||
"failed to create %s: %d\n", name, rc);
|
||||
return (rc);
|
||||
}
|
||||
}
|
||||
|
||||
handler = t4_evt_rx;
|
||||
i = 0; /* forward fwq's interrupt to the first fiq */
|
||||
} else {
|
||||
handler = NULL;
|
||||
i = 1; /* fwq should use vector 1 (0 is used by error) */
|
||||
int qidx = 0;
|
||||
struct port_info *pi;
|
||||
|
||||
for (i = 0; i < sc->params.nports; i++) {
|
||||
pi = sc->port[i];
|
||||
qsize = max((pi->nrxq + 1) * 2, INTR_IQ_QSIZE);
|
||||
for (j = 0; j < pi->nrxq; j++, qidx++, intr_idx++) {
|
||||
snprintf(name, sizeof(name), "%s intrq%d",
|
||||
device_get_nameunit(pi->dev), j);
|
||||
|
||||
iq = &sc->sge.intrq[qidx];
|
||||
init_iq(iq, sc, 0, 0, qsize, INTR_IQ_ESIZE,
|
||||
NULL, name);
|
||||
rc = alloc_intrq(sc, i, qidx, intr_idx);
|
||||
|
||||
if (rc != 0) {
|
||||
device_printf(sc->dev,
|
||||
"failed to create %s: %d\n",
|
||||
name, rc);
|
||||
return (rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Firmware event queue
|
||||
*/
|
||||
snprintf(name, sizeof(name), "%s fwq", device_get_nameunit(sc->dev));
|
||||
init_iq(fwq, sc, 0, 0, FW_IQ_QSIZE, FW_IQ_ESIZE, handler, name);
|
||||
rc = alloc_iq(fwq, i);
|
||||
if (sc->intr_count > T4_EXTRA_INTR) {
|
||||
handler = NULL;
|
||||
intr_idx = 1;
|
||||
} else {
|
||||
handler = t4_evt_rx;
|
||||
intr_idx = 0;
|
||||
}
|
||||
|
||||
iq = &sc->sge.fwq;
|
||||
init_iq(iq, sc, 0, 0, FW_IQ_QSIZE, FW_IQ_ESIZE, handler, name);
|
||||
rc = alloc_fwq(sc, intr_idx);
|
||||
if (rc != 0) {
|
||||
device_printf(sc->dev,
|
||||
"failed to create firmware event queue: %d\n", rc);
|
||||
@ -313,10 +346,10 @@ t4_setup_adapter_queues(struct adapter *sc)
|
||||
}
|
||||
|
||||
/*
|
||||
* Control queues - one per hardware channel.
|
||||
* Control queues - one per port.
|
||||
*/
|
||||
ctrlq = &sc->sge.ctrlq[0];
|
||||
for (i = 0; i < NCHAN; i++, ctrlq++) {
|
||||
for (i = 0; i < sc->params.nports; i++, ctrlq++) {
|
||||
snprintf(name, sizeof(name), "%s ctrlq%d",
|
||||
device_get_nameunit(sc->dev), i);
|
||||
init_eq(&ctrlq->eq, CTRL_EQ_QSIZE, name);
|
||||
@ -344,21 +377,22 @@ t4_teardown_adapter_queues(struct adapter *sc)
|
||||
ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
|
||||
|
||||
/* Do this before freeing the queues */
|
||||
if (sc->oid_ctrlq) {
|
||||
if (sc->oid_fwq || sc->oid_ctrlq || sc->oid_intrq) {
|
||||
sysctl_ctx_free(&sc->ctx);
|
||||
sc->oid_fwq = NULL;
|
||||
sc->oid_ctrlq = NULL;
|
||||
sc->oid_intrq = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < NCHAN; i++)
|
||||
for (i = 0; i < sc->params.nports; i++)
|
||||
free_ctrlq(sc, &sc->sge.ctrlq[i]);
|
||||
|
||||
iq = &sc->sge.fwq;
|
||||
free_iq(iq);
|
||||
if (sc->flags & INTR_FWD) {
|
||||
for (i = 0; i < NFIQ(sc); i++) {
|
||||
iq = &sc->sge.fiq[i];
|
||||
free_iq(iq);
|
||||
}
|
||||
free_fwq(iq);
|
||||
|
||||
for (i = 0; i < NINTRQ(sc); i++) {
|
||||
iq = &sc->sge.intrq[i];
|
||||
free_intrq(iq);
|
||||
}
|
||||
|
||||
return (0);
|
||||
@ -388,23 +422,19 @@ t4_setup_eth_queues(struct port_info *pi)
|
||||
snprintf(name, sizeof(name), "%s rxq%d-iq",
|
||||
device_get_nameunit(pi->dev), i);
|
||||
init_iq(&rxq->iq, sc, pi->tmr_idx, pi->pktc_idx,
|
||||
pi->qsize_rxq, RX_IQ_ESIZE,
|
||||
sc->flags & INTR_FWD ? t4_eth_rx : NULL, name);
|
||||
pi->qsize_rxq, RX_IQ_ESIZE, t4_eth_rx, name);
|
||||
|
||||
snprintf(name, sizeof(name), "%s rxq%d-fl",
|
||||
device_get_nameunit(pi->dev), i);
|
||||
init_fl(&rxq->fl, pi->qsize_rxq / 8, name);
|
||||
|
||||
if (sc->flags & INTR_FWD)
|
||||
intr_idx = (pi->first_rxq + i) % NFIQ(sc);
|
||||
else
|
||||
intr_idx = pi->first_rxq + i + 2;
|
||||
intr_idx = pi->first_rxq + i;
|
||||
if (sc->flags & INTR_SHARED)
|
||||
intr_idx %= NINTRQ(sc);
|
||||
|
||||
rc = alloc_rxq(pi, rxq, intr_idx, i);
|
||||
if (rc != 0)
|
||||
goto done;
|
||||
|
||||
intr_idx++;
|
||||
}
|
||||
|
||||
for_each_txq(pi, i, txq) {
|
||||
@ -452,25 +482,26 @@ t4_teardown_eth_queues(struct port_info *pi)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Deals with errors and forwarded interrupts */
|
||||
/* Deals with errors and the first (and only) interrupt queue */
|
||||
void
|
||||
t4_intr_all(void *arg)
|
||||
{
|
||||
struct adapter *sc = arg;
|
||||
|
||||
t4_intr_err(arg);
|
||||
t4_intr_fwd(&sc->sge.fiq[0]);
|
||||
t4_intr(&sc->sge.intrq[0]);
|
||||
}
|
||||
|
||||
/* Deals with forwarded interrupts on the given ingress queue */
|
||||
/* Deals with interrupts, and a few CPLs, on the given interrupt queue */
|
||||
void
|
||||
t4_intr_fwd(void *arg)
|
||||
t4_intr(void *arg)
|
||||
{
|
||||
struct sge_iq *iq = arg, *q;
|
||||
struct adapter *sc = iq->adapter;
|
||||
struct rsp_ctrl *ctrl;
|
||||
const struct rss_header *rss;
|
||||
int ndesc_pending = 0, ndesc_total = 0;
|
||||
int qid;
|
||||
int qid, rsp_type;
|
||||
|
||||
if (!atomic_cmpset_32(&iq->state, IQS_IDLE, IQS_BUSY))
|
||||
return;
|
||||
@ -479,17 +510,23 @@ t4_intr_fwd(void *arg)
|
||||
|
||||
rmb();
|
||||
|
||||
/* Only interrupt muxing expected on this queue */
|
||||
KASSERT(G_RSPD_TYPE(ctrl->u.type_gen) == X_RSPD_TYPE_INTR,
|
||||
("unexpected event on forwarded interrupt queue: %x",
|
||||
G_RSPD_TYPE(ctrl->u.type_gen)));
|
||||
rss = (const void *)iq->cdesc;
|
||||
rsp_type = G_RSPD_TYPE(ctrl->u.type_gen);
|
||||
|
||||
if (__predict_false(rsp_type == X_RSPD_TYPE_CPL)) {
|
||||
handle_cpl(sc, iq);
|
||||
goto nextdesc;
|
||||
}
|
||||
|
||||
qid = ntohl(ctrl->pldbuflen_qid) - sc->sge.iq_start;
|
||||
q = sc->sge.iqmap[qid];
|
||||
|
||||
q->handler(q);
|
||||
if (atomic_cmpset_32(&q->state, IQS_IDLE, IQS_BUSY)) {
|
||||
q->handler(q);
|
||||
atomic_cmpset_32(&q->state, IQS_BUSY, IQS_IDLE);
|
||||
}
|
||||
|
||||
ndesc_total++;
|
||||
nextdesc: ndesc_total++;
|
||||
if (++ndesc_pending >= iq->qsize / 4) {
|
||||
t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS),
|
||||
V_CIDXINC(ndesc_pending) |
|
||||
@ -514,9 +551,7 @@ t4_intr_err(void *arg)
|
||||
{
|
||||
struct adapter *sc = arg;
|
||||
|
||||
if (sc->intr_type == INTR_INTX)
|
||||
t4_write_reg(sc, MYPF_REG(A_PCIE_PF_CLI), 0);
|
||||
|
||||
t4_write_reg(sc, MYPF_REG(A_PCIE_PF_CLI), 0);
|
||||
t4_slow_intr_handler(sc);
|
||||
}
|
||||
|
||||
@ -526,70 +561,32 @@ t4_intr_evt(void *arg)
|
||||
{
|
||||
struct sge_iq *iq = arg;
|
||||
|
||||
if (!atomic_cmpset_32(&iq->state, IQS_IDLE, IQS_BUSY))
|
||||
return;
|
||||
|
||||
t4_evt_rx(arg);
|
||||
|
||||
atomic_cmpset_32(&iq->state, IQS_BUSY, IQS_IDLE);
|
||||
if (atomic_cmpset_32(&iq->state, IQS_IDLE, IQS_BUSY)) {
|
||||
t4_evt_rx(arg);
|
||||
atomic_cmpset_32(&iq->state, IQS_BUSY, IQS_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
t4_intr_data(void *arg)
|
||||
{
|
||||
struct sge_iq *iq = arg;
|
||||
|
||||
if (!atomic_cmpset_32(&iq->state, IQS_IDLE, IQS_BUSY))
|
||||
return;
|
||||
|
||||
t4_eth_rx(arg);
|
||||
|
||||
atomic_cmpset_32(&iq->state, IQS_BUSY, IQS_IDLE);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
t4_evt_rx(void *arg)
|
||||
{
|
||||
struct sge_iq *iq = arg;
|
||||
struct adapter *sc = iq->adapter;
|
||||
struct rsp_ctrl *ctrl;
|
||||
const struct rss_header *rss;
|
||||
int ndesc_pending = 0, ndesc_total = 0;
|
||||
|
||||
KASSERT(iq == &sc->sge.fwq, ("%s: unexpected ingress queue", __func__));
|
||||
|
||||
while (is_new_response(iq, &ctrl)) {
|
||||
int rsp_type;
|
||||
|
||||
rmb();
|
||||
|
||||
rss = (const void *)iq->cdesc;
|
||||
rsp_type = G_RSPD_TYPE(ctrl->u.type_gen);
|
||||
if (__predict_false(rsp_type != X_RSPD_TYPE_CPL))
|
||||
panic("%s: unexpected rsp_type %d", __func__, rsp_type);
|
||||
|
||||
/* Should only get CPL on this queue */
|
||||
KASSERT(G_RSPD_TYPE(ctrl->u.type_gen) == X_RSPD_TYPE_CPL,
|
||||
("%s: unexpected type %d", __func__,
|
||||
G_RSPD_TYPE(ctrl->u.type_gen)));
|
||||
|
||||
switch (rss->opcode) {
|
||||
case CPL_FW4_MSG:
|
||||
case CPL_FW6_MSG: {
|
||||
const struct cpl_fw6_msg *cpl;
|
||||
|
||||
cpl = (const void *)(rss + 1);
|
||||
if (cpl->type == FW6_TYPE_CMD_RPL)
|
||||
t4_handle_fw_rpl(sc, cpl->data);
|
||||
|
||||
break;
|
||||
}
|
||||
case CPL_SGE_EGR_UPDATE:
|
||||
handle_sge_egr_update(sc, (const void *)(rss + 1));
|
||||
break;
|
||||
case CPL_SET_TCB_RPL:
|
||||
filter_rpl(sc, (const void *) (rss + 1));
|
||||
break;
|
||||
default:
|
||||
device_printf(sc->dev,
|
||||
"can't handle CPL opcode %d.", rss->opcode);
|
||||
}
|
||||
handle_cpl(sc, iq);
|
||||
|
||||
ndesc_total++;
|
||||
if (++ndesc_pending >= iq->qsize / 4) {
|
||||
@ -600,6 +597,7 @@ t4_evt_rx(void *arg)
|
||||
V_QINTR_TIMER_IDX(X_TIMERREG_UPDATE_CIDX)));
|
||||
ndesc_pending = 0;
|
||||
}
|
||||
|
||||
iq_next(iq);
|
||||
}
|
||||
|
||||
@ -613,7 +611,7 @@ t4_evt_rx(void *arg)
|
||||
#define RX_COPY_THRESHOLD MINCLSIZE
|
||||
#endif
|
||||
|
||||
void
|
||||
static void
|
||||
t4_eth_rx(void *arg)
|
||||
{
|
||||
struct sge_rxq *rxq = arg;
|
||||
@ -644,17 +642,9 @@ t4_eth_rx(void *arg)
|
||||
rss = (const void *)iq->cdesc;
|
||||
i = G_RSPD_TYPE(ctrl->u.type_gen);
|
||||
|
||||
if (__predict_false(i == X_RSPD_TYPE_CPL)) {
|
||||
|
||||
/* Can't be anything except an egress update */
|
||||
KASSERT(rss->opcode == CPL_SGE_EGR_UPDATE,
|
||||
("%s: unexpected CPL %x", __func__, rss->opcode));
|
||||
|
||||
handle_sge_egr_update(sc, (const void *)(rss + 1));
|
||||
goto nextdesc;
|
||||
}
|
||||
KASSERT(i == X_RSPD_TYPE_FLBUF && rss->opcode == CPL_RX_PKT,
|
||||
("%s: unexpected CPL %x rsp %d", __func__, rss->opcode, i));
|
||||
("%s: unexpected type %d CPL opcode 0x%x",
|
||||
__func__, i, rss->opcode));
|
||||
|
||||
sd_next = sd + 1;
|
||||
if (__predict_false(fl->cidx + 1 == fl->cap))
|
||||
@ -786,16 +776,15 @@ t4_eth_rx(void *arg)
|
||||
refill_fl(sc, fl, 64, 32);
|
||||
FL_UNLOCK(fl);
|
||||
|
||||
nextdesc: ndescs++;
|
||||
iq_next(iq);
|
||||
|
||||
if (ndescs > 32) {
|
||||
if (++ndescs > 32) {
|
||||
t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS),
|
||||
V_CIDXINC(ndescs) |
|
||||
V_INGRESSQID((u32)iq->cntxt_id) |
|
||||
V_SEINTARM(V_QINTR_TIMER_IDX(X_TIMERREG_UPDATE_CIDX)));
|
||||
ndescs = 0;
|
||||
}
|
||||
|
||||
iq_next(iq);
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
@ -1008,7 +997,7 @@ t4_update_fl_bufsize(struct ifnet *ifp)
|
||||
|
||||
/*
|
||||
* A non-NULL handler indicates this iq will not receive direct interrupts, the
|
||||
* handler will be invoked by a forwarded interrupt queue.
|
||||
* handler will be invoked by an interrupt queue.
|
||||
*/
|
||||
static inline void
|
||||
init_iq(struct sge_iq *iq, struct adapter *sc, int tmr_idx, int pktc_idx,
|
||||
@ -1100,7 +1089,7 @@ free_ring(struct adapter *sc, bus_dma_tag_t tag, bus_dmamap_t map,
|
||||
*
|
||||
* If the ingress queue will take interrupts directly (iq->handler == NULL) then
|
||||
* the intr_idx specifies the vector, starting from 0. Otherwise it specifies
|
||||
* the index of the queue to which its interrupts will be forwarded.
|
||||
* the index of the interrupt queue to which its interrupts will be forwarded.
|
||||
*/
|
||||
static int
|
||||
alloc_iq_fl(struct port_info *pi, struct sge_iq *iq, struct sge_fl *fl,
|
||||
@ -1112,10 +1101,6 @@ alloc_iq_fl(struct port_info *pi, struct sge_iq *iq, struct sge_fl *fl,
|
||||
struct adapter *sc = iq->adapter;
|
||||
__be32 v = 0;
|
||||
|
||||
/* The adapter queues are nominally allocated in port[0]'s name */
|
||||
if (pi == NULL)
|
||||
pi = sc->port[0];
|
||||
|
||||
len = iq->qsize * iq->esize;
|
||||
rc = alloc_ring(sc, len, &iq->desc_tag, &iq->desc_map, &iq->ba,
|
||||
(void **)&iq->desc);
|
||||
@ -1135,10 +1120,10 @@ alloc_iq_fl(struct port_info *pi, struct sge_iq *iq, struct sge_fl *fl,
|
||||
v |= F_FW_IQ_CMD_IQASYNCH;
|
||||
|
||||
if (iq->handler) {
|
||||
KASSERT(intr_idx < NFIQ(sc),
|
||||
KASSERT(intr_idx < NINTRQ(sc),
|
||||
("%s: invalid indirect intr_idx %d", __func__, intr_idx));
|
||||
v |= F_FW_IQ_CMD_IQANDST;
|
||||
v |= V_FW_IQ_CMD_IQANDSTINDEX(sc->sge.fiq[intr_idx].abs_id);
|
||||
v |= V_FW_IQ_CMD_IQANDSTINDEX(sc->sge.intrq[intr_idx].abs_id);
|
||||
} else {
|
||||
KASSERT(intr_idx < sc->intr_count,
|
||||
("%s: invalid direct intr_idx %d", __func__, intr_idx));
|
||||
@ -1333,13 +1318,61 @@ free_iq_fl(struct port_info *pi, struct sge_iq *iq, struct sge_fl *fl)
|
||||
}
|
||||
|
||||
static int
|
||||
alloc_iq(struct sge_iq *iq, int intr_idx)
|
||||
alloc_intrq(struct adapter *sc, int port_idx, int intrq_idx, int intr_idx)
|
||||
{
|
||||
return alloc_iq_fl(NULL, iq, NULL, intr_idx, -1);
|
||||
int rc;
|
||||
struct sysctl_oid *oid;
|
||||
struct sysctl_oid_list *children;
|
||||
char name[16];
|
||||
struct sge_iq *intrq = &sc->sge.intrq[intrq_idx];
|
||||
|
||||
rc = alloc_iq_fl(sc->port[port_idx], intrq, NULL, intr_idx, -1);
|
||||
if (rc != 0)
|
||||
return (rc);
|
||||
|
||||
children = SYSCTL_CHILDREN(sc->oid_intrq);
|
||||
|
||||
snprintf(name, sizeof(name), "%d", intrq_idx);
|
||||
oid = SYSCTL_ADD_NODE(&sc->ctx, children, OID_AUTO, name, CTLFLAG_RD,
|
||||
NULL, "interrupt queue");
|
||||
children = SYSCTL_CHILDREN(oid);
|
||||
|
||||
SYSCTL_ADD_PROC(&sc->ctx, children, OID_AUTO, "cidx",
|
||||
CTLTYPE_INT | CTLFLAG_RD, &intrq->cidx, 0, sysctl_uint16, "I",
|
||||
"consumer index");
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static int
|
||||
free_iq(struct sge_iq *iq)
|
||||
free_intrq(struct sge_iq *iq)
|
||||
{
|
||||
return free_iq_fl(NULL, iq, NULL);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
alloc_fwq(struct adapter *sc, int intr_idx)
|
||||
{
|
||||
int rc;
|
||||
struct sysctl_oid_list *children;
|
||||
struct sge_iq *fwq = &sc->sge.fwq;
|
||||
|
||||
rc = alloc_iq_fl(sc->port[0], fwq, NULL, intr_idx, -1);
|
||||
if (rc != 0)
|
||||
return (rc);
|
||||
|
||||
children = SYSCTL_CHILDREN(sc->oid_fwq);
|
||||
|
||||
SYSCTL_ADD_PROC(&sc->ctx, children, OID_AUTO, "cidx",
|
||||
CTLTYPE_INT | CTLFLAG_RD, &fwq->cidx, 0, sysctl_uint16, "I",
|
||||
"consumer index");
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static int
|
||||
free_fwq(struct sge_iq *iq)
|
||||
{
|
||||
return free_iq_fl(NULL, iq, NULL);
|
||||
}
|
||||
@ -1375,7 +1408,7 @@ alloc_rxq(struct port_info *pi, struct sge_rxq *rxq, int intr_idx, int idx)
|
||||
children = SYSCTL_CHILDREN(oid);
|
||||
|
||||
SYSCTL_ADD_PROC(&pi->ctx, children, OID_AUTO, "abs_id",
|
||||
CTLTYPE_INT | CTLFLAG_RD, &rxq->iq.abs_id, 0, sysctl_abs_id, "I",
|
||||
CTLTYPE_INT | CTLFLAG_RD, &rxq->iq.abs_id, 0, sysctl_uint16, "I",
|
||||
"absolute id of the queue");
|
||||
#ifdef INET
|
||||
SYSCTL_ADD_INT(&pi->ctx, children, OID_AUTO, "lro_queued", CTLFLAG_RD,
|
||||
@ -1433,7 +1466,10 @@ alloc_ctrlq(struct adapter *sc, struct sge_ctrlq *ctrlq, int idx)
|
||||
eq->cap = eq->qsize - SPG_LEN / CTRL_EQ_ESIZE;
|
||||
eq->spg = (void *)&eq->desc[eq->cap];
|
||||
eq->avail = eq->cap - 1; /* one less to avoid cidx = pidx */
|
||||
eq->iqid = sc->sge.fwq.cntxt_id;
|
||||
if (sc->flags & INTR_SHARED)
|
||||
eq->iqid = sc->sge.intrq[idx % NINTRQ(sc)].cntxt_id;
|
||||
else
|
||||
eq->iqid = sc->sge.intrq[sc->port[idx]->first_rxq].cntxt_id;
|
||||
|
||||
bzero(&c, sizeof(c));
|
||||
|
||||
@ -1446,8 +1482,8 @@ alloc_ctrlq(struct adapter *sc, struct sge_ctrlq *ctrlq, int idx)
|
||||
c.physeqid_pkd = htobe32(0);
|
||||
c.fetchszm_to_iqid =
|
||||
htobe32(V_FW_EQ_CTRL_CMD_HOSTFCMODE(X_HOSTFCMODE_STATUS_PAGE) |
|
||||
V_FW_EQ_CTRL_CMD_PCIECHN(idx) | F_FW_EQ_CTRL_CMD_FETCHRO |
|
||||
V_FW_EQ_CTRL_CMD_IQID(eq->iqid));
|
||||
V_FW_EQ_CTRL_CMD_PCIECHN(sc->port[idx]->tx_chan) |
|
||||
F_FW_EQ_CTRL_CMD_FETCHRO | V_FW_EQ_CTRL_CMD_IQID(eq->iqid));
|
||||
c.dcaen_to_eqsize =
|
||||
htobe32(V_FW_EQ_CTRL_CMD_FBMIN(X_FETCHBURSTMIN_64B) |
|
||||
V_FW_EQ_CTRL_CMD_FBMAX(X_FETCHBURSTMAX_512B) |
|
||||
@ -1479,13 +1515,12 @@ alloc_ctrlq(struct adapter *sc, struct sge_ctrlq *ctrlq, int idx)
|
||||
NULL, "ctrl queue");
|
||||
children = SYSCTL_CHILDREN(oid);
|
||||
|
||||
SYSCTL_ADD_UQUAD(&sc->ctx, children, OID_AUTO, "total_wrs", CTLFLAG_RD,
|
||||
&ctrlq->total_wrs, "total # of work requests");
|
||||
SYSCTL_ADD_PROC(&sc->ctx, children, OID_AUTO, "pidx",
|
||||
CTLTYPE_INT | CTLFLAG_RD, &ctrlq->eq.pidx, 0, sysctl_uint16, "I",
|
||||
"producer index");
|
||||
SYSCTL_ADD_UINT(&sc->ctx, children, OID_AUTO, "no_desc", CTLFLAG_RD,
|
||||
&ctrlq->no_desc, 0,
|
||||
"# of times ctrlq ran out of hardware descriptors");
|
||||
SYSCTL_ADD_UINT(&sc->ctx, children, OID_AUTO, "too_long", CTLFLAG_RD,
|
||||
&ctrlq->too_long, 0, "# of oversized work requests");
|
||||
|
||||
return (rc);
|
||||
}
|
||||
@ -1526,6 +1561,7 @@ alloc_txq(struct port_info *pi, struct sge_txq *txq, int idx)
|
||||
char name[16];
|
||||
struct sysctl_oid *oid;
|
||||
struct sysctl_oid_list *children;
|
||||
struct sge_iq *intrq;
|
||||
|
||||
txq->ifp = pi->ifp;
|
||||
TASK_INIT(&txq->resume_tx, 0, cxgbe_txq_start, txq);
|
||||
@ -1544,7 +1580,12 @@ alloc_txq(struct port_info *pi, struct sge_txq *txq, int idx)
|
||||
txq->sdesc = malloc(eq->cap * sizeof(struct tx_sdesc), M_CXGBE,
|
||||
M_ZERO | M_WAITOK);
|
||||
txq->br = buf_ring_alloc(eq->qsize, M_CXGBE, M_WAITOK, &eq->eq_lock);
|
||||
eq->iqid = sc->sge.rxq[pi->first_rxq].iq.cntxt_id;
|
||||
|
||||
intrq = &sc->sge.intrq[0];
|
||||
if (sc->flags & INTR_SHARED)
|
||||
eq->iqid = intrq[(pi->first_txq + idx) % NINTRQ(sc)].cntxt_id;
|
||||
else
|
||||
eq->iqid = intrq[pi->first_rxq + (idx % pi->nrxq)].cntxt_id;
|
||||
|
||||
rc = bus_dma_tag_create(sc->dmat, 1, 0, BUS_SPACE_MAXADDR,
|
||||
BUS_SPACE_MAXADDR, NULL, NULL, 64 * 1024, TX_SGL_SEGS,
|
||||
@ -2324,7 +2365,7 @@ write_txpkts_wr(struct sge_txq *txq, struct txpkts *txpkts)
|
||||
wr->equiq_to_len16 = htobe32(ctrl);
|
||||
wr->plen = htobe16(txpkts->plen);
|
||||
wr->npkt = txpkts->npkt;
|
||||
wr->r3 = wr->r4 = 0;
|
||||
wr->r3 = wr->type = 0;
|
||||
|
||||
/* Everything else already written */
|
||||
|
||||
@ -2695,6 +2736,32 @@ handle_sge_egr_update(struct adapter *sc, const struct cpl_sge_egr_update *cpl)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_cpl(struct adapter *sc, struct sge_iq *iq)
|
||||
{
|
||||
const struct rss_header *rss = (const void *)iq->cdesc;
|
||||
const struct cpl_fw6_msg *cpl = (const void *)(rss + 1);
|
||||
|
||||
switch (rss->opcode) {
|
||||
case CPL_FW4_MSG:
|
||||
case CPL_FW6_MSG:
|
||||
if (cpl->type == FW6_TYPE_CMD_RPL)
|
||||
t4_handle_fw_rpl(sc, cpl->data);
|
||||
break;
|
||||
|
||||
case CPL_SGE_EGR_UPDATE:
|
||||
handle_sge_egr_update(sc, (const void *)cpl);
|
||||
break;
|
||||
|
||||
case CPL_SET_TCB_RPL:
|
||||
filter_rpl(sc, (const void *)cpl);
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("%s: unexpected CPL opcode 0x%x", __func__, rss->opcode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* m0 is freed on successful transmission.
|
||||
*/
|
||||
@ -2710,7 +2777,8 @@ ctrl_tx(struct adapter *sc, struct sge_ctrlq *ctrlq, struct mbuf *m0)
|
||||
M_ASSERTPKTHDR(m0);
|
||||
|
||||
if (m0->m_pkthdr.len > SGE_MAX_WR_LEN) {
|
||||
ctrlq->too_long++;
|
||||
log(LOG_ERR, "%s: %s work request too long (%d)",
|
||||
device_get_nameunit(sc->dev), __func__, m0->m_pkthdr.len);
|
||||
return (EMSGSIZE);
|
||||
}
|
||||
ndesc = howmany(m0->m_pkthdr.len, CTRL_EQ_ESIZE);
|
||||
@ -2738,7 +2806,6 @@ ctrl_tx(struct adapter *sc, struct sge_ctrlq *ctrlq, struct mbuf *m0)
|
||||
eq->pidx -= eq->cap;
|
||||
|
||||
eq->pending += ndesc;
|
||||
ctrlq->total_wrs++;
|
||||
ring_eq_db(sc, eq);
|
||||
failed:
|
||||
EQ_UNLOCK(eq);
|
||||
@ -2749,7 +2816,7 @@ ctrl_tx(struct adapter *sc, struct sge_ctrlq *ctrlq, struct mbuf *m0)
|
||||
}
|
||||
|
||||
static int
|
||||
sysctl_abs_id(SYSCTL_HANDLER_ARGS)
|
||||
sysctl_uint16(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
uint16_t *id = arg1;
|
||||
int i = *id;
|
||||
|
@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <powerpc/powermac/powermac_thermal.h>
|
||||
|
||||
#define FCU_ZERO_C_TO_K 2732
|
||||
|
||||
@ -63,8 +64,9 @@ __FBSDID("$FreeBSD$");
|
||||
uint8_t adc741x_config;
|
||||
|
||||
struct ad7417_sensor {
|
||||
struct pmac_therm therm;
|
||||
device_t dev;
|
||||
int id;
|
||||
char location[32];
|
||||
enum {
|
||||
ADC7417_TEMP_SENSOR,
|
||||
ADC7417_ADC_SENSOR
|
||||
@ -83,6 +85,9 @@ static int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg,
|
||||
uint8_t *data);
|
||||
static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg,
|
||||
uint16_t *data);
|
||||
static int ad7417_diode_read(struct ad7417_sensor *sens);
|
||||
static int ad7417_adc_read(struct ad7417_sensor *sens);
|
||||
static int ad7417_sensor_read(struct ad7417_sensor *sens);
|
||||
|
||||
struct ad7417_softc {
|
||||
device_t sc_dev;
|
||||
@ -243,7 +248,7 @@ ad7417_fill_sensor_prop(device_t dev)
|
||||
sizeof(location));
|
||||
while (len < prop_len) {
|
||||
if (sc->sc_sensors != NULL)
|
||||
strcpy(sc->sc_sensors[i].location, location + len);
|
||||
strcpy(sc->sc_sensors[i].therm.name, location + len);
|
||||
prev_len = strlen(location + len) + 1;
|
||||
len += prev_len;
|
||||
i++;
|
||||
@ -251,7 +256,7 @@ ad7417_fill_sensor_prop(device_t dev)
|
||||
if (sc->sc_sensors == NULL)
|
||||
return (i);
|
||||
|
||||
/* Fill the fan type property. */
|
||||
/* Fill the sensor type property. */
|
||||
len = 0;
|
||||
i = 0;
|
||||
prev_len = 0;
|
||||
@ -271,6 +276,36 @@ ad7417_fill_sensor_prop(device_t dev)
|
||||
for (j = 0; j < i; j++)
|
||||
sc->sc_sensors[j].id = id[j];
|
||||
|
||||
/* Fill the sensor zone property. Taken from OF. */
|
||||
prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id));
|
||||
for (j = 0; j < i; j++)
|
||||
sc->sc_sensors[j].therm.zone = id[j];
|
||||
|
||||
/* Finish setting up sensor properties */
|
||||
for (j = 0; j < i; j++) {
|
||||
sc->sc_sensors[j].dev = dev;
|
||||
|
||||
/* HACK: Apple wired a random diode to the ADC line */
|
||||
if (strstr(sc->sc_sensors[j].therm.name, "DIODE TEMP")
|
||||
!= NULL) {
|
||||
sc->sc_sensors[j].type = ADC7417_TEMP_SENSOR;
|
||||
sc->sc_sensors[j].therm.read =
|
||||
(int (*)(struct pmac_therm *))(ad7417_diode_read);
|
||||
} else {
|
||||
sc->sc_sensors[j].therm.read =
|
||||
(int (*)(struct pmac_therm *))(ad7417_sensor_read);
|
||||
}
|
||||
|
||||
if (sc->sc_sensors[j].type != ADC7417_TEMP_SENSOR)
|
||||
continue;
|
||||
|
||||
/* Make up some ranges */
|
||||
sc->sc_sensors[j].therm.target_temp = 500 + 2732;
|
||||
sc->sc_sensors[j].therm.max_temp = 900 + 2732;
|
||||
|
||||
pmac_thermal_sensor_register(&sc->sc_sensors[j].therm);
|
||||
}
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
@ -310,8 +345,9 @@ ad7417_attach(device_t dev)
|
||||
|
||||
/* Add sysctls for the sensors. */
|
||||
for (i = 0; i < sc->sc_nsensors; i++) {
|
||||
for (j = 0; j < strlen(sc->sc_sensors[i].location); j++) {
|
||||
sysctl_name[j] = tolower(sc->sc_sensors[i].location[j]);
|
||||
for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) {
|
||||
sysctl_name[j] =
|
||||
tolower(sc->sc_sensors[i].therm.name[j]);
|
||||
if (isspace(sysctl_name[j]))
|
||||
sysctl_name[j] = '_';
|
||||
}
|
||||
@ -341,7 +377,7 @@ ad7417_attach(device_t dev)
|
||||
device_printf(dev, "Sensors\n");
|
||||
for (i = 0; i < sc->sc_nsensors; i++) {
|
||||
device_printf(dev, "Location: %s ID: %d type: %d\n",
|
||||
sc->sc_sensors[i].location,
|
||||
sc->sc_sensors[i].therm.name,
|
||||
sc->sc_sensors[i].id,
|
||||
sc->sc_sensors[i].type);
|
||||
}
|
||||
@ -391,44 +427,91 @@ ad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value,
|
||||
}
|
||||
|
||||
static int
|
||||
ad7417_sensor_read(device_t dev, struct ad7417_sensor *sens, int *temp)
|
||||
ad7417_diode_read(struct ad7417_sensor *sens)
|
||||
{
|
||||
static int eeprom_read = 0;
|
||||
static cell_t eeprom[2][40];
|
||||
phandle_t eeprom_node;
|
||||
int rawval, diode_slope, diode_offset;
|
||||
int temp;
|
||||
|
||||
if (!eeprom_read) {
|
||||
eeprom_node = OF_finddevice("/u3/i2c/cpuid@a0");
|
||||
OF_getprop(eeprom_node, "cpuid", eeprom[0], sizeof(eeprom[0]));
|
||||
eeprom_node = OF_finddevice("/u3/i2c/cpuid@a2");
|
||||
OF_getprop(eeprom_node, "cpuid", eeprom[1], sizeof(eeprom[1]));
|
||||
eeprom_read = 1;
|
||||
}
|
||||
|
||||
rawval = ad7417_adc_read(sens);
|
||||
if (strstr(sens->therm.name, "CPU B") != NULL) {
|
||||
diode_slope = eeprom[1][0x11] >> 16;
|
||||
diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12;
|
||||
} else {
|
||||
diode_slope = eeprom[0][0x11] >> 16;
|
||||
diode_offset = (int16_t)(eeprom[0][0x11] & 0xffff) << 12;
|
||||
}
|
||||
|
||||
temp = (rawval*diode_slope + diode_offset) >> 2;
|
||||
temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16);
|
||||
|
||||
return (temp + FCU_ZERO_C_TO_K);
|
||||
}
|
||||
|
||||
static int
|
||||
ad7417_adc_read(struct ad7417_sensor *sens)
|
||||
{
|
||||
struct ad7417_softc *sc;
|
||||
uint8_t chan;
|
||||
int temp;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc = device_get_softc(sens->dev);
|
||||
|
||||
switch (sens->id) {
|
||||
case 11:
|
||||
case 16:
|
||||
chan = 1;
|
||||
break;
|
||||
case 12:
|
||||
case 17:
|
||||
chan = 2;
|
||||
break;
|
||||
case 13:
|
||||
case 18:
|
||||
chan = 3;
|
||||
break;
|
||||
case 14:
|
||||
case 19:
|
||||
chan = 4;
|
||||
break;
|
||||
default:
|
||||
chan = 1;
|
||||
}
|
||||
|
||||
ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan);
|
||||
|
||||
return (temp);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ad7417_sensor_read(struct ad7417_sensor *sens)
|
||||
{
|
||||
struct ad7417_softc *sc;
|
||||
int temp;
|
||||
|
||||
sc = device_get_softc(sens->dev);
|
||||
|
||||
/* Init the ADC. */
|
||||
ad7417_init_adc(sc->sc_dev, sc->sc_addr);
|
||||
|
||||
if (sens->type == ADC7417_TEMP_SENSOR) {
|
||||
ad7417_get_temp(sc->sc_dev, sc->sc_addr, temp);
|
||||
*temp += FCU_ZERO_C_TO_K;
|
||||
ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp);
|
||||
temp += FCU_ZERO_C_TO_K;
|
||||
} else {
|
||||
uint8_t chan;
|
||||
switch (sens->id) {
|
||||
case 11:
|
||||
case 16:
|
||||
chan = 1;
|
||||
break;
|
||||
case 12:
|
||||
case 17:
|
||||
chan = 2;
|
||||
break;
|
||||
case 13:
|
||||
case 18:
|
||||
chan = 3;
|
||||
break;
|
||||
case 14:
|
||||
case 19:
|
||||
chan = 4;
|
||||
break;
|
||||
default:
|
||||
chan = 1;
|
||||
}
|
||||
|
||||
ad7417_get_adc(sc->sc_dev, sc->sc_addr, temp, chan);
|
||||
temp = ad7417_adc_read(sens);
|
||||
}
|
||||
return (0);
|
||||
return (temp);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -439,19 +522,16 @@ ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
struct ad7417_sensor *sens;
|
||||
int value = 0;
|
||||
int error;
|
||||
int temp;
|
||||
|
||||
dev = arg1;
|
||||
sc = device_get_softc(dev);
|
||||
sens = &sc->sc_sensors[arg2];
|
||||
|
||||
error = ad7417_sensor_read(dev, sens, &value);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
value = sens->therm.read(&sens->therm);
|
||||
if (value < 0)
|
||||
return (ENXIO);
|
||||
|
||||
temp = value;
|
||||
|
||||
error = sysctl_handle_int(oidp, &temp, 0, req);
|
||||
error = sysctl_handle_int(oidp, &value, 0, req);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
@ -49,33 +49,31 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <powerpc/powermac/powermac_thermal.h>
|
||||
|
||||
#define FCU_ZERO_C_TO_K 2732
|
||||
|
||||
/* Drivebay sensor: LM75/DS1775. */
|
||||
#define DS1775_TEMP 0x0
|
||||
|
||||
struct ds1775_sensor {
|
||||
char location[32];
|
||||
};
|
||||
|
||||
/* Regular bus attachment functions */
|
||||
static int ds1775_probe(device_t);
|
||||
static int ds1775_attach(device_t);
|
||||
|
||||
struct ds1775_softc {
|
||||
struct pmac_therm sc_sensor;
|
||||
device_t sc_dev;
|
||||
struct intr_config_hook enum_hook;
|
||||
uint32_t sc_addr;
|
||||
};
|
||||
|
||||
/* Utility functions */
|
||||
static int ds1775_sensor_read(struct ds1775_softc *sc);
|
||||
static int ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS);
|
||||
static void ds1775_start(void *xdev);
|
||||
static int ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg,
|
||||
uint16_t *data);
|
||||
|
||||
struct ds1775_softc {
|
||||
device_t sc_dev;
|
||||
struct intr_config_hook enum_hook;
|
||||
uint32_t sc_addr;
|
||||
struct ds1775_sensor *sc_sensors;
|
||||
|
||||
};
|
||||
static device_method_t ds1775_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, ds1775_probe),
|
||||
@ -92,7 +90,6 @@ static driver_t ds1775_driver = {
|
||||
static devclass_t ds1775_devclass;
|
||||
|
||||
DRIVER_MODULE(ds1755, iicbus, ds1775_driver, ds1775_devclass, 0, 0);
|
||||
MALLOC_DEFINE(M_DS1775, "ds1775", "Temp-Monitor DS1775");
|
||||
|
||||
static int
|
||||
ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data)
|
||||
@ -169,7 +166,6 @@ ds1775_start(void *xdev)
|
||||
{
|
||||
phandle_t child;
|
||||
struct ds1775_softc *sc;
|
||||
struct ds1775_sensor *sens;
|
||||
struct sysctl_oid *sensroot_oid;
|
||||
struct sysctl_ctx_list *ctx;
|
||||
ssize_t plen;
|
||||
@ -183,30 +179,34 @@ ds1775_start(void *xdev)
|
||||
|
||||
child = ofw_bus_get_node(dev);
|
||||
|
||||
sc->sc_sensors = malloc (sizeof(struct ds1775_sensor),
|
||||
M_DS1775, M_WAITOK | M_ZERO);
|
||||
|
||||
sens = sc->sc_sensors;
|
||||
|
||||
ctx = device_get_sysctl_ctx(dev);
|
||||
sensroot_oid = device_get_sysctl_tree(dev);
|
||||
|
||||
plen = OF_getprop(child, "hwsensor-location", sens->location,
|
||||
sizeof(sens->location));
|
||||
OF_getprop(child, "hwsensor-zone", &sc->sc_sensor.zone, sizeof(int));
|
||||
plen = OF_getprop(child, "hwsensor-location", sc->sc_sensor.name,
|
||||
sizeof(sc->sc_sensor.name));
|
||||
units = "C";
|
||||
|
||||
if (plen == -1) {
|
||||
strcpy(sysctl_name, "sensor");
|
||||
} else {
|
||||
for (i = 0; i < strlen(sens->location); i++) {
|
||||
sysctl_name[i] = tolower(sens->location[i]);
|
||||
for (i = 0; i < strlen(sc->sc_sensor.name); i++) {
|
||||
sysctl_name[i] = tolower(sc->sc_sensor.name[i]);
|
||||
if (isspace(sysctl_name[i]))
|
||||
sysctl_name[i] = '_';
|
||||
}
|
||||
sysctl_name[i] = 0;
|
||||
}
|
||||
|
||||
sprintf(sysctl_desc,"%s (%s)", sens->location, units);
|
||||
/* Make up target temperatures. These are low, for the drive bay. */
|
||||
sc->sc_sensor.target_temp = 300 + FCU_ZERO_C_TO_K;
|
||||
sc->sc_sensor.max_temp = 600 + FCU_ZERO_C_TO_K;
|
||||
|
||||
sc->sc_sensor.read =
|
||||
(int (*)(struct pmac_therm *sc))(ds1775_sensor_read);
|
||||
pmac_thermal_sensor_register(&sc->sc_sensor);
|
||||
|
||||
sprintf(sysctl_desc,"%s (%s)", sc->sc_sensor.name, units);
|
||||
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO,
|
||||
sysctl_name,
|
||||
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
|
||||
@ -216,14 +216,11 @@ ds1775_start(void *xdev)
|
||||
}
|
||||
|
||||
static int
|
||||
ds1775_sensor_read(device_t dev, struct ds1775_sensor *sens, int *temp)
|
||||
ds1775_sensor_read(struct ds1775_softc *sc)
|
||||
{
|
||||
struct ds1775_softc *sc;
|
||||
uint16_t buf[2];
|
||||
uint16_t read;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
ds1775_read_2(sc->sc_dev, sc->sc_addr, DS1775_TEMP, buf);
|
||||
|
||||
read = *((int16_t *)buf);
|
||||
@ -231,29 +228,21 @@ ds1775_sensor_read(device_t dev, struct ds1775_sensor *sens, int *temp)
|
||||
/* The default mode of the ADC is 9 bit, the resolution is 0.5 C per
|
||||
bit. The temperature is in tenth kelvin.
|
||||
*/
|
||||
*temp = ((int16_t)(read) >> 7) * 5;
|
||||
|
||||
return (0);
|
||||
return (((int16_t)(read) >> 7) * 5 + FCU_ZERO_C_TO_K);
|
||||
}
|
||||
|
||||
static int
|
||||
ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
device_t dev;
|
||||
struct ds1775_softc *sc;
|
||||
struct ds1775_sensor *sens;
|
||||
int value;
|
||||
int error;
|
||||
unsigned int temp;
|
||||
|
||||
dev = arg1;
|
||||
sc = device_get_softc(dev);
|
||||
sens = &sc->sc_sensors[arg2];
|
||||
|
||||
error = ds1775_sensor_read(dev, sens, &value);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
temp = value + FCU_ZERO_C_TO_K;
|
||||
temp = ds1775_sensor_read(sc);
|
||||
|
||||
error = sysctl_handle_int(oidp, &temp, 0, req);
|
||||
|
||||
|
@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <powerpc/powermac/powermac_thermal.h>
|
||||
|
||||
#define FCU_ZERO_C_TO_K 2732
|
||||
|
||||
@ -61,8 +62,10 @@ __FBSDID("$FreeBSD$");
|
||||
#define MAX6690_TEMP_MASK 0xe0
|
||||
|
||||
struct max6690_sensor {
|
||||
struct pmac_therm therm;
|
||||
device_t dev;
|
||||
|
||||
int id;
|
||||
char location[32];
|
||||
};
|
||||
|
||||
/* Regular bus attachment functions */
|
||||
@ -70,6 +73,7 @@ static int max6690_probe(device_t);
|
||||
static int max6690_attach(device_t);
|
||||
|
||||
/* Utility functions */
|
||||
static int max6690_sensor_read(struct max6690_sensor *sens);
|
||||
static int max6690_sensor_sysctl(SYSCTL_HANDLER_ARGS);
|
||||
static void max6690_start(void *xdev);
|
||||
static int max6690_read_1(device_t dev, uint32_t addr, uint8_t reg,
|
||||
@ -167,7 +171,7 @@ max6690_fill_sensor_prop(device_t dev)
|
||||
sizeof(location));
|
||||
while (len < prop_len) {
|
||||
if (sc->sc_sensors != NULL)
|
||||
strcpy(sc->sc_sensors[i].location, location + len);
|
||||
strcpy(sc->sc_sensors[i].therm.name, location + len);
|
||||
prev_len = strlen(location + len) + 1;
|
||||
len += prev_len;
|
||||
i++;
|
||||
@ -180,6 +184,22 @@ max6690_fill_sensor_prop(device_t dev)
|
||||
for (j = 0; j < i; j++)
|
||||
sc->sc_sensors[j].id = (id[j] & 0xf);
|
||||
|
||||
/* Fill the sensor zone property. */
|
||||
prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id));
|
||||
for (j = 0; j < i; j++)
|
||||
sc->sc_sensors[j].therm.zone = id[j];
|
||||
|
||||
/* Set up remaining sensor properties */
|
||||
for (j = 0; j < i; j++) {
|
||||
sc->sc_sensors[j].dev = dev;
|
||||
|
||||
sc->sc_sensors[j].therm.target_temp = 400 + 2732;
|
||||
sc->sc_sensors[j].therm.max_temp = 800 + 2732;
|
||||
|
||||
sc->sc_sensors[j].therm.read =
|
||||
(int (*)(struct pmac_therm *))(max6690_sensor_read);
|
||||
}
|
||||
|
||||
return (i);
|
||||
}
|
||||
static int
|
||||
@ -240,10 +260,15 @@ max6690_start(void *xdev)
|
||||
/* Now we can fill the properties into the allocated struct. */
|
||||
sc->sc_nsensors = max6690_fill_sensor_prop(dev);
|
||||
|
||||
/* Register with powermac_thermal */
|
||||
for (i = 0; i < sc->sc_nsensors; i++)
|
||||
pmac_thermal_sensor_register(&sc->sc_sensors[i].therm);
|
||||
|
||||
/* Add sysctls for the sensors. */
|
||||
for (i = 0; i < sc->sc_nsensors; i++) {
|
||||
for (j = 0; j < strlen(sc->sc_sensors[i].location); j++) {
|
||||
sysctl_name[j] = tolower(sc->sc_sensors[i].location[j]);
|
||||
for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) {
|
||||
sysctl_name[j] =
|
||||
tolower(sc->sc_sensors[i].therm.name[j]);
|
||||
if (isspace(sysctl_name[j]))
|
||||
sysctl_name[j] = '_';
|
||||
}
|
||||
@ -265,7 +290,7 @@ max6690_start(void *xdev)
|
||||
device_printf(dev, "Sensors\n");
|
||||
for (i = 0; i < sc->sc_nsensors; i++) {
|
||||
device_printf(dev, "Location : %s ID: %d\n",
|
||||
sc->sc_sensors[i].location,
|
||||
sc->sc_sensors[i].therm.name,
|
||||
sc->sc_sensors[i].id);
|
||||
}
|
||||
}
|
||||
@ -274,14 +299,15 @@ max6690_start(void *xdev)
|
||||
}
|
||||
|
||||
static int
|
||||
max6690_sensor_read(device_t dev, struct max6690_sensor *sens, int *temp)
|
||||
max6690_sensor_read(struct max6690_sensor *sens)
|
||||
{
|
||||
uint8_t reg_int = 0, reg_ext = 0;
|
||||
uint8_t integer;
|
||||
uint8_t fraction;
|
||||
int temp;
|
||||
struct max6690_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc = device_get_softc(sens->dev);
|
||||
|
||||
/* The internal sensor id's are even, the external ar odd. */
|
||||
if ((sens->id % 2) == 0) {
|
||||
@ -301,9 +327,9 @@ max6690_sensor_read(device_t dev, struct max6690_sensor *sens, int *temp)
|
||||
/* The temperature is in tenth kelvin, the fractional part resolution
|
||||
is 0.125.
|
||||
*/
|
||||
*temp = (integer * 10) + (fraction >> 5) * 10 / 8;
|
||||
temp = (integer * 10) + (fraction >> 5) * 10 / 8;
|
||||
|
||||
return (0);
|
||||
return (temp + FCU_ZERO_C_TO_K);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -312,7 +338,6 @@ max6690_sensor_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
device_t dev;
|
||||
struct max6690_softc *sc;
|
||||
struct max6690_sensor *sens;
|
||||
int value = 0;
|
||||
int error;
|
||||
unsigned int temp;
|
||||
|
||||
@ -320,11 +345,9 @@ max6690_sensor_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
sc = device_get_softc(dev);
|
||||
sens = &sc->sc_sensors[arg2];
|
||||
|
||||
error = max6690_sensor_read(dev, sens, &value);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
temp = value + FCU_ZERO_C_TO_K;
|
||||
temp = max6690_sensor_read(sens);
|
||||
if (temp < 0)
|
||||
return (EIO);
|
||||
|
||||
error = sysctl_handle_int(oidp, &temp, 0, req);
|
||||
|
||||
|
@ -1445,37 +1445,37 @@ mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
|
||||
default:
|
||||
return (EINVAL);
|
||||
case MMC_IVAR_DSR_IMP:
|
||||
*(int *)result = ivar->csd.dsr_imp;
|
||||
*result = ivar->csd.dsr_imp;
|
||||
break;
|
||||
case MMC_IVAR_MEDIA_SIZE:
|
||||
*(off_t *)result = ivar->sec_count;
|
||||
*result = ivar->sec_count;
|
||||
break;
|
||||
case MMC_IVAR_RCA:
|
||||
*(int *)result = ivar->rca;
|
||||
*result = ivar->rca;
|
||||
break;
|
||||
case MMC_IVAR_SECTOR_SIZE:
|
||||
*(int *)result = MMC_SECTOR_SIZE;
|
||||
*result = MMC_SECTOR_SIZE;
|
||||
break;
|
||||
case MMC_IVAR_TRAN_SPEED:
|
||||
*(int *)result = mmcbr_get_clock(bus);
|
||||
*result = mmcbr_get_clock(bus);
|
||||
break;
|
||||
case MMC_IVAR_READ_ONLY:
|
||||
*(int *)result = ivar->read_only;
|
||||
*result = ivar->read_only;
|
||||
break;
|
||||
case MMC_IVAR_HIGH_CAP:
|
||||
*(int *)result = ivar->high_cap;
|
||||
*result = ivar->high_cap;
|
||||
break;
|
||||
case MMC_IVAR_CARD_TYPE:
|
||||
*(int *)result = ivar->mode;
|
||||
*result = ivar->mode;
|
||||
break;
|
||||
case MMC_IVAR_BUS_WIDTH:
|
||||
*(int *)result = ivar->bus_width;
|
||||
*result = ivar->bus_width;
|
||||
break;
|
||||
case MMC_IVAR_ERASE_SECTOR:
|
||||
*(int *)result = ivar->erase_sector;
|
||||
*result = ivar->erase_sector;
|
||||
break;
|
||||
case MMC_IVAR_MAX_DATA:
|
||||
*(int *)result = mmcbr_get_max_data(bus);
|
||||
*result = mmcbr_get_max_data(bus);
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
|
@ -79,7 +79,7 @@ enum mmc_device_ivars {
|
||||
__BUS_ACCESSOR(mmc, var, MMC, ivar, type)
|
||||
|
||||
MMC_ACCESSOR(dsr_imp, DSR_IMP, int)
|
||||
MMC_ACCESSOR(media_size, MEDIA_SIZE, off_t)
|
||||
MMC_ACCESSOR(media_size, MEDIA_SIZE, long)
|
||||
MMC_ACCESSOR(rca, RCA, int)
|
||||
MMC_ACCESSOR(sector_size, SECTOR_SIZE, int)
|
||||
MMC_ACCESSOR(tran_speed, TRAN_SPEED, int)
|
||||
|
@ -566,7 +566,7 @@ msk_miibus_statchg(device_t dev)
|
||||
msk_phy_writereg(sc_if, PHY_ADDR_MARV, PHY_MARV_INT_MASK, 0);
|
||||
/* Disable Rx/Tx MAC. */
|
||||
gmac = GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL);
|
||||
if ((GM_GPCR_RX_ENA | GM_GPCR_TX_ENA) != 0) {
|
||||
if ((gmac & (GM_GPCR_RX_ENA | GM_GPCR_TX_ENA)) != 0) {
|
||||
gmac &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
|
||||
GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, gmac);
|
||||
/* Read again to ensure writing. */
|
||||
|
@ -1443,46 +1443,46 @@ sdhci_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
|
||||
default:
|
||||
return (EINVAL);
|
||||
case MMCBR_IVAR_BUS_MODE:
|
||||
*(int *)result = slot->host.ios.bus_mode;
|
||||
*result = slot->host.ios.bus_mode;
|
||||
break;
|
||||
case MMCBR_IVAR_BUS_WIDTH:
|
||||
*(int *)result = slot->host.ios.bus_width;
|
||||
*result = slot->host.ios.bus_width;
|
||||
break;
|
||||
case MMCBR_IVAR_CHIP_SELECT:
|
||||
*(int *)result = slot->host.ios.chip_select;
|
||||
*result = slot->host.ios.chip_select;
|
||||
break;
|
||||
case MMCBR_IVAR_CLOCK:
|
||||
*(int *)result = slot->host.ios.clock;
|
||||
*result = slot->host.ios.clock;
|
||||
break;
|
||||
case MMCBR_IVAR_F_MIN:
|
||||
*(int *)result = slot->host.f_min;
|
||||
*result = slot->host.f_min;
|
||||
break;
|
||||
case MMCBR_IVAR_F_MAX:
|
||||
*(int *)result = slot->host.f_max;
|
||||
*result = slot->host.f_max;
|
||||
break;
|
||||
case MMCBR_IVAR_HOST_OCR:
|
||||
*(int *)result = slot->host.host_ocr;
|
||||
*result = slot->host.host_ocr;
|
||||
break;
|
||||
case MMCBR_IVAR_MODE:
|
||||
*(int *)result = slot->host.mode;
|
||||
*result = slot->host.mode;
|
||||
break;
|
||||
case MMCBR_IVAR_OCR:
|
||||
*(int *)result = slot->host.ocr;
|
||||
*result = slot->host.ocr;
|
||||
break;
|
||||
case MMCBR_IVAR_POWER_MODE:
|
||||
*(int *)result = slot->host.ios.power_mode;
|
||||
*result = slot->host.ios.power_mode;
|
||||
break;
|
||||
case MMCBR_IVAR_VDD:
|
||||
*(int *)result = slot->host.ios.vdd;
|
||||
*result = slot->host.ios.vdd;
|
||||
break;
|
||||
case MMCBR_IVAR_CAPS:
|
||||
*(int *)result = slot->host.caps;
|
||||
*result = slot->host.caps;
|
||||
break;
|
||||
case MMCBR_IVAR_TIMING:
|
||||
*(int *)result = slot->host.ios.timing;
|
||||
*result = slot->host.ios.timing;
|
||||
break;
|
||||
case MMCBR_IVAR_MAX_DATA:
|
||||
*(int *)result = 65535;
|
||||
*result = 65535;
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
|
@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/libkern.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/interrupt.h>
|
||||
@ -659,6 +660,41 @@ cpusetobj_strprint(char *buf, const cpuset_t *set)
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a valid cpuset_t object from a string representation.
|
||||
* It expects an incoming buffer at least sized as CPUSETBUFSIZ.
|
||||
*/
|
||||
int
|
||||
cpusetobj_strscan(cpuset_t *set, const char *buf)
|
||||
{
|
||||
u_int nwords;
|
||||
int i;
|
||||
|
||||
if (strlen(buf) > CPUSETBUFSIZ - 1)
|
||||
return (-1);
|
||||
|
||||
/* Allow to pass a shorter version of the mask when necessary. */
|
||||
nwords = 1;
|
||||
for (i = 0; buf[i] != '\0'; i++)
|
||||
if (buf[i] == ',')
|
||||
nwords++;
|
||||
if (nwords > _NCPUWORDS)
|
||||
return (-1);
|
||||
|
||||
CPU_ZERO(set);
|
||||
for (i = nwords - 1; i > 0; i--) {
|
||||
if (!sscanf(buf, "%lx, ", &set->__bits[i]))
|
||||
return (-1);
|
||||
buf = strstr(buf, " ");
|
||||
if (buf == NULL)
|
||||
return (-1);
|
||||
buf++;
|
||||
}
|
||||
if (!sscanf(buf, "%lx", &set->__bits[0]))
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply an anonymous mask to a single thread.
|
||||
*/
|
||||
|
@ -40,8 +40,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include "opt_alq.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/alq.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/libkern.h>
|
||||
@ -68,10 +70,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define KTR_MASK (0)
|
||||
#endif
|
||||
|
||||
#ifndef KTR_CPUMASK
|
||||
#define KTR_CPUMASK (~0)
|
||||
#endif
|
||||
|
||||
#ifndef KTR_TIME
|
||||
#define KTR_TIME get_cyclecount()
|
||||
#endif
|
||||
@ -84,11 +82,6 @@ FEATURE(ktr, "Kernel support for KTR kernel tracing facility");
|
||||
|
||||
SYSCTL_NODE(_debug, OID_AUTO, ktr, CTLFLAG_RD, 0, "KTR options");
|
||||
|
||||
int ktr_cpumask = KTR_CPUMASK;
|
||||
TUNABLE_INT("debug.ktr.cpumask", &ktr_cpumask);
|
||||
SYSCTL_INT(_debug_ktr, OID_AUTO, cpumask, CTLFLAG_RW,
|
||||
&ktr_cpumask, 0, "Bitmask of CPUs on which KTR logging is enabled");
|
||||
|
||||
int ktr_mask = KTR_MASK;
|
||||
TUNABLE_INT("debug.ktr.mask", &ktr_mask);
|
||||
SYSCTL_INT(_debug_ktr, OID_AUTO, mask, CTLFLAG_RW,
|
||||
@ -106,6 +99,54 @@ int ktr_version = KTR_VERSION;
|
||||
SYSCTL_INT(_debug_ktr, OID_AUTO, version, CTLFLAG_RD,
|
||||
&ktr_version, 0, "Version of the KTR interface");
|
||||
|
||||
cpuset_t ktr_cpumask;
|
||||
static char ktr_cpumask_str[CPUSETBUFSIZ];
|
||||
TUNABLE_STR("debug.ktr.cpumask", ktr_cpumask_str, sizeof(ktr_cpumask_str));
|
||||
|
||||
static void
|
||||
ktr_cpumask_initializer(void *dummy __unused)
|
||||
{
|
||||
|
||||
CPU_FILL(&ktr_cpumask);
|
||||
#ifdef KTR_CPUMASK
|
||||
if (cpusetobj_strscan(&ktr_cpumask, KTR_CPUMASK) == -1)
|
||||
CPU_FILL(&ktr_cpumask);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TUNABLE_STR() runs with SI_ORDER_MIDDLE priority, thus it must be
|
||||
* already set, if necessary.
|
||||
*/
|
||||
if (ktr_cpumask_str[0] != '\0' &&
|
||||
cpusetobj_strscan(&ktr_cpumask, ktr_cpumask_str) == -1)
|
||||
CPU_FILL(&ktr_cpumask);
|
||||
}
|
||||
SYSINIT(ktr_cpumask_initializer, SI_SUB_TUNABLES, SI_ORDER_ANY,
|
||||
ktr_cpumask_initializer, NULL);
|
||||
|
||||
static int
|
||||
sysctl_debug_ktr_cpumask(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
char lktr_cpumask_str[CPUSETBUFSIZ];
|
||||
cpuset_t imask;
|
||||
int error;
|
||||
|
||||
memset(lktr_cpumask_str, 0, sizeof(lktr_cpumask_str));
|
||||
error = sysctl_handle_string(oidp, lktr_cpumask_str,
|
||||
sizeof(lktr_cpumask_str), req);
|
||||
if (error != 0 || req->newptr == NULL)
|
||||
return (error);
|
||||
if (cpusetobj_strscan(&imask, lktr_cpumask_str) == -1)
|
||||
return (EINVAL);
|
||||
CPU_COPY(&imask, &ktr_cpumask);
|
||||
|
||||
return (error);
|
||||
}
|
||||
SYSCTL_PROC(_debug_ktr, OID_AUTO, cpumask,
|
||||
CTLFLAG_RW | CTLFLAG_MPSAFE | CTLTYPE_STRING, NULL, 0,
|
||||
sysctl_debug_ktr_cpumask, "S",
|
||||
"Bitmask of CPUs on which KTR logging is enabled");
|
||||
|
||||
volatile int ktr_idx = 0;
|
||||
struct ktr_entry ktr_buf[KTR_ENTRIES];
|
||||
|
||||
@ -213,7 +254,7 @@ ktr_tracepoint(u_int mask, const char *file, int line, const char *format,
|
||||
if ((ktr_mask & mask) == 0)
|
||||
return;
|
||||
cpu = KTR_CPU;
|
||||
if (((1 << cpu) & ktr_cpumask) == 0)
|
||||
if (!CPU_ISSET(cpu, &ktr_cpumask))
|
||||
return;
|
||||
#if defined(KTR_VERBOSE) || defined(KTR_ALQ)
|
||||
td = curthread;
|
||||
|
@ -6,7 +6,7 @@ CXGBE = ${.CURDIR}/../../../dev/cxgbe
|
||||
.PATH: ${CXGBE} ${CXGBE}/common
|
||||
|
||||
KMOD = if_cxgbe
|
||||
SRCS = t4_main.c t4_sge.c
|
||||
SRCS = t4_main.c t4_sge.c t4_l2t.c
|
||||
SRCS+= t4_hw.c
|
||||
SRCS+= device_if.h bus_if.h pci_if.h
|
||||
SRCS+= opt_inet.h
|
||||
|
@ -128,8 +128,12 @@ static VNET_DEFINE(int, ipport_tcplastcount);
|
||||
#define V_ipport_tcplastcount VNET(ipport_tcplastcount)
|
||||
|
||||
static void in_pcbremlists(struct inpcb *inp);
|
||||
|
||||
#ifdef INET
|
||||
static struct inpcb *in_pcblookup_hash_locked(struct inpcbinfo *pcbinfo,
|
||||
struct in_addr faddr, u_int fport_arg,
|
||||
struct in_addr laddr, u_int lport_arg,
|
||||
int lookupflags, struct ifnet *ifp);
|
||||
|
||||
#define RANGECHK(var, min, max) \
|
||||
if ((var) < (min)) { (var) = (min); } \
|
||||
else if ((var) > (max)) { (var) = (max); }
|
||||
@ -212,11 +216,13 @@ in_pcbinfo_init(struct inpcbinfo *pcbinfo, const char *name,
|
||||
{
|
||||
|
||||
INP_INFO_LOCK_INIT(pcbinfo, name);
|
||||
INP_HASH_LOCK_INIT(pcbinfo, "pcbinfohash"); /* XXXRW: argument? */
|
||||
#ifdef VIMAGE
|
||||
pcbinfo->ipi_vnet = curvnet;
|
||||
#endif
|
||||
pcbinfo->ipi_listhead = listhead;
|
||||
LIST_INIT(pcbinfo->ipi_listhead);
|
||||
pcbinfo->ipi_count = 0;
|
||||
pcbinfo->ipi_hashbase = hashinit(hash_nelements, M_PCB,
|
||||
&pcbinfo->ipi_hashmask);
|
||||
pcbinfo->ipi_porthashbase = hashinit(porthash_nelements, M_PCB,
|
||||
@ -234,10 +240,14 @@ void
|
||||
in_pcbinfo_destroy(struct inpcbinfo *pcbinfo)
|
||||
{
|
||||
|
||||
KASSERT(pcbinfo->ipi_count == 0,
|
||||
("%s: ipi_count = %u", __func__, pcbinfo->ipi_count));
|
||||
|
||||
hashdestroy(pcbinfo->ipi_hashbase, M_PCB, pcbinfo->ipi_hashmask);
|
||||
hashdestroy(pcbinfo->ipi_porthashbase, M_PCB,
|
||||
pcbinfo->ipi_porthashmask);
|
||||
uma_zdestroy(pcbinfo->ipi_zone);
|
||||
INP_HASH_LOCK_DESTROY(pcbinfo);
|
||||
INP_INFO_LOCK_DESTROY(pcbinfo);
|
||||
}
|
||||
|
||||
@ -309,8 +319,8 @@ in_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred)
|
||||
{
|
||||
int anonport, error;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
|
||||
if (inp->inp_lport != 0 || inp->inp_laddr.s_addr != INADDR_ANY)
|
||||
return (EINVAL);
|
||||
@ -351,8 +361,8 @@ in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp,
|
||||
* Because no actual state changes occur here, a global write lock on
|
||||
* the pcbinfo isn't required.
|
||||
*/
|
||||
INP_INFO_LOCK_ASSERT(pcbinfo);
|
||||
INP_LOCK_ASSERT(inp);
|
||||
INP_HASH_LOCK_ASSERT(pcbinfo);
|
||||
|
||||
if (inp->inp_flags & INP_HIGHPORT) {
|
||||
first = V_ipport_hifirstauto; /* sysctl */
|
||||
@ -473,11 +483,10 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Because no actual state changes occur here, a global write lock on
|
||||
* the pcbinfo isn't required.
|
||||
* No state changes, so read locks are sufficient here.
|
||||
*/
|
||||
INP_INFO_LOCK_ASSERT(pcbinfo);
|
||||
INP_LOCK_ASSERT(inp);
|
||||
INP_HASH_LOCK_ASSERT(pcbinfo);
|
||||
|
||||
if (TAILQ_EMPTY(&V_in_ifaddrhead)) /* XXX broken! */
|
||||
return (EADDRNOTAVAIL);
|
||||
@ -618,8 +627,8 @@ in_pcbconnect(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred)
|
||||
in_addr_t laddr, faddr;
|
||||
int anonport, error;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
|
||||
lport = inp->inp_lport;
|
||||
laddr = inp->inp_laddr.s_addr;
|
||||
@ -907,8 +916,8 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam,
|
||||
* Because a global state change doesn't actually occur here, a read
|
||||
* lock is sufficient.
|
||||
*/
|
||||
INP_INFO_LOCK_ASSERT(inp->inp_pcbinfo);
|
||||
INP_LOCK_ASSERT(inp);
|
||||
INP_HASH_LOCK_ASSERT(inp->inp_pcbinfo);
|
||||
|
||||
if (oinpp != NULL)
|
||||
*oinpp = NULL;
|
||||
@ -983,8 +992,8 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam,
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
oinp = in_pcblookup_hash(inp->inp_pcbinfo, faddr, fport, laddr, lport,
|
||||
0, NULL);
|
||||
oinp = in_pcblookup_hash_locked(inp->inp_pcbinfo, faddr, fport,
|
||||
laddr, lport, 0, NULL);
|
||||
if (oinp != NULL) {
|
||||
if (oinpp != NULL)
|
||||
*oinpp = oinp;
|
||||
@ -1007,8 +1016,8 @@ void
|
||||
in_pcbdisconnect(struct inpcb *inp)
|
||||
{
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
|
||||
inp->inp_faddr.s_addr = INADDR_ANY;
|
||||
inp->inp_fport = 0;
|
||||
@ -1187,19 +1196,24 @@ void
|
||||
in_pcbdrop(struct inpcb *inp)
|
||||
{
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
|
||||
/*
|
||||
* XXXRW: Possibly we should protect the setting of INP_DROPPED with
|
||||
* the hash lock...?
|
||||
*/
|
||||
inp->inp_flags |= INP_DROPPED;
|
||||
if (inp->inp_flags & INP_INHASHLIST) {
|
||||
struct inpcbport *phd = inp->inp_phd;
|
||||
|
||||
INP_HASH_WLOCK(inp->inp_pcbinfo);
|
||||
LIST_REMOVE(inp, inp_hash);
|
||||
LIST_REMOVE(inp, inp_portlist);
|
||||
if (LIST_FIRST(&phd->phd_pcblist) == NULL) {
|
||||
LIST_REMOVE(phd, phd_hash);
|
||||
free(phd, M_PCB);
|
||||
}
|
||||
INP_HASH_WUNLOCK(inp->inp_pcbinfo);
|
||||
inp->inp_flags &= ~INP_INHASHLIST;
|
||||
}
|
||||
}
|
||||
@ -1328,7 +1342,8 @@ in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp)
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup a PCB based on the local address and port.
|
||||
* Lookup a PCB based on the local address and port. Caller must hold the
|
||||
* hash lock. No inpcb locks or references are acquired.
|
||||
*/
|
||||
#define INP_LOOKUP_MAPPED_PCB_COST 3
|
||||
struct inpcb *
|
||||
@ -1346,7 +1361,7 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
|
||||
KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD)) == 0,
|
||||
("%s: invalid lookup flags %d", __func__, lookupflags));
|
||||
|
||||
INP_INFO_LOCK_ASSERT(pcbinfo);
|
||||
INP_HASH_LOCK_ASSERT(pcbinfo);
|
||||
|
||||
if ((lookupflags & INPLOOKUP_WILDCARD) == 0) {
|
||||
struct inpcbhead *head;
|
||||
@ -1450,10 +1465,12 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
|
||||
#undef INP_LOOKUP_MAPPED_PCB_COST
|
||||
|
||||
/*
|
||||
* Lookup PCB in hash list.
|
||||
* 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
|
||||
* locking or reference operations on either the hash list or the connection.
|
||||
*/
|
||||
struct inpcb *
|
||||
in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
|
||||
static struct inpcb *
|
||||
in_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in_addr faddr,
|
||||
u_int fport_arg, struct in_addr laddr, u_int lport_arg, int lookupflags,
|
||||
struct ifnet *ifp)
|
||||
{
|
||||
@ -1464,7 +1481,7 @@ in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
|
||||
KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD)) == 0,
|
||||
("%s: invalid lookup flags %d", __func__, lookupflags));
|
||||
|
||||
INP_INFO_LOCK_ASSERT(pcbinfo);
|
||||
INP_HASH_LOCK_ASSERT(pcbinfo);
|
||||
|
||||
/*
|
||||
* First look for an exact match.
|
||||
@ -1574,6 +1591,56 @@ in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup PCB in hash list, using pcbinfo tables. This variation locks the
|
||||
* hash list lock, and will return the inpcb locked (i.e., requires
|
||||
* INPLOOKUP_LOCKPCB).
|
||||
*/
|
||||
static struct inpcb *
|
||||
in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
|
||||
u_int fport, struct in_addr laddr, u_int lport, int lookupflags,
|
||||
struct ifnet *ifp)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
|
||||
INP_HASH_RLOCK(pcbinfo);
|
||||
inp = in_pcblookup_hash_locked(pcbinfo, faddr, fport, laddr, lport,
|
||||
(lookupflags & ~(INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)), ifp);
|
||||
if (inp != NULL) {
|
||||
in_pcbref(inp);
|
||||
INP_HASH_RUNLOCK(pcbinfo);
|
||||
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__);
|
||||
} else
|
||||
INP_HASH_RUNLOCK(pcbinfo);
|
||||
return (inp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public inpcb lookup routines, accepting a 4-tuple.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
|
||||
KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
|
||||
("%s: invalid lookup flags %d", __func__, lookupflags));
|
||||
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
|
||||
("%s: LOCKPCB not set", __func__));
|
||||
|
||||
return (in_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
|
||||
lookupflags, ifp));
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
/*
|
||||
@ -1588,8 +1655,9 @@ in_pcbinshash(struct inpcb *inp)
|
||||
struct inpcbport *phd;
|
||||
u_int32_t hashkey_faddr;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
||||
|
||||
KASSERT((inp->inp_flags & INP_INHASHLIST) == 0,
|
||||
("in_pcbinshash: INP_INHASHLIST"));
|
||||
|
||||
@ -1645,8 +1713,9 @@ in_pcbrehash(struct inpcb *inp)
|
||||
struct inpcbhead *head;
|
||||
u_int32_t hashkey_faddr;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
||||
|
||||
KASSERT(inp->inp_flags & INP_INHASHLIST,
|
||||
("in_pcbrehash: !INP_INHASHLIST"));
|
||||
|
||||
@ -1679,12 +1748,14 @@ in_pcbremlists(struct inpcb *inp)
|
||||
if (inp->inp_flags & INP_INHASHLIST) {
|
||||
struct inpcbport *phd = inp->inp_phd;
|
||||
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
LIST_REMOVE(inp, inp_hash);
|
||||
LIST_REMOVE(inp, inp_portlist);
|
||||
if (LIST_FIRST(&phd->phd_pcblist) == NULL) {
|
||||
LIST_REMOVE(phd, phd_hash);
|
||||
free(phd, M_PCB);
|
||||
}
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
inp->inp_flags &= ~INP_INHASHLIST;
|
||||
}
|
||||
LIST_REMOVE(inp, inp_list);
|
||||
|
@ -268,22 +268,22 @@ struct inpcbport {
|
||||
* Global data structure for each high-level protocol (UDP, TCP, ...) in both
|
||||
* IPv4 and IPv6. Holds inpcb lists and information for managing them.
|
||||
*
|
||||
* Each pcbinfo is protected by ipi_lock, covering mutable global fields (such
|
||||
* as the global pcb list) and hashed lookup tables. The lock order is:
|
||||
* Each pcbinfo is protected by two locks: ipi_lock and ipi_hash_lock,
|
||||
* 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
|
||||
* ipi_lock (before) inpcb locks (before) ipi_hash_lock
|
||||
*
|
||||
* Locking key:
|
||||
*
|
||||
* (c) Constant or nearly constant after initialisation
|
||||
* (g) Locked by ipi_lock
|
||||
* (h) Read using either ipi_lock or inpcb lock; write requires both.
|
||||
* (h) Read using either ipi_hash_lock or inpcb lock; write requires both.
|
||||
* (x) Synchronisation properties poorly defined
|
||||
*/
|
||||
struct inpcbinfo {
|
||||
/*
|
||||
* Global lock protecting global inpcb list, inpcb count, hash tables,
|
||||
* etc.
|
||||
* Global lock protecting global inpcb list, inpcb count, etc.
|
||||
*/
|
||||
struct rwlock ipi_lock;
|
||||
|
||||
@ -311,18 +311,23 @@ struct inpcbinfo {
|
||||
*/
|
||||
struct uma_zone *ipi_zone; /* (c) */
|
||||
|
||||
/*
|
||||
* Global lock protecting hash lookup tables.
|
||||
*/
|
||||
struct rwlock ipi_hash_lock;
|
||||
|
||||
/*
|
||||
* Global hash of inpcbs, hashed by local and foreign addresses and
|
||||
* port numbers.
|
||||
*/
|
||||
struct inpcbhead *ipi_hashbase; /* (g) */
|
||||
u_long ipi_hashmask; /* (g) */
|
||||
struct inpcbhead *ipi_hashbase; /* (h) */
|
||||
u_long ipi_hashmask; /* (h) */
|
||||
|
||||
/*
|
||||
* Global hash of inpcbs, hashed by only local port number.
|
||||
*/
|
||||
struct inpcbporthead *ipi_porthashbase; /* (g) */
|
||||
u_long ipi_porthashmask; /* (g) */
|
||||
struct inpcbporthead *ipi_porthashbase; /* (h) */
|
||||
u_long ipi_porthashmask; /* (h) */
|
||||
|
||||
/*
|
||||
* Pointer to network stack instance
|
||||
@ -406,6 +411,18 @@ void inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp,
|
||||
#define INP_INFO_WLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_WLOCKED)
|
||||
#define INP_INFO_UNLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_UNLOCKED)
|
||||
|
||||
#define INP_HASH_LOCK_INIT(ipi, d) \
|
||||
rw_init_flags(&(ipi)->ipi_hash_lock, (d), 0)
|
||||
#define INP_HASH_LOCK_DESTROY(ipi) rw_destroy(&(ipi)->ipi_hash_lock)
|
||||
#define INP_HASH_RLOCK(ipi) rw_rlock(&(ipi)->ipi_hash_lock)
|
||||
#define INP_HASH_WLOCK(ipi) rw_wlock(&(ipi)->ipi_hash_lock)
|
||||
#define INP_HASH_RUNLOCK(ipi) rw_runlock(&(ipi)->ipi_hash_lock)
|
||||
#define INP_HASH_WUNLOCK(ipi) rw_wunlock(&(ipi)->ipi_hash_lock)
|
||||
#define INP_HASH_LOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_hash_lock, \
|
||||
RA_LOCKED)
|
||||
#define INP_HASH_WLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_hash_lock, \
|
||||
RA_WLOCKED)
|
||||
|
||||
#define INP_PCBHASH(faddr, lport, fport, mask) \
|
||||
(((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport))) & (mask))
|
||||
#define INP_PCBPORTHASH(lport, mask) \
|
||||
@ -466,7 +483,16 @@ 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 INPLOOKUP_WILDCARD 1
|
||||
/*
|
||||
* Flags passed to in_pcblookup*() functions.
|
||||
*/
|
||||
#define INPLOOKUP_WILDCARD 0x00000001 /* Allow wildcard sockets. */
|
||||
#define INPLOOKUP_RLOCKPCB 0x00000002 /* Return inpcb read-locked. */
|
||||
#define INPLOOKUP_WLOCKPCB 0x00000004 /* Return inpcb write-locked. */
|
||||
|
||||
#define INPLOOKUP_MASK (INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB | \
|
||||
INPLOOKUP_WLOCKPCB)
|
||||
|
||||
#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb)
|
||||
#define sotoin6pcb(so) sotoinpcb(so) /* for KAME src sync over BSD*'s */
|
||||
|
||||
@ -527,7 +553,7 @@ struct inpcb *
|
||||
in_pcblookup_local(struct inpcbinfo *,
|
||||
struct in_addr, u_short, int, struct ucred *);
|
||||
struct inpcb *
|
||||
in_pcblookup_hash(struct inpcbinfo *, struct in_addr, u_int,
|
||||
in_pcblookup(struct inpcbinfo *, struct in_addr, u_int,
|
||||
struct in_addr, u_int, int, struct ifnet *);
|
||||
void in_pcbnotifyall(struct inpcbinfo *pcbinfo, struct in_addr,
|
||||
int, struct inpcb *(*)(struct inpcb *, int));
|
||||
|
@ -659,9 +659,9 @@ div_pcblist(SYSCTL_HANDLER_ARGS)
|
||||
INP_INFO_WLOCK(&V_divcbinfo);
|
||||
for (i = 0; i < n; i++) {
|
||||
inp = inp_list[i];
|
||||
INP_WLOCK(inp);
|
||||
if (!in_pcbrele(inp))
|
||||
INP_WUNLOCK(inp);
|
||||
INP_RLOCK(inp);
|
||||
if (!in_pcbrele_rlocked(inp))
|
||||
INP_RUNLOCK(inp);
|
||||
}
|
||||
INP_INFO_WUNLOCK(&V_divcbinfo);
|
||||
|
||||
|
@ -657,7 +657,7 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
|
||||
(struct bsd_ucred *)uc, ugid_lookupp, ((struct mbuf *)inp)->m_skb);
|
||||
#else /* FreeBSD */
|
||||
struct inpcbinfo *pi;
|
||||
int wildcard;
|
||||
int lookupflags;
|
||||
struct inpcb *pcb;
|
||||
int match;
|
||||
|
||||
@ -682,30 +682,31 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
|
||||
if (*ugid_lookupp == -1)
|
||||
return (0);
|
||||
if (proto == IPPROTO_TCP) {
|
||||
wildcard = 0;
|
||||
lookupflags = 0;
|
||||
pi = &V_tcbinfo;
|
||||
} else if (proto == IPPROTO_UDP) {
|
||||
wildcard = INPLOOKUP_WILDCARD;
|
||||
lookupflags = INPLOOKUP_WILDCARD;
|
||||
pi = &V_udbinfo;
|
||||
} else
|
||||
return 0;
|
||||
lookupflags |= INPLOOKUP_RLOCKPCB;
|
||||
match = 0;
|
||||
if (*ugid_lookupp == 0) {
|
||||
INP_INFO_RLOCK(pi);
|
||||
pcb = (oif) ?
|
||||
in_pcblookup_hash(pi,
|
||||
in_pcblookup(pi,
|
||||
dst_ip, htons(dst_port),
|
||||
src_ip, htons(src_port),
|
||||
wildcard, oif) :
|
||||
in_pcblookup_hash(pi,
|
||||
lookupflags, oif) :
|
||||
in_pcblookup(pi,
|
||||
src_ip, htons(src_port),
|
||||
dst_ip, htons(dst_port),
|
||||
wildcard, NULL);
|
||||
lookupflags, NULL);
|
||||
if (pcb != NULL) {
|
||||
INP_RLOCK_ASSERT(pcb);
|
||||
*uc = crhold(pcb->inp_cred);
|
||||
*ugid_lookupp = 1;
|
||||
INP_RUNLOCK(pcb);
|
||||
}
|
||||
INP_INFO_RUNLOCK(pi);
|
||||
if (*ugid_lookupp == 0) {
|
||||
/*
|
||||
* We tried and failed, set the variable to -1
|
||||
@ -1827,21 +1828,32 @@ do { \
|
||||
else
|
||||
break;
|
||||
|
||||
/*
|
||||
* XXXRW: so_user_cookie should almost
|
||||
* certainly be inp_user_cookie?
|
||||
*/
|
||||
|
||||
/* For incomming packet, lookup up the
|
||||
inpcb using the src/dest ip/port tuple */
|
||||
if (inp == NULL) {
|
||||
INP_INFO_RLOCK(pi);
|
||||
inp = in_pcblookup_hash(pi,
|
||||
inp = in_pcblookup(pi,
|
||||
src_ip, htons(src_port),
|
||||
dst_ip, htons(dst_port),
|
||||
0, NULL);
|
||||
INP_INFO_RUNLOCK(pi);
|
||||
}
|
||||
|
||||
if (inp && inp->inp_socket) {
|
||||
tablearg = inp->inp_socket->so_user_cookie;
|
||||
if (tablearg)
|
||||
match = 1;
|
||||
INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp != NULL) {
|
||||
tablearg =
|
||||
inp->inp_socket->so_user_cookie;
|
||||
if (tablearg)
|
||||
match = 1;
|
||||
INP_RUNLOCK(inp);
|
||||
}
|
||||
} else {
|
||||
if (inp->inp_socket) {
|
||||
tablearg =
|
||||
inp->inp_socket->so_user_cookie;
|
||||
if (tablearg)
|
||||
match = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2137,14 +2149,21 @@ do { \
|
||||
done = 1; /* exit outer loop */
|
||||
break;
|
||||
|
||||
case O_SETFIB:
|
||||
case O_SETFIB: {
|
||||
uint32_t fib;
|
||||
|
||||
f->pcnt++; /* update stats */
|
||||
f->bcnt += pktlen;
|
||||
f->timestamp = time_uptime;
|
||||
M_SETFIB(m, cmd->arg1);
|
||||
args->f_id.fib = cmd->arg1;
|
||||
fib = (cmd->arg1 == IP_FW_TABLEARG) ? tablearg:
|
||||
cmd->arg1;
|
||||
if (fib >= rt_numfibs)
|
||||
fib = 0;
|
||||
M_SETFIB(m, fib);
|
||||
args->f_id.fib = fib;
|
||||
l = 0; /* exit inner loop */
|
||||
break;
|
||||
}
|
||||
|
||||
case O_NAT:
|
||||
if (!IPFW_NAT_LOADED) {
|
||||
|
@ -606,7 +606,8 @@ check_ipfw_struct(struct ip_fw *rule, int size)
|
||||
case O_SETFIB:
|
||||
if (cmdlen != F_INSN_SIZE(ipfw_insn))
|
||||
goto bad_size;
|
||||
if (cmd->arg1 >= rt_numfibs) {
|
||||
if ((cmd->arg1 != IP_FW_TABLEARG) &&
|
||||
(cmd->arg1 >= rt_numfibs)) {
|
||||
printf("ipfw: invalid fib number %d\n",
|
||||
cmd->arg1);
|
||||
return EINVAL;
|
||||
|
@ -226,7 +226,7 @@ rip_append(struct inpcb *last, struct ip *ip, struct mbuf *n,
|
||||
{
|
||||
int policyfail = 0;
|
||||
|
||||
INP_RLOCK_ASSERT(last);
|
||||
INP_LOCK_ASSERT(last);
|
||||
|
||||
#ifdef IPSEC
|
||||
/* check AH/ESP integrity. */
|
||||
@ -834,16 +834,19 @@ rip_detach(struct socket *so)
|
||||
static void
|
||||
rip_dodisconnect(struct socket *so, struct inpcb *inp)
|
||||
{
|
||||
struct inpcbinfo *pcbinfo;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
|
||||
pcbinfo = inp->inp_pcbinfo;
|
||||
INP_INFO_WLOCK(pcbinfo);
|
||||
INP_WLOCK(inp);
|
||||
rip_delhash(inp);
|
||||
inp->inp_faddr.s_addr = INADDR_ANY;
|
||||
rip_inshash(inp);
|
||||
SOCK_LOCK(so);
|
||||
so->so_state &= ~SS_ISCONNECTED;
|
||||
SOCK_UNLOCK(so);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(pcbinfo);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -854,11 +857,7 @@ rip_abort(struct socket *so)
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("rip_abort: inp == NULL"));
|
||||
|
||||
INP_INFO_WLOCK(&V_ripcbinfo);
|
||||
INP_WLOCK(inp);
|
||||
rip_dodisconnect(so, inp);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_ripcbinfo);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -869,11 +868,7 @@ rip_close(struct socket *so)
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("rip_close: inp == NULL"));
|
||||
|
||||
INP_INFO_WLOCK(&V_ripcbinfo);
|
||||
INP_WLOCK(inp);
|
||||
rip_dodisconnect(so, inp);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_ripcbinfo);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -887,11 +882,7 @@ rip_disconnect(struct socket *so)
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("rip_disconnect: inp == NULL"));
|
||||
|
||||
INP_INFO_WLOCK(&V_ripcbinfo);
|
||||
INP_WLOCK(inp);
|
||||
rip_dodisconnect(so, inp);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_ripcbinfo);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1077,9 +1068,9 @@ rip_pcblist(SYSCTL_HANDLER_ARGS)
|
||||
INP_INFO_WLOCK(&V_ripcbinfo);
|
||||
for (i = 0; i < n; i++) {
|
||||
inp = inp_list[i];
|
||||
INP_WLOCK(inp);
|
||||
if (!in_pcbrele(inp))
|
||||
INP_WUNLOCK(inp);
|
||||
INP_RLOCK(inp);
|
||||
if (!in_pcbrele_rlocked(inp))
|
||||
INP_RUNLOCK(inp);
|
||||
}
|
||||
INP_INFO_WUNLOCK(&V_ripcbinfo);
|
||||
|
||||
|
@ -247,49 +247,6 @@ sctp_build_ctl_nchunk(struct sctp_inpcb *inp,
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
sctp_build_ctl_cchunk(struct sctp_inpcb *inp,
|
||||
int *control_len,
|
||||
struct sctp_sndrcvinfo *sinfo)
|
||||
{
|
||||
struct sctp_sndrcvinfo *outinfo;
|
||||
struct cmsghdr *cmh;
|
||||
char *buf;
|
||||
int len;
|
||||
int use_extended = 0;
|
||||
|
||||
if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
|
||||
/* user does not want the sndrcv ctl */
|
||||
return (NULL);
|
||||
}
|
||||
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
|
||||
use_extended = 1;
|
||||
len = CMSG_LEN(sizeof(struct sctp_extrcvinfo));
|
||||
} else {
|
||||
len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
|
||||
}
|
||||
SCTP_MALLOC(buf, char *, len, SCTP_M_CMSG);
|
||||
if (buf == NULL) {
|
||||
/* No space */
|
||||
return (buf);
|
||||
}
|
||||
/* We need a CMSG header followed by the struct */
|
||||
cmh = (struct cmsghdr *)buf;
|
||||
outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh);
|
||||
cmh->cmsg_level = IPPROTO_SCTP;
|
||||
if (use_extended) {
|
||||
cmh->cmsg_type = SCTP_EXTRCV;
|
||||
cmh->cmsg_len = len;
|
||||
memcpy(outinfo, sinfo, len);
|
||||
} else {
|
||||
cmh->cmsg_type = SCTP_SNDRCV;
|
||||
cmh->cmsg_len = len;
|
||||
*outinfo = *sinfo;
|
||||
}
|
||||
*control_len = len;
|
||||
return (buf);
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn)
|
||||
{
|
||||
|
@ -83,11 +83,6 @@ struct mbuf *
|
||||
sctp_build_ctl_nchunk(struct sctp_inpcb *inp,
|
||||
struct sctp_sndrcvinfo *sinfo);
|
||||
|
||||
char *
|
||||
sctp_build_ctl_cchunk(struct sctp_inpcb *inp,
|
||||
int *control_len,
|
||||
struct sctp_sndrcvinfo *sinfo);
|
||||
|
||||
void sctp_set_rwnd(struct sctp_tcb *, struct sctp_association *);
|
||||
|
||||
uint32_t
|
||||
|
@ -6184,71 +6184,6 @@ sctp_soreceive(struct socket *so,
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sctp_l_soreceive(struct socket *so,
|
||||
struct sockaddr **name,
|
||||
struct uio *uio,
|
||||
char **controlp,
|
||||
int *controllen,
|
||||
int *flag)
|
||||
{
|
||||
int error, fromlen;
|
||||
uint8_t sockbuf[256];
|
||||
struct sockaddr *from;
|
||||
struct sctp_extrcvinfo sinfo;
|
||||
int filling_sinfo = 1;
|
||||
struct sctp_inpcb *inp;
|
||||
|
||||
inp = (struct sctp_inpcb *)so->so_pcb;
|
||||
/* pickup the assoc we are reading from */
|
||||
if (inp == NULL) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
if ((sctp_is_feature_off(inp,
|
||||
SCTP_PCB_FLAGS_RECVDATAIOEVNT)) ||
|
||||
(controlp == NULL)) {
|
||||
/* user does not want the sndrcv ctl */
|
||||
filling_sinfo = 0;
|
||||
}
|
||||
if (name) {
|
||||
from = (struct sockaddr *)sockbuf;
|
||||
fromlen = sizeof(sockbuf);
|
||||
from->sa_len = 0;
|
||||
} else {
|
||||
from = NULL;
|
||||
fromlen = 0;
|
||||
}
|
||||
|
||||
error = sctp_sorecvmsg(so, uio,
|
||||
(struct mbuf **)NULL,
|
||||
from, fromlen, flag,
|
||||
(struct sctp_sndrcvinfo *)&sinfo,
|
||||
filling_sinfo);
|
||||
if ((controlp) && (filling_sinfo)) {
|
||||
/*
|
||||
* copy back the sinfo in a CMSG format note that the caller
|
||||
* has reponsibility for freeing the memory.
|
||||
*/
|
||||
if (filling_sinfo)
|
||||
*controlp = sctp_build_ctl_cchunk(inp,
|
||||
controllen,
|
||||
(struct sctp_sndrcvinfo *)&sinfo);
|
||||
}
|
||||
if (name) {
|
||||
/* copy back the address info */
|
||||
if (from && from->sa_len) {
|
||||
*name = sodupsockaddr(from, M_WAIT);
|
||||
} else {
|
||||
*name = NULL;
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -328,20 +328,6 @@ sctp_soreceive(struct socket *so, struct sockaddr **psa,
|
||||
struct mbuf **controlp,
|
||||
int *flagsp);
|
||||
|
||||
|
||||
/* For those not passing mbufs, this does the
|
||||
* translations for you. Caller owns memory
|
||||
* of size controllen returned in controlp.
|
||||
*/
|
||||
int
|
||||
sctp_l_soreceive(struct socket *so,
|
||||
struct sockaddr **name,
|
||||
struct uio *uio,
|
||||
char **controlp,
|
||||
int *controllen,
|
||||
int *flag);
|
||||
|
||||
|
||||
void
|
||||
sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d);
|
||||
|
||||
|
@ -696,17 +696,16 @@ siftr_findinpcb(int ipver, struct ip *ip, struct mbuf *m, uint16_t sport,
|
||||
|
||||
/* We need the tcbinfo lock. */
|
||||
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo);
|
||||
INP_INFO_RLOCK(&V_tcbinfo);
|
||||
|
||||
if (dir == PFIL_IN)
|
||||
inp = (ipver == INP_IPV4 ?
|
||||
in_pcblookup_hash(&V_tcbinfo, ip->ip_src, sport, ip->ip_dst,
|
||||
dport, 0, m->m_pkthdr.rcvif)
|
||||
in_pcblookup(&V_tcbinfo, ip->ip_src, sport, ip->ip_dst,
|
||||
dport, INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif)
|
||||
:
|
||||
#ifdef SIFTR_IPV6
|
||||
in6_pcblookup_hash(&V_tcbinfo,
|
||||
in6_pcblookup(&V_tcbinfo,
|
||||
&((struct ip6_hdr *)ip)->ip6_src, sport,
|
||||
&((struct ip6_hdr *)ip)->ip6_dst, dport, 0,
|
||||
&((struct ip6_hdr *)ip)->ip6_dst, dport, INPLOOKUP_RLOCKPCB,
|
||||
m->m_pkthdr.rcvif)
|
||||
#else
|
||||
NULL
|
||||
@ -715,13 +714,13 @@ siftr_findinpcb(int ipver, struct ip *ip, struct mbuf *m, uint16_t sport,
|
||||
|
||||
else
|
||||
inp = (ipver == INP_IPV4 ?
|
||||
in_pcblookup_hash(&V_tcbinfo, ip->ip_dst, dport, ip->ip_src,
|
||||
sport, 0, m->m_pkthdr.rcvif)
|
||||
in_pcblookup(&V_tcbinfo, ip->ip_dst, dport, ip->ip_src,
|
||||
sport, INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif)
|
||||
:
|
||||
#ifdef SIFTR_IPV6
|
||||
in6_pcblookup_hash(&V_tcbinfo,
|
||||
in6_pcblookup(&V_tcbinfo,
|
||||
&((struct ip6_hdr *)ip)->ip6_dst, dport,
|
||||
&((struct ip6_hdr *)ip)->ip6_src, sport, 0,
|
||||
&((struct ip6_hdr *)ip)->ip6_src, sport, INPLOOKUP_RLOCKPCB,
|
||||
m->m_pkthdr.rcvif)
|
||||
#else
|
||||
NULL
|
||||
@ -734,12 +733,7 @@ siftr_findinpcb(int ipver, struct ip *ip, struct mbuf *m, uint16_t sport,
|
||||
ss->nskip_in_inpcb++;
|
||||
else
|
||||
ss->nskip_out_inpcb++;
|
||||
} else {
|
||||
/* Acquire the inpcb lock. */
|
||||
INP_UNLOCK_ASSERT(inp);
|
||||
INP_RLOCK(inp);
|
||||
}
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
|
||||
return (inp);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Swinburne University of Technology, Melbourne, Australia.
|
||||
* Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org>
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* Copyright (c) 2010-2011 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed at the Centre for Advanced Internet
|
||||
@ -16,6 +17,9 @@
|
||||
* Internet Architectures, Swinburne University of Technology, Melbourne,
|
||||
* Australia by David Hayes under sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
* Portions of this software were 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:
|
||||
@ -197,10 +201,6 @@ SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, recvbuf_max, CTLFLAG_RW,
|
||||
&VNET_NAME(tcp_autorcvbuf_max), 0,
|
||||
"Max size of automatic receive buffer");
|
||||
|
||||
int tcp_read_locking = 1;
|
||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, read_locking, CTLFLAG_RW,
|
||||
&tcp_read_locking, 0, "Enable read locking strategy");
|
||||
|
||||
VNET_DEFINE(struct inpcbhead, tcb);
|
||||
#define tcb6 tcb /* for KAME src sync over BSD*'s */
|
||||
VNET_DEFINE(struct inpcbinfo, tcbinfo);
|
||||
@ -591,8 +591,7 @@ tcp_input(struct mbuf *m, int off0)
|
||||
char *s = NULL; /* address and port logging */
|
||||
int ti_locked;
|
||||
#define TI_UNLOCKED 1
|
||||
#define TI_RLOCKED 2
|
||||
#define TI_WLOCKED 3
|
||||
#define TI_WLOCKED 2
|
||||
|
||||
#ifdef TCPDEBUG
|
||||
/*
|
||||
@ -756,30 +755,25 @@ tcp_input(struct mbuf *m, int off0)
|
||||
drop_hdrlen = off0 + off;
|
||||
|
||||
/*
|
||||
* Locate pcb for segment, which requires a lock on tcbinfo.
|
||||
* Optimisticaly acquire a global read lock rather than a write lock
|
||||
* unless header flags necessarily imply a state change. There are
|
||||
* two cases where we might discover later we need a write lock
|
||||
* despite the flags: ACKs moving a connection out of the syncache,
|
||||
* and ACKs for a connection in TIMEWAIT.
|
||||
* Locate pcb for segment; if we're likely to add or remove a
|
||||
* connection then first acquire pcbinfo lock. There are two cases
|
||||
* where we might discover later we need a write lock despite the
|
||||
* flags: ACKs moving a connection out of the syncache, and ACKs for
|
||||
* a connection in TIMEWAIT.
|
||||
*/
|
||||
if ((thflags & (TH_SYN | TH_FIN | TH_RST)) != 0 ||
|
||||
tcp_read_locking == 0) {
|
||||
if ((thflags & (TH_SYN | TH_FIN | TH_RST)) != 0) {
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
ti_locked = TI_WLOCKED;
|
||||
} else {
|
||||
INP_INFO_RLOCK(&V_tcbinfo);
|
||||
ti_locked = TI_RLOCKED;
|
||||
}
|
||||
} else
|
||||
ti_locked = TI_UNLOCKED;
|
||||
|
||||
findpcb:
|
||||
#ifdef INVARIANTS
|
||||
if (ti_locked == TI_RLOCKED)
|
||||
INP_INFO_RLOCK_ASSERT(&V_tcbinfo);
|
||||
else if (ti_locked == TI_WLOCKED)
|
||||
if (ti_locked == TI_WLOCKED) {
|
||||
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
|
||||
else
|
||||
panic("%s: findpcb ti_locked %d\n", __func__, ti_locked);
|
||||
} else {
|
||||
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INET
|
||||
@ -797,20 +791,18 @@ tcp_input(struct mbuf *m, int off0)
|
||||
* Transparently forwarded. Pretend to be the destination.
|
||||
* already got one like this?
|
||||
*/
|
||||
inp = in_pcblookup_hash(&V_tcbinfo,
|
||||
ip->ip_src, th->th_sport,
|
||||
ip->ip_dst, th->th_dport,
|
||||
0, m->m_pkthdr.rcvif);
|
||||
inp = in_pcblookup(&V_tcbinfo, ip->ip_src, th->th_sport,
|
||||
ip->ip_dst, th->th_dport, INPLOOKUP_WLOCKPCB,
|
||||
m->m_pkthdr.rcvif);
|
||||
if (!inp) {
|
||||
/* It's new. Try to find the ambushing socket. */
|
||||
inp = in_pcblookup_hash(&V_tcbinfo,
|
||||
ip->ip_src, th->th_sport,
|
||||
next_hop->sin_addr,
|
||||
next_hop->sin_port ?
|
||||
ntohs(next_hop->sin_port) :
|
||||
th->th_dport,
|
||||
INPLOOKUP_WILDCARD,
|
||||
m->m_pkthdr.rcvif);
|
||||
/*
|
||||
* It's new. Try to find the ambushing socket.
|
||||
*/
|
||||
inp = in_pcblookup(&V_tcbinfo, ip->ip_src,
|
||||
th->th_sport, next_hop->sin_addr,
|
||||
next_hop->sin_port ? ntohs(next_hop->sin_port) :
|
||||
th->th_dport, INPLOOKUP_WILDCARD |
|
||||
INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif);
|
||||
}
|
||||
/* Remove the tag from the packet. We don't need it anymore. */
|
||||
m_tag_delete(m, fwd_tag);
|
||||
@ -820,21 +812,19 @@ tcp_input(struct mbuf *m, int off0)
|
||||
{
|
||||
#ifdef INET6
|
||||
if (isipv6)
|
||||
inp = in6_pcblookup_hash(&V_tcbinfo,
|
||||
&ip6->ip6_src, th->th_sport,
|
||||
&ip6->ip6_dst, th->th_dport,
|
||||
INPLOOKUP_WILDCARD,
|
||||
m->m_pkthdr.rcvif);
|
||||
inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_src,
|
||||
th->th_sport, &ip6->ip6_dst, th->th_dport,
|
||||
INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB,
|
||||
m->m_pkthdr.rcvif);
|
||||
#endif
|
||||
#if defined(INET) && defined(INET6)
|
||||
else
|
||||
#endif
|
||||
#ifdef INET
|
||||
inp = in_pcblookup_hash(&V_tcbinfo,
|
||||
ip->ip_src, th->th_sport,
|
||||
ip->ip_dst, th->th_dport,
|
||||
INPLOOKUP_WILDCARD,
|
||||
m->m_pkthdr.rcvif);
|
||||
inp = in_pcblookup(&V_tcbinfo, ip->ip_src,
|
||||
th->th_sport, ip->ip_dst, th->th_dport,
|
||||
INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB,
|
||||
m->m_pkthdr.rcvif);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -865,7 +855,7 @@ tcp_input(struct mbuf *m, int off0)
|
||||
rstreason = BANDLIM_RST_CLOSEDPORT;
|
||||
goto dropwithreset;
|
||||
}
|
||||
INP_WLOCK(inp);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
if (!(inp->inp_flags & INP_HW_FLOWID)
|
||||
&& (m->m_flags & M_FLOWID)
|
||||
&& ((inp->inp_socket == NULL)
|
||||
@ -906,28 +896,26 @@ tcp_input(struct mbuf *m, int off0)
|
||||
* legitimate new connection attempt the old INPCB gets removed and
|
||||
* we can try again to find a listening socket.
|
||||
*
|
||||
* At this point, due to earlier optimism, we may hold a read lock on
|
||||
* the inpcbinfo, rather than a write lock. If so, we need to
|
||||
* upgrade, or if that fails, acquire a reference on the inpcb, drop
|
||||
* all locks, acquire a global write lock, and then re-acquire the
|
||||
* inpcb lock. We may at that point discover that another thread has
|
||||
* tried to free the inpcb, in which case we need to loop back and
|
||||
* try to find a new inpcb to deliver to.
|
||||
* At this point, due to earlier optimism, we may hold only an inpcb
|
||||
* lock, and not the inpcbinfo write lock. If so, we need to try to
|
||||
* acquire it, or if that fails, acquire a reference on the inpcb,
|
||||
* drop all locks, acquire a global write lock, and then re-acquire
|
||||
* the inpcb lock. We may at that point discover that another thread
|
||||
* has tried to free the inpcb, in which case we need to loop back
|
||||
* and try to find a new inpcb to deliver to.
|
||||
*
|
||||
* XXXRW: It may be time to rethink timewait locking.
|
||||
*/
|
||||
relocked:
|
||||
if (inp->inp_flags & INP_TIMEWAIT) {
|
||||
KASSERT(ti_locked == TI_RLOCKED || ti_locked == TI_WLOCKED,
|
||||
("%s: INP_TIMEWAIT ti_locked %d", __func__, ti_locked));
|
||||
|
||||
if (ti_locked == TI_RLOCKED) {
|
||||
if (INP_INFO_TRY_UPGRADE(&V_tcbinfo) == 0) {
|
||||
if (ti_locked == TI_UNLOCKED) {
|
||||
if (INP_INFO_TRY_WLOCK(&V_tcbinfo) == 0) {
|
||||
in_pcbref(inp);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
ti_locked = TI_WLOCKED;
|
||||
INP_WLOCK(inp);
|
||||
if (in_pcbrele(inp)) {
|
||||
if (in_pcbrele_wlocked(inp)) {
|
||||
inp = NULL;
|
||||
goto findpcb;
|
||||
}
|
||||
@ -975,26 +963,24 @@ tcp_input(struct mbuf *m, int off0)
|
||||
|
||||
/*
|
||||
* We've identified a valid inpcb, but it could be that we need an
|
||||
* inpcbinfo write lock and have only a read lock. In this case,
|
||||
* attempt to upgrade/relock using the same strategy as the TIMEWAIT
|
||||
* case above. If we relock, we have to jump back to 'relocked' as
|
||||
* the connection might now be in TIMEWAIT.
|
||||
* inpcbinfo write lock but don't hold it. In this case, attempt to
|
||||
* acquire using the same strategy as the TIMEWAIT case above. If we
|
||||
* relock, we have to jump back to 'relocked' as the connection might
|
||||
* now be in TIMEWAIT.
|
||||
*/
|
||||
if (tp->t_state != TCPS_ESTABLISHED ||
|
||||
(thflags & (TH_SYN | TH_FIN | TH_RST)) != 0 ||
|
||||
tcp_read_locking == 0) {
|
||||
KASSERT(ti_locked == TI_RLOCKED || ti_locked == TI_WLOCKED,
|
||||
("%s: upgrade check ti_locked %d", __func__, ti_locked));
|
||||
|
||||
if (ti_locked == TI_RLOCKED) {
|
||||
if (INP_INFO_TRY_UPGRADE(&V_tcbinfo) == 0) {
|
||||
#ifdef INVARIANTS
|
||||
if ((thflags & (TH_SYN | TH_FIN | TH_RST)) != 0)
|
||||
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
|
||||
#endif
|
||||
if (tp->t_state != TCPS_ESTABLISHED) {
|
||||
if (ti_locked == TI_UNLOCKED) {
|
||||
if (INP_INFO_TRY_WLOCK(&V_tcbinfo) == 0) {
|
||||
in_pcbref(inp);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
ti_locked = TI_WLOCKED;
|
||||
INP_WLOCK(inp);
|
||||
if (in_pcbrele(inp)) {
|
||||
if (in_pcbrele_wlocked(inp)) {
|
||||
inp = NULL;
|
||||
goto findpcb;
|
||||
}
|
||||
@ -1027,13 +1013,16 @@ tcp_input(struct mbuf *m, int off0)
|
||||
/*
|
||||
* When the socket is accepting connections (the INPCB is in LISTEN
|
||||
* state) we look into the SYN cache if this is a new connection
|
||||
* attempt or the completion of a previous one.
|
||||
* attempt or the completion of a previous one. Because listen
|
||||
* sockets are never in TCPS_ESTABLISHED, the V_tcbinfo lock will be
|
||||
* held in this case.
|
||||
*/
|
||||
if (so->so_options & SO_ACCEPTCONN) {
|
||||
struct in_conninfo inc;
|
||||
|
||||
KASSERT(tp->t_state == TCPS_LISTEN, ("%s: so accepting but "
|
||||
"tp not listening", __func__));
|
||||
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
|
||||
|
||||
bzero(&inc, sizeof(inc));
|
||||
#ifdef INET6
|
||||
@ -1371,13 +1360,17 @@ tcp_input(struct mbuf *m, int off0)
|
||||
return;
|
||||
|
||||
dropwithreset:
|
||||
if (ti_locked == TI_RLOCKED)
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
else if (ti_locked == TI_WLOCKED)
|
||||
if (ti_locked == TI_WLOCKED) {
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
else
|
||||
panic("%s: dropwithreset ti_locked %d", __func__, ti_locked);
|
||||
ti_locked = TI_UNLOCKED;
|
||||
ti_locked = TI_UNLOCKED;
|
||||
}
|
||||
#ifdef INVARIANTS
|
||||
else {
|
||||
KASSERT(ti_locked == TI_UNLOCKED, ("%s: dropwithreset "
|
||||
"ti_locked: %d", __func__, ti_locked));
|
||||
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (inp != NULL) {
|
||||
tcp_dropwithreset(m, th, tp, tlen, rstreason);
|
||||
@ -1388,13 +1381,17 @@ tcp_input(struct mbuf *m, int off0)
|
||||
goto drop;
|
||||
|
||||
dropunlock:
|
||||
if (ti_locked == TI_RLOCKED)
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
else if (ti_locked == TI_WLOCKED)
|
||||
if (ti_locked == TI_WLOCKED) {
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
else
|
||||
panic("%s: dropunlock ti_locked %d", __func__, ti_locked);
|
||||
ti_locked = TI_UNLOCKED;
|
||||
ti_locked = TI_UNLOCKED;
|
||||
}
|
||||
#ifdef INVARIANTS
|
||||
else {
|
||||
KASSERT(ti_locked == TI_UNLOCKED, ("%s: dropunlock "
|
||||
"ti_locked: %d", __func__, ti_locked));
|
||||
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (inp != NULL)
|
||||
INP_WUNLOCK(inp);
|
||||
@ -1449,13 +1446,13 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
|
||||
} else {
|
||||
#ifdef INVARIANTS
|
||||
if (ti_locked == TI_RLOCKED)
|
||||
INP_INFO_RLOCK_ASSERT(&V_tcbinfo);
|
||||
else if (ti_locked == TI_WLOCKED)
|
||||
if (ti_locked == TI_WLOCKED)
|
||||
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
|
||||
else
|
||||
panic("%s: ti_locked %d for EST", __func__,
|
||||
ti_locked);
|
||||
else {
|
||||
KASSERT(ti_locked == TI_UNLOCKED, ("%s: EST "
|
||||
"ti_locked: %d", __func__, ti_locked));
|
||||
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
INP_WLOCK_ASSERT(tp->t_inpcb);
|
||||
@ -1601,13 +1598,8 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
/*
|
||||
* This is a pure ack for outstanding data.
|
||||
*/
|
||||
if (ti_locked == TI_RLOCKED)
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
else if (ti_locked == TI_WLOCKED)
|
||||
if (ti_locked == TI_WLOCKED)
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
else
|
||||
panic("%s: ti_locked %d on pure ACK",
|
||||
__func__, ti_locked);
|
||||
ti_locked = TI_UNLOCKED;
|
||||
|
||||
TCPSTAT_INC(tcps_predack);
|
||||
@ -1708,13 +1700,8 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
* nothing on the reassembly queue and we have enough
|
||||
* buffer space to take it.
|
||||
*/
|
||||
if (ti_locked == TI_RLOCKED)
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
else if (ti_locked == TI_WLOCKED)
|
||||
if (ti_locked == TI_WLOCKED)
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
else
|
||||
panic("%s: ti_locked %d on pure data "
|
||||
"segment", __func__, ti_locked);
|
||||
ti_locked = TI_UNLOCKED;
|
||||
|
||||
/* Clean receiver SACK report if present */
|
||||
@ -2550,9 +2537,6 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
}
|
||||
|
||||
process_ACK:
|
||||
INP_INFO_LOCK_ASSERT(&V_tcbinfo);
|
||||
KASSERT(ti_locked == TI_RLOCKED || ti_locked == TI_WLOCKED,
|
||||
("tcp_input: process_ACK ti_locked %d", ti_locked));
|
||||
INP_WLOCK_ASSERT(tp->t_inpcb);
|
||||
|
||||
acked = BYTES_THIS_ACK(tp, th);
|
||||
@ -2716,9 +2700,6 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
}
|
||||
|
||||
step6:
|
||||
INP_INFO_LOCK_ASSERT(&V_tcbinfo);
|
||||
KASSERT(ti_locked == TI_RLOCKED || ti_locked == TI_WLOCKED,
|
||||
("tcp_do_segment: step6 ti_locked %d", ti_locked));
|
||||
INP_WLOCK_ASSERT(tp->t_inpcb);
|
||||
|
||||
/*
|
||||
@ -2804,9 +2785,6 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
tp->rcv_up = tp->rcv_nxt;
|
||||
}
|
||||
dodata: /* XXX */
|
||||
INP_INFO_LOCK_ASSERT(&V_tcbinfo);
|
||||
KASSERT(ti_locked == TI_RLOCKED || ti_locked == TI_WLOCKED,
|
||||
("tcp_do_segment: dodata ti_locked %d", ti_locked));
|
||||
INP_WLOCK_ASSERT(tp->t_inpcb);
|
||||
|
||||
/*
|
||||
@ -2938,13 +2916,8 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ti_locked == TI_RLOCKED)
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
else if (ti_locked == TI_WLOCKED)
|
||||
if (ti_locked == TI_WLOCKED)
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
else
|
||||
panic("%s: dodata epilogue ti_locked %d", __func__,
|
||||
ti_locked);
|
||||
ti_locked = TI_UNLOCKED;
|
||||
|
||||
#ifdef TCPDEBUG
|
||||
@ -2973,9 +2946,6 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
return;
|
||||
|
||||
dropafterack:
|
||||
KASSERT(ti_locked == TI_RLOCKED || ti_locked == TI_WLOCKED,
|
||||
("tcp_do_segment: dropafterack ti_locked %d", ti_locked));
|
||||
|
||||
/*
|
||||
* Generate an ACK dropping incoming segment if it occupies
|
||||
* sequence space, where the ACK reflects our state.
|
||||
@ -3002,13 +2972,8 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen,
|
||||
&tcp_savetcp, 0);
|
||||
#endif
|
||||
if (ti_locked == TI_RLOCKED)
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
else if (ti_locked == TI_WLOCKED)
|
||||
if (ti_locked == TI_WLOCKED)
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
else
|
||||
panic("%s: dropafterack epilogue ti_locked %d", __func__,
|
||||
ti_locked);
|
||||
ti_locked = TI_UNLOCKED;
|
||||
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
@ -3018,12 +2983,8 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
return;
|
||||
|
||||
dropwithreset:
|
||||
if (ti_locked == TI_RLOCKED)
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
else if (ti_locked == TI_WLOCKED)
|
||||
if (ti_locked == TI_WLOCKED)
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
else
|
||||
panic("%s: dropwithreset ti_locked %d", __func__, ti_locked);
|
||||
ti_locked = TI_UNLOCKED;
|
||||
|
||||
if (tp != NULL) {
|
||||
@ -3034,15 +2995,14 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
return;
|
||||
|
||||
drop:
|
||||
if (ti_locked == TI_RLOCKED)
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
else if (ti_locked == TI_WLOCKED)
|
||||
if (ti_locked == TI_WLOCKED) {
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
ti_locked = TI_UNLOCKED;
|
||||
}
|
||||
#ifdef INVARIANTS
|
||||
else
|
||||
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo);
|
||||
#endif
|
||||
ti_locked = TI_UNLOCKED;
|
||||
|
||||
/*
|
||||
* Drop space held by incoming segment and return.
|
||||
|
@ -1184,9 +1184,9 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS)
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
for (i = 0; i < n; i++) {
|
||||
inp = inp_list[i];
|
||||
INP_WLOCK(inp);
|
||||
if (!in_pcbrele(inp))
|
||||
INP_WUNLOCK(inp);
|
||||
INP_RLOCK(inp);
|
||||
if (!in_pcbrele_rlocked(inp))
|
||||
INP_RUNLOCK(inp);
|
||||
}
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
|
||||
@ -1228,12 +1228,9 @@ tcp_getcred(SYSCTL_HANDLER_ARGS)
|
||||
error = SYSCTL_IN(req, addrs, sizeof(addrs));
|
||||
if (error)
|
||||
return (error);
|
||||
INP_INFO_RLOCK(&V_tcbinfo);
|
||||
inp = in_pcblookup_hash(&V_tcbinfo, addrs[1].sin_addr,
|
||||
addrs[1].sin_port, addrs[0].sin_addr, addrs[0].sin_port, 0, NULL);
|
||||
inp = in_pcblookup(&V_tcbinfo, addrs[1].sin_addr, addrs[1].sin_port,
|
||||
addrs[0].sin_addr, addrs[0].sin_port, INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp != NULL) {
|
||||
INP_RLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
if (inp->inp_socket == NULL)
|
||||
error = ENOENT;
|
||||
if (error == 0)
|
||||
@ -1241,10 +1238,8 @@ tcp_getcred(SYSCTL_HANDLER_ARGS)
|
||||
if (error == 0)
|
||||
cru2x(inp->inp_cred, &xuc);
|
||||
INP_RUNLOCK(inp);
|
||||
} else {
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
} else
|
||||
error = ENOENT;
|
||||
}
|
||||
if (error == 0)
|
||||
error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
|
||||
return (error);
|
||||
@ -1286,23 +1281,20 @@ tcp6_getcred(SYSCTL_HANDLER_ARGS)
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
INP_INFO_RLOCK(&V_tcbinfo);
|
||||
#ifdef INET
|
||||
if (mapped == 1)
|
||||
inp = in_pcblookup_hash(&V_tcbinfo,
|
||||
inp = in_pcblookup(&V_tcbinfo,
|
||||
*(struct in_addr *)&addrs[1].sin6_addr.s6_addr[12],
|
||||
addrs[1].sin6_port,
|
||||
*(struct in_addr *)&addrs[0].sin6_addr.s6_addr[12],
|
||||
addrs[0].sin6_port,
|
||||
0, NULL);
|
||||
addrs[0].sin6_port, INPLOOKUP_RLOCKPCB, NULL);
|
||||
else
|
||||
#endif
|
||||
inp = in6_pcblookup_hash(&V_tcbinfo,
|
||||
inp = in6_pcblookup(&V_tcbinfo,
|
||||
&addrs[1].sin6_addr, addrs[1].sin6_port,
|
||||
&addrs[0].sin6_addr, addrs[0].sin6_port, 0, NULL);
|
||||
&addrs[0].sin6_addr, addrs[0].sin6_port,
|
||||
INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp != NULL) {
|
||||
INP_RLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
if (inp->inp_socket == NULL)
|
||||
error = ENOENT;
|
||||
if (error == 0)
|
||||
@ -1310,10 +1302,8 @@ tcp6_getcred(SYSCTL_HANDLER_ARGS)
|
||||
if (error == 0)
|
||||
cru2x(inp->inp_cred, &xuc);
|
||||
INP_RUNLOCK(inp);
|
||||
} else {
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
} else
|
||||
error = ENOENT;
|
||||
}
|
||||
if (error == 0)
|
||||
error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
|
||||
return (error);
|
||||
@ -1374,10 +1364,9 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
|
||||
th = (struct tcphdr *)((caddr_t)ip
|
||||
+ (ip->ip_hl << 2));
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
inp = in_pcblookup_hash(&V_tcbinfo, faddr, th->th_dport,
|
||||
ip->ip_src, th->th_sport, 0, NULL);
|
||||
inp = in_pcblookup(&V_tcbinfo, faddr, th->th_dport,
|
||||
ip->ip_src, th->th_sport, INPLOOKUP_WLOCKPCB, NULL);
|
||||
if (inp != NULL) {
|
||||
INP_WLOCK(inp);
|
||||
if (!(inp->inp_flags & INP_TIMEWAIT) &&
|
||||
!(inp->inp_flags & INP_DROPPED) &&
|
||||
!(inp->inp_socket == NULL)) {
|
||||
@ -2154,20 +2143,19 @@ sysctl_drop(SYSCTL_HANDLER_ARGS)
|
||||
switch (addrs[0].ss_family) {
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
inp = in6_pcblookup_hash(&V_tcbinfo, &fin6->sin6_addr,
|
||||
fin6->sin6_port, &lin6->sin6_addr, lin6->sin6_port, 0,
|
||||
NULL);
|
||||
inp = in6_pcblookup(&V_tcbinfo, &fin6->sin6_addr,
|
||||
fin6->sin6_port, &lin6->sin6_addr, lin6->sin6_port,
|
||||
INPLOOKUP_WLOCKPCB, NULL);
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
inp = in_pcblookup_hash(&V_tcbinfo, fin->sin_addr,
|
||||
fin->sin_port, lin->sin_addr, lin->sin_port, 0, NULL);
|
||||
inp = in_pcblookup(&V_tcbinfo, fin->sin_addr, fin->sin_port,
|
||||
lin->sin_addr, lin->sin_port, INPLOOKUP_WLOCKPCB, NULL);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (inp != NULL) {
|
||||
INP_WLOCK(inp);
|
||||
if (inp->inp_flags & INP_TIMEWAIT) {
|
||||
/*
|
||||
* XXXRW: There currently exists a state where an
|
||||
|
@ -661,6 +661,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
|
||||
inp = sotoinpcb(so);
|
||||
inp->inp_inc.inc_fibnum = so->so_fibnum;
|
||||
INP_WLOCK(inp);
|
||||
INP_HASH_WLOCK(&V_tcbinfo);
|
||||
|
||||
/* Insert new socket into PCB hash list. */
|
||||
inp->inp_inc.inc_flags = sc->sc_inc.inc_flags;
|
||||
@ -694,6 +695,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
|
||||
s, __func__, error);
|
||||
free(s, M_TCPLOG);
|
||||
}
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
goto abort;
|
||||
}
|
||||
#ifdef IPSEC
|
||||
@ -737,6 +739,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
|
||||
s, __func__, error);
|
||||
free(s, M_TCPLOG);
|
||||
}
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
goto abort;
|
||||
}
|
||||
/* Override flowlabel from in6_pcbconnect. */
|
||||
@ -776,10 +779,12 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
|
||||
s, __func__, error);
|
||||
free(s, M_TCPLOG);
|
||||
}
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
#endif /* INET */
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
tp = intotcpcb(inp);
|
||||
tp->t_state = TCPS_SYN_RECEIVED;
|
||||
tp->iss = sc->sc_iss;
|
||||
|
@ -490,7 +490,7 @@ tcp_timer_rexmt(void * xtp)
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
INP_WLOCK(inp);
|
||||
if (in_pcbrele(inp)) {
|
||||
if (in_pcbrele_wlocked(inp)) {
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
CURVNET_RESTORE();
|
||||
return;
|
||||
|
@ -2,8 +2,12 @@
|
||||
* Copyright (c) 1982, 1986, 1988, 1993
|
||||
* The Regents of the University of California.
|
||||
* Copyright (c) 2006-2007 Robert N. M. Watson
|
||||
* Copyright (c) 2010-2011 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were 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:
|
||||
@ -251,7 +255,6 @@ tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
return (EAFNOSUPPORT);
|
||||
|
||||
TCPDEBUG0;
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("tcp_usr_bind: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
@ -261,11 +264,12 @@ tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
}
|
||||
tp = intotcpcb(inp);
|
||||
TCPDEBUG1();
|
||||
INP_HASH_WLOCK(&V_tcbinfo);
|
||||
error = in_pcbbind(inp, nam, td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
out:
|
||||
TCPDEBUG2(PRU_BIND);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -292,7 +296,6 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
return (EAFNOSUPPORT);
|
||||
|
||||
TCPDEBUG0;
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("tcp6_usr_bind: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
@ -302,6 +305,7 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
}
|
||||
tp = intotcpcb(inp);
|
||||
TCPDEBUG1();
|
||||
INP_HASH_WLOCK(&V_tcbinfo);
|
||||
inp->inp_vflag &= ~INP_IPV4;
|
||||
inp->inp_vflag |= INP_IPV6;
|
||||
#ifdef INET
|
||||
@ -316,15 +320,16 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
inp->inp_vflag &= ~INP_IPV6;
|
||||
error = in_pcbbind(inp, (struct sockaddr *)&sin,
|
||||
td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
error = in6_pcbbind(inp, nam, td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
out:
|
||||
TCPDEBUG2(PRU_BIND);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
return (error);
|
||||
}
|
||||
#endif /* INET6 */
|
||||
@ -341,7 +346,6 @@ tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
|
||||
struct tcpcb *tp = NULL;
|
||||
|
||||
TCPDEBUG0;
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("tcp_usr_listen: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
@ -353,8 +357,10 @@ tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
|
||||
TCPDEBUG1();
|
||||
SOCK_LOCK(so);
|
||||
error = solisten_proto_check(so);
|
||||
INP_HASH_WLOCK(&V_tcbinfo);
|
||||
if (error == 0 && inp->inp_lport == 0)
|
||||
error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
if (error == 0) {
|
||||
tp->t_state = TCPS_LISTEN;
|
||||
solisten_proto(so, backlog);
|
||||
@ -365,7 +371,6 @@ tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
|
||||
out:
|
||||
TCPDEBUG2(PRU_LISTEN);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
return (error);
|
||||
}
|
||||
#endif /* INET */
|
||||
@ -379,7 +384,6 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
|
||||
struct tcpcb *tp = NULL;
|
||||
|
||||
TCPDEBUG0;
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("tcp6_usr_listen: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
@ -391,12 +395,14 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
|
||||
TCPDEBUG1();
|
||||
SOCK_LOCK(so);
|
||||
error = solisten_proto_check(so);
|
||||
INP_HASH_WLOCK(&V_tcbinfo);
|
||||
if (error == 0 && inp->inp_lport == 0) {
|
||||
inp->inp_vflag &= ~INP_IPV4;
|
||||
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
|
||||
inp->inp_vflag |= INP_IPV4;
|
||||
error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
|
||||
}
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
if (error == 0) {
|
||||
tp->t_state = TCPS_LISTEN;
|
||||
solisten_proto(so, backlog);
|
||||
@ -406,7 +412,6 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
|
||||
out:
|
||||
TCPDEBUG2(PRU_LISTEN);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
return (error);
|
||||
}
|
||||
#endif /* INET6 */
|
||||
@ -440,7 +445,6 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
return (error);
|
||||
|
||||
TCPDEBUG0;
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("tcp_usr_connect: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
@ -456,7 +460,6 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
out:
|
||||
TCPDEBUG2(PRU_CONNECT);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
return (error);
|
||||
}
|
||||
#endif /* INET */
|
||||
@ -482,7 +485,6 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
&& IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
|
||||
return (EAFNOSUPPORT);
|
||||
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("tcp6_usr_connect: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
@ -493,6 +495,11 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
tp = intotcpcb(inp);
|
||||
TCPDEBUG1();
|
||||
#ifdef INET
|
||||
/*
|
||||
* XXXRW: Some confusion: V4/V6 flags relate to binding, and
|
||||
* therefore probably require the hash lock, which isn't held here.
|
||||
* Is this a significant problem?
|
||||
*/
|
||||
if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
|
||||
struct sockaddr_in sin;
|
||||
|
||||
@ -525,7 +532,6 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
out:
|
||||
TCPDEBUG2(PRU_CONNECT);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
return (error);
|
||||
}
|
||||
#endif /* INET6 */
|
||||
@ -639,6 +645,7 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam)
|
||||
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("tcp6_usr_accept: inp == NULL"));
|
||||
INP_INFO_RLOCK(&V_tcbinfo);
|
||||
INP_WLOCK(inp);
|
||||
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
|
||||
error = ECONNABORTED;
|
||||
@ -664,6 +671,7 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam)
|
||||
out:
|
||||
TCPDEBUG2(PRU_ACCEPT);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
if (error == 0) {
|
||||
if (v4)
|
||||
*nam = in6_v4mapsin6_sockaddr(port, &addr);
|
||||
@ -750,25 +758,17 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
||||
int error = 0;
|
||||
struct inpcb *inp;
|
||||
struct tcpcb *tp = NULL;
|
||||
int headlocked = 0;
|
||||
#ifdef INET6
|
||||
int isipv6;
|
||||
#endif
|
||||
TCPDEBUG0;
|
||||
|
||||
/*
|
||||
* We require the pcbinfo lock in two cases:
|
||||
*
|
||||
* (1) An implied connect is taking place, which can result in
|
||||
* binding IPs and ports and hence modification of the pcb hash
|
||||
* chains.
|
||||
*
|
||||
* (2) PRUS_EOF is set, resulting in explicit close on the send.
|
||||
* We require the pcbinfo lock if we will close the socket as part of
|
||||
* this call.
|
||||
*/
|
||||
if ((nam != NULL) || (flags & PRUS_EOF)) {
|
||||
if (flags & PRUS_EOF)
|
||||
INP_INFO_WLOCK(&V_tcbinfo);
|
||||
headlocked = 1;
|
||||
}
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL"));
|
||||
INP_WLOCK(inp);
|
||||
@ -805,7 +805,6 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
||||
* initialize maxseg/maxopd using peer's cached
|
||||
* MSS.
|
||||
*/
|
||||
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
|
||||
#ifdef INET6
|
||||
if (isipv6)
|
||||
error = tcp6_connect(tp, nam, td);
|
||||
@ -830,10 +829,6 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
||||
socantsendmore(so);
|
||||
tcp_usrclosed(tp);
|
||||
}
|
||||
if (headlocked) {
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
headlocked = 0;
|
||||
}
|
||||
if (!(inp->inp_flags & INP_DROPPED)) {
|
||||
if (flags & PRUS_MORETOCOME)
|
||||
tp->t_flags |= TF_MORETOCOME;
|
||||
@ -869,7 +864,6 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
||||
* initialize maxseg/maxopd using peer's cached
|
||||
* MSS.
|
||||
*/
|
||||
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
|
||||
#ifdef INET6
|
||||
if (isipv6)
|
||||
error = tcp6_connect(tp, nam, td);
|
||||
@ -884,11 +878,6 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
||||
goto out;
|
||||
tp->snd_wnd = TTCP_CLIENT_SND_WND;
|
||||
tcp_mss(tp, -1);
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
headlocked = 0;
|
||||
} else if (nam) {
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
headlocked = 0;
|
||||
}
|
||||
tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
|
||||
tp->t_flags |= TF_FORCEDATA;
|
||||
@ -899,7 +888,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
||||
TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB :
|
||||
((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
|
||||
INP_WUNLOCK(inp);
|
||||
if (headlocked)
|
||||
if (flags & PRUS_EOF)
|
||||
INP_INFO_WUNLOCK(&V_tcbinfo);
|
||||
return (error);
|
||||
}
|
||||
@ -1087,13 +1076,13 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||
u_short lport;
|
||||
int error;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK(&V_tcbinfo);
|
||||
|
||||
if (inp->inp_lport == 0) {
|
||||
error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
|
||||
if (error)
|
||||
return error;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1106,11 +1095,14 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||
error = in_pcbconnect_setup(inp, nam, &laddr.s_addr, &lport,
|
||||
&inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, td->td_ucred);
|
||||
if (error && oinp == NULL)
|
||||
return error;
|
||||
if (oinp)
|
||||
return EADDRINUSE;
|
||||
goto out;
|
||||
if (oinp) {
|
||||
error = EADDRINUSE;
|
||||
goto out;
|
||||
}
|
||||
inp->inp_laddr = laddr;
|
||||
in_pcbrehash(inp);
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
|
||||
/*
|
||||
* Compute window scaling to request:
|
||||
@ -1129,6 +1121,10 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||
tcp_sendseqinit(tp);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
return (error);
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
@ -1142,13 +1138,13 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||
struct in6_addr addr6;
|
||||
int error;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK(&V_tcbinfo);
|
||||
|
||||
if (inp->inp_lport == 0) {
|
||||
error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
|
||||
if (error)
|
||||
return error;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1156,18 +1152,23 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||
* earlier incarnation of this same connection still in
|
||||
* TIME_WAIT state, creating an ADDRINUSE error.
|
||||
* in6_pcbladdr() also handles scope zone IDs.
|
||||
*
|
||||
* XXXRW: We wouldn't need to expose in6_pcblookup_hash_locked()
|
||||
* outside of in6_pcb.c if there were an in6_pcbconnect_setup().
|
||||
*/
|
||||
error = in6_pcbladdr(inp, nam, &addr6);
|
||||
if (error)
|
||||
return error;
|
||||
oinp = in6_pcblookup_hash(inp->inp_pcbinfo,
|
||||
oinp = in6_pcblookup_hash_locked(inp->inp_pcbinfo,
|
||||
&sin6->sin6_addr, sin6->sin6_port,
|
||||
IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
|
||||
? &addr6
|
||||
: &inp->in6p_laddr,
|
||||
inp->inp_lport, 0, NULL);
|
||||
if (oinp)
|
||||
return EADDRINUSE;
|
||||
if (oinp) {
|
||||
error = EADDRINUSE;
|
||||
goto out;
|
||||
}
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
|
||||
inp->in6p_laddr = addr6;
|
||||
inp->in6p_faddr = sin6->sin6_addr;
|
||||
@ -1178,6 +1179,7 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||
inp->inp_flow |=
|
||||
(htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
|
||||
in_pcbrehash(inp);
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
|
||||
/* Compute window scaling to request. */
|
||||
while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
|
||||
@ -1192,6 +1194,10 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||
tcp_sendseqinit(tp);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||
return error;
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
||||
|
@ -2,8 +2,12 @@
|
||||
* Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
|
||||
* The Regents of the University of California.
|
||||
* Copyright (c) 2008 Robert N. M. Watson
|
||||
* Copyright (c) 2010-2011 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were 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:
|
||||
@ -253,7 +257,7 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
|
||||
#endif
|
||||
struct udpcb *up;
|
||||
|
||||
INP_RLOCK_ASSERT(inp);
|
||||
INP_LOCK_ASSERT(inp);
|
||||
|
||||
/*
|
||||
* Engage the tunneling protocol.
|
||||
@ -458,12 +462,12 @@ udp_input(struct mbuf *m, int off)
|
||||
}
|
||||
#endif
|
||||
|
||||
INP_INFO_RLOCK(&V_udbinfo);
|
||||
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
|
||||
in_broadcast(ip->ip_dst, ifp)) {
|
||||
struct inpcb *last;
|
||||
struct ip_moptions *imo;
|
||||
|
||||
INP_INFO_RLOCK(&V_udbinfo);
|
||||
last = NULL;
|
||||
LIST_FOREACH(inp, &V_udb, inp_list) {
|
||||
if (inp->inp_lport != uh->uh_dport)
|
||||
@ -484,6 +488,13 @@ udp_input(struct mbuf *m, int off)
|
||||
|
||||
INP_RLOCK(inp);
|
||||
|
||||
/*
|
||||
* XXXRW: Because we weren't holding either the inpcb
|
||||
* or the hash lock when we checked for a match
|
||||
* before, we should probably recheck now that the
|
||||
* inpcb lock is held.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Handle socket delivery policy for any-source
|
||||
* and source-specific multicast. [RFC3678]
|
||||
@ -542,7 +553,10 @@ udp_input(struct mbuf *m, int off)
|
||||
* or multicast datgram.)
|
||||
*/
|
||||
UDPSTAT_INC(udps_noportbcast);
|
||||
goto badheadlocked;
|
||||
if (inp)
|
||||
INP_RUNLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
goto badunlocked;
|
||||
}
|
||||
udp_append(last, ip, m, iphlen, &udp_in);
|
||||
INP_RUNLOCK(last);
|
||||
@ -553,8 +567,9 @@ udp_input(struct mbuf *m, int off)
|
||||
/*
|
||||
* Locate pcb for datagram.
|
||||
*/
|
||||
inp = in_pcblookup_hash(&V_udbinfo, ip->ip_src, uh->uh_sport,
|
||||
ip->ip_dst, uh->uh_dport, 1, ifp);
|
||||
inp = in_pcblookup(&V_udbinfo, ip->ip_src, uh->uh_sport,
|
||||
ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB,
|
||||
ifp);
|
||||
if (inp == NULL) {
|
||||
if (udp_log_in_vain) {
|
||||
char buf[4*sizeof "123"];
|
||||
@ -568,36 +583,31 @@ udp_input(struct mbuf *m, int off)
|
||||
UDPSTAT_INC(udps_noport);
|
||||
if (m->m_flags & (M_BCAST | M_MCAST)) {
|
||||
UDPSTAT_INC(udps_noportbcast);
|
||||
goto badheadlocked;
|
||||
goto badunlocked;
|
||||
}
|
||||
if (V_udp_blackhole)
|
||||
goto badheadlocked;
|
||||
goto badunlocked;
|
||||
if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0)
|
||||
goto badheadlocked;
|
||||
goto badunlocked;
|
||||
*ip = save_ip;
|
||||
ip->ip_len += iphlen;
|
||||
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the minimum TTL for socket.
|
||||
*/
|
||||
INP_RLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
INP_RLOCK_ASSERT(inp);
|
||||
if (inp->inp_ip_minttl && inp->inp_ip_minttl > ip->ip_ttl) {
|
||||
INP_RUNLOCK(inp);
|
||||
goto badunlocked;
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
udp_append(inp, ip, m, iphlen, &udp_in);
|
||||
INP_RUNLOCK(inp);
|
||||
return;
|
||||
|
||||
badheadlocked:
|
||||
if (inp)
|
||||
INP_RUNLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
badunlocked:
|
||||
m_freem(m);
|
||||
}
|
||||
@ -656,17 +666,15 @@ udp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
|
||||
return;
|
||||
if (ip != NULL) {
|
||||
uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
|
||||
INP_INFO_RLOCK(&V_udbinfo);
|
||||
inp = in_pcblookup_hash(&V_udbinfo, faddr, uh->uh_dport,
|
||||
ip->ip_src, uh->uh_sport, 0, NULL);
|
||||
inp = in_pcblookup(&V_udbinfo, faddr, uh->uh_dport,
|
||||
ip->ip_src, uh->uh_sport, INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp != NULL) {
|
||||
INP_RLOCK(inp);
|
||||
INP_RLOCK_ASSERT(inp);
|
||||
if (inp->inp_socket != NULL) {
|
||||
udp_notify(inp, inetctlerrmap[cmd]);
|
||||
}
|
||||
INP_RUNLOCK(inp);
|
||||
}
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
} else
|
||||
in_pcbnotifyall(&V_udbinfo, faddr, inetctlerrmap[cmd],
|
||||
udp_notify);
|
||||
@ -756,9 +764,9 @@ udp_pcblist(SYSCTL_HANDLER_ARGS)
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
for (i = 0; i < n; i++) {
|
||||
inp = inp_list[i];
|
||||
INP_WLOCK(inp);
|
||||
if (!in_pcbrele(inp))
|
||||
INP_WUNLOCK(inp);
|
||||
INP_RLOCK(inp);
|
||||
if (!in_pcbrele_rlocked(inp))
|
||||
INP_RUNLOCK(inp);
|
||||
}
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
|
||||
@ -799,12 +807,11 @@ udp_getcred(SYSCTL_HANDLER_ARGS)
|
||||
error = SYSCTL_IN(req, addrs, sizeof(addrs));
|
||||
if (error)
|
||||
return (error);
|
||||
INP_INFO_RLOCK(&V_udbinfo);
|
||||
inp = in_pcblookup_hash(&V_udbinfo, addrs[1].sin_addr, addrs[1].sin_port,
|
||||
addrs[0].sin_addr, addrs[0].sin_port, 1, NULL);
|
||||
inp = in_pcblookup(&V_udbinfo, addrs[1].sin_addr, addrs[1].sin_port,
|
||||
addrs[0].sin_addr, addrs[0].sin_port,
|
||||
INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp != NULL) {
|
||||
INP_RLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
INP_RLOCK_ASSERT(inp);
|
||||
if (inp->inp_socket == NULL)
|
||||
error = ENOENT;
|
||||
if (error == 0)
|
||||
@ -812,10 +819,8 @@ udp_getcred(SYSCTL_HANDLER_ARGS)
|
||||
if (error == 0)
|
||||
cru2x(inp->inp_cred, &xuc);
|
||||
INP_RUNLOCK(inp);
|
||||
} else {
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
} else
|
||||
error = ENOENT;
|
||||
}
|
||||
if (error == 0)
|
||||
error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
|
||||
return (error);
|
||||
@ -924,6 +929,9 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
#define UH_WLOCKED 2
|
||||
#define UH_RLOCKED 1
|
||||
#define UH_UNLOCKED 0
|
||||
static int
|
||||
udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
struct mbuf *control, struct thread *td)
|
||||
@ -1016,29 +1024,27 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
* conservative locks than required the second time around, so later
|
||||
* assertions have to accept that. Further analysis of the number of
|
||||
* misses under contention is required.
|
||||
*
|
||||
* XXXRW: Check that hash locking update here is correct.
|
||||
*/
|
||||
sin = (struct sockaddr_in *)addr;
|
||||
INP_RLOCK(inp);
|
||||
if (sin != NULL &&
|
||||
(inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0)) {
|
||||
INP_RUNLOCK(inp);
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
unlock_udbinfo = 2;
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
unlock_udbinfo = UH_WLOCKED;
|
||||
} else if ((sin != NULL && (
|
||||
(sin->sin_addr.s_addr == INADDR_ANY) ||
|
||||
(sin->sin_addr.s_addr == INADDR_BROADCAST) ||
|
||||
(inp->inp_laddr.s_addr == INADDR_ANY) ||
|
||||
(inp->inp_lport == 0))) ||
|
||||
(src.sin_family == AF_INET)) {
|
||||
if (!INP_INFO_TRY_RLOCK(&V_udbinfo)) {
|
||||
INP_RUNLOCK(inp);
|
||||
INP_INFO_RLOCK(&V_udbinfo);
|
||||
INP_RLOCK(inp);
|
||||
}
|
||||
unlock_udbinfo = 1;
|
||||
INP_HASH_RLOCK(&V_udbinfo);
|
||||
unlock_udbinfo = UH_RLOCKED;
|
||||
} else
|
||||
unlock_udbinfo = 0;
|
||||
unlock_udbinfo = UH_UNLOCKED;
|
||||
|
||||
/*
|
||||
* If the IP_SENDSRCADDR control message was specified, override the
|
||||
@ -1048,7 +1054,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
laddr = inp->inp_laddr;
|
||||
lport = inp->inp_lport;
|
||||
if (src.sin_family == AF_INET) {
|
||||
INP_INFO_LOCK_ASSERT(&V_udbinfo);
|
||||
INP_HASH_LOCK_ASSERT(&V_udbinfo);
|
||||
if ((lport == 0) ||
|
||||
(laddr.s_addr == INADDR_ANY &&
|
||||
src.sin_addr.s_addr == INADDR_ANY)) {
|
||||
@ -1099,7 +1105,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
inp->inp_lport == 0 ||
|
||||
sin->sin_addr.s_addr == INADDR_ANY ||
|
||||
sin->sin_addr.s_addr == INADDR_BROADCAST) {
|
||||
INP_INFO_LOCK_ASSERT(&V_udbinfo);
|
||||
INP_HASH_LOCK_ASSERT(&V_udbinfo);
|
||||
error = in_pcbconnect_setup(inp, addr, &laddr.s_addr,
|
||||
&lport, &faddr.s_addr, &fport, NULL,
|
||||
td->td_ucred);
|
||||
@ -1113,8 +1119,8 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
/* Commit the local port if newly assigned. */
|
||||
if (inp->inp_laddr.s_addr == INADDR_ANY &&
|
||||
inp->inp_lport == 0) {
|
||||
INP_INFO_WLOCK_ASSERT(&V_udbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(&V_udbinfo);
|
||||
/*
|
||||
* Remember addr if jailed, to prevent
|
||||
* rebinding.
|
||||
@ -1209,25 +1215,25 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
||||
((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
|
||||
UDPSTAT_INC(udps_opackets);
|
||||
|
||||
if (unlock_udbinfo == 2)
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
else if (unlock_udbinfo == 1)
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
if (unlock_udbinfo == UH_WLOCKED)
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
else if (unlock_udbinfo == UH_RLOCKED)
|
||||
INP_HASH_RUNLOCK(&V_udbinfo);
|
||||
error = ip_output(m, inp->inp_options, NULL, ipflags,
|
||||
inp->inp_moptions, inp);
|
||||
if (unlock_udbinfo == 2)
|
||||
if (unlock_udbinfo == UH_WLOCKED)
|
||||
INP_WUNLOCK(inp);
|
||||
else
|
||||
INP_RUNLOCK(inp);
|
||||
return (error);
|
||||
|
||||
release:
|
||||
if (unlock_udbinfo == 2) {
|
||||
if (unlock_udbinfo == UH_WLOCKED) {
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
} else if (unlock_udbinfo == 1) {
|
||||
} else if (unlock_udbinfo == UH_RLOCKED) {
|
||||
INP_HASH_RUNLOCK(&V_udbinfo);
|
||||
INP_RUNLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
} else
|
||||
INP_RUNLOCK(inp);
|
||||
m_freem(m);
|
||||
@ -1376,15 +1382,15 @@ udp_abort(struct socket *so)
|
||||
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_abort: inp == NULL"));
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
if (inp->inp_faddr.s_addr != INADDR_ANY) {
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
in_pcbdisconnect(inp);
|
||||
inp->inp_laddr.s_addr = INADDR_ANY;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1453,11 +1459,11 @@ udp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_bind: inp == NULL"));
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
error = in_pcbbind(inp, nam, td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -1468,15 +1474,15 @@ udp_close(struct socket *so)
|
||||
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_close: inp == NULL"));
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
if (inp->inp_faddr.s_addr != INADDR_ANY) {
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
in_pcbdisconnect(inp);
|
||||
inp->inp_laddr.s_addr = INADDR_ANY;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1488,25 +1494,23 @@ udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_connect: inp == NULL"));
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
if (inp->inp_faddr.s_addr != INADDR_ANY) {
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
return (EISCONN);
|
||||
}
|
||||
sin = (struct sockaddr_in *)nam;
|
||||
error = prison_remote_ip4(td->td_ucred, &sin->sin_addr);
|
||||
if (error != 0) {
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
return (error);
|
||||
}
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
error = in_pcbconnect(inp, nam, td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
if (error == 0)
|
||||
soisconnected(so);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -1538,21 +1542,19 @@ udp_disconnect(struct socket *so)
|
||||
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp_disconnect: inp == NULL"));
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
if (inp->inp_faddr.s_addr == INADDR_ANY) {
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
return (ENOTCONN);
|
||||
}
|
||||
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
in_pcbdisconnect(inp);
|
||||
inp->inp_laddr.s_addr = INADDR_ANY;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
SOCK_LOCK(so);
|
||||
so->so_state &= ~SS_ISCONNECTED; /* XXX */
|
||||
SOCK_UNLOCK(so);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,11 @@
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* Copyright (c) 2010-2011 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were 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:
|
||||
@ -114,8 +118,8 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
|
||||
int error, lookupflags = 0;
|
||||
int reuseport = (so->so_options & SO_REUSEPORT);
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
||||
|
||||
if (TAILQ_EMPTY(&V_in6_ifaddrhead)) /* XXX broken! */
|
||||
return (EADDRNOTAVAIL);
|
||||
@ -298,8 +302,8 @@ in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
|
||||
int scope_ambiguous = 0;
|
||||
struct in6_addr in6a;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); /* XXXRW: why? */
|
||||
|
||||
if (nam->sa_len != sizeof (*sin6))
|
||||
return (EINVAL);
|
||||
@ -363,12 +367,13 @@ int
|
||||
in6_pcbconnect(register struct inpcb *inp, struct sockaddr *nam,
|
||||
struct ucred *cred)
|
||||
{
|
||||
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
|
||||
register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
|
||||
struct in6_addr addr6;
|
||||
int error;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
||||
|
||||
/*
|
||||
* Call inner routine, to assign local interface address.
|
||||
@ -377,7 +382,7 @@ in6_pcbconnect(register struct inpcb *inp, struct sockaddr *nam,
|
||||
if ((error = in6_pcbladdr(inp, nam, &addr6)) != 0)
|
||||
return (error);
|
||||
|
||||
if (in6_pcblookup_hash(inp->inp_pcbinfo, &sin6->sin6_addr,
|
||||
if (in6_pcblookup_hash_locked(pcbinfo, &sin6->sin6_addr,
|
||||
sin6->sin6_port,
|
||||
IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
|
||||
? &addr6 : &inp->in6p_laddr,
|
||||
@ -409,8 +414,8 @@ void
|
||||
in6_pcbdisconnect(struct inpcb *inp)
|
||||
{
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
|
||||
bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr));
|
||||
inp->inp_fport = 0;
|
||||
@ -649,7 +654,8 @@ in6_pcbnotify(struct inpcbinfo *pcbinfo, struct sockaddr *dst,
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup a PCB based on the local address and port.
|
||||
* Lookup a PCB based on the local address and port. Caller must hold the
|
||||
* hash lock. No inpcb locks or references are acquired.
|
||||
*/
|
||||
struct inpcb *
|
||||
in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr,
|
||||
@ -661,7 +667,7 @@ in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr,
|
||||
KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD)) == 0,
|
||||
("%s: invalid lookup flags %d", __func__, lookupflags));
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(pcbinfo);
|
||||
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
||||
|
||||
if ((lookupflags & INPLOOKUP_WILDCARD) == 0) {
|
||||
struct inpcbhead *head;
|
||||
@ -818,9 +824,9 @@ in6_rtchange(struct inpcb *inp, int errno)
|
||||
* Lookup PCB in hash list.
|
||||
*/
|
||||
struct inpcb *
|
||||
in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
|
||||
u_int fport_arg, struct in6_addr *laddr, u_int lport_arg, int lookupflags,
|
||||
struct ifnet *ifp)
|
||||
in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, 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;
|
||||
@ -830,7 +836,7 @@ in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
|
||||
KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD)) == 0,
|
||||
("%s: invalid lookup flags %d", __func__, lookupflags));
|
||||
|
||||
INP_INFO_LOCK_ASSERT(pcbinfo);
|
||||
INP_HASH_LOCK_ASSERT(pcbinfo);
|
||||
|
||||
if (faithprefix_p != NULL)
|
||||
faith = (*faithprefix_p)(laddr);
|
||||
@ -934,6 +940,56 @@ in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup PCB in hash list, using pcbinfo tables. This variation locks the
|
||||
* hash list lock, and will return the inpcb locked (i.e., requires
|
||||
* INPLOOKUP_LOCKPCB).
|
||||
*/
|
||||
static struct inpcb *
|
||||
in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
|
||||
u_int fport, struct in6_addr *laddr, u_int lport, int lookupflags,
|
||||
struct ifnet *ifp)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
|
||||
INP_HASH_RLOCK(pcbinfo);
|
||||
inp = in6_pcblookup_hash_locked(pcbinfo, faddr, fport, laddr, lport,
|
||||
(lookupflags & ~(INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)), ifp);
|
||||
if (inp != NULL) {
|
||||
in_pcbref(inp);
|
||||
INP_HASH_RUNLOCK(pcbinfo);
|
||||
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__);
|
||||
} else
|
||||
INP_HASH_RUNLOCK(pcbinfo);
|
||||
return (inp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public inpcb lookup routines, accepting a 4-tuple.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
|
||||
KASSERT((lookupflags & ~INPLOOKUP_MASK) == 0,
|
||||
("%s: invalid lookup flags %d", __func__, lookupflags));
|
||||
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
|
||||
("%s: LOCKPCB not set", __func__));
|
||||
|
||||
return (in6_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,
|
||||
lookupflags, ifp));
|
||||
}
|
||||
|
||||
void
|
||||
init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m)
|
||||
{
|
||||
|
@ -80,9 +80,13 @@ struct inpcb *
|
||||
struct in6_addr *, u_short, int,
|
||||
struct ucred *));
|
||||
struct inpcb *
|
||||
in6_pcblookup_hash __P((struct inpcbinfo *,
|
||||
struct in6_addr *, u_int, struct in6_addr *,
|
||||
u_int, int, struct ifnet *));
|
||||
in6_pcblookup __P((struct inpcbinfo *, struct in6_addr *,
|
||||
u_int, struct in6_addr *, u_int, int,
|
||||
struct ifnet *));
|
||||
struct inpcb *
|
||||
in6_pcblookup_hash_locked __P((struct inpcbinfo *, struct in6_addr *,
|
||||
u_int, struct in6_addr *, u_int, int,
|
||||
struct ifnet *));
|
||||
void in6_pcbnotify __P((struct inpcbinfo *, struct sockaddr *,
|
||||
u_int, const struct sockaddr *, u_int, int, void *,
|
||||
struct inpcb *(*)(struct inpcb *, int)));
|
||||
|
@ -856,8 +856,8 @@ in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct ucred *cred)
|
||||
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
|
||||
#endif
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
||||
|
||||
error = prison_local_ip6(cred, laddr,
|
||||
((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0));
|
||||
|
@ -1,7 +1,11 @@
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* Copyright (c) 2010-2011 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were 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:
|
||||
@ -231,11 +235,11 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
init_sin6(&fromsa, m);
|
||||
fromsa.sin6_port = uh->uh_sport;
|
||||
|
||||
INP_INFO_RLOCK(&V_udbinfo);
|
||||
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
|
||||
struct inpcb *last;
|
||||
struct ip6_moptions *imo;
|
||||
|
||||
INP_INFO_RLOCK(&V_udbinfo);
|
||||
/*
|
||||
* In the event that laddr should be set to the link-local
|
||||
* address (this happens in RIPng), the multicast address
|
||||
@ -272,6 +276,13 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXRW: Because we weren't holding either the inpcb
|
||||
* or the hash lock when we checked for a match
|
||||
* before, we should probably recheck now that the
|
||||
* inpcb lock is (supposed to be) held.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Handle socket delivery policy for any-source
|
||||
* and source-specific multicast. [RFC3678]
|
||||
@ -366,8 +377,9 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
/*
|
||||
* Locate pcb for datagram.
|
||||
*/
|
||||
inp = in6_pcblookup_hash(&V_udbinfo, &ip6->ip6_src, uh->uh_sport,
|
||||
&ip6->ip6_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif);
|
||||
inp = in6_pcblookup(&V_udbinfo, &ip6->ip6_src, uh->uh_sport,
|
||||
&ip6->ip6_dst, uh->uh_dport, INPLOOKUP_WILDCARD |
|
||||
INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif);
|
||||
if (inp == NULL) {
|
||||
if (udp_log_in_vain) {
|
||||
char ip6bufs[INET6_ADDRSTRLEN];
|
||||
@ -384,9 +396,8 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
if (m->m_flags & M_MCAST) {
|
||||
printf("UDP6: M_MCAST is set in a unicast packet.\n");
|
||||
UDPSTAT_INC(udps_noportmcast);
|
||||
goto badheadlocked;
|
||||
goto badunlocked;
|
||||
}
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
if (V_udp_blackhole)
|
||||
goto badunlocked;
|
||||
if (badport_bandlim(BANDLIM_ICMP6_UNREACH) < 0)
|
||||
@ -394,8 +405,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
INP_RLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
INP_RLOCK_ASSERT(inp);
|
||||
up = intoudpcb(inp);
|
||||
if (up->u_tun_func == NULL) {
|
||||
udp6_append(inp, m, off, &fromsa);
|
||||
@ -505,13 +515,11 @@ udp6_getcred(SYSCTL_HANDLER_ARGS)
|
||||
(error = sa6_embedscope(&addrs[1], V_ip6_use_defzone)) != 0) {
|
||||
return (error);
|
||||
}
|
||||
INP_INFO_RLOCK(&V_udbinfo);
|
||||
inp = in6_pcblookup_hash(&V_udbinfo, &addrs[1].sin6_addr,
|
||||
addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port, 1,
|
||||
NULL);
|
||||
inp = in6_pcblookup(&V_udbinfo, &addrs[1].sin6_addr,
|
||||
addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port,
|
||||
INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL);
|
||||
if (inp != NULL) {
|
||||
INP_RLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
INP_RLOCK_ASSERT(inp);
|
||||
if (inp->inp_socket == NULL)
|
||||
error = ENOENT;
|
||||
if (error == 0)
|
||||
@ -520,10 +528,8 @@ udp6_getcred(SYSCTL_HANDLER_ARGS)
|
||||
if (error == 0)
|
||||
cru2x(inp->inp_cred, &xuc);
|
||||
INP_RUNLOCK(inp);
|
||||
} else {
|
||||
INP_INFO_RUNLOCK(&V_udbinfo);
|
||||
} else
|
||||
error = ENOENT;
|
||||
}
|
||||
if (error == 0)
|
||||
error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
|
||||
return (error);
|
||||
@ -552,6 +558,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
|
||||
struct sockaddr_in6 tmp;
|
||||
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
|
||||
if (addr6) {
|
||||
/* addr6 has been validated in udp6_send(). */
|
||||
@ -772,15 +779,15 @@ udp6_abort(struct socket *so)
|
||||
}
|
||||
#endif
|
||||
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
in6_pcbdisconnect(inp);
|
||||
inp->in6p_laddr = in6addr_any;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -838,8 +845,8 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp6_bind: inp == NULL"));
|
||||
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
inp->inp_vflag &= ~INP_IPV4;
|
||||
inp->inp_vflag |= INP_IPV6;
|
||||
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
|
||||
@ -867,8 +874,8 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
#ifdef INET
|
||||
out:
|
||||
#endif
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -889,15 +896,15 @@ udp6_close(struct socket *so)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
in6_pcbdisconnect(inp);
|
||||
inp->in6p_laddr = in6addr_any;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -911,7 +918,9 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
sin6 = (struct sockaddr_in6 *)nam;
|
||||
KASSERT(inp != NULL, ("udp6_connect: inp == NULL"));
|
||||
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
/*
|
||||
* XXXRW: Need to clarify locking of v4/v6 flags.
|
||||
*/
|
||||
INP_WLOCK(inp);
|
||||
#ifdef INET
|
||||
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
|
||||
@ -931,8 +940,10 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
error = prison_remote_ip4(td->td_ucred, &sin.sin_addr);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
error = in_pcbconnect(inp, (struct sockaddr *)&sin,
|
||||
td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
if (error == 0)
|
||||
soisconnected(so);
|
||||
goto out;
|
||||
@ -947,12 +958,13 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
error = prison_remote_ip6(td->td_ucred, &sin6->sin6_addr);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
error = in6_pcbconnect(inp, nam, td->td_ucred);
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
if (error == 0)
|
||||
soisconnected(so);
|
||||
out:
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -984,32 +996,32 @@ udp6_disconnect(struct socket *so)
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL"));
|
||||
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
|
||||
#ifdef INET
|
||||
if (inp->inp_vflag & INP_IPV4) {
|
||||
struct pr_usrreqs *pru;
|
||||
|
||||
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
|
||||
error = (*pru->pru_disconnect)(so);
|
||||
goto out;
|
||||
(void)(*pru->pru_disconnect)(so);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
INP_WLOCK(inp);
|
||||
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
||||
error = ENOTCONN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
in6_pcbdisconnect(inp);
|
||||
inp->in6p_laddr = in6addr_any;
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
SOCK_LOCK(so);
|
||||
so->so_state &= ~SS_ISCONNECTED; /* XXX */
|
||||
SOCK_UNLOCK(so);
|
||||
out:
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1023,7 +1035,6 @@ udp6_send(struct socket *so, int flags, struct mbuf *m,
|
||||
inp = sotoinpcb(so);
|
||||
KASSERT(inp != NULL, ("udp6_send: inp == NULL"));
|
||||
|
||||
INP_INFO_WLOCK(&V_udbinfo);
|
||||
INP_WLOCK(inp);
|
||||
if (addr) {
|
||||
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
|
||||
@ -1060,7 +1071,6 @@ udp6_send(struct socket *so, int flags, struct mbuf *m,
|
||||
* select the UDPv4 output routine are invalidated?
|
||||
*/
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
if (sin6)
|
||||
in6_sin6_2_sin_in_sock(addr);
|
||||
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
|
||||
@ -1073,16 +1083,16 @@ udp6_send(struct socket *so, int flags, struct mbuf *m,
|
||||
#ifdef MAC
|
||||
mac_inpcb_create_mbuf(inp, m);
|
||||
#endif
|
||||
INP_HASH_WLOCK(&V_udbinfo);
|
||||
error = udp6_output(inp, m, addr, control, td);
|
||||
INP_HASH_WUNLOCK(&V_udbinfo);
|
||||
#ifdef INET
|
||||
#endif
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
return (error);
|
||||
|
||||
bad:
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_udbinfo);
|
||||
m_freem(m);
|
||||
return (error);
|
||||
}
|
||||
|
@ -1408,10 +1408,20 @@ nfs_sync(struct mount *mp, int waitfor)
|
||||
|
||||
td = curthread;
|
||||
|
||||
MNT_ILOCK(mp);
|
||||
/*
|
||||
* If a forced dismount is in progress, return from here so that
|
||||
* the umount(2) syscall doesn't get stuck in VFS_SYNC() before
|
||||
* calling VFS_UNMOUNT().
|
||||
*/
|
||||
if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
|
||||
MNT_IUNLOCK(mp);
|
||||
return (EBADF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Force stale buffer cache information to be flushed.
|
||||
*/
|
||||
MNT_ILOCK(mp);
|
||||
loop:
|
||||
MNT_VNODE_FOREACH(vp, mp, mvp) {
|
||||
VI_LOCK(vp);
|
||||
|
@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <powerpc/powermac/powermac_thermal.h>
|
||||
|
||||
/* FCU registers
|
||||
* /u3@0,f8000000/i2c@f8001000/fan@15e
|
||||
@ -66,10 +67,10 @@ __FBSDID("$FreeBSD$");
|
||||
#define FCU_PWM_SGET(x) 0x30 + (x) * 2 /* Set or get PWM. */
|
||||
|
||||
struct fcu_fan {
|
||||
struct pmac_fan fan;
|
||||
device_t dev;
|
||||
|
||||
int id;
|
||||
cell_t min;
|
||||
cell_t max;
|
||||
char location[32];
|
||||
enum {
|
||||
FCU_FAN_RPM,
|
||||
FCU_FAN_PWM
|
||||
@ -103,9 +104,9 @@ static int fcu_attach(device_t);
|
||||
/* Utility functions */
|
||||
static void fcu_attach_fans(device_t dev);
|
||||
static int fcu_fill_fan_prop(device_t dev);
|
||||
static int fcu_fan_set_rpm(device_t dev, struct fcu_fan *fan, int rpm);
|
||||
static int fcu_fan_get_rpm(device_t dev, struct fcu_fan *fan, int *rpm);
|
||||
static int fcu_fan_set_pwm(device_t dev, struct fcu_fan *fan, int pwm);
|
||||
static int fcu_fan_set_rpm(struct fcu_fan *fan, int rpm);
|
||||
static int fcu_fan_get_rpm(struct fcu_fan *fan);
|
||||
static int fcu_fan_set_pwm(struct fcu_fan *fan, int pwm);
|
||||
static int fcu_fan_get_pwm(device_t dev, struct fcu_fan *fan, int *pwm,
|
||||
int *rpm);
|
||||
static int fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS);
|
||||
@ -249,23 +250,23 @@ fcu_start(void *xdev)
|
||||
}
|
||||
|
||||
static int
|
||||
fcu_fan_set_rpm(device_t dev, struct fcu_fan *fan, int rpm)
|
||||
fcu_fan_set_rpm(struct fcu_fan *fan, int rpm)
|
||||
{
|
||||
uint8_t reg;
|
||||
struct fcu_softc *sc;
|
||||
unsigned char buf[2];
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc = device_get_softc(fan->dev);
|
||||
|
||||
/* Clamp to allowed range */
|
||||
rpm = max(fan->min, rpm);
|
||||
rpm = min(fan->max, rpm);
|
||||
rpm = max(fan->fan.min_rpm, rpm);
|
||||
rpm = min(fan->fan.max_rpm, rpm);
|
||||
|
||||
if (fan->type == FCU_FAN_RPM) {
|
||||
reg = FCU_RPM_SET(fan->id);
|
||||
fan->setpoint = rpm;
|
||||
} else {
|
||||
device_printf(dev, "Unknown fan type: %d\n", fan->type);
|
||||
device_printf(fan->dev, "Unknown fan type: %d\n", fan->type);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
@ -278,66 +279,68 @@ fcu_fan_set_rpm(device_t dev, struct fcu_fan *fan, int rpm)
|
||||
}
|
||||
|
||||
static int
|
||||
fcu_fan_get_rpm(device_t dev, struct fcu_fan *fan, int *rpm)
|
||||
fcu_fan_get_rpm(struct fcu_fan *fan)
|
||||
{
|
||||
uint8_t reg;
|
||||
struct fcu_softc *sc;
|
||||
uint8_t buff[2] = { 0, 0 };
|
||||
uint8_t active = 0, avail = 0, fail = 0;
|
||||
int rpm;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc = device_get_softc(fan->dev);
|
||||
|
||||
if (fan->type == FCU_FAN_RPM) {
|
||||
/* Check if the fan is available. */
|
||||
reg = FCU_RPM_AVAILABLE;
|
||||
fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &avail);
|
||||
if ((avail & (1 << fan->id)) == 0) {
|
||||
device_printf(dev, "RPM Fan not available ID: %d\n",
|
||||
fan->id);
|
||||
return (EIO);
|
||||
device_printf(fan->dev,
|
||||
"RPM Fan not available ID: %d\n", fan->id);
|
||||
return (-1);
|
||||
}
|
||||
/* Check if we have a failed fan. */
|
||||
reg = FCU_RPM_FAIL;
|
||||
fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &fail);
|
||||
if ((fail & (1 << fan->id)) != 0) {
|
||||
device_printf(dev, "RPM Fan failed ID: %d\n", fan->id);
|
||||
return (EIO);
|
||||
device_printf(fan->dev,
|
||||
"RPM Fan failed ID: %d\n", fan->id);
|
||||
return (-1);
|
||||
}
|
||||
/* Check if fan is active. */
|
||||
reg = FCU_RPM_ACTIVE;
|
||||
fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &active);
|
||||
if ((active & (1 << fan->id)) == 0) {
|
||||
device_printf(dev, "RPM Fan not active ID: %d\n",
|
||||
device_printf(fan->dev, "RPM Fan not active ID: %d\n",
|
||||
fan->id);
|
||||
return (ENXIO);
|
||||
return (-1);
|
||||
}
|
||||
reg = FCU_RPM_READ(fan->id);
|
||||
|
||||
} else {
|
||||
device_printf(dev, "Unknown fan type: %d\n", fan->type);
|
||||
return (EIO);
|
||||
device_printf(fan->dev, "Unknown fan type: %d\n", fan->type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* It seems that we can read the fans rpm. */
|
||||
fcu_read_1(sc->sc_dev, sc->sc_addr, reg, buff);
|
||||
|
||||
*rpm = (buff[0] << (8 - fcu_rpm_shift)) | buff[1] >> fcu_rpm_shift;
|
||||
rpm = (buff[0] << (8 - fcu_rpm_shift)) | buff[1] >> fcu_rpm_shift;
|
||||
|
||||
return (0);
|
||||
return (rpm);
|
||||
}
|
||||
|
||||
static int
|
||||
fcu_fan_set_pwm(device_t dev, struct fcu_fan *fan, int pwm)
|
||||
fcu_fan_set_pwm(struct fcu_fan *fan, int pwm)
|
||||
{
|
||||
uint8_t reg;
|
||||
struct fcu_softc *sc;
|
||||
uint8_t buf[2];
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc = device_get_softc(fan->dev);
|
||||
|
||||
/* Clamp to allowed range */
|
||||
pwm = max(fan->min, pwm);
|
||||
pwm = min(fan->max, pwm);
|
||||
pwm = max(fan->fan.min_rpm, pwm);
|
||||
pwm = min(fan->fan.max_rpm, pwm);
|
||||
|
||||
if (fan->type == FCU_FAN_PWM) {
|
||||
reg = FCU_PWM_SGET(fan->id);
|
||||
@ -347,7 +350,7 @@ fcu_fan_set_pwm(device_t dev, struct fcu_fan *fan, int pwm)
|
||||
pwm = 30;
|
||||
fan->setpoint = pwm;
|
||||
} else {
|
||||
device_printf(dev, "Unknown fan type: %d\n", fan->type);
|
||||
device_printf(fan->dev, "Unknown fan type: %d\n", fan->type);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
@ -434,7 +437,7 @@ fcu_fill_fan_prop(device_t dev)
|
||||
sizeof(location));
|
||||
while (len < prop_len) {
|
||||
if (sc->sc_fans != NULL) {
|
||||
strcpy(sc->sc_fans[i].location, location + len);
|
||||
strcpy(sc->sc_fans[i].fan.name, location + len);
|
||||
}
|
||||
prev_len = strlen(location + len) + 1;
|
||||
len += prev_len;
|
||||
@ -463,6 +466,33 @@ fcu_fill_fan_prop(device_t dev)
|
||||
for (j = 0; j < i; j++)
|
||||
sc->sc_fans[j].id = ((id[j] >> 8) & 0x0f) % 8;
|
||||
|
||||
/* Fill the fan zone property. */
|
||||
prop_len = OF_getprop(child, "hwctrl-zone", id, sizeof(id));
|
||||
for (j = 0; j < i; j++)
|
||||
sc->sc_fans[j].fan.zone = id[j];
|
||||
|
||||
/* Finish setting up fan properties */
|
||||
for (j = 0; j < i; j++) {
|
||||
sc->sc_fans[j].dev = sc->sc_dev;
|
||||
if (sc->sc_fans[j].type == FCU_FAN_RPM) {
|
||||
sc->sc_fans[j].fan.min_rpm = 4800 >> fcu_rpm_shift;
|
||||
sc->sc_fans[j].fan.max_rpm = 56000 >> fcu_rpm_shift;
|
||||
sc->sc_fans[j].setpoint =
|
||||
fcu_fan_get_rpm(&sc->sc_fans[j]);
|
||||
sc->sc_fans[j].fan.read =
|
||||
(int (*)(struct pmac_fan *))(fcu_fan_get_rpm);
|
||||
sc->sc_fans[j].fan.set =
|
||||
(int (*)(struct pmac_fan *, int))(fcu_fan_set_rpm);
|
||||
} else {
|
||||
sc->sc_fans[j].fan.min_rpm = 40; /* Percent */
|
||||
sc->sc_fans[j].fan.max_rpm = 100;
|
||||
sc->sc_fans[j].fan.read = NULL;
|
||||
sc->sc_fans[j].fan.set =
|
||||
(int (*)(struct pmac_fan *, int))(fcu_fan_set_pwm);
|
||||
}
|
||||
sc->sc_fans[j].fan.default_rpm = sc->sc_fans[j].fan.max_rpm;
|
||||
}
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
@ -478,7 +508,7 @@ fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
sc = device_get_softc(fcu);
|
||||
fan = &sc->sc_fans[arg2 & 0x00ff];
|
||||
if (fan->type == FCU_FAN_RPM) {
|
||||
fcu_fan_get_rpm(fcu, fan, &rpm);
|
||||
rpm = fcu_fan_get_rpm(fan);
|
||||
error = sysctl_handle_int(oidp, &rpm, 0, req);
|
||||
} else {
|
||||
fcu_fan_get_pwm(fcu, fan, &pwm, &rpm);
|
||||
@ -504,9 +534,9 @@ fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
return (error);
|
||||
|
||||
if (fan->type == FCU_FAN_RPM)
|
||||
return (fcu_fan_set_rpm(fcu, fan, rpm));
|
||||
return (fcu_fan_set_rpm(fan, rpm));
|
||||
else
|
||||
return (fcu_fan_set_pwm(fcu, fan, pwm));
|
||||
return (fcu_fan_set_pwm(fan, pwm));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -543,39 +573,36 @@ fcu_attach_fans(device_t dev)
|
||||
/* Now we can fill the properties into the allocated struct. */
|
||||
sc->sc_nfans = fcu_fill_fan_prop(dev);
|
||||
|
||||
/* Register fans with pmac_thermal */
|
||||
for (i = 0; i < sc->sc_nfans; i++)
|
||||
pmac_thermal_fan_register(&sc->sc_fans[i].fan);
|
||||
|
||||
/* Add sysctls for the fans. */
|
||||
for (i = 0; i < sc->sc_nfans; i++) {
|
||||
for (j = 0; j < strlen(sc->sc_fans[i].location); j++) {
|
||||
sysctl_name[j] = tolower(sc->sc_fans[i].location[j]);
|
||||
for (j = 0; j < strlen(sc->sc_fans[i].fan.name); j++) {
|
||||
sysctl_name[j] = tolower(sc->sc_fans[i].fan.name[j]);
|
||||
if (isspace(sysctl_name[j]))
|
||||
sysctl_name[j] = '_';
|
||||
}
|
||||
sysctl_name[j] = 0;
|
||||
|
||||
if (sc->sc_fans[i].type == FCU_FAN_RPM) {
|
||||
sc->sc_fans[i].min = 2400 >> fcu_rpm_shift;
|
||||
sc->sc_fans[i].max = 56000 >> fcu_rpm_shift;
|
||||
fcu_fan_get_rpm(dev, &sc->sc_fans[i],
|
||||
&sc->sc_fans[i].setpoint);
|
||||
|
||||
oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid),
|
||||
OID_AUTO, sysctl_name,
|
||||
CTLFLAG_RD, 0, "Fan Information");
|
||||
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
|
||||
"minrpm", CTLTYPE_INT | CTLFLAG_RD,
|
||||
&(sc->sc_fans[i].min), sizeof(cell_t),
|
||||
"Minimum allowed RPM");
|
||||
&(sc->sc_fans[i].fan.min_rpm),
|
||||
sizeof(int), "Minimum allowed RPM");
|
||||
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
|
||||
"maxrpm", CTLTYPE_INT | CTLFLAG_RD,
|
||||
&(sc->sc_fans[i].max), sizeof(cell_t),
|
||||
"Maximum allowed RPM");
|
||||
&(sc->sc_fans[i].fan.max_rpm),
|
||||
sizeof(int), "Maximum allowed RPM");
|
||||
/* I use i to pass the fan id. */
|
||||
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
|
||||
"rpm", CTLTYPE_INT | CTLFLAG_RW, dev, i,
|
||||
fcu_fanrpm_sysctl, "I", "Fan RPM");
|
||||
} else {
|
||||
sc->sc_fans[i].min = 30;
|
||||
sc->sc_fans[i].max = 100;
|
||||
fcu_fan_get_pwm(dev, &sc->sc_fans[i],
|
||||
&sc->sc_fans[i].setpoint,
|
||||
&sc->sc_fans[i].rpm);
|
||||
@ -585,12 +612,12 @@ fcu_attach_fans(device_t dev)
|
||||
CTLFLAG_RD, 0, "Fan Information");
|
||||
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
|
||||
"minpwm", CTLTYPE_INT | CTLFLAG_RD,
|
||||
&(sc->sc_fans[i].min), sizeof(cell_t),
|
||||
"Minimum allowed PWM in %");
|
||||
&(sc->sc_fans[i].fan.min_rpm),
|
||||
sizeof(int), "Minimum allowed PWM in %");
|
||||
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
|
||||
"maxpwm", CTLTYPE_INT | CTLFLAG_RD,
|
||||
&(sc->sc_fans[i].max), sizeof(cell_t),
|
||||
"Maximum allowed PWM in %");
|
||||
&(sc->sc_fans[i].fan.max_rpm),
|
||||
sizeof(int), "Maximum allowed PWM in %");
|
||||
/* I use i to pass the fan id or'ed with the type
|
||||
* of info I want to display/modify.
|
||||
*/
|
||||
@ -610,7 +637,7 @@ fcu_attach_fans(device_t dev)
|
||||
device_printf(dev, "Fans\n");
|
||||
for (i = 0; i < sc->sc_nfans; i++) {
|
||||
device_printf(dev, "Location: %s type: %d ID: %d "
|
||||
"RPM: %d\n", sc->sc_fans[i].location,
|
||||
"RPM: %d\n", sc->sc_fans[i].fan.name,
|
||||
sc->sc_fans[i].type, sc->sc_fans[i].id,
|
||||
(sc->sc_fans[i].type == FCU_FAN_RPM) ?
|
||||
sc->sc_fans[i].setpoint :
|
||||
|
@ -79,7 +79,7 @@ fan_management_proc(void)
|
||||
{
|
||||
/* Nothing to manage? */
|
||||
if (SLIST_EMPTY(&fans))
|
||||
return;
|
||||
kproc_exit(0);
|
||||
|
||||
while (1) {
|
||||
pmac_therm_manage_fans();
|
||||
@ -94,13 +94,17 @@ pmac_therm_manage_fans(void)
|
||||
struct pmac_fan_le *fan;
|
||||
int average_excess, max_excess_zone, frac_excess;
|
||||
int nsens, nsens_zone;
|
||||
int temp;
|
||||
|
||||
if (!enable_pmac_thermal)
|
||||
return;
|
||||
|
||||
/* Read all the sensors */
|
||||
SLIST_FOREACH(sensor, &sensors, entries) {
|
||||
sensor->last_val = sensor->sensor->read(sensor->sensor);
|
||||
temp = sensor->sensor->read(sensor->sensor);
|
||||
if (temp > 0) /* Use the previous temp in case of error */
|
||||
sensor->last_val = temp;
|
||||
|
||||
if (sensor->last_val > sensor->sensor->max_temp) {
|
||||
printf("WARNING: Current temperature (%s: %d.%d C) "
|
||||
"exceeds critical temperature (%d.%d C)! "
|
||||
@ -121,6 +125,8 @@ pmac_therm_manage_fans(void)
|
||||
sensor->sensor->target_temp)*100 /
|
||||
(sensor->sensor->max_temp -
|
||||
sensor->sensor->target_temp);
|
||||
if (frac_excess < 0)
|
||||
frac_excess = 0;
|
||||
if (sensor->sensor->zone == fan->fan->zone) {
|
||||
max_excess_zone = imax(max_excess_zone,
|
||||
frac_excess);
|
||||
|
@ -854,7 +854,7 @@ smu_sensor_read(struct smu_sensor *sens)
|
||||
value <<= 1;
|
||||
|
||||
/* Convert from 16.16 fixed point degC into integer 0.1 K. */
|
||||
value = 10*(value >> 16) + 2732;
|
||||
value = 10*(value >> 16) + ((10*(value & 0xffff)) >> 16) + 2732;
|
||||
break;
|
||||
case SMU_VOLTAGE_SENSOR:
|
||||
value *= sc->sc_cpu_volt_scale;
|
||||
|
@ -235,7 +235,7 @@ smusat_sensor_read(struct smu_sensor *sens)
|
||||
/* 16.16 */
|
||||
value <<= 10;
|
||||
/* From 16.16 to 0.1 C */
|
||||
value = 10*(value >> 16) + 2732;
|
||||
value = 10*(value >> 16) + ((10*(value & 0xffff)) >> 16) + 2732;
|
||||
break;
|
||||
case SMU_VOLTAGE_SENSOR:
|
||||
/* 16.16 */
|
||||
|
@ -85,7 +85,9 @@ l2: add r2, 1, r3 ; \
|
||||
lduw [PCPU(MID)], r1 ; \
|
||||
mov 1, r2 ; \
|
||||
sllx r2, r1, r1 ; \
|
||||
#ifdef notyet \
|
||||
TEST(ktr_cpumask, r1, r2, r3, l3) ; \
|
||||
#endif \
|
||||
ATR(desc, r1, r2, r3, l1, l2)
|
||||
|
||||
#endif /* LOCORE */
|
||||
|
@ -214,6 +214,7 @@ int cpuset_create_root(struct prison *, struct cpuset **);
|
||||
int cpuset_setproc_update_set(struct proc *, struct cpuset *);
|
||||
int cpusetobj_ffs(const cpuset_t *);
|
||||
char *cpusetobj_strprint(char *, const cpuset_t *);
|
||||
int cpusetobj_strscan(cpuset_t *, const char *);
|
||||
|
||||
#else
|
||||
__BEGIN_DECLS
|
||||
|
@ -97,6 +97,9 @@
|
||||
|
||||
#ifndef LOCORE
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/_cpuset.h>
|
||||
|
||||
struct ktr_entry {
|
||||
u_int64_t ktr_timestamp;
|
||||
int ktr_cpu;
|
||||
@ -107,7 +110,7 @@ struct ktr_entry {
|
||||
u_long ktr_parms[KTR_PARMS];
|
||||
};
|
||||
|
||||
extern int ktr_cpumask;
|
||||
extern cpuset_t ktr_cpumask;
|
||||
extern int ktr_mask;
|
||||
extern int ktr_entries;
|
||||
extern int ktr_verbose;
|
||||
|
6
tools/regression/bin/sh/parser/func2.0
Normal file
6
tools/regression/bin/sh/parser/func2.0
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
f() { return 42; }
|
||||
f() { return 3; } &
|
||||
f
|
||||
[ $? -eq 42 ]
|
6
tools/regression/bin/sh/parser/func3.0
Normal file
6
tools/regression/bin/sh/parser/func3.0
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
name=/var/empty/nosuch
|
||||
f() { true; } <$name
|
||||
name=/dev/null
|
||||
f
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
@ -1,7 +1,11 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Robert N. M. Watson
|
||||
* Copyright (c) 2011 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were 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:
|
||||
@ -46,8 +50,6 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TCP_PORT 9001
|
||||
|
||||
static int
|
||||
tcp_drop(struct sockaddr_in *sin_local, struct sockaddr_in *sin_remote)
|
||||
{
|
||||
@ -66,41 +68,12 @@ tcp_drop(struct sockaddr_in *sin_local, struct sockaddr_in *sin_remote)
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_server(pid_t partner)
|
||||
tcp_server(pid_t partner, int listen_fd)
|
||||
{
|
||||
int error, listen_fd, accept_fd;
|
||||
struct sockaddr_in sin;
|
||||
int error, accept_fd;
|
||||
ssize_t len;
|
||||
char ch;
|
||||
|
||||
listen_fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0) {
|
||||
error = errno;
|
||||
(void)kill(partner, SIGTERM);
|
||||
errno = error;
|
||||
err(-1, "tcp_server: socket");
|
||||
}
|
||||
|
||||
bzero(&sin, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
sin.sin_port = htons(TCP_PORT);
|
||||
|
||||
if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
|
||||
error = errno;
|
||||
(void)kill(partner, SIGTERM);
|
||||
errno = error;
|
||||
err(-1, "tcp_server: bind");
|
||||
}
|
||||
|
||||
if (listen(listen_fd, -1) < 0) {
|
||||
error = errno;
|
||||
(void)kill(partner, SIGTERM);
|
||||
errno = error;
|
||||
err(-1, "tcp_server: listen");
|
||||
}
|
||||
|
||||
accept_fd = accept(listen_fd, NULL, NULL);
|
||||
if (accept_fd < 0) {
|
||||
error = errno;
|
||||
@ -146,7 +119,7 @@ tcp_server(pid_t partner)
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_client(pid_t partner)
|
||||
tcp_client(pid_t partner, u_short port)
|
||||
{
|
||||
struct sockaddr_in sin, sin_local;
|
||||
int error, sock;
|
||||
@ -168,7 +141,7 @@ tcp_client(pid_t partner)
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
|
||||
sin.sin_port = htons(TCP_PORT);
|
||||
sin.sin_port = port;
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
|
||||
error = errno;
|
||||
@ -230,6 +203,40 @@ int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
pid_t child_pid, parent_pid;
|
||||
struct sockaddr_in sin;
|
||||
int listen_fd;
|
||||
u_short port;
|
||||
socklen_t len;
|
||||
|
||||
listen_fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0)
|
||||
err(-1, "socket");
|
||||
|
||||
/*
|
||||
* We use the loopback, but let the kernel select a port for the
|
||||
* server socket.
|
||||
*/
|
||||
bzero(&sin, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
|
||||
err(-1, "bind");
|
||||
|
||||
if (listen(listen_fd, -1) < 0)
|
||||
err(-1, "listen");
|
||||
|
||||
/*
|
||||
* Query the port so that the client can use it.
|
||||
*/
|
||||
bzero(&sin, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0)
|
||||
err(-1, "getsockname");
|
||||
port = sin.sin_port;
|
||||
printf("Using port %d\n", ntohs(port));
|
||||
|
||||
if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
|
||||
err(-1, "signal");
|
||||
@ -240,9 +247,9 @@ main(int argc, char *argv[])
|
||||
err(-1, "fork");
|
||||
if (child_pid == 0) {
|
||||
child_pid = getpid();
|
||||
tcp_server(parent_pid);
|
||||
tcp_server(parent_pid, listen_fd);
|
||||
} else
|
||||
tcp_client(child_pid);
|
||||
tcp_client(child_pid, port);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -1,7 +1,11 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Robert N. M. Watson
|
||||
* Copyright (c) 2011 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were 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:
|
||||
@ -41,45 +45,15 @@
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TCP_PORT 9001
|
||||
|
||||
static void
|
||||
tcp_server(pid_t partner)
|
||||
tcp_server(pid_t partner, int listen_fd)
|
||||
{
|
||||
int error, listen_fd, accept_fd;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
listen_fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0) {
|
||||
error = errno;
|
||||
(void)kill(partner, SIGTERM);
|
||||
errno = error;
|
||||
err(-1, "tcp_server: socket");
|
||||
}
|
||||
|
||||
bzero(&sin, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
sin.sin_port = htons(TCP_PORT);
|
||||
|
||||
if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
|
||||
error = errno;
|
||||
(void)kill(partner, SIGTERM);
|
||||
errno = error;
|
||||
err(-1, "tcp_server: bind");
|
||||
}
|
||||
|
||||
if (listen(listen_fd, -1) < 0) {
|
||||
error = errno;
|
||||
(void)kill(partner, SIGTERM);
|
||||
errno = error;
|
||||
err(-1, "tcp_server: listen");
|
||||
}
|
||||
int error, accept_fd;
|
||||
|
||||
accept_fd = accept(listen_fd, NULL, NULL);
|
||||
if (accept_fd < 0) {
|
||||
@ -93,7 +67,7 @@ tcp_server(pid_t partner)
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_client(pid_t partner, int secs)
|
||||
tcp_client(pid_t partner, u_short port, int secs)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
int error, sock;
|
||||
@ -112,7 +86,7 @@ tcp_client(pid_t partner, int secs)
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
|
||||
sin.sin_port = htons(TCP_PORT);
|
||||
sin.sin_port = port;
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
|
||||
error = errno;
|
||||
@ -135,7 +109,11 @@ tcp_client(pid_t partner, int secs)
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
pid_t child_pid, parent_pid;
|
||||
int listen_fd;
|
||||
socklen_t len;
|
||||
u_short port;
|
||||
|
||||
if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
|
||||
err(-1, "signal");
|
||||
@ -144,19 +122,38 @@ main(int argc, char *argv[])
|
||||
* Run the whole thing twice: once, with a short sleep in the client,
|
||||
* so that we close before time wait runs out, and once with a long
|
||||
* sleep so that the time wait terminates while the socket is open.
|
||||
* We don't reuse listen sockets between runs.
|
||||
*/
|
||||
parent_pid = getpid();
|
||||
child_pid = fork();
|
||||
if (child_pid < 0)
|
||||
err(-1, "fork");
|
||||
if (child_pid == 0) {
|
||||
child_pid = getpid();
|
||||
tcp_server(child_pid);
|
||||
exit(0);
|
||||
} else
|
||||
tcp_client(parent_pid, 1);
|
||||
(void)kill(child_pid, SIGTERM);
|
||||
sleep(5);
|
||||
listen_fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0)
|
||||
err(-1, "socket");
|
||||
|
||||
/*
|
||||
* We use the loopback, but let the kernel select a port for the
|
||||
* server socket.
|
||||
*/
|
||||
bzero(&sin, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
|
||||
err(-1, "bind");
|
||||
|
||||
if (listen(listen_fd, -1) < 0)
|
||||
err(-1, "listen");
|
||||
|
||||
/*
|
||||
* Query the port so that the client can use it.
|
||||
*/
|
||||
bzero(&sin, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
len = sizeof(sin);
|
||||
if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0)
|
||||
err(-1, "getsockname");
|
||||
port = sin.sin_port;
|
||||
printf("Using port %d\n", ntohs(port));
|
||||
|
||||
parent_pid = getpid();
|
||||
child_pid = fork();
|
||||
@ -164,9 +161,57 @@ main(int argc, char *argv[])
|
||||
err(-1, "fork");
|
||||
if (child_pid == 0) {
|
||||
child_pid = getpid();
|
||||
tcp_server(parent_pid);
|
||||
tcp_server(child_pid, listen_fd);
|
||||
exit(0);
|
||||
} else
|
||||
tcp_client(child_pid, 800);
|
||||
tcp_client(parent_pid, port, 1);
|
||||
(void)kill(child_pid, SIGTERM);
|
||||
close(listen_fd);
|
||||
sleep(5);
|
||||
|
||||
/*
|
||||
* Start again, this time long sleep.
|
||||
*/
|
||||
listen_fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0)
|
||||
err(-1, "socket");
|
||||
|
||||
/*
|
||||
* We use the loopback, but let the kernel select a port for the
|
||||
* server socket.
|
||||
*/
|
||||
bzero(&sin, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
|
||||
err(-1, "bind");
|
||||
|
||||
if (listen(listen_fd, -1) < 0)
|
||||
err(-1, "listen");
|
||||
|
||||
/*
|
||||
* Query the port so that the client can use it.
|
||||
*/
|
||||
bzero(&sin, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
len = sizeof(sin);
|
||||
if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0)
|
||||
err(-1, "getsockname");
|
||||
port = sin.sin_port;
|
||||
printf("Using port %d\n", ntohs(port));
|
||||
|
||||
parent_pid = getpid();
|
||||
child_pid = fork();
|
||||
if (child_pid < 0)
|
||||
err(-1, "fork");
|
||||
if (child_pid == 0) {
|
||||
child_pid = getpid();
|
||||
tcp_server(parent_pid, listen_fd);
|
||||
} else
|
||||
tcp_client(child_pid, port, 800);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ main(int argc, __unused char *argv[])
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
struct jail thejail;
|
||||
struct in_addr ia4;
|
||||
|
||||
if (argc != 1)
|
||||
usage();
|
||||
@ -94,12 +95,18 @@ main(int argc, __unused char *argv[])
|
||||
|
||||
/*
|
||||
* Now re-run in a jail.
|
||||
* XXX-BZ should switch to jail_set(2).
|
||||
*/
|
||||
ia4.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
bzero(&thejail, sizeof(thejail));
|
||||
thejail.version = 0;
|
||||
thejail.version = JAIL_API_VERSION;
|
||||
thejail.path = "/";
|
||||
thejail.hostname = "jail";
|
||||
thejail.ip_number = INADDR_LOOPBACK;
|
||||
thejail.jailname = "udpconnectjail";
|
||||
thejail.ip4s = 1;
|
||||
thejail.ip4 = &ia4;
|
||||
|
||||
if (jail(&thejail) < 0)
|
||||
errx(-1, "jail: %s", strerror(errno));
|
||||
test("in jail", &sin);
|
||||
|
@ -1,7 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
SCRIPTS= auto adduser checksum config hostname jail keymap mirrorselect \
|
||||
mount netconfig rootpass services time umount wlanconfig
|
||||
mount netconfig netconfig_ipv4 netconfig_ipv6 rootpass services \
|
||||
time umount wlanconfig
|
||||
BINDIR= /usr/libexec/bsdinstall
|
||||
|
||||
NO_MAN= true
|
||||
|
@ -2,6 +2,11 @@
|
||||
#-
|
||||
# Copyright (c) 2011 Nathan Whitehorn
|
||||
# All rights reserved.
|
||||
# Copyright (c) 2011 The FreeBSD Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
# Portions of this software were developed by Bjoern Zeeb
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
@ -66,56 +71,124 @@ if ifconfig $INTERFACE | grep -q 'media: IEEE 802.11 Wireless'; then
|
||||
INTERFACE="$NEXT_WLAN_IFACE"
|
||||
fi
|
||||
|
||||
dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --yesno 'Would you like to use DHCP to configure this interface?' 0 0
|
||||
if [ $? -eq $DIALOG_OK ]; then
|
||||
echo ifconfig_$INTERFACE=\"${IFCONFIG_PREFIX}DHCP\" >> $BSDINSTALL_TMPETC/rc.conf.net
|
||||
IPV6_AVAIL=0
|
||||
IPV4_AVAIL=0
|
||||
sysctl -N kern.features.inet6 > /dev/null 2>&1
|
||||
case $? in
|
||||
0) IPV6_AVAIL=1 ;;
|
||||
esac
|
||||
sysctl -N kern.features.inet > /dev/null 2>&1
|
||||
case $? in
|
||||
0) IPV4_AVAIL=1 ;;
|
||||
esac
|
||||
|
||||
if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
|
||||
dialog --backtitle 'FreeBSD Installer' --infobox "Acquiring DHCP lease..." 0 0
|
||||
dhclient $INTERFACE 2>> $BSDINSTALL_LOG
|
||||
if [ $? -ne 0 ]; then
|
||||
dialog --backtitle 'FreeBSD Installer' --msgbox "DHCP lease acquisition failed." 0 0
|
||||
exec $0
|
||||
fi
|
||||
if [ ${IPV4_AVAIL} -eq 1 ]; then
|
||||
dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \
|
||||
--yesno 'Would you like to configure IPv4 for this interface?' 0 0
|
||||
if [ $? -eq $DIALOG_OK ]; then
|
||||
bsdinstall netconfig_ipv4 ${INTERFACE} "${IFCONFIG_PREFIX}" || \
|
||||
exec $0
|
||||
else
|
||||
IPV4_AVAIL=0
|
||||
fi
|
||||
fi
|
||||
# In case wlanconfig left an option and we do not support IPv4 we need to write
|
||||
# it out on its own. We cannot write it out with IPv6 as that suffix.
|
||||
if [ ${IPV4_AVAIL} -eq 0 -a -n ${IFCONFIG_PREFIX} ]; then
|
||||
echo ifconfig_${INTERFACE}=\"${IFCONFIG_PREFIX}\" >> $BSDINSTALL_TMPETC/rc.conf.net
|
||||
fi
|
||||
if [ ${IPV6_AVAIL} -eq 1 ]; then
|
||||
dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \
|
||||
--yesno 'Would you like to configure IPv6 for this interface?' 0 0
|
||||
if [ $? -eq $DIALOG_OK ]; then
|
||||
bsdinstall netconfig_ipv6 ${INTERFACE} || exec $0
|
||||
else
|
||||
IPV6_AVAIL=0
|
||||
fi
|
||||
fi
|
||||
|
||||
SEARCH=""
|
||||
IP4_1=""
|
||||
IP4_2=""
|
||||
IP6_1=""
|
||||
IP6_2=""
|
||||
while read key value; do
|
||||
case "${key}" in
|
||||
search) SEARCH="${value}" ;;
|
||||
nameserver) # is more trick as we have to distinguish v4 and v6
|
||||
case "${value}" in
|
||||
[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)
|
||||
if [ -z "${IP4_1}" ] ; then
|
||||
IP4_1="${value}"
|
||||
elif [ -z "${IP4_2}" ]; then
|
||||
IP4_2="${value}"
|
||||
fi
|
||||
;;
|
||||
[0-9A-Fa-f:]*:*)
|
||||
if [ -z "${IP6_1}" ] ; then
|
||||
IP6_1="${value}"
|
||||
elif [ -z "${IP6_2}" ]; then
|
||||
IP6_2="${value}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
# ignore others
|
||||
esac
|
||||
done < ${BSDINSTALL_TMPETC}/resolv.conf
|
||||
|
||||
RESOLV=""
|
||||
if [ ${IPV6_AVAIL} -eq 1 -a ${IPV4_AVAIL} -eq 1 ]; then
|
||||
RESOLV="
|
||||
'Search' 1 0 \"${SEARCH}\" 1 16 50 0 0
|
||||
'Nameserver' 2 0 \"Nameserver\" 2 16 50 0 2
|
||||
'IPv6 DNS #1' 2 0 \"${IP6_1}\" 2 16 50 0 0
|
||||
'IPv6 DNS #2' 3 0 \"${IP6_2}\" 3 16 50 0 0
|
||||
'IPv4 DNS #1' 4 0 \"${IP4_1}\" 4 16 16 0 0
|
||||
'IPv4 DNS #2' 5 0 \"${IP4_2}\" 5 16 16 0 0"
|
||||
elif [ ${IPV6_AVAIL} -eq 1 ]; then
|
||||
RESOLV="
|
||||
'Search' 1 0 \"${SEARCH}\" 1 16 50 0 0
|
||||
'Nameserver' 2 0 \"Nameserver\" 2 16 50 0 2
|
||||
'IPv6 DNS #1' 2 0 \"${IP6_1}\" 2 16 50 0 0
|
||||
'IPv6 DNS #2' 3 0 \"${IP6_2}\" 3 16 50 0 0"
|
||||
elif [ ${IPV4_AVAIL} -eq 1 ]; then
|
||||
RESOLV="
|
||||
'Search' 1 0 \"${SEARCH}\" 1 16 50 0 0
|
||||
'Nameserver' 2 0 \"Nameserver\" 2 16 50 0 2
|
||||
'IPv4 DNS #1' 2 0 \"${IP4_1}\" 2 16 16 0 0
|
||||
'IPv4 DNS #2' 3 0 \"${IP4_2}\" 3 16 16 0 0"
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
IP_ADDRESS=`ifconfig $INTERFACE inet | awk '/inet/ {printf("%s\n", $2); }'`
|
||||
NETMASK=`ifconfig $INTERFACE inet | awk '/inet/ {printf("%s\n", $4); }'`
|
||||
ROUTER=`netstat -rn -f inet | awk '/default/ {printf("%s\n", $2);}'`
|
||||
|
||||
exec 3>&1
|
||||
IF_CONFIG=$(dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --form 'Static Network Interface Configuration' 0 0 0 \
|
||||
'IP Address' 1 0 "$IP_ADDRESS" 1 20 16 0 \
|
||||
'Subnet Mask' 2 0 "$NETMASK" 2 20 16 0 \
|
||||
'Default Router' 3 0 "$ROUTER" 3 20 16 0 \
|
||||
\
|
||||
'Nameserver' 5 0 "" 5 20 16 0 \
|
||||
'Search Domain' 6 0 "" 6 20 20 0 \
|
||||
RESOLV=$(echo "${RESOLV}" | xargs dialog --backtitle 'FreeBSD Installer' \
|
||||
--title 'Network Configuration' \
|
||||
--mixedform 'Resovler Configuration' 0 0 0 \
|
||||
2>&1 1>&3)
|
||||
if [ $? -eq $DIALOG_CANCEL ]; then exec $0; fi
|
||||
exec 3>&-
|
||||
|
||||
echo $INTERFACE $IF_CONFIG |
|
||||
awk -v prefix="$IFCONFIG_PREFIX" '{
|
||||
printf("ifconfig_%s=\"%s%s netmask %s\"\n", $1, prefix, $2, $3);
|
||||
printf("defaultrouter=\"%s\"\n", $4);
|
||||
}' >> $BSDINSTALL_TMPETC/rc.conf.net
|
||||
|
||||
if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
|
||||
. $BSDINSTALL_TMPETC/rc.conf.net
|
||||
ifconfig $INTERFACE `eval echo \\\$ifconfig_$INTERFACE`
|
||||
route delete default
|
||||
route add default $defaultrouter
|
||||
fi
|
||||
|
||||
|
||||
echo $IF_CONFIG |
|
||||
awk '{
|
||||
if ($4 != "")
|
||||
printf("nameserver %s\n", $4);
|
||||
if ($5 != "")
|
||||
printf("search %s\n", $5);
|
||||
}' > $BSDINSTALL_TMPETC/resolv.conf
|
||||
echo ${RESOLV} | tr ' ' '\n' | \
|
||||
awk '
|
||||
BEGIN {
|
||||
search=1
|
||||
printf "search ";
|
||||
}
|
||||
{
|
||||
if (/^[[:space:]]+$/) {
|
||||
next;
|
||||
}
|
||||
if (/^Nameserver$/) {
|
||||
printf "\n";
|
||||
search=0;
|
||||
next;
|
||||
}
|
||||
if (search > 0) {
|
||||
printf "%s%s", (search > 1) ? "," : "", $1;
|
||||
next;
|
||||
}
|
||||
printf "nameserver %s\n", $1;
|
||||
}' > ${BSDINSTALL_TMPETC}/resolv.conf
|
||||
|
||||
|
85
usr.sbin/bsdinstall/scripts/netconfig_ipv4
Executable file
85
usr.sbin/bsdinstall/scripts/netconfig_ipv4
Executable file
@ -0,0 +1,85 @@
|
||||
#!/bin/sh
|
||||
#-
|
||||
# Copyright (c) 2011 Nathan Whitehorn
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# $FreeBSD$
|
||||
|
||||
: ${DIALOG_OK=0}
|
||||
: ${DIALOG_CANCEL=1}
|
||||
: ${DIALOG_HELP=2}
|
||||
: ${DIALOG_EXTRA=3}
|
||||
: ${DIALOG_ITEM_HELP=4}
|
||||
: ${DIALOG_ESC=255}
|
||||
|
||||
INTERFACE=$1
|
||||
IFCONFIG_PREFIX="$2"
|
||||
case "${INTERFACE}" in
|
||||
"") dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \
|
||||
--msgbox 'No interface specified for IPv4 configuration.' 0 0
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --yesno 'Would you like to use DHCP to configure this interface?' 0 0
|
||||
if [ $? -eq $DIALOG_OK ]; then
|
||||
echo ifconfig_$INTERFACE=\"${IFCONFIG_PREFIX}DHCP\" >> $BSDINSTALL_TMPETC/rc.conf.net
|
||||
|
||||
if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
|
||||
dialog --backtitle 'FreeBSD Installer' --infobox "Acquiring DHCP lease..." 0 0
|
||||
dhclient $INTERFACE 2>> $BSDINSTALL_LOG
|
||||
if [ $? -ne 0 ]; then
|
||||
dialog --backtitle 'FreeBSD Installer' --msgbox "DHCP lease acquisition failed." 0 0
|
||||
exec $0 ${INTERFACE} "${IFCONFIG_PREFIX}"
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
IP_ADDRESS=`ifconfig $INTERFACE inet | awk '/inet/ {printf("%s\n", $2); }'`
|
||||
NETMASK=`ifconfig $INTERFACE inet | awk '/inet/ {printf("%s\n", $4); }'`
|
||||
ROUTER=`netstat -rn -f inet | awk '/default/ {printf("%s\n", $2);}'`
|
||||
|
||||
exec 3>&1
|
||||
IF_CONFIG=$(dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' --form 'Static Network Interface Configuration' 0 0 0 \
|
||||
'IP Address' 1 0 "$IP_ADDRESS" 1 20 16 0 \
|
||||
'Subnet Mask' 2 0 "$NETMASK" 2 20 16 0 \
|
||||
'Default Router' 3 0 "$ROUTER" 3 20 16 0 \
|
||||
2>&1 1>&3)
|
||||
if [ $? -eq $DIALOG_CANCEL ]; then exit 1; fi
|
||||
exec 3>&-
|
||||
|
||||
echo $INTERFACE $IF_CONFIG |
|
||||
awk -v prefix="$IFCONFIG_PREFIX" '{
|
||||
printf("ifconfig_%s=\"%s inet %s netmask %s\"\n", $1, prefix, $2, $3);
|
||||
printf("defaultrouter=\"%s\"\n", $4);
|
||||
}' >> $BSDINSTALL_TMPETC/rc.conf.net
|
||||
|
||||
if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
|
||||
. $BSDINSTALL_TMPETC/rc.conf.net
|
||||
ifconfig $INTERFACE inet `eval echo \\\$ifconfig_$INTERFACE`
|
||||
route delete -inet default
|
||||
route add -inet default $defaultrouter
|
||||
fi
|
||||
|
149
usr.sbin/bsdinstall/scripts/netconfig_ipv6
Executable file
149
usr.sbin/bsdinstall/scripts/netconfig_ipv6
Executable file
@ -0,0 +1,149 @@
|
||||
#!/bin/sh
|
||||
#-
|
||||
# Copyright (c) 2011 Nathan Whitehorn
|
||||
# All rights reserved.
|
||||
# Copyright (c) 2011 The FreeBSD Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
# Portions of this software were developed by Bjoern Zeeb
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# $FreeBSD$
|
||||
|
||||
#
|
||||
# TODO:
|
||||
# - Add -R /sbin/resolvconf to rtsol once support is in tree.
|
||||
# - Add DHCPv6 support once FreeBSD ships with it.
|
||||
#
|
||||
|
||||
: ${DIALOG_OK=0}
|
||||
: ${DIALOG_CANCEL=1}
|
||||
: ${DIALOG_HELP=2}
|
||||
: ${DIALOG_EXTRA=3}
|
||||
: ${DIALOG_ITEM_HELP=4}
|
||||
: ${DIALOG_ESC=255}
|
||||
|
||||
INTERFACE=$1
|
||||
case "${INTERFACE}" in
|
||||
"") dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \
|
||||
--msgbox 'No interface specified for IPv6 configuration.' 0 0
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
AGAIN=""
|
||||
while : ; do
|
||||
MSG="Would you like to try stateless address autoconfiguration (SLAAC)${AGAIN}?"
|
||||
dialog --backtitle 'FreeBSD Installer' --title 'Network Configuration' \
|
||||
--yesno "${MSG}" 0 0
|
||||
if [ $? -eq $DIALOG_OK ]; then
|
||||
if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
|
||||
dialog --backtitle 'FreeBSD Installer' \
|
||||
--infobox "Sending Router Solicitation ..." 0 0
|
||||
ifconfig ${INTERFACE} inet6 -ifdisabled accept_rtadv up
|
||||
rtsol -F $INTERFACE 2>> $BSDINSTALL_LOG
|
||||
if [ $? -ne 0 ]; then
|
||||
dialog --backtitle 'FreeBSD Installer' --msgbox "SLAAC failed." 0 0
|
||||
AGAIN=" again"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
echo ifconfig_${INTERFACE}_ipv6=\"inet6 accept_rtadv\" >> $BSDINSTALL_TMPETC/rc.conf.net
|
||||
exit 0
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
ROUTER6=`netstat -Wrn -f inet6 | awk '/default/ {printf("%s\n", $2);}'`
|
||||
ADDRS=`ifconfig ${INTERFACE} inet6 | \
|
||||
awk -v dfr="${ROUTER6}" '
|
||||
BEGIN {
|
||||
n=0;
|
||||
}
|
||||
{
|
||||
if (/inet6/) {
|
||||
if (match($2, "^fe80:")) { next; };
|
||||
# For the moment ignore all but the first address; it might confuse the user.
|
||||
if (n > 0) { next; };
|
||||
n++;
|
||||
printf "\"IPv6 Address\" %d 0 \"%s/%s\" %d 16 50 0 0 ", n, $2, $4, n;
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (n == 0) {
|
||||
n++;
|
||||
printf "\"IPv6 Address\" %d 0 \"\" %d 16 50 0 0 ", n, n;
|
||||
}
|
||||
n++;
|
||||
# Nasty trick adding a (hidden, same y) read-only field as a marker
|
||||
# to separate interface address(es) from the default router.
|
||||
printf "\"Default Router\" %d 0 \"%s\" %d 16 50 0 2 ", n, "DefaultRouter", n;
|
||||
printf "\"Default Router\" %d 0 \"%s\" %d 16 50 0 0 ", n, dfr, n;
|
||||
}'`
|
||||
|
||||
exec 3>&1
|
||||
IF_CONFIG=$(echo ${ADDRS} | xargs dialog --backtitle 'FreeBSD Installer' \
|
||||
--title 'Network Configuration' \
|
||||
--mixedform 'Static IPv6 Network Interface Configuration' 0 0 0 \
|
||||
2>&1 1>&3)
|
||||
if [ $? -eq $DIALOG_CANCEL ]; then exit 1; fi
|
||||
exec 3>&-
|
||||
|
||||
echo ${IF_CONFIG} | tr ' ' '\n' | \
|
||||
awk -v iface="${INTERFACE}" '
|
||||
BEGIN {
|
||||
dfr=0;
|
||||
count=0;
|
||||
}
|
||||
{
|
||||
if (/^[[:space:]]+$/) {
|
||||
next;
|
||||
}
|
||||
if (/DefaultRouter/) {
|
||||
dfr=1;
|
||||
next;
|
||||
}
|
||||
if (dfr == 1) {
|
||||
printf("ipv6_defaultrouter=\"%s\"\n", $1);
|
||||
next;
|
||||
}
|
||||
if (count > 0) {
|
||||
# Ignore all but the first IP address for now.
|
||||
next;
|
||||
}
|
||||
count++;
|
||||
if (!match($1, "/")) {
|
||||
sub("$", "/64", $1);
|
||||
}
|
||||
printf("ifconfig_%s_ipv6=\"inet6 %s\"\n", iface, $1);
|
||||
}' >> $BSDINSTALL_TMPETC/rc.conf.net
|
||||
|
||||
if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
|
||||
. $BSDINSTALL_TMPETC/rc.conf.net
|
||||
ifconfig ${INTERFACE} `eval echo \\\$ifconfig_${INTERFACE}_ipv6`
|
||||
route delete default
|
||||
route add default ${ipv6_defaultrouter}
|
||||
fi
|
||||
|
@ -10,5 +10,8 @@ LDADD= -ljail -lutil
|
||||
.if ${MK_INET6_SUPPORT} != "no"
|
||||
CFLAGS+= -DINET6
|
||||
.endif
|
||||
.if ${MK_INET_SUPPORT} != "no"
|
||||
CFLAGS+= -DINET
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -54,12 +54,18 @@ static struct jailparam *params;
|
||||
static char **param_values;
|
||||
static int nparams;
|
||||
|
||||
static char *ip4_addr;
|
||||
#ifdef INET6
|
||||
static int ip6_ok;
|
||||
static char *ip6_addr;
|
||||
#endif
|
||||
#ifdef INET
|
||||
static int ip4_ok;
|
||||
static char *ip4_addr;
|
||||
#endif
|
||||
|
||||
#if defined(INET6) || defined(INET)
|
||||
static void add_ip_addr(char **addrp, char *newaddr);
|
||||
#endif
|
||||
#ifdef INET6
|
||||
static void add_ip_addr46(char *newaddr);
|
||||
#endif
|
||||
@ -194,6 +200,13 @@ main(int argc, char **argv)
|
||||
if (uflag)
|
||||
GET_USER_INFO;
|
||||
|
||||
#ifdef INET6
|
||||
ip6_ok = feature_present("inet6");
|
||||
#endif
|
||||
#ifdef INET
|
||||
ip4_ok = feature_present("inet");
|
||||
#endif
|
||||
|
||||
if (jailname)
|
||||
set_param("name", jailname);
|
||||
if (securelevel)
|
||||
@ -207,10 +220,12 @@ main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
if (hflag) {
|
||||
#ifdef INET
|
||||
if (!strncmp(argv[i], "ip4.addr=", 9)) {
|
||||
add_ip_addr(&ip4_addr, argv[i] + 9);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (!strncmp(argv[i], "ip6.addr=", 9)) {
|
||||
add_ip_addr(&ip6_addr, argv[i] + 9);
|
||||
@ -231,11 +246,13 @@ main(int argc, char **argv)
|
||||
set_param("host.hostname", argv[1]);
|
||||
if (hflag)
|
||||
add_ip_addrinfo(0, argv[1]);
|
||||
#if defined(INET6) || defined(INET)
|
||||
if (argv[2][0] != '\0')
|
||||
#ifdef INET6
|
||||
add_ip_addr46(argv[2]);
|
||||
#else
|
||||
add_ip_addr(&ip4_addr, argv[2]);
|
||||
#endif
|
||||
#endif
|
||||
cmdarg = 3;
|
||||
/* Emulate the defaults from security.jail.* sysctls */
|
||||
@ -259,8 +276,10 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef INET
|
||||
if (ip4_addr != NULL)
|
||||
set_param("ip4.addr", ip4_addr);
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (ip6_addr != NULL)
|
||||
set_param("ip6.addr", ip6_addr);
|
||||
@ -297,14 +316,19 @@ main(int argc, char **argv)
|
||||
for (i = 0; i < nparams; i++)
|
||||
if (!strcmp(params[i].jp_name, "path"))
|
||||
break;
|
||||
#ifdef INET6
|
||||
#if defined(INET6) && defined(INET)
|
||||
fprintf(fp, "%d\t%s\t%s\t%s%s%s\t%s\n",
|
||||
jid, i < nparams
|
||||
? (char *)params[i].jp_value : argv[0],
|
||||
argv[1], ip4_addr ? ip4_addr : "",
|
||||
ip4_addr && ip4_addr[0] && ip6_addr && ip6_addr[0]
|
||||
? "," : "", ip6_addr ? ip6_addr : "", argv[3]);
|
||||
#else
|
||||
#elif defined(INET6)
|
||||
fprintf(fp, "%d\t%s\t%s\t%s\t%s\n",
|
||||
jid, i < nparams
|
||||
? (char *)params[i].jp_value : argv[0],
|
||||
argv[1], ip6_addr ? ip6_addr : "", argv[3]);
|
||||
#elif defined(INET)
|
||||
fprintf(fp, "%d\t%s\t%s\t%s\t%s\n",
|
||||
jid, i < nparams
|
||||
? (char *)params[i].jp_value : argv[0],
|
||||
@ -348,6 +372,7 @@ main(int argc, char **argv)
|
||||
err(1, "execvp: %s", argv[cmdarg]);
|
||||
}
|
||||
|
||||
#if defined(INET6) || defined(INET)
|
||||
static void
|
||||
add_ip_addr(char **addrp, char *value)
|
||||
{
|
||||
@ -368,6 +393,7 @@ add_ip_addr(char **addrp, char *value)
|
||||
*addrp = addr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
static void
|
||||
@ -391,23 +417,24 @@ static void
|
||||
add_ip_addrinfo(int ai_flags, char *value)
|
||||
{
|
||||
struct addrinfo hints, *ai0, *ai;
|
||||
struct in_addr addr4;
|
||||
size_t size;
|
||||
int error, ip4ok;
|
||||
int mib[4];
|
||||
int error;
|
||||
#ifdef INET
|
||||
char avalue4[INET_ADDRSTRLEN];
|
||||
struct in_addr addr4;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
struct in6_addr addr6;
|
||||
int ip6ok;
|
||||
char avalue6[INET6_ADDRSTRLEN];
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
|
||||
/* Look up the hostname (or get the address) */
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
#ifdef INET6
|
||||
#if defined(INET6) && defined(INET)
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
#else
|
||||
#elif defined(INET6)
|
||||
hints.ai_family = PF_INET6;
|
||||
#elif defined(INET)
|
||||
hints.ai_family = PF_INET;
|
||||
#endif
|
||||
hints.ai_flags = ai_flags;
|
||||
@ -415,32 +442,12 @@ add_ip_addrinfo(int ai_flags, char *value)
|
||||
if (error != 0)
|
||||
errx(1, "hostname %s: %s", value, gai_strerror(error));
|
||||
|
||||
/*
|
||||
* Silently ignore unsupported address families from DNS lookups.
|
||||
* But if this is a numeric address, let the kernel give the error.
|
||||
*/
|
||||
if (ai_flags & AI_NUMERICHOST)
|
||||
ip4ok =
|
||||
#ifdef INET6
|
||||
ip6ok =
|
||||
#endif
|
||||
1;
|
||||
else {
|
||||
size = 4;
|
||||
ip4ok = (sysctlnametomib("security.jail.param.ip4", mib,
|
||||
&size) == 0);
|
||||
#ifdef INET6
|
||||
size = 4;
|
||||
ip6ok = (sysctlnametomib("security.jail.param.ip6", mib,
|
||||
&size) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Convert the addresses to ASCII so set_param can convert them back. */
|
||||
for (ai = ai0; ai; ai = ai->ai_next)
|
||||
switch (ai->ai_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
if (!ip4ok)
|
||||
if (!ip4_ok && (ai_flags & AI_NUMERICHOST) == 0)
|
||||
break;
|
||||
memcpy(&addr4, &((struct sockaddr_in *)
|
||||
(void *)ai->ai_addr)->sin_addr, sizeof(addr4));
|
||||
@ -449,9 +456,10 @@ add_ip_addrinfo(int ai_flags, char *value)
|
||||
err(1, "inet_ntop");
|
||||
add_ip_addr(&ip4_addr, avalue4);
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
if (!ip6ok)
|
||||
if (!ip6_ok && (ai_flags & AI_NUMERICHOST) == 0)
|
||||
break;
|
||||
memcpy(&addr6, &((struct sockaddr_in6 *)
|
||||
(void *)ai->ai_addr)->sin6_addr, sizeof(addr6));
|
||||
|
@ -1,8 +1,17 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= jls
|
||||
MAN= jls.8
|
||||
DPADD= ${LIBJAIL}
|
||||
LDADD= -ljail
|
||||
|
||||
.if ${MK_INET6_SUPPORT} != "no"
|
||||
CFLAGS+= -DINET6
|
||||
.endif
|
||||
.if ${MK_INET_SUPPORT} != "no"
|
||||
CFLAGS+= -DINET
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -59,6 +59,12 @@ __FBSDID("$FreeBSD$");
|
||||
static struct jailparam *params;
|
||||
static int *param_parent;
|
||||
static int nparams;
|
||||
#ifdef INET6
|
||||
static int ip6_ok;
|
||||
#endif
|
||||
#ifdef INET
|
||||
static int ip4_ok;
|
||||
#endif
|
||||
|
||||
static int add_param(const char *name, void *value, size_t valuelen,
|
||||
struct jailparam *source, unsigned flags);
|
||||
@ -112,6 +118,13 @@ main(int argc, char **argv)
|
||||
errx(1, "usage: jls [-dhnqv] [-j jail] [param ...]");
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
ip6_ok = feature_present("inet6");
|
||||
#endif
|
||||
#ifdef INET
|
||||
ip4_ok = feature_present("inet");
|
||||
#endif
|
||||
|
||||
/* Add the parameters to print. */
|
||||
if (optind == argc) {
|
||||
if (pflags & (PRINT_HEADER | PRINT_NAMEVAL))
|
||||
@ -124,13 +137,24 @@ main(int argc, char **argv)
|
||||
add_param("name", NULL, (size_t)0, NULL, JP_USER);
|
||||
add_param("dying", NULL, (size_t)0, NULL, JP_USER);
|
||||
add_param("cpuset.id", NULL, (size_t)0, NULL, JP_USER);
|
||||
add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER);
|
||||
add_param("ip6.addr", NULL, (size_t)0, NULL,
|
||||
JP_USER | JP_OPT);
|
||||
#ifdef INET
|
||||
if (ip4_ok)
|
||||
add_param("ip4.addr", NULL, (size_t)0, NULL,
|
||||
JP_USER);
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (ip6_ok)
|
||||
add_param("ip6.addr", NULL, (size_t)0, NULL,
|
||||
JP_USER | JP_OPT);
|
||||
#endif
|
||||
} else {
|
||||
pflags |= PRINT_DEFAULT;
|
||||
add_param("jid", NULL, (size_t)0, NULL, JP_USER);
|
||||
add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER);
|
||||
#ifdef INET
|
||||
if (ip4_ok)
|
||||
add_param("ip4.addr", NULL, (size_t)0, NULL,
|
||||
JP_USER);
|
||||
#endif
|
||||
add_param("host.hostname", NULL, (size_t)0, NULL,
|
||||
JP_USER);
|
||||
add_param("path", NULL, (size_t)0, NULL, JP_USER);
|
||||
@ -327,7 +351,7 @@ print_jail(int pflags, int jflags)
|
||||
{
|
||||
char *nname;
|
||||
char **param_values;
|
||||
int i, ai, jid, count, spc;
|
||||
int i, ai, jid, count, n, spc;
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
|
||||
jid = jailparam_get(params, nparams, jflags);
|
||||
@ -345,31 +369,45 @@ print_jail(int pflags, int jflags)
|
||||
*(int *)params[4].jp_value ? "DYING" : "ACTIVE",
|
||||
"",
|
||||
*(int *)params[5].jp_value);
|
||||
count = params[6].jp_valuelen / sizeof(struct in_addr);
|
||||
for (ai = 0; ai < count; ai++)
|
||||
if (inet_ntop(AF_INET,
|
||||
&((struct in_addr *)params[6].jp_value)[ai],
|
||||
ipbuf, sizeof(ipbuf)) == NULL)
|
||||
err(1, "inet_ntop");
|
||||
else
|
||||
printf("%6s %-15.15s\n", "", ipbuf);
|
||||
if (!strcmp(params[7].jp_name, "ip6.addr")) {
|
||||
count = params[7].jp_valuelen / sizeof(struct in6_addr);
|
||||
n = 6;
|
||||
#ifdef INET
|
||||
if (ip4_ok && !strcmp(params[n].jp_name, "ip.addr")) {
|
||||
count = params[n].jp_valuelen / sizeof(struct in_addr);
|
||||
for (ai = 0; ai < count; ai++)
|
||||
if (inet_ntop(AF_INET,
|
||||
&((struct in_addr *)params[n].jp_value)[ai],
|
||||
ipbuf, sizeof(ipbuf)) == NULL)
|
||||
err(1, "inet_ntop");
|
||||
else
|
||||
printf("%6s %-15.15s\n", "", ipbuf);
|
||||
n++;
|
||||
}
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (ip6_ok && !strcmp(params[n].jp_name, "ip6.addr")) {
|
||||
count = params[n].jp_valuelen / sizeof(struct in6_addr);
|
||||
for (ai = 0; ai < count; ai++)
|
||||
if (inet_ntop(AF_INET6,
|
||||
&((struct in6_addr *)params[7].jp_value)[ai],
|
||||
&((struct in6_addr *)
|
||||
params[n].jp_value)[ai],
|
||||
ipbuf, sizeof(ipbuf)) == NULL)
|
||||
err(1, "inet_ntop");
|
||||
else
|
||||
printf("%6s %s\n", "", ipbuf);
|
||||
n++;
|
||||
}
|
||||
#endif
|
||||
} else if (pflags & PRINT_DEFAULT)
|
||||
printf("%6d %-15.15s %-29.29s %.74s\n",
|
||||
*(int *)params[0].jp_value,
|
||||
params[1].jp_valuelen == 0 ? "-"
|
||||
#ifdef INET
|
||||
(!ip4_ok || params[1].jp_valuelen == 0) ? "-"
|
||||
: inet_ntoa(*(struct in_addr *)params[1].jp_value),
|
||||
(char *)params[2].jp_value,
|
||||
(char *)params[3].jp_value);
|
||||
#else
|
||||
"-"
|
||||
#endif
|
||||
(char *)params[2-!ip4_ok].jp_value,
|
||||
(char *)params[3-!ip4_ok].jp_value);
|
||||
else {
|
||||
param_values = alloca(nparams * sizeof(*param_values));
|
||||
for (i = 0; i < nparams; i++) {
|
||||
|
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd December 4, 2010
|
||||
.Dd May 31, 2011
|
||||
.Dt USBDUMP 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -63,16 +63,16 @@ Write the raw packets to
|
||||
.Ar file .
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Captures USB raw packets on usbus2:
|
||||
Capture the USB raw packets on usbus2:
|
||||
.Pp
|
||||
.Dl "usbdump -i usbus2 -s 256 -v"
|
||||
.Pp
|
||||
Dumps the USB raw packets of usbus2 into the file without packet
|
||||
Dump the USB raw packets of usbus2 into the file without packet
|
||||
size limit:
|
||||
.Pp
|
||||
.Dl "usbdump -i usbus2 -s 0 -w /tmp/dump_pkts"
|
||||
.Pp
|
||||
Read the USB raw packets from previous file:
|
||||
Read and display the USB raw packets from previous file:
|
||||
.Pp
|
||||
.Dl "usbdump -r /tmp/dump_pkts -v"
|
||||
.Sh OUTPUT FORMAT
|
||||
|
Loading…
Reference in New Issue
Block a user