Compare commits

...

8 Commits

Author SHA1 Message Date
Allan Jude
9206c79961 usr.bin/netstat: -n should not print symbolic names
Some checks are pending
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-14, /usr/lib/llvm-14/bin, ubuntu-22.04, bmake libarchive-dev clang-14 lld-14, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-14, /usr/lib/llvm-14/bin, ubuntu-22.04, bmake libarchive-dev clang-14 lld-14, arm64, aarch64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /opt/homebrew/opt/llvm@18/bin, macos-latest, bmake libarchive llvm@18, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /opt/homebrew/opt/llvm@18/bin, macos-latest, bmake libarchive llvm@18, arm64, aarch64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /usr/lib/llvm-18/bin, ubuntu-24.04, bmake libarchive-dev clang-18 lld-18, amd64, amd64) (push) Waiting to run
Cross-build Kernel / ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) (clang-18, /usr/lib/llvm-18/bin, ubuntu-24.04, bmake libarchive-dev clang-18 lld-18, arm64, aarch64) (push) Waiting to run
In numeric mode, the default route is printed as "default" rather
than 0.0.0.0/0 or ::/0

From the man page:
"-n: Show network addresses and ports as numbers.
Normally netstat attempts to resolve addresses and ports, and display
them symbolically.  If the -n option is specified, the address is
printed numerically, according to the address family.
For more information regarding the Internet IPv4 ``dot format'', refer
to inet(3).  Unspecified, or `wildcard'', addresses and ports appear
as `*''."

Reported By:	rgrimes
Reviewed by:	emaste, ngie, eadler, seanc
Relnotes:	yes
Sponsored by:	Klara, Inc.
Differential Revision:	https://reviews.freebsd.org/D10320
2024-11-26 14:56:21 +00:00
Christos Margiolis
6d77827b96 sound: Remove unused CHN_F_SILENCE
No functional change intended.

Sponsored by:	The FreeBSD Foundation
MFC after:	2 days
Reviewed by:	dev_submerge.ch, markj, emaste
Differential Revision:	https://reviews.freebsd.org/D47664
2024-11-26 15:48:42 +01:00
Christos Margiolis
5317480967 sound: Remove CHN_F_SLEEPING
The KASSERT in chn_sleep() can be triggered if more than one thread
wants to sleep on a given channel at the same time. While this is not
really a common scenario, tools such as stress2, which use fork() and
the child process(es) inherit the parent's FDs as a result, we can end
up triggering such scenarios.

Fix this by removing CHN_F_SLEEPING altogether, which is not very useful
in the first place:
- CHN_BROADCAST() checks cv_waiters already, so there is no need to
  check CHN_F_SLEEPING as well.
- We can check whether cv_waiters is 0 in pcm_killchans(), instead of
  whether CHN_F_SLEEPING is not set.

Reported by:	dougm, pho (stress2)
Sponsored by:	The FreeBSD Foundation
MFC after:	2 days
Reviewed by:	dev_submerge.ch, markj
Differential Revision:	https://reviews.freebsd.org/D47559
2024-11-26 15:48:36 +01:00
Christos Margiolis
6d4c59e261 sound: Remove PCM_DETACHING(), SD_F_DETACHING and SD_F_DYING
Since SD_F_REGISTERED is cleared at the same time SD_F_DETACHING and
SD_F_DYING are set, and since PCM_DETACHING() is always used in
conjuction with PCM_REGISTERED()/DSP_REGISTERED(), it is enough to just
check SD_F_REGISTERED.

Sponsored by:	The FreeBSD Foundation
MFC after:	2 days
Reviewed by:	dev_submerge.ch, markj
Differential Revision:	https://reviews.freebsd.org/D47463
2024-11-26 15:48:30 +01:00
Christos Margiolis
2839ad58dd sound: Fix hot-unload panics
This patch fixes multiple different panic scenarios occuring during
hot-unload:

1. The channel is unlocked in chn_read()/chn_write() for uiomove(9) and
   in the meantime we enter pcm_killchans() and free it. By the time we
   have returned from userland and try to lock it back, the channel will
   have been freed.
2. The parent channel has been freed in pcm_killchans(), but at the same
   time, some yet-unstopped vchan's chn_read()/chn_write() calls
   chn_start(), which eventually calls vchan_trigger(), which references
   the freed parent.
3. PCM_WAIT() panics because it references a freed PCM lock.

For scenarios 1 and 2, refactor pcm_killchans() to first make sure all
channels have been stopped, and then proceed to free them one by one, as
opposed to freeing the first free channel until all channels have been
freed. This change makes the code more robust, but might introduce some
performance overhead when many channels are allocated, since we
continuously loop through the channel list until all of them are
stopped, and then we loop one last time to free them.

