Home | History | Annotate | Line # | Download | only in altq
altq_subr.c revision 1.24.18.1
      1 /*	$NetBSD: altq_subr.c,v 1.24.18.1 2008/05/18 12:31:18 yamt Exp $	*/
      2 /*	$KAME: altq_subr.c,v 1.24 2005/04/13 03:44:25 suz Exp $	*/
      3 
      4 /*
      5  * Copyright (C) 1997-2003
      6  *	Sony Computer Science Laboratories Inc.  All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 
     30 #include <sys/cdefs.h>
     31 __KERNEL_RCSID(0, "$NetBSD: altq_subr.c,v 1.24.18.1 2008/05/18 12:31:18 yamt Exp $");
     32 
     33 #ifdef _KERNEL_OPT
     34 #include "opt_altq.h"
     35 #include "opt_inet.h"
     36 #include "pf.h"
     37 #endif
     38 
     39 #include <sys/param.h>
     40 #include <sys/malloc.h>
     41 #include <sys/mbuf.h>
     42 #include <sys/systm.h>
     43 #include <sys/proc.h>
     44 #include <sys/socket.h>
     45 #include <sys/socketvar.h>
     46 #include <sys/kernel.h>
     47 #include <sys/errno.h>
     48 #include <sys/syslog.h>
     49 #include <sys/sysctl.h>
     50 #include <sys/queue.h>
     51 
     52 #include <net/if.h>
     53 #include <net/if_dl.h>
     54 #include <net/if_types.h>
     55 
     56 #include <netinet/in.h>
     57 #include <netinet/in_systm.h>
     58 #include <netinet/ip.h>
     59 #ifdef INET6
     60 #include <netinet/ip6.h>
     61 #endif
     62 #include <netinet/tcp.h>
     63 #include <netinet/udp.h>
     64 
     65 #if NPF > 0
     66 #include <net/pfvar.h>
     67 #endif
     68 #include <altq/altq.h>
     69 #ifdef ALTQ3_COMPAT
     70 #include <altq/altq_conf.h>
     71 #endif
     72 
     73 /* machine dependent clock related includes */
     74 #ifdef __HAVE_CPU_COUNTER
     75 #include <machine/cpu_counter.h>		/* for pentium tsc */
     76 #endif
     77 
     78 /*
     79  * internal function prototypes
     80  */
     81 static void	tbr_timeout(void *);
     82 int (*altq_input)(struct mbuf *, int) = NULL;
     83 static int tbr_timer = 0;	/* token bucket regulator timer */
     84 static struct callout tbr_callout;
     85 
     86 #ifdef ALTQ3_CLFIER_COMPAT
     87 static int 	extract_ports4(struct mbuf *, struct ip *, struct flowinfo_in *);
     88 #ifdef INET6
     89 static int 	extract_ports6(struct mbuf *, struct ip6_hdr *,
     90 			       struct flowinfo_in6 *);
     91 #endif
     92 static int	apply_filter4(u_int32_t, struct flow_filter *,
     93 			      struct flowinfo_in *);
     94 static int	apply_ppfilter4(u_int32_t, struct flow_filter *,
     95 				struct flowinfo_in *);
     96 #ifdef INET6
     97 static int	apply_filter6(u_int32_t, struct flow_filter6 *,
     98 			      struct flowinfo_in6 *);
     99 #endif
    100 static int	apply_tosfilter4(u_int32_t, struct flow_filter *,
    101 				 struct flowinfo_in *);
    102 static u_long	get_filt_handle(struct acc_classifier *, int);
    103 static struct acc_filter *filth_to_filtp(struct acc_classifier *, u_long);
    104 static u_int32_t filt2fibmask(struct flow_filter *);
    105 
    106 static void 	ip4f_cache(struct ip *, struct flowinfo_in *);
    107 static int 	ip4f_lookup(struct ip *, struct flowinfo_in *);
    108 static int 	ip4f_init(void);
    109 static struct ip4_frag	*ip4f_alloc(void);
    110 static void 	ip4f_free(struct ip4_frag *);
    111 #endif /* ALTQ3_CLFIER_COMPAT */
    112 
    113 /*
    114  * alternate queueing support routines
    115  */
    116 
    117 /* look up the queue state by the interface name and the queueing type. */
    118 void *
    119 altq_lookup(char *name, int type)
    120 {
    121 	struct ifnet *ifp;
    122 
    123 	if ((ifp = ifunit(name)) != NULL) {
    124 		if (type != ALTQT_NONE && ifp->if_snd.altq_type == type)
    125 			return (ifp->if_snd.altq_disc);
    126 	}
    127 
    128 	return NULL;
    129 }
    130 
    131 int
    132 altq_attach(struct ifaltq *ifq, int type, void *discipline,
    133     int (*enqueue)(struct ifaltq *, struct mbuf *, struct altq_pktattr *),
    134     struct mbuf *(*dequeue)(struct ifaltq *, int),
    135     int (*request)(struct ifaltq *, int, void *),
    136     void *clfier, void *(*classify)(void *, struct mbuf *, int))
    137 {
    138 	if (!ALTQ_IS_READY(ifq))
    139 		return ENXIO;
    140 
    141 #ifdef ALTQ3_COMPAT
    142 	/*
    143 	 * pfaltq can override the existing discipline, but altq3 cannot.
    144 	 * check these if clfier is not NULL (which implies altq3).
    145 	 */
    146 	if (clfier != NULL) {
    147 		if (ALTQ_IS_ENABLED(ifq))
    148 			return EBUSY;
    149 		if (ALTQ_IS_ATTACHED(ifq))
    150 			return EEXIST;
    151 	}
    152 #endif
    153 	ifq->altq_type     = type;
    154 	ifq->altq_disc     = discipline;
    155 	ifq->altq_enqueue  = enqueue;
    156 	ifq->altq_dequeue  = dequeue;
    157 	ifq->altq_request  = request;
    158 	ifq->altq_clfier   = clfier;
    159 	ifq->altq_classify = classify;
    160 	ifq->altq_flags &= (ALTQF_CANTCHANGE|ALTQF_ENABLED);
    161 #ifdef ALTQ3_COMPAT
    162 #ifdef ALTQ_KLD
    163 	altq_module_incref(type);
    164 #endif
    165 #endif
    166 	return 0;
    167 }
    168 
    169 int
    170 altq_detach(struct ifaltq *ifq)
    171 {
    172 	if (!ALTQ_IS_READY(ifq))
    173 		return ENXIO;
    174 	if (ALTQ_IS_ENABLED(ifq))
    175 		return EBUSY;
    176 	if (!ALTQ_IS_ATTACHED(ifq))
    177 		return (0);
    178 #ifdef ALTQ3_COMPAT
    179 #ifdef ALTQ_KLD
    180 	altq_module_declref(ifq->altq_type);
    181 #endif
    182 #endif
    183 
    184 	ifq->altq_type     = ALTQT_NONE;
    185 	ifq->altq_disc     = NULL;
    186 	ifq->altq_enqueue  = NULL;
    187 	ifq->altq_dequeue  = NULL;
    188 	ifq->altq_request  = NULL;
    189 	ifq->altq_clfier   = NULL;
    190 	ifq->altq_classify = NULL;
    191 	ifq->altq_flags &= ALTQF_CANTCHANGE;
    192 	return 0;
    193 }
    194 
    195 int
    196 altq_enable(struct ifaltq *ifq)
    197 {
    198 	int s;
    199 
    200 	if (!ALTQ_IS_READY(ifq))
    201 		return ENXIO;
    202 	if (ALTQ_IS_ENABLED(ifq))
    203 		return 0;
    204 
    205 	s = splnet();
    206 	IFQ_PURGE(ifq);
    207 	ASSERT(ifq->ifq_len == 0);
    208 	ifq->altq_flags |= ALTQF_ENABLED;
    209 	if (ifq->altq_clfier != NULL)
    210 		ifq->altq_flags |= ALTQF_CLASSIFY;
    211 	splx(s);
    212 
    213 	return 0;
    214 }
    215 
    216 int
    217 altq_disable(struct ifaltq *ifq)
    218 {
    219 	int s;
    220 
    221 	if (!ALTQ_IS_ENABLED(ifq))
    222 		return 0;
    223 
    224 	s = splnet();
    225 	IFQ_PURGE(ifq);
    226 	ASSERT(ifq->ifq_len == 0);
    227 	ifq->altq_flags &= ~(ALTQF_ENABLED|ALTQF_CLASSIFY);
    228 	splx(s);
    229 	return 0;
    230 }
    231 
    232 #ifdef ALTQ_DEBUG
    233 void
    234 altq_assert(const char *file, int line, const char *failedexpr)
    235 {
    236 	(void)printf("altq assertion \"%s\" failed: file \"%s\", line %d\n",
    237 		     failedexpr, file, line);
    238 	panic("altq assertion");
    239 	/* NOTREACHED */
    240 }
    241 #endif
    242 
    243 /*
    244  * internal representation of token bucket parameters
    245  *	rate:	byte_per_unittime << 32
    246  *		(((bits_per_sec) / 8) << 32) / machclk_freq
    247  *	depth:	byte << 32
    248  *
    249  */
    250 #define	TBR_SHIFT	32
    251 #define	TBR_SCALE(x)	((int64_t)(x) << TBR_SHIFT)
    252 #define	TBR_UNSCALE(x)	((x) >> TBR_SHIFT)
    253 
    254 struct mbuf *
    255 tbr_dequeue(struct ifaltq *ifq, int op)
    256 {
    257 	struct tb_regulator *tbr;
    258 	struct mbuf *m;
    259 	int64_t interval;
    260 	u_int64_t now;
    261 
    262 	tbr = ifq->altq_tbr;
    263 	if (op == ALTDQ_REMOVE && tbr->tbr_lastop == ALTDQ_POLL) {
    264 		/* if this is a remove after poll, bypass tbr check */
    265 	} else {
    266 		/* update token only when it is negative */
    267 		if (tbr->tbr_token <= 0) {
    268 			now = read_machclk();
    269 			interval = now - tbr->tbr_last;
    270 			if (interval >= tbr->tbr_filluptime)
    271 				tbr->tbr_token = tbr->tbr_depth;
    272 			else {
    273 				tbr->tbr_token += interval * tbr->tbr_rate;
    274 				if (tbr->tbr_token > tbr->tbr_depth)
    275 					tbr->tbr_token = tbr->tbr_depth;
    276 			}
    277 			tbr->tbr_last = now;
    278 		}
    279 		/* if token is still negative, don't allow dequeue */
    280 		if (tbr->tbr_token <= 0)
    281 			return (NULL);
    282 	}
    283 
    284 	if (ALTQ_IS_ENABLED(ifq))
    285 		m = (*ifq->altq_dequeue)(ifq, op);
    286 	else {
    287 		if (op == ALTDQ_POLL)
    288 			IF_POLL(ifq, m);
    289 		else
    290 			IF_DEQUEUE(ifq, m);
    291 	}
    292 
    293 	if (m != NULL && op == ALTDQ_REMOVE)
    294 		tbr->tbr_token -= TBR_SCALE(m_pktlen(m));
    295 	tbr->tbr_lastop = op;
    296 	return (m);
    297 }
    298 
    299 /*
    300  * set a token bucket regulator.
    301  * if the specified rate is zero, the token bucket regulator is deleted.
    302  */
    303 int
    304 tbr_set(struct ifaltq *ifq, struct tb_profile *profile)
    305 {
    306 	struct tb_regulator *tbr, *otbr;
    307 
    308 	if (machclk_freq == 0)
    309 		init_machclk();
    310 	if (machclk_freq == 0) {
    311 		printf("tbr_set: no CPU clock available!\n");
    312 		return (ENXIO);
    313 	}
    314 
    315 	if (profile->rate == 0) {
    316 		/* delete this tbr */
    317 		if ((tbr = ifq->altq_tbr) == NULL)
    318 			return (ENOENT);
    319 		ifq->altq_tbr = NULL;
    320 		free(tbr, M_DEVBUF);
    321 		return (0);
    322 	}
    323 
    324 	tbr = malloc(sizeof(struct tb_regulator), M_DEVBUF, M_WAITOK|M_ZERO);
    325 	if (tbr == NULL)
    326 		return (ENOMEM);
    327 
    328 	tbr->tbr_rate = TBR_SCALE(profile->rate / 8) / machclk_freq;
    329 	tbr->tbr_depth = TBR_SCALE(profile->depth);
    330 	if (tbr->tbr_rate > 0)
    331 		tbr->tbr_filluptime = tbr->tbr_depth / tbr->tbr_rate;
    332 	else
    333 		tbr->tbr_filluptime = 0xffffffffffffffffLL;
    334 	tbr->tbr_token = tbr->tbr_depth;
    335 	tbr->tbr_last = read_machclk();
    336 	tbr->tbr_lastop = ALTDQ_REMOVE;
    337 
    338 	otbr = ifq->altq_tbr;
    339 	ifq->altq_tbr = tbr;	/* set the new tbr */
    340 
    341 	if (otbr != NULL)
    342 		free(otbr, M_DEVBUF);
    343 	else {
    344 		if (tbr_timer == 0) {
    345 			CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0);
    346 			tbr_timer = 1;
    347 		}
    348 	}
    349 	return (0);
    350 }
    351 
    352 /*
    353  * tbr_timeout goes through the interface list, and kicks the drivers
    354  * if necessary.
    355  */
    356 static void
    357 tbr_timeout(void *arg)
    358 {
    359 	struct ifnet *ifp;
    360 	int active, s;
    361 
    362 	active = 0;
    363 	s = splnet();
    364 	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
    365 		if (!TBR_IS_ENABLED(&ifp->if_snd))
    366 			continue;
    367 		active++;
    368 		if (!IFQ_IS_EMPTY(&ifp->if_snd) && ifp->if_start != NULL)
    369 			(*ifp->if_start)(ifp);
    370 	}
    371 	splx(s);
    372 	if (active > 0)
    373 		CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0);
    374 	else
    375 		tbr_timer = 0;	/* don't need tbr_timer anymore */
    376 #if defined(__alpha__) && !defined(ALTQ_NOPCC)
    377 	{
    378 		/*
    379 		 * XXX read out the machine dependent clock once a second
    380 		 * to detect counter wrap-around.
    381 		 */
    382 		static u_int cnt;
    383 
    384 		if (++cnt >= hz) {
    385 			(void)read_machclk();
    386 			cnt = 0;
    387 		}
    388 	}
    389 #endif /* __alpha__ && !ALTQ_NOPCC */
    390 }
    391 
    392 /*
    393  * get token bucket regulator profile
    394  */
    395 int
    396 tbr_get(struct ifaltq *ifq, struct tb_profile *profile)
    397 {
    398 	struct tb_regulator *tbr;
    399 
    400 	if ((tbr = ifq->altq_tbr) == NULL) {
    401 		profile->rate = 0;
    402 		profile->depth = 0;
    403 	} else {
    404 		profile->rate =
    405 		    (u_int)TBR_UNSCALE(tbr->tbr_rate * 8 * machclk_freq);
    406 		profile->depth = (u_int)TBR_UNSCALE(tbr->tbr_depth);
    407 	}
    408 	return (0);
    409 }
    410 
    411 #if NPF > 0
    412 /*
    413  * attach a discipline to the interface.  if one already exists, it is
    414  * overridden.
    415  */
    416 int
    417 altq_pfattach(struct pf_altq *a)
    418 {
    419 	int error = 0;
    420 
    421 	switch (a->scheduler) {
    422 	case ALTQT_NONE:
    423 		break;
    424 #ifdef ALTQ_CBQ
    425 	case ALTQT_CBQ:
    426 		error = cbq_pfattach(a);
    427 		break;
    428 #endif
    429 #ifdef ALTQ_PRIQ
    430 	case ALTQT_PRIQ:
    431 		error = priq_pfattach(a);
    432 		break;
    433 #endif
    434 #ifdef ALTQ_HFSC
    435 	case ALTQT_HFSC:
    436 		error = hfsc_pfattach(a);
    437 		break;
    438 #endif
    439 	default:
    440 		error = ENXIO;
    441 	}
    442 
    443 	return (error);
    444 }
    445 
    446 /*
    447  * detach a discipline from the interface.
    448  * it is possible that the discipline was already overridden by another
    449  * discipline.
    450  */
    451 int
    452 altq_pfdetach(struct pf_altq *a)
    453 {
    454 	struct ifnet *ifp;
    455 	int s, error = 0;
    456 
    457 	if ((ifp = ifunit(a->ifname)) == NULL)
    458 		return (EINVAL);
    459 
    460 	/* if this discipline is no longer referenced, just return */
    461 	if (a->altq_disc == NULL || a->altq_disc != ifp->if_snd.altq_disc)
    462 		return (0);
    463 
    464 	s = splnet();
    465 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
    466 		error = altq_disable(&ifp->if_snd);
    467 	if (error == 0)
    468 		error = altq_detach(&ifp->if_snd);
    469 	splx(s);
    470 
    471 	return (error);
    472 }
    473 
    474 /*
    475  * add a discipline or a queue
    476  */
    477 int
    478 altq_add(struct pf_altq *a)
    479 {
    480 	int error = 0;
    481 
    482 	if (a->qname[0] != 0)
    483 		return (altq_add_queue(a));
    484 
    485 	if (machclk_freq == 0)
    486 		init_machclk();
    487 	if (machclk_freq == 0)
    488 		panic("altq_add: no CPU clock");
    489 
    490 	switch (a->scheduler) {
    491 #ifdef ALTQ_CBQ
    492 	case ALTQT_CBQ:
    493 		error = cbq_add_altq(a);
    494 		break;
    495 #endif
    496 #ifdef ALTQ_PRIQ
    497 	case ALTQT_PRIQ:
    498 		error = priq_add_altq(a);
    499 		break;
    500 #endif
    501 #ifdef ALTQ_HFSC
    502 	case ALTQT_HFSC:
    503 		error = hfsc_add_altq(a);
    504 		break;
    505 #endif
    506 	default:
    507 		error = ENXIO;
    508 	}
    509 
    510 	return (error);
    511 }
    512 
    513 /*
    514  * remove a discipline or a queue
    515  */
    516 int
    517 altq_remove(struct pf_altq *a)
    518 {
    519 	int error = 0;
    520 
    521 	if (a->qname[0] != 0)
    522 		return (altq_remove_queue(a));
    523 
    524 	switch (a->scheduler) {
    525 #ifdef ALTQ_CBQ
    526 	case ALTQT_CBQ:
    527 		error = cbq_remove_altq(a);
    528 		break;
    529 #endif
    530 #ifdef ALTQ_PRIQ
    531 	case ALTQT_PRIQ:
    532 		error = priq_remove_altq(a);
    533 		break;
    534 #endif
    535 #ifdef ALTQ_HFSC
    536 	case ALTQT_HFSC:
    537 		error = hfsc_remove_altq(a);
    538 		break;
    539 #endif
    540 	default:
    541 		error = ENXIO;
    542 	}
    543 
    544 	return (error);
    545 }
    546 
    547 /*
    548  * add a queue to the discipline
    549  */
    550 int
    551 altq_add_queue(struct pf_altq *a)
    552 {
    553 	int error = 0;
    554 
    555 	switch (a->scheduler) {
    556 #ifdef ALTQ_CBQ
    557 	case ALTQT_CBQ:
    558 		error = cbq_add_queue(a);
    559 		break;
    560 #endif
    561 #ifdef ALTQ_PRIQ
    562 	case ALTQT_PRIQ:
    563 		error = priq_add_queue(a);
    564 		break;
    565 #endif
    566 #ifdef ALTQ_HFSC
    567 	case ALTQT_HFSC:
    568 		error = hfsc_add_queue(a);
    569 		break;
    570 #endif
    571 	default:
    572 		error = ENXIO;
    573 	}
    574 
    575 	return (error);
    576 }
    577 
    578 /*
    579  * remove a queue from the discipline
    580  */
    581 int
    582 altq_remove_queue(struct pf_altq *a)
    583 {
    584 	int error = 0;
    585 
    586 	switch (a->scheduler) {
    587 #ifdef ALTQ_CBQ
    588 	case ALTQT_CBQ:
    589 		error = cbq_remove_queue(a);
    590 		break;
    591 #endif
    592 #ifdef ALTQ_PRIQ
    593 	case ALTQT_PRIQ:
    594 		error = priq_remove_queue(a);
    595 		break;
    596 #endif
    597 #ifdef ALTQ_HFSC
    598 	case ALTQT_HFSC:
    599 		error = hfsc_remove_queue(a);
    600 		break;
    601 #endif
    602 	default:
    603 		error = ENXIO;
    604 	}
    605 
    606 	return (error);
    607 }
    608 
    609 /*
    610  * get queue statistics
    611  */
    612 int
    613 altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
    614 {
    615 	int error = 0;
    616 
    617 	switch (a->scheduler) {
    618 #ifdef ALTQ_CBQ
    619 	case ALTQT_CBQ:
    620 		error = cbq_getqstats(a, ubuf, nbytes);
    621 		break;
    622 #endif
    623 #ifdef ALTQ_PRIQ
    624 	case ALTQT_PRIQ:
    625 		error = priq_getqstats(a, ubuf, nbytes);
    626 		break;
    627 #endif
    628 #ifdef ALTQ_HFSC
    629 	case ALTQT_HFSC:
    630 		error = hfsc_getqstats(a, ubuf, nbytes);
    631 		break;
    632 #endif
    633 	default:
    634 		error = ENXIO;
    635 	}
    636 
    637 	return (error);
    638 }
    639 #endif /* NPF > 0 */
    640 
    641 /*
    642  * read and write diffserv field in IPv4 or IPv6 header
    643  */
    644 u_int8_t
    645 read_dsfield(struct mbuf *m, struct altq_pktattr *pktattr)
    646 {
    647 	struct mbuf *m0;
    648 	u_int8_t ds_field = 0;
    649 
    650 	if (pktattr == NULL ||
    651 	    (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
    652 		return ((u_int8_t)0);
    653 
    654 	/* verify that pattr_hdr is within the mbuf data */
    655 	for (m0 = m; m0 != NULL; m0 = m0->m_next)
    656 		if (((char *)pktattr->pattr_hdr >= m0->m_data) &&
    657 		    ((char *)pktattr->pattr_hdr < m0->m_data + m0->m_len))
    658 			break;
    659 	if (m0 == NULL) {
    660 		/* ick, pattr_hdr is stale */
    661 		pktattr->pattr_af = AF_UNSPEC;
    662 #ifdef ALTQ_DEBUG
    663 		printf("read_dsfield: can't locate header!\n");
    664 #endif
    665 		return ((u_int8_t)0);
    666 	}
    667 
    668 	if (pktattr->pattr_af == AF_INET) {
    669 		struct ip *ip = (struct ip *)pktattr->pattr_hdr;
    670 
    671 		if (ip->ip_v != 4)
    672 			return ((u_int8_t)0);	/* version mismatch! */
    673 		ds_field = ip->ip_tos;
    674 	}
    675 #ifdef INET6
    676 	else if (pktattr->pattr_af == AF_INET6) {
    677 		struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
    678 		u_int32_t flowlabel;
    679 
    680 		flowlabel = ntohl(ip6->ip6_flow);
    681 		if ((flowlabel >> 28) != 6)
    682 			return ((u_int8_t)0);	/* version mismatch! */
    683 		ds_field = (flowlabel >> 20) & 0xff;
    684 	}
    685 #endif
    686 	return (ds_field);
    687 }
    688 
    689 void
    690 write_dsfield(struct mbuf *m, struct altq_pktattr *pktattr, u_int8_t dsfield)
    691 {
    692 	struct mbuf *m0;
    693 
    694 	if (pktattr == NULL ||
    695 	    (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
    696 		return;
    697 
    698 	/* verify that pattr_hdr is within the mbuf data */
    699 	for (m0 = m; m0 != NULL; m0 = m0->m_next)
    700 		if (((char *)pktattr->pattr_hdr >= m0->m_data) &&
    701 		    ((char *)pktattr->pattr_hdr < m0->m_data + m0->m_len))
    702 			break;
    703 	if (m0 == NULL) {
    704 		/* ick, pattr_hdr is stale */
    705 		pktattr->pattr_af = AF_UNSPEC;
    706 #ifdef ALTQ_DEBUG
    707 		printf("write_dsfield: can't locate header!\n");
    708 #endif
    709 		return;
    710 	}
    711 
    712 	if (pktattr->pattr_af == AF_INET) {
    713 		struct ip *ip = (struct ip *)pktattr->pattr_hdr;
    714 		u_int8_t old;
    715 		int32_t sum;
    716 
    717 		if (ip->ip_v != 4)
    718 			return;		/* version mismatch! */
    719 		old = ip->ip_tos;
    720 		dsfield |= old & 3;	/* leave CU bits */
    721 		if (old == dsfield)
    722 			return;
    723 		ip->ip_tos = dsfield;
    724 		/*
    725 		 * update checksum (from RFC1624)
    726 		 *	   HC' = ~(~HC + ~m + m')
    727 		 */
    728 		sum = ~ntohs(ip->ip_sum) & 0xffff;
    729 		sum += 0xff00 + (~old & 0xff) + dsfield;
    730 		sum = (sum >> 16) + (sum & 0xffff);
    731 		sum += (sum >> 16);  /* add carry */
    732 
    733 		ip->ip_sum = htons(~sum & 0xffff);
    734 	}
    735 #ifdef INET6
    736 	else if (pktattr->pattr_af == AF_INET6) {
    737 		struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
    738 		u_int32_t flowlabel;
    739 
    740 		flowlabel = ntohl(ip6->ip6_flow);
    741 		if ((flowlabel >> 28) != 6)
    742 			return;		/* version mismatch! */
    743 		flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20);
    744 		ip6->ip6_flow = htonl(flowlabel);
    745 	}
    746 #endif
    747 	return;
    748 }
    749 
    750 
    751 /*
    752  * high resolution clock support taking advantage of a machine dependent
    753  * high resolution time counter (e.g., timestamp counter of intel pentium).
    754  * we assume
    755  *  - 64-bit-long monotonically-increasing counter
    756  *  - frequency range is 100M-4GHz (CPU speed)
    757  */
    758 /* if pcc is not available or disabled, emulate 256MHz using microtime() */
    759 #define	MACHCLK_SHIFT	8
    760 
    761 int machclk_usepcc;
    762 u_int32_t machclk_freq = 0;
    763 u_int32_t machclk_per_tick = 0;
    764 
    765 #ifdef __alpha__
    766 #ifdef __FreeBSD__
    767 extern u_int32_t cycles_per_sec;	/* alpha cpu clock frequency */
    768 #elif defined(__NetBSD__) || defined(__OpenBSD__)
    769 extern u_int64_t cycles_per_usec;	/* alpha cpu clock frequency */
    770 #endif
    771 #endif /* __alpha__ */
    772 
    773 void
    774 init_machclk(void)
    775 {
    776 
    777 	callout_init(&tbr_callout, 0);
    778 
    779 #ifdef __HAVE_CPU_COUNTER
    780 	/* check if TSC is available */
    781 	machclk_usepcc = cpu_hascounter();
    782 	machclk_freq = cpu_frequency(curcpu());
    783 #endif
    784 
    785 	if (machclk_usepcc == 0) {
    786 		/* emulate 256MHz using microtime() */
    787 		machclk_freq = 1000000 << MACHCLK_SHIFT;
    788 		machclk_per_tick = machclk_freq / hz;
    789 #ifdef ALTQ_DEBUG
    790 		printf("altq: emulate %uHz CPU clock\n", machclk_freq);
    791 #endif
    792 		return;
    793 	}
    794 
    795 	/*
    796 	 * if we don't know the clock frequency, measure it.
    797 	 */
    798 	if (machclk_freq == 0) {
    799 		static int	wait;
    800 		struct timeval	tv_start, tv_end;
    801 		u_int64_t	start, end, diff;
    802 		int		timo;
    803 
    804 		microtime(&tv_start);
    805 		start = read_machclk();
    806 		timo = hz;	/* 1 sec */
    807 		(void)tsleep(&wait, PWAIT | PCATCH, "init_machclk", timo);
    808 		microtime(&tv_end);
    809 		end = read_machclk();
    810 		diff = (u_int64_t)(tv_end.tv_sec - tv_start.tv_sec) * 1000000
    811 		    + tv_end.tv_usec - tv_start.tv_usec;
    812 		if (diff != 0)
    813 			machclk_freq = (u_int)((end - start) * 1000000 / diff);
    814 	}
    815 
    816 	machclk_per_tick = machclk_freq / hz;
    817 
    818 #ifdef ALTQ_DEBUG
    819 	printf("altq: CPU clock: %uHz\n", machclk_freq);
    820 #endif
    821 }
    822 
    823 u_int64_t
    824 read_machclk(void)
    825 {
    826 	u_int64_t val;
    827 
    828 	if (machclk_usepcc) {
    829 #ifdef __HAVE_CPU_COUNTER
    830 		return cpu_counter();
    831 #endif
    832 	} else {
    833 		struct timeval tv;
    834 
    835 		microtime(&tv);
    836 		val = (((u_int64_t)(tv.tv_sec - boottime.tv_sec) * 1000000
    837 		    + tv.tv_usec) << MACHCLK_SHIFT);
    838 	}
    839 	return (val);
    840 }
    841 
    842 #ifdef ALTQ3_CLFIER_COMPAT
    843 
    844 #ifndef IPPROTO_ESP
    845 #define	IPPROTO_ESP	50		/* encapsulating security payload */
    846 #endif
    847 #ifndef IPPROTO_AH
    848 #define	IPPROTO_AH	51		/* authentication header */
    849 #endif
    850 
    851 /*
    852  * extract flow information from a given packet.
    853  * filt_mask shows flowinfo fields required.
    854  * we assume the ip header is in one mbuf, and addresses and ports are
    855  * in network byte order.
    856  */
    857 int
    858 altq_extractflow(struct mbuf *m, int af, struct flowinfo *flow,
    859     u_int32_t filt_bmask)
    860 {
    861 
    862 	switch (af) {
    863 	case PF_INET: {
    864 		struct flowinfo_in *fin;
    865 		struct ip *ip;
    866 
    867 		ip = mtod(m, struct ip *);
    868 
    869 		if (ip->ip_v != 4)
    870 			break;
    871 
    872 		fin = (struct flowinfo_in *)flow;
    873 		fin->fi_len = sizeof(struct flowinfo_in);
    874 		fin->fi_family = AF_INET;
    875 
    876 		fin->fi_proto = ip->ip_p;
    877 		fin->fi_tos = ip->ip_tos;
    878 
    879 		fin->fi_src.s_addr = ip->ip_src.s_addr;
    880 		fin->fi_dst.s_addr = ip->ip_dst.s_addr;
    881 
    882 		if (filt_bmask & FIMB4_PORTS)
    883 			/* if port info is required, extract port numbers */
    884 			extract_ports4(m, ip, fin);
    885 		else {
    886 			fin->fi_sport = 0;
    887 			fin->fi_dport = 0;
    888 			fin->fi_gpi = 0;
    889 		}
    890 		return (1);
    891 	}
    892 
    893 #ifdef INET6
    894 	case PF_INET6: {
    895 		struct flowinfo_in6 *fin6;
    896 		struct ip6_hdr *ip6;
    897 
    898 		ip6 = mtod(m, struct ip6_hdr *);
    899 		/* should we check the ip version? */
    900 
    901 		fin6 = (struct flowinfo_in6 *)flow;
    902 		fin6->fi6_len = sizeof(struct flowinfo_in6);
    903 		fin6->fi6_family = AF_INET6;
    904 
    905 		fin6->fi6_proto = ip6->ip6_nxt;
    906 		fin6->fi6_tclass   = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
    907 
    908 		fin6->fi6_flowlabel = ip6->ip6_flow & htonl(0x000fffff);
    909 		fin6->fi6_src = ip6->ip6_src;
    910 		fin6->fi6_dst = ip6->ip6_dst;
    911 
    912 		if ((filt_bmask & FIMB6_PORTS) ||
    913 		    ((filt_bmask & FIMB6_PROTO)
    914 		     && ip6->ip6_nxt > IPPROTO_IPV6))
    915 			/*
    916 			 * if port info is required, or proto is required
    917 			 * but there are option headers, extract port
    918 			 * and protocol numbers.
    919 			 */
    920 			extract_ports6(m, ip6, fin6);
    921 		else {
    922 			fin6->fi6_sport = 0;
    923 			fin6->fi6_dport = 0;
    924 			fin6->fi6_gpi = 0;
    925 		}
    926 		return (1);
    927 	}
    928 #endif /* INET6 */
    929 
    930 	default:
    931 		break;
    932 	}
    933 
    934 	/* failed */
    935 	flow->fi_len = sizeof(struct flowinfo);
    936 	flow->fi_family = AF_UNSPEC;
    937 	return (0);
    938 }
    939 
    940 /*
    941  * helper routine to extract port numbers
    942  */
    943 /* structure for ipsec and ipv6 option header template */
    944 struct _opt6 {
    945 	u_int8_t	opt6_nxt;	/* next header */
    946 	u_int8_t	opt6_hlen;	/* header extension length */
    947 	u_int16_t	_pad;
    948 	u_int32_t	ah_spi;		/* security parameter index
    949 					   for authentication header */
    950 };
    951 
    952 /*
    953  * extract port numbers from a ipv4 packet.
    954  */
    955 static int
    956 extract_ports4(struct mbuf *m, struct ip *ip, struct flowinfo_in *fin)
    957 {
    958 	struct mbuf *m0;
    959 	u_short ip_off;
    960 	u_int8_t proto;
    961 	int 	off;
    962 
    963 	fin->fi_sport = 0;
    964 	fin->fi_dport = 0;
    965 	fin->fi_gpi = 0;
    966 
    967 	ip_off = ntohs(ip->ip_off);
    968 	/* if it is a fragment, try cached fragment info */
    969 	if (ip_off & IP_OFFMASK) {
    970 		ip4f_lookup(ip, fin);
    971 		return (1);
    972 	}
    973 
    974 	/* locate the mbuf containing the protocol header */
    975 	for (m0 = m; m0 != NULL; m0 = m0->m_next)
    976 		if (((char *)ip >= m0->m_data) &&
    977 		    ((char *)ip < m0->m_data + m0->m_len))
    978 			break;
    979 	if (m0 == NULL) {
    980 #ifdef ALTQ_DEBUG
    981 		printf("extract_ports4: can't locate header! ip=%p\n", ip);
    982 #endif
    983 		return (0);
    984 	}
    985 	off = ((char *)ip - m0->m_data) + (ip->ip_hl << 2);
    986 	proto = ip->ip_p;
    987 
    988 #ifdef ALTQ_IPSEC
    989  again:
    990 #endif
    991 	while (off >= m0->m_len) {
    992 		off -= m0->m_len;
    993 		m0 = m0->m_next;
    994 		if (m0 == NULL)
    995 			return (0);  /* bogus ip_hl! */
    996 	}
    997 	if (m0->m_len < off + 4)
    998 		return (0);
    999 
   1000 	switch (proto) {
   1001 	case IPPROTO_TCP:
   1002 	case IPPROTO_UDP: {
   1003 		struct udphdr *udp;
   1004 
   1005 		udp = (struct udphdr *)(mtod(m0, char *) + off);
   1006 		fin->fi_sport = udp->uh_sport;
   1007 		fin->fi_dport = udp->uh_dport;
   1008 		fin->fi_proto = proto;
   1009 		}
   1010 		break;
   1011 
   1012 #ifdef ALTQ_IPSEC
   1013 	case IPPROTO_ESP:
   1014 		if (fin->fi_gpi == 0){
   1015 			u_int32_t *gpi;
   1016 
   1017 			gpi = (u_int32_t *)(mtod(m0, char *) + off);
   1018 			fin->fi_gpi   = *gpi;
   1019 		}
   1020 		fin->fi_proto = proto;
   1021 		break;
   1022 
   1023 	case IPPROTO_AH: {
   1024 			/* get next header and header length */
   1025 			struct _opt6 *opt6;
   1026 
   1027 			opt6 = (struct _opt6 *)(mtod(m0, char *) + off);
   1028 			proto = opt6->opt6_nxt;
   1029 			off += 8 + (opt6->opt6_hlen * 4);
   1030 			if (fin->fi_gpi == 0 && m0->m_len >= off + 8)
   1031 				fin->fi_gpi = opt6->ah_spi;
   1032 		}
   1033 		/* goto the next header */
   1034 		goto again;
   1035 #endif  /* ALTQ_IPSEC */
   1036 
   1037 	default:
   1038 		fin->fi_proto = proto;
   1039 		return (0);
   1040 	}
   1041 
   1042 	/* if this is a first fragment, cache it. */
   1043 	if (ip_off & IP_MF)
   1044 		ip4f_cache(ip, fin);
   1045 
   1046 	return (1);
   1047 }
   1048 
   1049 #ifdef INET6
   1050 static int
   1051 extract_ports6(struct mbuf *m, struct ip6_hdr *ip6, struct flowinfo_in6 *fin6)
   1052 {
   1053 	struct mbuf *m0;
   1054 	int	off;
   1055 	u_int8_t proto;
   1056 
   1057 	fin6->fi6_gpi   = 0;
   1058 	fin6->fi6_sport = 0;
   1059 	fin6->fi6_dport = 0;
   1060 
   1061 	/* locate the mbuf containing the protocol header */
   1062 	for (m0 = m; m0 != NULL; m0 = m0->m_next)
   1063 		if (((char *)ip6 >= m0->m_data) &&
   1064 		    ((char *)ip6 < m0->m_data + m0->m_len))
   1065 			break;
   1066 	if (m0 == NULL) {
   1067 #ifdef ALTQ_DEBUG
   1068 		printf("extract_ports6: can't locate header! ip6=%p\n", ip6);
   1069 #endif
   1070 		return (0);
   1071 	}
   1072 	off = ((char *)ip6 - m0->m_data) + sizeof(struct ip6_hdr);
   1073 
   1074 	proto = ip6->ip6_nxt;
   1075 	do {
   1076 		while (off >= m0->m_len) {
   1077 			off -= m0->m_len;
   1078 			m0 = m0->m_next;
   1079 			if (m0 == NULL)
   1080 				return (0);
   1081 		}
   1082 		if (m0->m_len < off + 4)
   1083 			return (0);
   1084 
   1085 		switch (proto) {
   1086 		case IPPROTO_TCP:
   1087 		case IPPROTO_UDP: {
   1088 			struct udphdr *udp;
   1089 
   1090 			udp = (struct udphdr *)(mtod(m0, char *) + off);
   1091 			fin6->fi6_sport = udp->uh_sport;
   1092 			fin6->fi6_dport = udp->uh_dport;
   1093 			fin6->fi6_proto = proto;
   1094 			}
   1095 			return (1);
   1096 
   1097 		case IPPROTO_ESP:
   1098 			if (fin6->fi6_gpi == 0) {
   1099 				u_int32_t *gpi;
   1100 
   1101 				gpi = (u_int32_t *)(mtod(m0, char *) + off);
   1102 				fin6->fi6_gpi   = *gpi;
   1103 			}
   1104 			fin6->fi6_proto = proto;
   1105 			return (1);
   1106 
   1107 		case IPPROTO_AH: {
   1108 			/* get next header and header length */
   1109 			struct _opt6 *opt6;
   1110 
   1111 			opt6 = (struct _opt6 *)(mtod(m0, char *) + off);
   1112 			if (fin6->fi6_gpi == 0 && m0->m_len >= off + 8)
   1113 				fin6->fi6_gpi = opt6->ah_spi;
   1114 			proto = opt6->opt6_nxt;
   1115 			off += 8 + (opt6->opt6_hlen * 4);
   1116 			/* goto the next header */
   1117 			break;
   1118 			}
   1119 
   1120 		case IPPROTO_HOPOPTS:
   1121 		case IPPROTO_ROUTING:
   1122 		case IPPROTO_DSTOPTS: {
   1123 			/* get next header and header length */
   1124 			struct _opt6 *opt6;
   1125 
   1126 			opt6 = (struct _opt6 *)(mtod(m0, char *) + off);
   1127 			proto = opt6->opt6_nxt;
   1128 			off += (opt6->opt6_hlen + 1) * 8;
   1129 			/* goto the next header */
   1130 			break;
   1131 			}
   1132 
   1133 		case IPPROTO_FRAGMENT:
   1134 			/* ipv6 fragmentations are not supported yet */
   1135 		default:
   1136 			fin6->fi6_proto = proto;
   1137 			return (0);
   1138 		}
   1139 	} while (1);
   1140 	/*NOTREACHED*/
   1141 }
   1142 #endif /* INET6 */
   1143 
   1144 /*
   1145  * altq common classifier
   1146  */
   1147 int
   1148 acc_add_filter(struct acc_classifier *classifier, struct flow_filter *filter,
   1149     void *class, u_long *phandle)
   1150 {
   1151 	struct acc_filter *afp, *prev, *tmp;
   1152 	int	i, s;
   1153 
   1154 #ifdef INET6
   1155 	if (filter->ff_flow.fi_family != AF_INET &&
   1156 	    filter->ff_flow.fi_family != AF_INET6)
   1157 		return (EINVAL);
   1158 #else
   1159 	if (filter->ff_flow.fi_family != AF_INET)
   1160 		return (EINVAL);
   1161 #endif
   1162 
   1163 	afp = malloc(sizeof(struct acc_filter), M_DEVBUF, M_WAITOK|M_ZERO);
   1164 	if (afp == NULL)
   1165 		return (ENOMEM);
   1166 
   1167 	afp->f_filter = *filter;
   1168 	afp->f_class = class;
   1169 
   1170 	i = ACC_WILDCARD_INDEX;
   1171 	if (filter->ff_flow.fi_family == AF_INET) {
   1172 		struct flow_filter *filter4 = &afp->f_filter;
   1173 
   1174 		/*
   1175 		 * if address is 0, it's a wildcard.  if address mask
   1176 		 * isn't set, use full mask.
   1177 		 */
   1178 		if (filter4->ff_flow.fi_dst.s_addr == 0)
   1179 			filter4->ff_mask.mask_dst.s_addr = 0;
   1180 		else if (filter4->ff_mask.mask_dst.s_addr == 0)
   1181 			filter4->ff_mask.mask_dst.s_addr = 0xffffffff;
   1182 		if (filter4->ff_flow.fi_src.s_addr == 0)
   1183 			filter4->ff_mask.mask_src.s_addr = 0;
   1184 		else if (filter4->ff_mask.mask_src.s_addr == 0)
   1185 			filter4->ff_mask.mask_src.s_addr = 0xffffffff;
   1186 
   1187 		/* clear extra bits in addresses  */
   1188 		   filter4->ff_flow.fi_dst.s_addr &=
   1189 		       filter4->ff_mask.mask_dst.s_addr;
   1190 		   filter4->ff_flow.fi_src.s_addr &=
   1191 		       filter4->ff_mask.mask_src.s_addr;
   1192 
   1193 		/*
   1194 		 * if dst address is a wildcard, use hash-entry
   1195 		 * ACC_WILDCARD_INDEX.
   1196 		 */
   1197 		if (filter4->ff_mask.mask_dst.s_addr != 0xffffffff)
   1198 			i = ACC_WILDCARD_INDEX;
   1199 		else
   1200 			i = ACC_GET_HASH_INDEX(filter4->ff_flow.fi_dst.s_addr);
   1201 	}
   1202 #ifdef INET6
   1203 	else if (filter->ff_flow.fi_family == AF_INET6) {
   1204 		struct flow_filter6 *filter6 =
   1205 			(struct flow_filter6 *)&afp->f_filter;
   1206 #ifndef IN6MASK0 /* taken from kame ipv6 */
   1207 #define	IN6MASK0	{{{ 0, 0, 0, 0 }}}
   1208 #define	IN6MASK128	{{{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }}}
   1209 		const struct in6_addr in6mask0 = IN6MASK0;
   1210 		const struct in6_addr in6mask128 = IN6MASK128;
   1211 #endif
   1212 
   1213 		if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_flow6.fi6_dst))
   1214 			filter6->ff_mask6.mask6_dst = in6mask0;
   1215 		else if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_mask6.mask6_dst))
   1216 			filter6->ff_mask6.mask6_dst = in6mask128;
   1217 		if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_flow6.fi6_src))
   1218 			filter6->ff_mask6.mask6_src = in6mask0;
   1219 		else if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_mask6.mask6_src))
   1220 			filter6->ff_mask6.mask6_src = in6mask128;
   1221 
   1222 		/* clear extra bits in addresses  */
   1223 		for (i = 0; i < 16; i++)
   1224 			filter6->ff_flow6.fi6_dst.s6_addr[i] &=
   1225 			    filter6->ff_mask6.mask6_dst.s6_addr[i];
   1226 		for (i = 0; i < 16; i++)
   1227 			filter6->ff_flow6.fi6_src.s6_addr[i] &=
   1228 			    filter6->ff_mask6.mask6_src.s6_addr[i];
   1229 
   1230 		if (filter6->ff_flow6.fi6_flowlabel == 0)
   1231 			i = ACC_WILDCARD_INDEX;
   1232 		else
   1233 			i = ACC_GET_HASH_INDEX(filter6->ff_flow6.fi6_flowlabel);
   1234 	}
   1235 #endif /* INET6 */
   1236 
   1237 	afp->f_handle = get_filt_handle(classifier, i);
   1238 
   1239 	/* update filter bitmask */
   1240 	afp->f_fbmask = filt2fibmask(filter);
   1241 	classifier->acc_fbmask |= afp->f_fbmask;
   1242 
   1243 	/*
   1244 	 * add this filter to the filter list.
   1245 	 * filters are ordered from the highest rule number.
   1246 	 */
   1247 	s = splnet();
   1248 	prev = NULL;
   1249 	LIST_FOREACH(tmp, &classifier->acc_filters[i], f_chain) {
   1250 		if (tmp->f_filter.ff_ruleno > afp->f_filter.ff_ruleno)
   1251 			prev = tmp;
   1252 		else
   1253 			break;
   1254 	}
   1255 	if (prev == NULL)
   1256 		LIST_INSERT_HEAD(&classifier->acc_filters[i], afp, f_chain);
   1257 	else
   1258 		LIST_INSERT_AFTER(prev, afp, f_chain);
   1259 	splx(s);
   1260 
   1261 	*phandle = afp->f_handle;
   1262 	return (0);
   1263 }
   1264 
   1265 int
   1266 acc_delete_filter(struct acc_classifier *classifier, u_long handle)
   1267 {
   1268 	struct acc_filter *afp;
   1269 	int	s;
   1270 
   1271 	if ((afp = filth_to_filtp(classifier, handle)) == NULL)
   1272 		return (EINVAL);
   1273 
   1274 	s = splnet();
   1275 	LIST_REMOVE(afp, f_chain);
   1276 	splx(s);
   1277 
   1278 	free(afp, M_DEVBUF);
   1279 
   1280 	/* todo: update filt_bmask */
   1281 
   1282 	return (0);
   1283 }
   1284 
   1285 /*
   1286  * delete filters referencing to the specified class.
   1287  * if the all flag is not 0, delete all the filters.
   1288  */
   1289 int
   1290 acc_discard_filters(struct acc_classifier *classifier, void *class, int all)
   1291 {
   1292 	struct acc_filter *afp;
   1293 	int	i, s;
   1294 
   1295 	s = splnet();
   1296 	for (i = 0; i < ACC_FILTER_TABLESIZE; i++) {
   1297 		do {
   1298 			LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
   1299 				if (all || afp->f_class == class) {
   1300 					LIST_REMOVE(afp, f_chain);
   1301 					free(afp, M_DEVBUF);
   1302 					/* start again from the head */
   1303 					break;
   1304 				}
   1305 		} while (afp != NULL);
   1306 	}
   1307 	splx(s);
   1308 
   1309 	if (all)
   1310 		classifier->acc_fbmask = 0;
   1311 
   1312 	return (0);
   1313 }
   1314 
   1315 void *
   1316 acc_classify(void *clfier, struct mbuf *m, int af)
   1317 {
   1318 	struct acc_classifier *classifier;
   1319 	struct flowinfo flow;
   1320 	struct acc_filter *afp;
   1321 	int	i;
   1322 
   1323 	classifier = (struct acc_classifier *)clfier;
   1324 	altq_extractflow(m, af, &flow, classifier->acc_fbmask);
   1325 
   1326 	if (flow.fi_family == AF_INET) {
   1327 		struct flowinfo_in *fp = (struct flowinfo_in *)&flow;
   1328 
   1329 		if ((classifier->acc_fbmask & FIMB4_ALL) == FIMB4_TOS) {
   1330 			/* only tos is used */
   1331 			LIST_FOREACH(afp,
   1332 				 &classifier->acc_filters[ACC_WILDCARD_INDEX],
   1333 				 f_chain)
   1334 				if (apply_tosfilter4(afp->f_fbmask,
   1335 						     &afp->f_filter, fp))
   1336 					/* filter matched */
   1337 					return (afp->f_class);
   1338 		} else if ((classifier->acc_fbmask &
   1339 			(~(FIMB4_PROTO|FIMB4_SPORT|FIMB4_DPORT) & FIMB4_ALL))
   1340 		    == 0) {
   1341 			/* only proto and ports are used */
   1342 			LIST_FOREACH(afp,
   1343 				 &classifier->acc_filters[ACC_WILDCARD_INDEX],
   1344 				 f_chain)
   1345 				if (apply_ppfilter4(afp->f_fbmask,
   1346 						    &afp->f_filter, fp))
   1347 					/* filter matched */
   1348 					return (afp->f_class);
   1349 		} else {
   1350 			/* get the filter hash entry from its dest address */
   1351 			i = ACC_GET_HASH_INDEX(fp->fi_dst.s_addr);
   1352 			do {
   1353 				/*
   1354 				 * go through this loop twice.  first for dst
   1355 				 * hash, second for wildcards.
   1356 				 */
   1357 				LIST_FOREACH(afp, &classifier->acc_filters[i],
   1358 					     f_chain)
   1359 					if (apply_filter4(afp->f_fbmask,
   1360 							  &afp->f_filter, fp))
   1361 						/* filter matched */
   1362 						return (afp->f_class);
   1363 
   1364 				/*
   1365 				 * check again for filters with a dst addr
   1366 				 * wildcard.
   1367 				 * (daddr == 0 || dmask != 0xffffffff).
   1368 				 */
   1369 				if (i != ACC_WILDCARD_INDEX)
   1370 					i = ACC_WILDCARD_INDEX;
   1371 				else
   1372 					break;
   1373 			} while (1);
   1374 		}
   1375 	}
   1376 #ifdef INET6
   1377 	else if (flow.fi_family == AF_INET6) {
   1378 		struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)&flow;
   1379 
   1380 		/* get the filter hash entry from its flow ID */
   1381 		if (fp6->fi6_flowlabel != 0)
   1382 			i = ACC_GET_HASH_INDEX(fp6->fi6_flowlabel);
   1383 		else
   1384 			/* flowlable can be zero */
   1385 			i = ACC_WILDCARD_INDEX;
   1386 
   1387 		/* go through this loop twice.  first for flow hash, second
   1388 		   for wildcards. */
   1389 		do {
   1390 			LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
   1391 				if (apply_filter6(afp->f_fbmask,
   1392 					(struct flow_filter6 *)&afp->f_filter,
   1393 					fp6))
   1394 					/* filter matched */
   1395 					return (afp->f_class);
   1396 
   1397 			/*
   1398 			 * check again for filters with a wildcard.
   1399 			 */
   1400 			if (i != ACC_WILDCARD_INDEX)
   1401 				i = ACC_WILDCARD_INDEX;
   1402 			else
   1403 				break;
   1404 		} while (1);
   1405 	}
   1406 #endif /* INET6 */
   1407 
   1408 	/* no filter matched */
   1409 	return (NULL);
   1410 }
   1411 
   1412 static int
   1413 apply_filter4(u_int32_t fbmask, struct flow_filter *filt,
   1414     struct flowinfo_in *pkt)
   1415 {
   1416 	if (filt->ff_flow.fi_family != AF_INET)
   1417 		return (0);
   1418 	if ((fbmask & FIMB4_SPORT) && filt->ff_flow.fi_sport != pkt->fi_sport)
   1419 		return (0);
   1420 	if ((fbmask & FIMB4_DPORT) && filt->ff_flow.fi_dport != pkt->fi_dport)
   1421 		return (0);
   1422 	if ((fbmask & FIMB4_DADDR) &&
   1423 	    filt->ff_flow.fi_dst.s_addr !=
   1424 	    (pkt->fi_dst.s_addr & filt->ff_mask.mask_dst.s_addr))
   1425 		return (0);
   1426 	if ((fbmask & FIMB4_SADDR) &&
   1427 	    filt->ff_flow.fi_src.s_addr !=
   1428 	    (pkt->fi_src.s_addr & filt->ff_mask.mask_src.s_addr))
   1429 		return (0);
   1430 	if ((fbmask & FIMB4_PROTO) && filt->ff_flow.fi_proto != pkt->fi_proto)
   1431 		return (0);
   1432 	if ((fbmask & FIMB4_TOS) && filt->ff_flow.fi_tos !=
   1433 	    (pkt->fi_tos & filt->ff_mask.mask_tos))
   1434 		return (0);
   1435 	if ((fbmask & FIMB4_GPI) && filt->ff_flow.fi_gpi != (pkt->fi_gpi))
   1436 		return (0);
   1437 	/* match */
   1438 	return (1);
   1439 }
   1440 
   1441 /*
   1442  * filter matching function optimized for a common case that checks
   1443  * only protocol and port numbers
   1444  */
   1445 static int
   1446 apply_ppfilter4(u_int32_t fbmask, struct flow_filter *filt,
   1447     struct flowinfo_in *pkt)
   1448 {
   1449 	if (filt->ff_flow.fi_family != AF_INET)
   1450 		return (0);
   1451 	if ((fbmask & FIMB4_SPORT) && filt->ff_flow.fi_sport != pkt->fi_sport)
   1452 		return (0);
   1453 	if ((fbmask & FIMB4_DPORT) && filt->ff_flow.fi_dport != pkt->fi_dport)
   1454 		return (0);
   1455 	if ((fbmask & FIMB4_PROTO) && filt->ff_flow.fi_proto != pkt->fi_proto)
   1456 		return (0);
   1457 	/* match */
   1458 	return (1);
   1459 }
   1460 
   1461 /*
   1462  * filter matching function only for tos field.
   1463  */
   1464 static int
   1465 apply_tosfilter4(u_int32_t fbmask, struct flow_filter *filt,
   1466     struct flowinfo_in *pkt)
   1467 {
   1468 	if (filt->ff_flow.fi_family != AF_INET)
   1469 		return (0);
   1470 	if ((fbmask & FIMB4_TOS) && filt->ff_flow.fi_tos !=
   1471 	    (pkt->fi_tos & filt->ff_mask.mask_tos))
   1472 		return (0);
   1473 	/* match */
   1474 	return (1);
   1475 }
   1476 
   1477 #ifdef INET6
   1478 static int
   1479 apply_filter6(u_int32_t fbmask, struct flow_filter6 *filt,
   1480     struct flowinfo_in6 *pkt)
   1481 {
   1482 	int i;
   1483 
   1484 	if (filt->ff_flow6.fi6_family != AF_INET6)
   1485 		return (0);
   1486 	if ((fbmask & FIMB6_FLABEL) &&
   1487 	    filt->ff_flow6.fi6_flowlabel != pkt->fi6_flowlabel)
   1488 		return (0);
   1489 	if ((fbmask & FIMB6_PROTO) &&
   1490 	    filt->ff_flow6.fi6_proto != pkt->fi6_proto)
   1491 		return (0);
   1492 	if ((fbmask & FIMB6_SPORT) &&
   1493 	    filt->ff_flow6.fi6_sport != pkt->fi6_sport)
   1494 		return (0);
   1495 	if ((fbmask & FIMB6_DPORT) &&
   1496 	    filt->ff_flow6.fi6_dport != pkt->fi6_dport)
   1497 		return (0);
   1498 	if (fbmask & FIMB6_SADDR) {
   1499 		for (i = 0; i < 4; i++)
   1500 			if (filt->ff_flow6.fi6_src.s6_addr32[i] !=
   1501 			    (pkt->fi6_src.s6_addr32[i] &
   1502 			     filt->ff_mask6.mask6_src.s6_addr32[i]))
   1503 				return (0);
   1504 	}
   1505 	if (fbmask & FIMB6_DADDR) {
   1506 		for (i = 0; i < 4; i++)
   1507 			if (filt->ff_flow6.fi6_dst.s6_addr32[i] !=
   1508 			    (pkt->fi6_dst.s6_addr32[i] &
   1509 			     filt->ff_mask6.mask6_dst.s6_addr32[i]))
   1510 				return (0);
   1511 	}
   1512 	if ((fbmask & FIMB6_TCLASS) &&
   1513 	    filt->ff_flow6.fi6_tclass !=
   1514 	    (pkt->fi6_tclass & filt->ff_mask6.mask6_tclass))
   1515 		return (0);
   1516 	if ((fbmask & FIMB6_GPI) &&
   1517 	    filt->ff_flow6.fi6_gpi != pkt->fi6_gpi)
   1518 		return (0);
   1519 	/* match */
   1520 	return (1);
   1521 }
   1522 #endif /* INET6 */
   1523 
   1524 /*
   1525  *  filter handle:
   1526  *	bit 20-28: index to the filter hash table
   1527  *	bit  0-19: unique id in the hash bucket.
   1528  */
   1529 static u_long
   1530 get_filt_handle(struct acc_classifier *classifier, int i)
   1531 {
   1532 	static u_long handle_number = 1;
   1533 	u_long 	handle;
   1534 	struct acc_filter *afp;
   1535 
   1536 	while (1) {
   1537 		handle = handle_number++ & 0x000fffff;
   1538 
   1539 		if (LIST_EMPTY(&classifier->acc_filters[i]))
   1540 			break;
   1541 
   1542 		LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
   1543 			if ((afp->f_handle & 0x000fffff) == handle)
   1544 				break;
   1545 		if (afp == NULL)
   1546 			break;
   1547 		/* this handle is already used, try again */
   1548 	}
   1549 
   1550 	return ((i << 20) | handle);
   1551 }
   1552 
   1553 /* convert filter handle to filter pointer */
   1554 static struct acc_filter *
   1555 filth_to_filtp(struct acc_classifier *classifier, u_long handle)
   1556 {
   1557 	struct acc_filter *afp;
   1558 	int	i;
   1559 
   1560 	i = ACC_GET_HINDEX(handle);
   1561 
   1562 	LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
   1563 		if (afp->f_handle == handle)
   1564 			return (afp);
   1565 
   1566 	return (NULL);
   1567 }
   1568 
   1569 /* create flowinfo bitmask */
   1570 static u_int32_t
   1571 filt2fibmask(struct flow_filter *filt)
   1572 {
   1573 	u_int32_t mask = 0;
   1574 #ifdef INET6
   1575 	struct flow_filter6 *filt6;
   1576 #endif
   1577 
   1578 	switch (filt->ff_flow.fi_family) {
   1579 	case AF_INET:
   1580 		if (filt->ff_flow.fi_proto != 0)
   1581 			mask |= FIMB4_PROTO;
   1582 		if (filt->ff_flow.fi_tos != 0)
   1583 			mask |= FIMB4_TOS;
   1584 		if (filt->ff_flow.fi_dst.s_addr != 0)
   1585 			mask |= FIMB4_DADDR;
   1586 		if (filt->ff_flow.fi_src.s_addr != 0)
   1587 			mask |= FIMB4_SADDR;
   1588 		if (filt->ff_flow.fi_sport != 0)
   1589 			mask |= FIMB4_SPORT;
   1590 		if (filt->ff_flow.fi_dport != 0)
   1591 			mask |= FIMB4_DPORT;
   1592 		if (filt->ff_flow.fi_gpi != 0)
   1593 			mask |= FIMB4_GPI;
   1594 		break;
   1595 #ifdef INET6
   1596 	case AF_INET6:
   1597 		filt6 = (struct flow_filter6 *)filt;
   1598 
   1599 		if (filt6->ff_flow6.fi6_proto != 0)
   1600 			mask |= FIMB6_PROTO;
   1601 		if (filt6->ff_flow6.fi6_tclass != 0)
   1602 			mask |= FIMB6_TCLASS;
   1603 		if (!IN6_IS_ADDR_UNSPECIFIED(&filt6->ff_flow6.fi6_dst))
   1604 			mask |= FIMB6_DADDR;
   1605 		if (!IN6_IS_ADDR_UNSPECIFIED(&filt6->ff_flow6.fi6_src))
   1606 			mask |= FIMB6_SADDR;
   1607 		if (filt6->ff_flow6.fi6_sport != 0)
   1608 			mask |= FIMB6_SPORT;
   1609 		if (filt6->ff_flow6.fi6_dport != 0)
   1610 			mask |= FIMB6_DPORT;
   1611 		if (filt6->ff_flow6.fi6_gpi != 0)
   1612 			mask |= FIMB6_GPI;
   1613 		if (filt6->ff_flow6.fi6_flowlabel != 0)
   1614 			mask |= FIMB6_FLABEL;
   1615 		break;
   1616 #endif /* INET6 */
   1617 	}
   1618 	return (mask);
   1619 }
   1620 
   1621 
   1622 /*
   1623  * helper functions to handle IPv4 fragments.
   1624  * currently only in-sequence fragments are handled.
   1625  *	- fragment info is cached in a LRU list.
   1626  *	- when a first fragment is found, cache its flow info.
   1627  *	- when a non-first fragment is found, lookup the cache.
   1628  */
   1629 
   1630 struct ip4_frag {
   1631     TAILQ_ENTRY(ip4_frag) ip4f_chain;
   1632     char    ip4f_valid;
   1633     u_short ip4f_id;
   1634     struct flowinfo_in ip4f_info;
   1635 };
   1636 
   1637 static TAILQ_HEAD(ip4f_list, ip4_frag) ip4f_list; /* IPv4 fragment cache */
   1638 
   1639 #define	IP4F_TABSIZE		16	/* IPv4 fragment cache size */
   1640 
   1641 
   1642 static void
   1643 ip4f_cache(struct ip *ip, struct flowinfo_in *fin)
   1644 {
   1645 	struct ip4_frag *fp;
   1646 
   1647 	if (TAILQ_EMPTY(&ip4f_list)) {
   1648 		/* first time call, allocate fragment cache entries. */
   1649 		if (ip4f_init() < 0)
   1650 			/* allocation failed! */
   1651 			return;
   1652 	}
   1653 
   1654 	fp = ip4f_alloc();
   1655 	fp->ip4f_id = ip->ip_id;
   1656 	fp->ip4f_info.fi_proto = ip->ip_p;
   1657 	fp->ip4f_info.fi_src.s_addr = ip->ip_src.s_addr;
   1658 	fp->ip4f_info.fi_dst.s_addr = ip->ip_dst.s_addr;
   1659 
   1660 	/* save port numbers */
   1661 	fp->ip4f_info.fi_sport = fin->fi_sport;
   1662 	fp->ip4f_info.fi_dport = fin->fi_dport;
   1663 	fp->ip4f_info.fi_gpi   = fin->fi_gpi;
   1664 }
   1665 
   1666 static int
   1667 ip4f_lookup(struct ip *ip, struct flowinfo_in *fin)
   1668 {
   1669 	struct ip4_frag *fp;
   1670 
   1671 	for (fp = TAILQ_FIRST(&ip4f_list); fp != NULL && fp->ip4f_valid;
   1672 	     fp = TAILQ_NEXT(fp, ip4f_chain))
   1673 		if (ip->ip_id == fp->ip4f_id &&
   1674 		    ip->ip_src.s_addr == fp->ip4f_info.fi_src.s_addr &&
   1675 		    ip->ip_dst.s_addr == fp->ip4f_info.fi_dst.s_addr &&
   1676 		    ip->ip_p == fp->ip4f_info.fi_proto) {
   1677 
   1678 			/* found the matching entry */
   1679 			fin->fi_sport = fp->ip4f_info.fi_sport;
   1680 			fin->fi_dport = fp->ip4f_info.fi_dport;
   1681 			fin->fi_gpi   = fp->ip4f_info.fi_gpi;
   1682 
   1683 			if ((ntohs(ip->ip_off) & IP_MF) == 0)
   1684 				/* this is the last fragment,
   1685 				   release the entry. */
   1686 				ip4f_free(fp);
   1687 
   1688 			return (1);
   1689 		}
   1690 
   1691 	/* no matching entry found */
   1692 	return (0);
   1693 }
   1694 
   1695 static int
   1696 ip4f_init(void)
   1697 {
   1698 	struct ip4_frag *fp;
   1699 	int i;
   1700 
   1701 	TAILQ_INIT(&ip4f_list);
   1702 	for (i=0; i<IP4F_TABSIZE; i++) {
   1703 		fp = malloc(sizeof(struct ip4_frag), M_DEVBUF, M_NOWAIT);
   1704 		if (fp == NULL) {
   1705 			printf("ip4f_init: can't alloc %dth entry!\n", i);
   1706 			if (i == 0)
   1707 				return (-1);
   1708 			return (0);
   1709 		}
   1710 		fp->ip4f_valid = 0;
   1711 		TAILQ_INSERT_TAIL(&ip4f_list, fp, ip4f_chain);
   1712 	}
   1713 	return (0);
   1714 }
   1715 
   1716 static struct ip4_frag *
   1717 ip4f_alloc(void)
   1718 {
   1719 	struct ip4_frag *fp;
   1720 
   1721 	/* reclaim an entry at the tail, put it at the head */
   1722 	fp = TAILQ_LAST(&ip4f_list, ip4f_list);
   1723 	TAILQ_REMOVE(&ip4f_list, fp, ip4f_chain);
   1724 	fp->ip4f_valid = 1;
   1725 	TAILQ_INSERT_HEAD(&ip4f_list, fp, ip4f_chain);
   1726 	return (fp);
   1727 }
   1728 
   1729 static void
   1730 ip4f_free(struct ip4_frag *fp)
   1731 {
   1732 	TAILQ_REMOVE(&ip4f_list, fp, ip4f_chain);
   1733 	fp->ip4f_valid = 0;
   1734 	TAILQ_INSERT_TAIL(&ip4f_list, fp, ip4f_chain);
   1735 }
   1736 
   1737 #endif /* ALTQ3_CLFIER_COMPAT */
   1738