/*
* Copyright (C) 1997-2002
* Sony Computer Science Laboratories 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 SONY CSL 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 SONY CSL 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.
*/
#ifdef ALTQ_FIFOQ /* fifoq is enabled by ALTQ_FIFOQ option in opt_altq.h */
/*
* FIFOQ is an altq sample implementation. There will be little
* need to use FIFOQ as an alternative queueing scheme.
* But this code is provided as a template for those who want to
* write their own queueing schemes.
*/
int
fifoqopen(dev_t dev, int flag, int fmt,
struct lwp *l)
{
/* everything will be done when the queueing scheme is attached. */
return 0;
}
/*
* there are 2 ways to act on close.
* detach-all-on-close:
* use for the daemon style approach. if the daemon dies, all the
* resource will be released.
* no-action-on-close:
* use for the command style approach. (e.g. fifoq on/off)
*
* note: close is called not on every close but when the last reference
* is removed (only once with multiple simultaneous references.)
*/
int
fifoqclose(dev_t dev, int flag, int fmt,
struct lwp *l)
{
fifoq_state_t *q;
int err, error = 0;
while ((q = fifoq_list) != NULL) {
/* destroy all */
err = fifoq_detach(q);
if (err != 0 && error == 0)
error = err;
}
return error;
}
int
fifoqioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag,
struct lwp *l)
{
fifoq_state_t *q;
struct fifoq_interface *ifacep;
struct ifnet *ifp;
int error = 0;
case FIFOQ_CONFIG:
do {
struct fifoq_conf *fc;
int limit;
fc = (struct fifoq_conf *)addr;
if ((q = altq_lookup(fc->iface.fifoq_ifname,
ALTQT_FIFOQ)) == NULL) {
error = EBADF;
break;
}
limit = fc->fifoq_limit;
if (limit < 0)
limit = 0;
q->q_limit = limit;
fc->fifoq_limit = limit;
} while (/*CONSTCOND*/ 0);
break;
default:
error = EINVAL;
break;
}
return error;
}
/*
* fifoq support routines
*/
/*
* enqueue routine:
*
* returns: 0 when successfully queued.
* ENOBUFS when drop occurs.
*/
static int
fifoq_enqueue(struct ifaltq *ifq, struct mbuf *m)
{
fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
/* if the queue is full, drop the incoming packet(drop-tail) */
if (q->q_len >= q->q_limit) {
#ifdef FIFOQ_STATS
PKTCNTR_ADD(&q->q_stats.drop_cnt, m_pktlen(m));
#endif
m_freem(m);
return ENOBUFS;
}
/* enqueue the packet at the taile of the queue */
m->m_nextpkt = NULL;
if (q->q_tail == NULL)
q->q_head = m;
else
q->q_tail->m_nextpkt = m;
q->q_tail = m;
q->q_len++;
ifq->ifq_len++;
return 0;
}
/*
* dequeue routine:
* must be called in splnet.
*
* returns: mbuf dequeued.
* NULL when no packet is available in the queue.
*/
/*
* ALTDQ_PEEK is provided for drivers which need to know the next packet
* to send in advance.
* when ALTDQ_PEEK is specified, the next packet to be dequeued is
* returned without dequeueing the packet.
* when ALTDQ_DEQUEUE is called *immediately after* an ALTDQ_PEEK
* operation, the same packet should be returned.
*/
static struct mbuf *
fifoq_dequeue(struct ifaltq *ifq, int op)
{
fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
struct mbuf *m = NULL;
if (op == ALTDQ_POLL)
return (q->q_head);
if ((m = q->q_head) == NULL)
return NULL;
if ((q->q_head = m->m_nextpkt) == NULL)
q->q_tail = NULL;
m->m_nextpkt = NULL;
q->q_len--;
ifq->ifq_len--;
#ifdef FIFOQ_STATS
PKTCNTR_ADD(&q->q_stats.xmit_cnt, m_pktlen(m));
if (q->q_len == 0)
q->q_stats.period++;
#endif
return m;
}
static int
fifoq_request(struct ifaltq *ifq, int req, void *arg)
{
fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;