#if PF_ALTQ && PKTSCHED_PRIQ
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <net/if.h>
#include <net/pfvar.h>
#include <net/net_osdep.h>
#include <net/altq/altq.h>
#include <net/altq/altq_priq.h>
#include <netinet/in.h>
static int altq_priq_enqueue(struct ifaltq *, struct mbuf *);
static struct mbuf *altq_priq_dequeue(struct ifaltq *, enum altdq_op);
static int altq_priq_request(struct ifaltq *, enum altrq, void *);
int
altq_priq_pfattach(struct pf_altq *a)
{
struct ifnet *ifp;
int error;
lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
return (EINVAL);
IFCQ_LOCK(&ifp->if_snd);
error = altq_attach(IFCQ_ALTQ(&ifp->if_snd), ALTQT_PRIQ, a->altq_disc,
altq_priq_enqueue, altq_priq_dequeue, NULL, altq_priq_request);
IFCQ_UNLOCK(&ifp->if_snd);
return (error);
}
int
altq_priq_add(struct pf_altq *a)
{
struct priq_if *pif;
struct ifnet *ifp;
lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
if ((ifp = ifunit(a->ifname)) == NULL)
return (EINVAL);
if (!ALTQ_IS_READY(IFCQ_ALTQ(&ifp->if_snd)))
return (ENODEV);
pif = priq_alloc(ifp, M_WAITOK, TRUE);
if (pif == NULL)
return (ENOMEM);
a->altq_disc = pif;
return (0);
}
int
altq_priq_remove(struct pf_altq *a)
{
struct priq_if *pif;
lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
if ((pif = a->altq_disc) == NULL)
return (EINVAL);
a->altq_disc = NULL;
return (priq_destroy(pif));
}
int
altq_priq_add_queue(struct pf_altq *a)
{
struct priq_if *pif;
int err;
lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
if ((pif = a->altq_disc) == NULL)
return (EINVAL);
IFCQ_LOCK(pif->pif_ifq);
err = priq_add_queue(pif, a->priority, a->qlimit,
a->pq_u.priq_opts.flags, a->qid, NULL);
IFCQ_UNLOCK(pif->pif_ifq);
return (err);
}
int
altq_priq_remove_queue(struct pf_altq *a)
{
struct priq_if *pif;
int err;
lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
if ((pif = a->altq_disc) == NULL)
return (EINVAL);
IFCQ_LOCK(pif->pif_ifq);
err = priq_remove_queue(pif, a->qid);
IFCQ_UNLOCK(pif->pif_ifq);
return (err);
}
int
altq_priq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
{
struct ifclassq *ifq = NULL;
struct priq_if *pif;
struct priq_classstats stats;
int error = 0;
lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
if ((unsigned)*nbytes < sizeof (stats))
return (EINVAL);
if ((pif = altq_lookup(a->ifname, ALTQT_PRIQ)) == NULL)
return (EBADF);
ifq = pif->pif_ifq;
IFCQ_LOCK_ASSERT_HELD(ifq);
error = priq_get_class_stats(pif, a->qid, &stats);
IFCQ_UNLOCK(ifq);
if (error != 0)
return (error);
if ((error = copyout((caddr_t)&stats, (user_addr_t)(uintptr_t)ubuf,
sizeof (stats))) != 0)
return (error);
*nbytes = sizeof (stats);
return (0);
}
static int
altq_priq_request(struct ifaltq *altq, enum altrq req, void *arg)
{
struct priq_if *pif = (struct priq_if *)altq->altq_disc;
switch (req) {
case ALTRQ_PURGE:
priq_purge(pif);
break;
case ALTRQ_PURGE_SC:
case ALTRQ_THROTTLE:
break;
case ALTRQ_EVENT:
priq_event(pif, (cqev_t)arg);
break;
}
return (0);
}
static int
altq_priq_enqueue(struct ifaltq *altq, struct mbuf *m)
{
if (!(m->m_flags & M_PKTHDR)) {
printf("%s: packet for %s does not have pkthdr\n", __func__,
if_name(altq->altq_ifcq->ifcq_ifp));
m_freem(m);
return (ENOBUFS);
}
return (priq_enqueue(altq->altq_disc, NULL, m, m_pftag(m)));
}
static struct mbuf *
altq_priq_dequeue(struct ifaltq *altq, enum altdq_op op)
{
return (priq_dequeue(altq->altq_disc, (cqdq_op_t)op));
}
#endif