For scenario 3, restructure the code so that we can use destroy_dev(9)
instead of destroy_dev_sched(9) in dsp_destroy_dev(). Because
destroy_dev(9) blocks until all references to the device have went away,
we ensure that the PCM cv and lock will be freed safely.

While here, move the delete_unrhdr(9) calls to pcm_killchans() and
re-order some lines.

Sponsored by:	The FreeBSD Foundation
MFC after:	2 days
Reviewed by:	dev_submerge.ch
Differential Revision:	https://reviews.freebsd.org/D47462
2024-11-26 15:48:24 +01:00
Christos Margiolis
5ac39263d8 sound: Fix chn_trigger() and vchan_trigger() races
Consider the following scenario:

1. CHN currently has its trigger set to PCMTRIG_STOP.
2. Thread A locks CHN, calls CHANNEL_TRIGGER(PCMTRIG_START), sets the
   trigger to PCMTRIG_START and unlocks.
3. Thread B picks up the lock, calls CHANNEL_TRIGGER(PCMTRIG_ABORT) and
   returns a non-zero value, so it returns from chn_trigger() as well.
4. Thread A picks up the lock and adds CHN to the list, which is
   _wrong_, because the last call to CHANNEL_TRIGGER() was with
   PCMTRIG_ABORT, meaning the channel is stopped, yet we are adding it
   to the list and marking it as started.

Another problematic scenario:

1. Thread A locks CHN, sets the trigger to PCMTRIG_ABORT, and unlocks
   CHN. It then locks PCM and _removes_ CHN from the list.
2. In the meantime, since thread A unlocked CHN, thread B has locked it,
   set the trigger to PCMTRIG_START, unlocked it, and is now blocking on
   PCM held by thread A.
3. At the same time, thread C locks CHN, sets the trigger back to
   PCMTRIG_ABORT, unlocks CHN, and is also blocking on PCM. However,
   once thread A unlocks PCM, because thread C is higher-priority than
   thread B, it picks up the PCM lock instead of thread B, and because
   CHN is already removed from the list, and thread B hasn't added it
   back yet, we take a page fault in CHN_REMOVE() by trying to remove a
   non-existent element.

