This commit is contained in:
Attilio Rao 2011-05-31 14:18:10 +00:00
commit 5b6ea0b538
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/largeSMP/; revision=222526
97 changed files with 3122 additions and 1243 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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.
*/

View File

@ -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:

View File

@ -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:

View File

@ -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();

View File

@ -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} \

View File

@ -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
View 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.

View File

@ -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
View 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.

View File

@ -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

View File

@ -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 .

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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.

View File

@ -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
#

View File

@ -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

View File

@ -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;

View File

@ -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) {
/*

View File

@ -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;

View File

@ -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 *);

View File

@ -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 */

View 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 */

View File

@ -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,

View File

@ -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.
*/

View File

@ -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)

View File

@ -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
View 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
View 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 */

View File

@ -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--;
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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. */

View File

@ -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);

View File

@ -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.
*/

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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)
{

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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)));

View File

@ -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));

View File

@ -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);
}

View File

@ -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);

View File

@ -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 :

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -0,0 +1,6 @@
# $FreeBSD$
f() { return 42; }
f() { return 3; } &
f
[ $? -eq 42 ]

View File

@ -0,0 +1,6 @@
# $FreeBSD$
name=/var/empty/nosuch
f() { true; } <$name
name=/dev/null
f

View File

@ -34,6 +34,7 @@
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>

View File

@ -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);
}

View File

@ -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>

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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

View 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

View 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

View File

@ -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>

View File

@ -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));

View File

@ -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>

View File

@ -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++) {

View File

@ -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