mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-26 20:12:44 +00:00
Compare commits
8 Commits
4cc5d081d8
...
9206c79961
Author | SHA1 | Date | |
---|---|---|---|
|
9206c79961 | ||
|
6d77827b96 | ||
|
5317480967 | ||
|
6d4c59e261 | ||
|
2839ad58dd | ||
|
5ac39263d8 | ||
|
5bd08172b4 | ||
|
56b7685ae3 |
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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" \
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 *);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user