To fix the former scenario, set the channel trigger before the call to
CHANNEL_TRIGGER() (could also come after, doesn't really matter) and
check if anything changed one we lock CHN back.

To fix the latter scenario, use the SAFE variants of CHN_INSERT_HEAD()
and CHN_REMOVE(). A similar scenario can occur in vchan_trigger(), so do
the trigger setting after we've locked the parent channel.

Sponsored by:	The FreeBSD Foundation
MFC after:	2 days
Reviewed by:	dev_submerge.ch
Differential Revision:	https://reviews.freebsd.org/D47461
2024-11-26 15:48:18 +01:00
Christos Margiolis
5bd08172b4 snd_dummy: Fix callout(9) races
Use callout_init_mtx(9) to associate the callback with the driver's
lock. Also make sure the callout is stopped properly during detach.

While here, introduce a dummy_active() function to know when it's
appropriate to stop or not reschedule the callout.

Sponsored by:	The FreeBSD Foundation
MFC after:	2 days
Reviewed by:	dev_submerge.ch, markj
Differential Revision:	https://reviews.freebsd.org/D47459
2024-11-26 15:48:02 +01:00
Kristof Provost
56b7685ae3 pf: handle IPv6 fragmentation for route-to
If a fragmented IPv6 packet hits a route-to rule we have to first prevent
the pf_test(PF_OUT) check in pf_route6() from refragmenting (and calling
ip6_output()/ip6_forward()). We then have to refragment in pf_route6() and
transmit the packets on the route-to interface.

Split pf_refragment6() into two parts, the first to perform the refragmentation,
the second to call ip6_output()/ip6_forward() and call the former from
pf_route6().

Add a test case for route-to-ing fragmented IPv6 packets to verify this works
as expected.

Sponsored by:	Rubicon Communications, LLC ("Netgate")
Differential Revision:	https://reviews.freebsd.org/D47684
2024-11-26 15:06:52 +01:00
13 changed files with 254 additions and 171 deletions

View File

@ -67,6 +67,24 @@ struct dummy_softc {
struct mtx *lock;
};
static bool
dummy_active(struct dummy_softc *sc)
{
struct dummy_chan *ch;
int i;
snd_mtxassert(sc->lock);
for (i = 0; i < sc->chnum; i++) {
ch = &sc->chans[i];
if (ch->run)
return (true);
}
/* No channel is running at the moment. */
return (false);
}
static void
dummy_chan_io(void *arg)
{
@ -74,7 +92,9 @@ dummy_chan_io(void *arg)
struct dummy_chan *ch;
int i = 0;
snd_mtxlock(sc->lock);
/* Do not reschedule if no channel is running. */
if (!dummy_active(sc))
return;
for (i = 0; i < sc->chnum; i++) {
ch = &sc->chans[i];
@ -89,8 +109,6 @@ dummy_chan_io(void *arg)
snd_mtxlock(sc->lock);
}
callout_schedule(&sc->callout, 1);
snd_mtxunlock(sc->lock);
}
static int
@ -179,15 +197,15 @@ dummy_chan_trigger(kobj_t obj, void *data, int go)
switch (go) {
case PCMTRIG_START:
if (!callout_active(&sc->callout))
callout_reset(&sc->callout, 1, dummy_chan_io, sc);
ch->ptr = 0;
ch->run = 1;
callout_reset(&sc->callout, 1, dummy_chan_io, sc);
break;
case PCMTRIG_STOP:
case PCMTRIG_ABORT:
ch->run = 0;
if (callout_active(&sc->callout))
/* If all channels are stopped, stop the callout as well. */
if (!dummy_active(sc))
callout_stop(&sc->callout);
default:
break;
@ -292,6 +310,7 @@ dummy_attach(device_t dev)
sc = device_get_softc(dev);
sc->dev = dev;
sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_dummy softc");
callout_init_mtx(&sc->callout, sc->lock, 0);
sc->cap_fmts[0] = SND_FORMAT(AFMT_S32_LE, 2, 0);
sc->cap_fmts[1] = SND_FORMAT(AFMT_S24_LE, 2, 0);
@ -316,7 +335,6 @@ dummy_attach(device_t dev)
if (pcm_register(dev, status))
return (ENXIO);
mixer_init(dev, &dummy_mixer_class, sc);
callout_init(&sc->callout, 1);
return (0);
}
@ -327,8 +345,8 @@ dummy_detach(device_t dev)
struct dummy_softc *sc = device_get_softc(dev);
int err;
callout_drain(&sc->callout);
err = pcm_unregister(dev);
callout_drain(&sc->callout);
snd_mtxfree(sc->lock);
return (err);

View File

@ -309,14 +309,7 @@ chn_wakeup(struct pcm_channel *c)
if (CHN_EMPTY(c, children.busy)) {
if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
selwakeuppri(sndbuf_getsel(bs), PRIBIO);
if (c->flags & CHN_F_SLEEPING) {
/*
* Ok, I can just panic it right here since it is
* quite obvious that we never allow multiple waiters
* from userland. I'm too generous...
*/
CHN_BROADCAST(&c->intr_cv);
}
CHN_BROADCAST(&c->intr_cv);
} else {
CHN_FOREACH(ch, c, children.busy) {
CHN_LOCK(ch);
@ -332,15 +325,11 @@ chn_sleep(struct pcm_channel *c, int timeout)
int ret;
CHN_LOCKASSERT(c);
KASSERT((c->flags & CHN_F_SLEEPING) == 0,
("%s(): entered with CHN_F_SLEEPING", __func__));
if (c->flags & CHN_F_DEAD)
return (EINVAL);
c->flags |= CHN_F_SLEEPING;
ret = cv_timedwait_sig(&c->intr_cv, c->lock, timeout);
c->flags &= ~CHN_F_SLEEPING;
return ((c->flags & CHN_F_DEAD) ? EINVAL : ret);
}
@ -2318,44 +2307,46 @@ chn_trigger(struct pcm_channel *c, int go)
if (go == c->trigger)
return (0);
if (snd_verbose > 3) {
device_printf(c->dev, "%s() %s: calling go=0x%08x , "
"prev=0x%08x\n", __func__, c->name, go, c->trigger);
}
c->trigger = go;
ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go);
if (ret != 0)
return (ret);
CHN_UNLOCK(c);
PCM_LOCK(d);
CHN_LOCK(c);
/*
* Do nothing if another thread set a different trigger while we had
* dropped the mutex.
*/
if (go != c->trigger) {
PCM_UNLOCK(d);
return (0);
}
/*
* Use the SAFE variants to prevent inserting/removing an already
* existing/missing element.
*/
switch (go) {
case PCMTRIG_START:
if (snd_verbose > 3)
device_printf(c->dev,
"%s() %s: calling go=0x%08x , "
"prev=0x%08x\n", __func__, c->name, go,
c->trigger);
if (c->trigger != PCMTRIG_START) {
c->trigger = go;
CHN_UNLOCK(c);
PCM_LOCK(d);
CHN_INSERT_HEAD(d, c, channels.pcm.busy);
PCM_UNLOCK(d);
CHN_LOCK(c);
chn_syncstate(c);
}
CHN_INSERT_HEAD_SAFE(d, c, channels.pcm.busy);
PCM_UNLOCK(d);
chn_syncstate(c);
break;
case PCMTRIG_STOP:
case PCMTRIG_ABORT:
if (snd_verbose > 3)
device_printf(c->dev,
"%s() %s: calling go=0x%08x , "
"prev=0x%08x\n", __func__, c->name, go,
c->trigger);
if (c->trigger == PCMTRIG_START) {
c->trigger = go;
CHN_UNLOCK(c);
PCM_LOCK(d);
CHN_REMOVE(d, c, channels.pcm.busy);
PCM_UNLOCK(d);
CHN_LOCK(c);
}
CHN_REMOVE_SAFE(d, c, channels.pcm.busy);
PCM_UNLOCK(d);
break;
default:
PCM_UNLOCK(d);
break;
}

View File

@ -354,7 +354,7 @@ enum {
#define CHN_F_RUNNING 0x00000004 /* dma is running */
#define CHN_F_TRIGGERED 0x00000008
#define CHN_F_NOTRIGGER 0x00000010
#define CHN_F_SLEEPING 0x00000020
/* unused 0x00000020 */
#define CHN_F_NBIO 0x00000040 /* do non-blocking i/o */
#define CHN_F_MMAP 0x00000080 /* has been mmap()ed */
@ -362,7 +362,7 @@ enum {
#define CHN_F_BUSY 0x00000100 /* has been opened */
#define CHN_F_DIRTY 0x00000200 /* need re-config */
#define CHN_F_DEAD 0x00000400 /* too many errors, dead, mdk */
#define CHN_F_SILENCE 0x00000800 /* silence, nil, null, yada */
/* unused 0x00000800 */
#define CHN_F_HAS_SIZE 0x00001000 /* user set block size */
#define CHN_F_HAS_VCHAN 0x00002000 /* vchan master */
@ -381,14 +381,14 @@ enum {
"\002ABORTING" \
"\003RUNNING" \
"\004TRIGGERED" \
/* \006 */ \
"\005NOTRIGGER" \
"\006SLEEPING" \
"\007NBIO" \
"\010MMAP" \
"\011BUSY" \
"\012DIRTY" \
"\013DEAD" \
"\014SILENCE" \
/* \014 */ \
"\015HAS_SIZE" \
"\016HAS_VCHAN" \
"\017VCHAN_PASSTHROUGH" \

View File

@ -137,7 +137,7 @@ dsp_destroy_dev(device_t dev)
struct snddev_info *d;
d = device_get_softc(dev);
destroy_dev_sched(d->dsp_dev);
destroy_dev(d->dsp_dev);
}
static void
@ -177,7 +177,7 @@ dsp_close(void *data)
d = priv->sc;
/* At this point pcm_unregister() will destroy all channels anyway. */
if (!DSP_REGISTERED(d) || PCM_DETACHING(d))
if (!DSP_REGISTERED(d))
goto skip;
PCM_GIANT_ENTER(d);
@ -264,7 +264,7 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
return (ENODEV);
d = i_dev->si_drv1;
if (!DSP_REGISTERED(d) || PCM_DETACHING(d))
if (!DSP_REGISTERED(d))
return (EBADF);
priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK | M_ZERO);
@ -445,7 +445,7 @@ dsp_io_ops(struct dsp_cdevpriv *priv, struct uio *buf)
("%s(): io train wreck!", __func__));
d = priv->sc;
if (!DSP_REGISTERED(d) || PCM_DETACHING(d))
if (!DSP_REGISTERED(d))
return (EBADF);
PCM_GIANT_ENTER(d);
@ -664,7 +664,7 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
return (err);
d = priv->sc;
if (!DSP_REGISTERED(d) || PCM_DETACHING(d))
if (!DSP_REGISTERED(d))
return (EBADF);
PCM_GIANT_ENTER(d);
@ -1783,7 +1783,7 @@ dsp_poll(struct cdev *i_dev, int events, struct thread *td)
if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
return (err);
d = priv->sc;
if (!DSP_REGISTERED(d) || PCM_DETACHING(d)) {
if (!DSP_REGISTERED(d)) {
/* XXX many clients don't understand POLLNVAL */
return (events & (POLLHUP | POLLPRI | POLLIN |
POLLRDNORM | POLLOUT | POLLWRNORM));
@ -1865,7 +1865,7 @@ dsp_mmap_single(struct cdev *i_dev, vm_ooffset_t *offset,
if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
return (err);
d = priv->sc;
if (!DSP_REGISTERED(d) || PCM_DETACHING(d))
if (!DSP_REGISTERED(d))
return (EINVAL);
PCM_GIANT_ENTER(d);

View File

@ -146,7 +146,7 @@ mixer_set_softpcmvol(struct snd_mixer *m, struct snddev_info *d,
struct pcm_channel *c;
int dropmtx, acquiremtx;
if (!PCM_REGISTERED(d) || PCM_DETACHING(d))
if (!PCM_REGISTERED(d))
return (EINVAL);
if (mtx_owned(m->lock))
@ -199,7 +199,7 @@ mixer_set_eq(struct snd_mixer *m, struct snddev_info *d,
else
return (EINVAL);
if (!PCM_REGISTERED(d) || PCM_DETACHING(d))
if (!PCM_REGISTERED(d))
return (EINVAL);
if (mtx_owned(m->lock))
@ -1053,7 +1053,7 @@ mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
m = i_dev->si_drv1;
d = device_get_softc(m->dev);
if (!PCM_REGISTERED(d) || PCM_DETACHING(d))
if (!PCM_REGISTERED(d))
return (EBADF);
/* XXX Need Giant magic entry ??? */
@ -1209,7 +1209,7 @@ mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
return (EBADF);
d = device_get_softc(((struct snd_mixer *)i_dev->si_drv1)->dev);
if (!PCM_REGISTERED(d) || PCM_DETACHING(d))
if (!PCM_REGISTERED(d))
return (EBADF);
PCM_GIANT_ENTER(d);
@ -1447,7 +1447,7 @@ mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
for (i = 0; pcm_devclass != NULL &&
i < devclass_get_maxunit(pcm_devclass); i++) {
d = devclass_get_softc(pcm_devclass, i);
if (!PCM_REGISTERED(d) || PCM_DETACHING(d)) {
if (!PCM_REGISTERED(d)) {
if ((mi->dev == -1 && i == snd_unit) || mi->dev == i) {
mixer_oss_mixerinfo_unavail(mi, i);
return (0);

View File

@ -211,40 +211,53 @@ static void
pcm_killchans(struct snddev_info *d)
{
struct pcm_channel *ch;
bool found;
bool again;
PCM_BUSYASSERT(d);
do {
found = false;
KASSERT(!PCM_REGISTERED(d), ("%s(): still registered\n", __func__));
for (;;) {
again = false;
/* Make sure all channels are stopped. */
CHN_FOREACH(ch, d, channels.pcm) {
CHN_LOCK(ch);
/*
* Make sure no channel has went to sleep in the
* meantime.
*/
chn_shutdown(ch);
/*
* We have to give a thread sleeping in chn_sleep() a
* chance to observe that the channel is dead.
*/
if ((ch->flags & CHN_F_SLEEPING) == 0) {
found = true;
if (ch->intr_cv.cv_waiters == 0 && CHN_STOPPED(ch) &&
ch->inprog == 0) {
CHN_UNLOCK(ch);
break;
continue;
}
chn_shutdown(ch);
if (ch->direction == PCMDIR_PLAY)
chn_flush(ch);
else
chn_abort(ch);
CHN_UNLOCK(ch);
again = true;
}
/*
* All channels are still sleeping. Sleep for a bit and try
* again to see if any of them is awake now.
* Some channels are still active. Sleep for a bit and try
* again.
*/
if (!found) {
pause_sbt("pcmkillchans", SBT_1MS * 5, 0, 0);
continue;
}
if (again)
pause_sbt("pcmkillchans", mstosbt(5), 0, 0);
else
break;
}
/* All channels are finally dead. */
while (!CHN_EMPTY(d, channels.pcm)) {
ch = CHN_FIRST(d, channels.pcm);
chn_kill(ch);
} while (!CHN_EMPTY(d, channels.pcm));
}
if (d->p_unr != NULL)
delete_unrhdr(d->p_unr);
if (d->vp_unr != NULL)
delete_unrhdr(d->vp_unr);
if (d->r_unr != NULL)
delete_unrhdr(d->r_unr);
if (d->vr_unr != NULL)
delete_unrhdr(d->vr_unr);
}
static int
@ -512,7 +525,6 @@ int
pcm_unregister(device_t dev)
{
struct snddev_info *d;
struct pcm_channel *ch;
d = device_get_softc(dev);
@ -524,29 +536,14 @@ pcm_unregister(device_t dev)
PCM_LOCK(d);
PCM_WAIT(d);
d->flags |= SD_F_DETACHING;
d->flags &= ~SD_F_REGISTERED;
PCM_ACQUIRE(d);
PCM_UNLOCK(d);
CHN_FOREACH(ch, d, channels.pcm) {
CHN_LOCK(ch);
/*
* Do not wait for the timeout in chn_read()/chn_write(). Wake
* up the sleeping thread and kill the channel.
*/
chn_shutdown(ch);
chn_abort(ch);
CHN_UNLOCK(ch);
}
pcm_killchans(d);
/* remove /dev/sndstat entry first */
sndstat_unregister(dev);
PCM_LOCK(d);
d->flags |= SD_F_DYING;
d->flags &= ~SD_F_REGISTERED;
PCM_UNLOCK(d);
PCM_RELEASE_QUICK(d);
if (d->play_sysctl_tree != NULL) {
sysctl_ctx_free(&d->play_sysctl_ctx);
@ -557,24 +554,12 @@ pcm_unregister(device_t dev)
d->rec_sysctl_tree = NULL;
}
sndstat_unregister(dev);
mixer_uninit(dev);
dsp_destroy_dev(dev);
(void)mixer_uninit(dev);
pcm_killchans(d);
PCM_LOCK(d);
PCM_RELEASE(d);
cv_destroy(&d->cv);
PCM_UNLOCK(d);
snd_mtxfree(d->lock);
if (d->p_unr != NULL)
delete_unrhdr(d->p_unr);
if (d->vp_unr != NULL)
delete_unrhdr(d->vp_unr);
if (d->r_unr != NULL)
delete_unrhdr(d->r_unr);
if (d->vr_unr != NULL)
delete_unrhdr(d->vr_unr);
if (snd_unit == device_get_unit(dev)) {
snd_unit = pcm_best_unit(-1);

View File

@ -104,17 +104,15 @@ struct snd_mixer;
#define SD_F_SIMPLEX 0x00000001
#define SD_F_AUTOVCHAN 0x00000002
#define SD_F_SOFTPCMVOL 0x00000004
#define SD_F_DYING 0x00000008
#define SD_F_DETACHING 0x00000010
#define SD_F_BUSY 0x00000020
#define SD_F_MPSAFE 0x00000040
#define SD_F_REGISTERED 0x00000080
#define SD_F_BITPERFECT 0x00000100
#define SD_F_VPC 0x00000200 /* volume-per-channel */
#define SD_F_EQ 0x00000400 /* EQ */
#define SD_F_EQ_ENABLED 0x00000800 /* EQ enabled */
#define SD_F_EQ_BYPASSED 0x00001000 /* EQ bypassed */
#define SD_F_EQ_PC 0x00002000 /* EQ per-channel */
#define SD_F_BUSY 0x00000008
#define SD_F_MPSAFE 0x00000010
#define SD_F_REGISTERED 0x00000020
#define SD_F_BITPERFECT 0x00000040
#define SD_F_VPC 0x00000080 /* volume-per-channel */
#define SD_F_EQ 0x00000100 /* EQ */
#define SD_F_EQ_ENABLED 0x00000200 /* EQ enabled */
#define SD_F_EQ_BYPASSED 0x00000400 /* EQ bypassed */
#define SD_F_EQ_PC 0x00000800 /* EQ per-channel */
#define SD_F_EQ_DEFAULT (SD_F_EQ | SD_F_EQ_ENABLED)
#define SD_F_EQ_MASK (SD_F_EQ | SD_F_EQ_ENABLED | \
@ -127,26 +125,20 @@ struct snd_mixer;
"\001SIMPLEX" \
"\002AUTOVCHAN" \
"\003SOFTPCMVOL" \
"\004DYING" \
"\005DETACHING" \
"\006BUSY" \
"\007MPSAFE" \
"\010REGISTERED" \
"\011BITPERFECT" \
"\012VPC" \
"\013EQ" \
"\014EQ_ENABLED" \
"\015EQ_BYPASSED" \
"\016EQ_PC" \
"\004BUSY" \
"\005MPSAFE" \
"\006REGISTERED" \
"\007BITPERFECT" \
"\010VPC" \
"\011EQ" \
"\012EQ_ENABLED" \
"\013EQ_BYPASSED" \
"\014EQ_PC" \
"\035PRIO_RD" \
"\036PRIO_WR"
#define PCM_ALIVE(x) ((x) != NULL && (x)->lock != NULL && \
!((x)->flags & SD_F_DYING))
#define PCM_REGISTERED(x) (PCM_ALIVE(x) && \
((x)->flags & SD_F_REGISTERED))
#define PCM_DETACHING(x) ((x)->flags & SD_F_DETACHING)
#define PCM_ALIVE(x) ((x) != NULL && (x)->lock != NULL)
#define PCM_REGISTERED(x) (PCM_ALIVE(x) && ((x)->flags & SD_F_REGISTERED))
#define PCM_CHANCOUNT(d) \
(d->playcount + d->pvchancount + d->reccount + d->rvchancount)

View File

@ -146,20 +146,19 @@ vchan_trigger(kobj_t obj, void *data, int go)
int ret, otrigger;
info = data;
c = info->channel;
p = c->parentchannel;
CHN_LOCKASSERT(c);
if (!PCMTRIG_COMMON(go) || go == info->trigger)
return (0);
c = info->channel;
p = c->parentchannel;
otrigger = info->trigger;
info->trigger = go;
CHN_LOCKASSERT(c);
CHN_UNLOCK(c);
CHN_LOCK(p);
otrigger = info->trigger;
info->trigger = go;
switch (go) {
case PCMTRIG_START:
if (otrigger != PCMTRIG_START)

View File

@ -70,6 +70,8 @@
#ifdef _KERNEL
#define PF_PFIL_NOREFRAGMENT 0x80000000
#if defined(__arm__)
#define PF_WANT_32_TO_64_COUNTER
#endif
@ -2372,7 +2374,8 @@ void pf_poolmask(struct pf_addr *, struct pf_addr*,
struct pf_addr *, struct pf_addr *, sa_family_t);
void pf_addr_inc(struct pf_addr *, sa_family_t);
int pf_max_frag_size(struct mbuf *);
int pf_refragment6(struct ifnet *, struct mbuf **, struct m_tag *, bool);
int pf_refragment6(struct ifnet *, struct mbuf **, struct m_tag *,
struct ifnet *, bool);
#endif /* INET6 */
int pf_multihome_scan_init(int, int, struct pf_pdesc *);

View File

@ -7927,6 +7927,7 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp)
{
struct mbuf *m0, *md;
struct m_tag *mtag;
struct sockaddr_in6 dst;
struct ip6_hdr *ip6;
struct pfi_kkif *nkif = NULL;
@ -8053,8 +8054,8 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
}
if (pd->dir == PF_IN) {
if (pf_test(AF_INET6, PF_OUT, PFIL_FWD, ifp, &m0, inp,
&pd->act) != PF_PASS) {
if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT,
ifp, &m0, inp, &pd->act) != PF_PASS) {
SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
goto bad;
} else if (m0 == NULL) {
@ -8087,6 +8088,14 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
*/
if (IN6_IS_SCOPE_EMBED(&dst.sin6_addr))
dst.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
mtag = m_tag_find(m0, PACKET_TAG_PF_REASSEMBLED, NULL);
if (mtag != NULL) {
int ret;
ret = pf_refragment6(ifp, &m0, mtag, ifp, true);
SDT_PROBE2(pf, ip6, route_to, output, ifp, ret);
goto done;
}
if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
md = m0;
pf_dummynet_route(pd, s, r, ifp, sintosa(&dst), &md);
@ -9474,14 +9483,15 @@ eat_pkt:
if (s)
PF_STATE_UNLOCK(s);
out:
#ifdef INET6
/* If reassembled packet passed, create new fragments. */
if (af == AF_INET6 && action == PF_PASS && *m0 && dir == PF_OUT &&
(! (pflags & PF_PFIL_NOREFRAGMENT)) &&
(mtag = m_tag_find(pd.m, PACKET_TAG_PF_REASSEMBLED, NULL)) != NULL)
action = pf_refragment6(ifp, m0, mtag, pflags & PFIL_FWD);
action = pf_refragment6(ifp, m0, mtag, NULL, pflags & PFIL_FWD);
#endif
out:
pf_sctp_multihome_delayed(&pd, kif, s, action);
return (action);

View File

@ -42,6 +42,7 @@
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/vnet.h>
#include <net/pfvar.h>
#include <net/if_pflog.h>
@ -49,6 +50,8 @@
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/scope6_var.h>
#include <netinet/tcp.h>
@ -958,7 +961,7 @@ pf_max_frag_size(struct mbuf *m)
int
pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag,
bool forward)
struct ifnet *rt, bool forward)
{
struct mbuf *m = *m0, *t;
struct ip6_hdr *hdr;
@ -1029,16 +1032,27 @@ pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag,
m->m_flags |= M_SKIP_FIREWALL;
memset(&pd, 0, sizeof(pd));
pd.pf_mtag = pf_find_mtag(m);
if (error == 0)
if (forward) {
MPASS(m->m_pkthdr.rcvif != NULL);
ip6_forward(m, 0);
} else {
(void)ip6_output(m, NULL, NULL, 0, NULL, NULL,
NULL);
}
else
if (error != 0) {
m_freem(m);
continue;
}
if (rt != NULL) {
struct sockaddr_in6 dst;
hdr = mtod(m, struct ip6_hdr *);
bzero(&dst, sizeof(dst));
dst.sin6_family = AF_INET6;
dst.sin6_len = sizeof(dst);
dst.sin6_addr = hdr->ip6_dst;
nd6_output_ifp(rt, rt, m, &dst, NULL);
} else if (forward) {
MPASS(m->m_pkthdr.rcvif != NULL);
ip6_forward(m, 0);
} else {
(void)ip6_output(m, NULL, NULL, 0, NULL, NULL,
NULL);
}
}
return (action);

View File

@ -155,6 +155,75 @@ v6_cleanup()
pft_cleanup
}
atf_test_case "v6_route_to" "cleanup"
v6_route_to_head()
{
atf_set descr 'Test IPv6 reassembly combined with route-to'
atf_set require.user root
}
v6_route_to_body()
{
pft_init
}
v6_route_to_cleanup()
{
pft_cleanup
epair_send=$(vnet_mkepair)
epair_link=$(vnet_mkepair)
vnet_mkjail alcatraz ${epair_send}b ${epair_link}a
vnet_mkjail singsing ${epair_link}b
ifconfig ${epair_send}a inet6 2001:db8:42::1/64 no_dad up
jexec alcatraz ifconfig ${epair_send}b inet6 2001:db8:42::2/64 no_dad up
jexec alcatraz ifconfig ${epair_link}a inet6 2001:db8:43::2/64 no_dad up
jexec alcatraz sysctl net.inet6.ip6.forwarding=1
jexec singsing ifconfig ${epair_link}b inet6 2001:db8:43::3/64 no_dad up
jexec singsing route add -6 2001:db8:42::/64 2001:db8:43::2
route add -6 2001:db8:43::/64 2001:db8:42::2
jexec alcatraz ifconfig ${epair_send}b inet6 -ifdisabled
jexec alcatraz ifconfig ${epair_link}a inet6 -ifdisabled
jexec singsing ifconfig ${epair_link}b inet6 -ifdisabled
ifconfig ${epair_send}a inet6 -ifdisabled
jexec alcatraz pfctl -e
pft_set_rules alcatraz \
"set reassemble yes" \
"pass" \
"pass in route-to (${epair_link}a 2001:db8:43::3) inet6 proto icmp6 from any to 2001:db8:43::3 keep state"
# Forwarding test
atf_check -s exit:0 -o ignore \
ping -6 -c 1 2001:db8:43::3
atf_check -s exit:0 -o ignore \
ping -6 -c 1 -s 4500 2001:db8:43::3
atf_check -s exit:0 -o ignore\
ping -6 -c 1 -b 70000 -s 65000 2001:db8:43::3
# Now test this without fragmentation
pft_set_rules alcatraz \
"set reassemble no" \
"pass" \
"pass in route-to (${epair_link}a 2001:db8:43::3) inet6 proto icmp6 from any to 2001:db8:43::3 keep state"
atf_check -s exit:0 -o ignore \
ping -6 -c 1 2001:db8:43::3
atf_check -s exit:0 -o ignore \
ping -6 -c 1 -s 4500 2001:db8:43::3
atf_check -s exit:0 -o ignore\
ping -6 -c 1 -b 70000 -s 65000 2001:db8:43::3
}
atf_test_case "mtu_diff" "cleanup"
mtu_diff_head()
{
@ -544,6 +613,7 @@ atf_init_test_cases()
{
atf_add_test_case "too_many_fragments"
atf_add_test_case "v6"
atf_add_test_case "v6_route_to"
atf_add_test_case "mtu_diff"
atf_add_test_case "overreplace"
atf_add_test_case "overindex"

View File

@ -578,7 +578,7 @@ netname4(in_addr_t in, in_addr_t mask)
struct netent *np = 0;
in_addr_t i;
if (in == INADDR_ANY && mask == 0) {
if (!numeric_addr && in == INADDR_ANY && mask == 0) {
strlcpy(line, "default", sizeof(line));
return (line);
}
@ -673,7 +673,8 @@ netname6(struct sockaddr_in6 *sa6, struct sockaddr_in6 *mask)
else
masklen = 128;
if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
if (!numeric_addr && masklen == 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
return("default");
getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, nline, sizeof(nline),