Home | History | Annotate | Line # | Download | only in libaltq
parser.c revision 1.8
      1 /*	$NetBSD: parser.c,v 1.8 2003/01/28 22:19:30 wiz Exp $	*/
      2 /*	$KAME: parser.c,v 1.16 2002/02/20 10:40:39 kjc Exp $	*/
      3 /*
      4  * Copyright (C) 1999-2002
      5  *	Sony Computer Science Laboratories, Inc.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/param.h>
     30 #include <sys/socket.h>
     31 #include <net/if.h>
     32 #include <netinet/in.h>
     33 #include <arpa/inet.h>
     34 
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <unistd.h>
     38 #include <stddef.h>
     39 #include <string.h>
     40 #include <ctype.h>
     41 #include <errno.h>
     42 #include <syslog.h>
     43 #include <netdb.h>
     44 #include <err.h>
     45 
     46 #include <altq/altq.h>
     47 #include <altq/altq_cdnr.h>
     48 #include <altq/altq_red.h>
     49 #include <altq/altq_rio.h>
     50 #include "altq_qop.h"
     51 #include "qop_cdnr.h"
     52 
     53 static int is_qdisc_name(const char *);
     54 static int qdisc_interface_parser(const char *, const char *, int, char **);
     55 static int qdisc_class_parser(const char *, const char *, const char *,
     56 			      const char *, int, char **);
     57 static int next_word(char **, char *);
     58 
     59 static int get_ifname(char **, char **);
     60 static int get_addr(char **, struct in_addr *, struct in_addr *);
     61 static int get_port(const char *, u_int16_t *);
     62 static int get_proto(const char *, int *);
     63 static int get_fltr_opts(char **, char *, size_t, int *);
     64 static int interface_parser(char *);
     65 static int class_parser(char *) ;
     66 static int filter_parser(char *);
     67 #ifdef INET6
     68 static int filter6_parser(char *);
     69 static int get_ip6addr(char **, struct in6_addr *, struct in6_addr *);
     70 #endif
     71 static int ctl_parser(char *);
     72 static int delete_parser(char *);
     73 static int red_parser(char *);
     74 static int rio_parser(char *);
     75 static int conditioner_parser(char *);
     76 static int tc_action_parser(char *, char **, struct tc_action *);
     77 
     78 #define MAX_LINE	1024
     79 #define MAX_WORD	64
     80 #define MAX_ARGS	64
     81 #define MAX_ACTIONS	16
     82 
     83 #ifndef MAX
     84 #define MAX(a,b) (((a)>(b))?(a):(b))
     85 #endif
     86 #ifndef MIN
     87 #define MIN(a,b) (((a)<(b))?(a):(b))
     88 #endif
     89 #define EQUAL(s1, s2)	(strcmp((s1), (s2)) == 0)
     90 
     91 int	line_no = 0;
     92 int	filter_dontwarn;
     93 
     94 static char	curifname[IFNAMSIZ];
     95 static struct if_nameindex *if_namelist = NULL;
     96 
     97 struct cmd_tab {
     98 	const char	*cmd;
     99 	int		(*parser)(char *);
    100 	const char	*help;
    101 } cmd_tab[] = {
    102 	{"help",	NULL,	"help | ?"},
    103 	{"quit",	NULL,	"quit"},
    104 	{"interface",	interface_parser,	"interface if_name [bandwidth bps] [cbq|hfsc]"},
    105 	{"class",	class_parser,	"class discipline if_name class_name [parent]"},
    106 	{"filter",	filter_parser,	"filter if_name class_name [name filt_name] dst [netmask #] dport src [netmask #] sport proto [tos # [tosmask #] [gpi #] [dontwarn]"},
    107 	{"altq",	ctl_parser,	"altq if_name {enable|disable}"},
    108 	{"delete",	delete_parser,	"delete if_name class_name [filter_name]"},
    109 #ifdef INET6
    110 	{"filter6",	filter6_parser,	"filter6 if_name class_name [name filt_name] dst[/prefix] dport src[/prefix] sport proto [flowlabel #][tclass # [tclassmask #]][gpi #] [dontwarn]"},
    111 #endif
    112 	{"red",		red_parser,	"red th_min th_max inv_pmax"},
    113 	{"rio",		rio_parser,	"rio low_th_min low_th_max low_inv_pmax med_th_min med_th_max med_inv_pmax high_th_min high_th_max high_inv_pmax"},
    114 	{"conditioner",	conditioner_parser,	"conditioner if_name cdnr_name <tc_action>"},
    115 	{"debug",	NULL,		"debug"},
    116 	{NULL,		NULL,		NULL}	/* termination */
    117 };
    118 
    119 /*
    120  * read one line from the specified stream. if it's a command,
    121  * execute the command.
    122  * returns 1 if OK, 0 if error or EOF.
    123  */
    124 int
    125 do_command(FILE *fp)
    126 {
    127 	char	cmd_line[MAX_LINE], cmd[MAX_WORD], *cp;
    128 	struct cmd_tab *tp;
    129 	int	len, rval;
    130 
    131 	/*
    132 	 * read a line from the stream and make it a null-terminated string
    133 	 */
    134 	cp = cmd_line;
    135 read_line:
    136 	if (fgets(cp, &cmd_line[MAX_LINE] - cp, fp) == NULL)
    137 		/* EOF or error */
    138 		return(0);
    139 	line_no++;
    140 
    141 	/* null-terminate the line */
    142 	if ((len = strlen(cmd_line)) > 0) {
    143 		cp = cmd_line + len - 1;
    144 		if (*cp == '\n') {
    145 			/* if escaped newline, read next line */
    146 			if (len > 1 &&  *(cp - 1) == '\\')
    147 				goto read_line;
    148 			*cp = '\0';
    149 		} else if (!feof(fp))
    150 			err(1, "LINE %d too long!", line_no);
    151 	}
    152 	/* trim comments */
    153 	if ((cp = strchr(cmd_line, '#')) != NULL)
    154 		*cp = '\0';
    155 
    156 	cp = cmd_line;
    157 	if ((len = next_word(&cp, cmd)) == 0)
    158 		/* no command in this line */
    159 		return (1);
    160 
    161 	/* fnind the corresponding parser */
    162 	rval = 0;
    163 	for (tp = cmd_tab; tp->cmd != NULL; tp++)
    164 		if (strncmp(cmd, tp->cmd, len) == 0)
    165 			break;
    166 
    167 	if (tp->cmd == NULL) {
    168 		if (fp == stdin) {
    169 			printf(" ?? %s\n", cmd);
    170 			rval = 1;
    171 		} else
    172 			LOG(LOG_ERR, 0, "unknown command: %s", cmd);
    173 		return (rval);
    174 	}
    175 
    176 	if (tp->parser != NULL)
    177 		rval = (*tp->parser)(cp);
    178 	else {
    179 		/* handle other commands */
    180 		if (strcmp(tp->cmd, "quit") == 0)
    181 			rval = 0;
    182 		else if (strcmp(tp->cmd, "help") == 0 ||
    183 			 strcmp(tp->cmd, "?") == 0) {
    184 			for (tp = cmd_tab; tp->cmd != NULL; tp++)
    185 				printf("%s\n", tp->help);
    186 			rval = 1;
    187 		} else if (strcmp(tp->cmd, "debug") == 0) {
    188 			if (m_debug & DEBUG_ALTQ) {
    189 				/* turn off verbose */
    190 				l_debug = LOG_INFO;
    191 				m_debug &= ~DEBUG_ALTQ;
    192 			} else {
    193 				/* turn on verbose */
    194 				l_debug = LOG_DEBUG;
    195 				m_debug |= DEBUG_ALTQ;
    196 			}
    197 			rval = 1;
    198 		}
    199 	}
    200 	return (rval);
    201 }
    202 
    203 static int
    204 is_qdisc_name(const char *qname)
    205 {
    206 	struct qdisc_parser *qp;
    207 
    208 	for (qp = qdisc_parser; qp->qname != NULL; qp++)
    209 		if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0)
    210 			return (1);
    211 	return (0);
    212 }
    213 
    214 static int
    215 qdisc_interface_parser(const char * qname, const char *ifname,
    216 		       int argc, char **argv)
    217 {
    218 	struct qdisc_parser *qp;
    219 
    220 	for (qp = qdisc_parser; qp->qname != NULL; qp++)
    221 		if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0)
    222 			return (*qp->interface_parser)(ifname, argc, argv);
    223 	return (0);
    224 }
    225 
    226 static int
    227 qdisc_class_parser(const char *qname, const char *ifname,
    228 		   const char *class_name, const char *parent_name,
    229 		   int argc, char **argv)
    230 {
    231 	struct qdisc_parser *qp;
    232 	struct ifinfo	*ifinfo;
    233 
    234 	for (qp = qdisc_parser; qp->qname != NULL; qp++)
    235 		if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0) {
    236 			if (qp->class_parser == NULL) {
    237 				LOG(LOG_ERR, 0,
    238 				    "class can't be specified for %s", qp->qname);
    239 				return (0);
    240 			}
    241 			if ((ifinfo = ifname2ifinfo(ifname)) == NULL) {
    242 				LOG(LOG_ERR, 0, "no such interface");
    243 				return (0);
    244 			}
    245 			if (strncmp(ifinfo->qdisc->qname, qname,
    246 				    strlen(ifinfo->qdisc->qname)) != 0) {
    247 				LOG(LOG_ERR, 0,
    248 				    "qname doesn't match the interface");
    249 				return (0);
    250 			}
    251 			return (*qp->class_parser)(ifname, class_name,
    252 						   parent_name, argc, argv);
    253 		}
    254 	return (0);
    255 }
    256 
    257 /*
    258  * read the config file
    259  */
    260 int
    261 qcmd_config(void)
    262 {
    263 	FILE	*fp;
    264 	int	rval;
    265 
    266 	if (if_namelist != NULL)
    267 		if_freenameindex(if_namelist);
    268 	if_namelist = if_nameindex();
    269 	curifname[0] = '\0';
    270 
    271 	LOG(LOG_INFO, 0, "ALTQ config file is %s", altqconfigfile);
    272 
    273 	fp = fopen(altqconfigfile, "r");
    274 	if (fp == NULL) {
    275 		LOG(LOG_ERR, errno, "can't open %s", altqconfigfile, 0);
    276 		return (QOPERR_INVAL);
    277 	}
    278 	line_no = 0;
    279 	rval = 1;
    280 	while (rval)
    281 		rval = do_command(fp);
    282 
    283 	if (!feof(fp)) {
    284 		LOG(LOG_ERR, 0, "Error in %s, line %d.  config failed.",
    285 		    altqconfigfile, line_no);
    286 		(void) qcmd_destroyall();
    287 		rval = QOPERR_INVAL;
    288 	} else
    289 		rval = 0;
    290 
    291 	(void)fclose(fp);
    292 	line_no = 0;
    293 	return (rval);
    294 }
    295 
    296 static int
    297 next_word(char **cpp, char *b)
    298 {
    299 	char	*cp;
    300 	int	i;
    301 
    302 	cp = *cpp;
    303 	while (*cp == ' ' || *cp == '\t')
    304 		cp++;
    305 	for (i = 0; i < MAX_WORD - 1; i++) {
    306 		if (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\0')
    307 			break;
    308 		*b++ = *cp++;
    309 	}
    310 	*b = '\0';
    311 	*cpp = cp;
    312 	return (i);
    313 }
    314 
    315 char *
    316 cur_ifname(void)
    317 {
    318 	return (curifname);
    319 }
    320 
    321 u_int
    322 get_ifindex(const char *ifname)
    323 {
    324 	struct if_nameindex *ifnp;
    325 
    326 	for (ifnp = if_namelist; ifnp->if_name != NULL; ifnp++)
    327 		if (strcmp(ifname, ifnp->if_name) == 0)
    328 			return (ifnp->if_index);
    329 	return (0);
    330 }
    331 
    332 static int
    333 get_ifname(char **cpp, char **ifnamep)
    334 {
    335 	char w[MAX_WORD], *ocp;
    336 	struct if_nameindex *ifnp;
    337 
    338 	ocp = *cpp;
    339 	if (next_word(&ocp, w) && if_namelist != NULL)
    340 		for (ifnp = if_namelist; ifnp->if_name != NULL; ifnp++)
    341 			if (strcmp(w, ifnp->if_name) == 0) {
    342 				/* if_name found. advance the word pointer */
    343 				*cpp = ocp;
    344 				strlcpy(curifname, w, sizeof(curifname));
    345 				*ifnamep = curifname;
    346 				return (1);
    347 			}
    348 
    349 	/* this is not interface name. use one in the context. */
    350 	if (curifname[0] == '\0')
    351 		return (0);
    352 	*ifnamep = curifname;
    353 	return (1);
    354 }
    355 
    356 /* set address and netmask in network byte order */
    357 static int
    358 get_addr(char **cpp, struct in_addr *addr, struct in_addr *mask)
    359 {
    360 	char w[MAX_WORD], *ocp;
    361 	struct in_addr tmp;
    362 
    363 	addr->s_addr = 0;
    364 	mask->s_addr = 0xffffffff;
    365 
    366 	if (!next_word(cpp, w))
    367 		return (0);
    368 
    369 	if (inet_aton((char *)w, &tmp) != 1) {
    370 		/* try gethostbyname */
    371 		struct hostent *h;
    372 
    373 		if ((h = gethostbyname(w)) == NULL ||
    374 		    h->h_addrtype != AF_INET || h->h_length != 4)
    375 			return (0);
    376 		bcopy(h->h_addr, &tmp, (size_t)h->h_length);
    377 	}
    378 	addr->s_addr = tmp.s_addr;
    379 
    380 	/* check if netmask option is present */
    381 	ocp = *cpp;
    382 	if (next_word(&ocp, w) && EQUAL(w, "netmask")) {
    383 		if (!next_word(&ocp, w))
    384 			return (0);
    385 		if (inet_aton((char *)w, (struct in_addr *)&tmp) != 1)
    386 			return (0);
    387 
    388 		mask->s_addr = tmp.s_addr;
    389 		*cpp = ocp;
    390 		return (1);
    391 	}
    392 	/* no netmask option */
    393 	return (1);
    394 }
    395 
    396 /* returns service number in network byte order */
    397 static int
    398 get_port(const char *name, u_int16_t *port_no)
    399 {
    400 	struct servent *s;
    401 	u_int16_t num;
    402 
    403 	if (isdigit(name[0])) {
    404 		num = (u_int16_t)strtol(name, NULL, 0);
    405 		*port_no = htons(num);
    406 		return (1);
    407 	}
    408 
    409 	if ((s = getservbyname(name, 0)) == NULL)
    410 		return (0);
    411 
    412 	*port_no = (u_int16_t)s->s_port;
    413 	return (1);
    414 }
    415 
    416 static int
    417 get_proto(const char *name, int *proto_no)
    418 {
    419 	struct protoent *p;
    420 
    421 	if (isdigit(name[0])) {
    422 		*proto_no = (int)strtol(name, NULL, 0);
    423 		return (1);
    424 	}
    425 
    426 	if ((p = getprotobyname(name)) == NULL)
    427 		return (0);
    428 
    429 	*proto_no = p->p_proto;
    430 	return (1);
    431 }
    432 
    433 static int
    434 get_fltr_opts(char **cpp, char *fltr_name, size_t len, int *ruleno)
    435 {
    436 	char w[MAX_WORD], *ocp;
    437 
    438 	ocp = *cpp;
    439 	while (next_word(&ocp, w)) {
    440 		if (EQUAL(w, "name")) {
    441 			if (!next_word(&ocp, w))
    442 				return (0);
    443 			strlcpy(fltr_name, w, len);
    444 			*cpp = ocp;
    445 		} else if (EQUAL(w, "ruleno")) {
    446 			if (!next_word(&ocp, w))
    447 				return (0);
    448 			*ruleno = (int)strtol(w, NULL, 0);
    449 			*cpp = ocp;
    450 		} else
    451 			break;
    452 	}
    453 	return (1);
    454 }
    455 
    456 
    457 #define	DISCIPLINE_NONE		0
    458 
    459 static int
    460 interface_parser(char *cmdbuf)
    461 {
    462 	char	w[MAX_WORD], *ap, *cp = cmdbuf;
    463 	char	*ifname, *argv[MAX_ARGS], qdisc_name[MAX_WORD];
    464 	int     argc;
    465 
    466 	if (!get_ifname(&cp, &ifname)) {
    467 		LOG(LOG_ERR, 0, "missing interface name");
    468 		return (0);
    469 	}
    470 
    471 	/* create argment list & look for scheduling discipline options. */
    472 	snprintf(qdisc_name, sizeof qdisc_name, "null");
    473 	argc = 0;
    474 	ap = w;
    475 	while (next_word(&cp, ap)) {
    476 		if (is_qdisc_name(ap))
    477 			strlcpy(qdisc_name, ap, sizeof qdisc_name);
    478 
    479 		argv[argc] = ap;
    480 		ap += strlen(ap) + 1;
    481 		argc++;
    482 		if (argc >= MAX_ARGS) {
    483 			LOG(LOG_ERR, 0, "too many args");
    484 			return (0);
    485 		}
    486 	}
    487 
    488 	return qdisc_interface_parser(qdisc_name, ifname, argc, argv);
    489 }
    490 
    491 
    492 static int
    493 class_parser(char *cmdbuf)
    494 {
    495 	char	w[MAX_WORD], *cp = cmdbuf;
    496 	char 	*ifname, qdisc_name[MAX_WORD];
    497 	char	class_name[MAX_WORD], parent_name[MAX_WORD];
    498 	char	*clname = class_name;
    499 	char	*parent = NULL;
    500 	char	*argv[MAX_ARGS], *ap;
    501 	int	argc;
    502 
    503 	/* get scheduling class */
    504 	if (!next_word(&cp, qdisc_name)) {
    505 		LOG(LOG_ERR, 0, "missing discipline");
    506 		return (0);
    507 	}
    508 	if (!is_qdisc_name(qdisc_name)) {
    509 		LOG(LOG_ERR, 0, "unknown discipline '%s'", qdisc_name);
    510 		return (0);
    511 	}
    512 
    513 	/* get interface name */
    514 	if (!get_ifname(&cp, &ifname)) {
    515 		LOG(LOG_ERR, 0, "missing interface name");
    516 		return (0);
    517 	}
    518 
    519 	/* get class name */
    520 	if (!next_word(&cp, class_name)) {
    521 		LOG(LOG_ERR, 0, "missing class name");
    522 		return (0);
    523 	}
    524 
    525 	/* get parent name */
    526 	if (!next_word(&cp, parent_name)) {
    527 		LOG(LOG_ERR, 0, "missing parent class");
    528 		return (0);
    529 	}
    530 	if (!EQUAL(parent_name, "null") && !EQUAL(parent_name, "NULL"))
    531 		parent = parent_name;
    532 	else
    533 		parent = NULL;
    534 
    535 	ap = w;
    536 	argc = 0;
    537 	while (next_word(&cp, ap)) {
    538 		argv[argc] = ap;
    539 		ap += strlen(ap) + 1;
    540 		argc++;
    541 		if (argc >= MAX_ARGS) {
    542 			LOG(LOG_ERR, 0, "too many args");
    543 			return (0);
    544 		}
    545 	}
    546 
    547 	return qdisc_class_parser(qdisc_name, ifname, clname, parent,
    548 				  argc, argv);
    549 }
    550 
    551 static int
    552 filter_parser(char *cmdbuf)
    553 {
    554 	char 	w[MAX_WORD], *cp = cmdbuf;
    555 	char 	*ifname, class_name[MAX_WORD], fltr_name[MAX_WORD];
    556 	char	*flname = NULL;
    557 	struct flow_filter	sfilt;
    558 	int	protocol;
    559 	u_char	tos, tosmask;
    560 	int	ruleno;
    561 	int	dontwarn = 0;
    562 	int	error;
    563 
    564 	memset(&sfilt, 0, sizeof(sfilt));
    565 	sfilt.ff_flow.fi_family = AF_INET;
    566 
    567 	if (!get_ifname(&cp, &ifname)) {
    568 		LOG(LOG_ERR, 0, "missing interface name in filter command");
    569 		return (0);
    570 	}
    571 
    572 	if (!next_word(&cp, class_name)) {
    573 		LOG(LOG_ERR, 0, "missing class name in filter command");
    574 		return (0);
    575 	}
    576 
    577 	fltr_name[0] = '\0';
    578 	ruleno = 0;
    579 	if (!get_fltr_opts(&cp, &fltr_name[0], sizeof(fltr_name), &ruleno)) {
    580 		LOG(LOG_ERR, 0, "bad filter option");
    581 		return (0);
    582 	}
    583 	if (fltr_name[0] != '\0')
    584 		flname = fltr_name;
    585 	sfilt.ff_ruleno = ruleno;
    586 
    587 	/* get filter destination Address */
    588 	if (!get_addr(&cp, &sfilt.ff_flow.fi_dst, &sfilt.ff_mask.mask_dst)) {
    589 		LOG(LOG_ERR, 0, "bad filter destination address");
    590 		return (0);
    591 	}
    592 
    593 	/* get filter destination port */
    594 	if (!next_word(&cp, w)) {
    595 		LOG(LOG_ERR, 0, "missing filter destination port");
    596 		return (0);
    597 	}
    598 	if (!get_port(w, &sfilt.ff_flow.fi_dport)) {
    599 		LOG(LOG_ERR, 0, "bad filter destination port");
    600 		return (0);
    601 	}
    602 
    603 	/* get filter source address */
    604 	if (!get_addr(&cp, &sfilt.ff_flow.fi_src, &sfilt.ff_mask.mask_src)) {
    605 		LOG(LOG_ERR, 0, "bad filter source address");
    606 		return (0);
    607 	}
    608 
    609 	/* get filter source port */
    610 	if (!next_word(&cp, w)) {
    611 		LOG(LOG_ERR, 0, "missing filter source port");
    612 		return (0);
    613 	}
    614 	if (!get_port(w, &sfilt.ff_flow.fi_sport)) {
    615 		LOG(LOG_ERR, 0, "bad filter source port");
    616 		return (0);
    617 	}
    618 
    619 	/* get filter protocol id */
    620 	if (!next_word(&cp, w)) {
    621 		LOG(LOG_ERR, 0, "missing filter protocol");
    622 		return (0);
    623 	}
    624 	if (!get_proto(w, &protocol)) {
    625 		LOG(LOG_ERR, 0, "bad protocol");
    626 		return (0);
    627 	}
    628 	sfilt.ff_flow.fi_proto = protocol;
    629 
    630 	while (next_word(&cp, w)) {
    631 		if (EQUAL(w, "tos")) {
    632 			tos = 0;
    633 			tosmask = 0xff;
    634 
    635 			if (next_word(&cp, w)) {
    636 				tos = (u_char)strtol(w, NULL, 0);
    637 				if (next_word(&cp, w)) {
    638 					if (EQUAL(w, "tosmask")) {
    639 						next_word(&cp, w);
    640 						tosmask = (u_char)strtol(w, NULL, 0);
    641 					}
    642 				}
    643 			}
    644 			sfilt.ff_flow.fi_tos = tos;
    645 			sfilt.ff_mask.mask_tos = tosmask;
    646 		} else if (EQUAL(w, "gpi")) {
    647 			if (next_word(&cp, w)) {
    648 				sfilt.ff_flow.fi_gpi =
    649 					(u_int32_t)strtoul(w, NULL, 0);
    650 				sfilt.ff_flow.fi_gpi =
    651 					htonl(sfilt.ff_flow.fi_gpi);
    652 			}
    653 		} else if (EQUAL(w, "dontwarn"))
    654 			dontwarn = 1;
    655 	}
    656 
    657 	/*
    658 	 * Add the filter.
    659 	 */
    660 	filter_dontwarn = dontwarn;	/* XXX */
    661 	error = qcmd_add_filter(ifname, class_name, flname, &sfilt);
    662 	filter_dontwarn = 0;		/* XXX */
    663 	if (error) {
    664 		LOG(LOG_ERR, 0,
    665 		    "can't add filter to class '%s' on interface '%s'",
    666 		    class_name, ifname);
    667 		return (0);
    668 	}
    669 	return (1);
    670 }
    671 
    672 #ifdef INET6
    673 static int
    674 filter6_parser(char *cmdbuf)
    675 {
    676 	char 	w[MAX_WORD], *cp = cmdbuf;
    677 	char 	*ifname, class_name[MAX_WORD], fltr_name[MAX_WORD];
    678 	char	*flname = NULL;
    679 	struct flow_filter6	sfilt;
    680 	int	protocol;
    681 	u_char	tclass, tclassmask;
    682 	int	ruleno;
    683 	int	dontwarn = 0;
    684 	int	ret;
    685 
    686 	memset(&sfilt, 0, sizeof(sfilt));
    687 	sfilt.ff_flow6.fi6_family = AF_INET6;
    688 
    689 	if (!get_ifname(&cp, &ifname)) {
    690 		LOG(LOG_ERR, 0, "missing interface name");
    691 		return (0);
    692 	}
    693 
    694 	if (!next_word(&cp, class_name)) {
    695 		LOG(LOG_ERR, 0, "missing class name");
    696 		return (0);
    697 	}
    698 
    699 	fltr_name[0] = '\0';
    700 	ruleno = 0;
    701 	if (!get_fltr_opts(&cp, &fltr_name[0], sizeof(fltr_name), &ruleno)) {
    702 		LOG(LOG_ERR, 0, "bad filter option");
    703 		return (0);
    704 	}
    705 	if (fltr_name[0] != '\0')
    706 		flname = fltr_name;
    707 	sfilt.ff_ruleno = ruleno;
    708 
    709 	/* get filter destination address */
    710 	if (!get_ip6addr(&cp, &sfilt.ff_flow6.fi6_dst,
    711 			 &sfilt.ff_mask6.mask6_dst)) {
    712 		LOG(LOG_ERR, 0, "bad destination address");
    713 		return (0);
    714 	}
    715 
    716 	/* get filter destination port */
    717 	if (!next_word(&cp, w)) {
    718 		LOG(LOG_ERR, 0, "missing filter destination port");
    719 		return (0);
    720 	}
    721 	if (!get_port(w, &sfilt.ff_flow6.fi6_dport)) {
    722 		LOG(LOG_ERR, 0, "bad filter destination port");
    723 		return (0);
    724 	}
    725 
    726 	/* get filter source address */
    727 	if (!get_ip6addr(&cp, &sfilt.ff_flow6.fi6_src,
    728 			 &sfilt.ff_mask6.mask6_src)) {
    729 		LOG(LOG_ERR, 0, "bad source address");
    730 		return (0);
    731 	}
    732 
    733 	/* get filter source port */
    734 	if (!next_word(&cp, w)) {
    735 		LOG(LOG_ERR, 0, "missing filter source port");
    736 		return (0);
    737 	}
    738 	if (!get_port(w, &sfilt.ff_flow6.fi6_sport)) {
    739 		LOG(LOG_ERR, 0, "bad filter source port");
    740 		return (0);
    741 	}
    742 
    743 	/* get filter protocol id */
    744 	if (!next_word(&cp, w)) {
    745 		LOG(LOG_ERR, 0, "missing filter protocol");
    746 		return (0);
    747 	}
    748 	if (!get_proto(w, &protocol)) {
    749 		LOG(LOG_ERR, 0, "bad protocol");
    750 		return (0);
    751 	}
    752 	sfilt.ff_flow6.fi6_proto = protocol;
    753 
    754 	while (next_word(&cp, w)) {
    755 		if (EQUAL(w, "tclass")) {
    756 			tclass = 0;
    757 			tclassmask = 0xff;
    758 
    759 			if (next_word(&cp, w)) {
    760 				tclass = (u_char)strtol(w, NULL, 0);
    761 				if (next_word(&cp, w)) {
    762 					if (EQUAL(w, "tclassmask")) {
    763 						next_word(&cp, w);
    764 						tclassmask =
    765 						    (u_char)strtol(w, NULL, 0);
    766 					}
    767 				}
    768 			}
    769 			sfilt.ff_flow6.fi6_tclass = tclass;
    770 			sfilt.ff_mask6.mask6_tclass = tclassmask;
    771 		} else if (EQUAL(w, "gpi")) {
    772 			if (next_word(&cp, w)) {
    773 				sfilt.ff_flow6.fi6_gpi =
    774 					(u_int32_t)strtoul(w, NULL, 0);
    775 				sfilt.ff_flow6.fi6_gpi =
    776 					htonl(sfilt.ff_flow6.fi6_gpi);
    777 			}
    778 		} else if (EQUAL(w, "flowlabel")) {
    779 			if (next_word(&cp, w)) {
    780 				sfilt.ff_flow6.fi6_flowlabel =
    781 				   (u_int32_t)strtoul(w, NULL, 0) & 0x000fffff;
    782 				sfilt.ff_flow6.fi6_flowlabel =
    783 					htonl(sfilt.ff_flow6.fi6_flowlabel);
    784 			}
    785 		} else if (EQUAL(w, "dontwarn"))
    786 			dontwarn = 1;
    787 	}
    788 
    789 	/*
    790 	 * Add the filter.
    791 	 */
    792 	filter_dontwarn = dontwarn;	/* XXX */
    793 	ret = qcmd_add_filter(ifname, class_name, flname,
    794 			      (struct flow_filter *)&sfilt);
    795 	filter_dontwarn = 0;		/* XXX */
    796 	if (ret) {
    797 		LOG(LOG_ERR, 0,
    798 		    "can't add filter to class '%s' on interface '%s'",
    799 		    class_name, ifname);
    800 		return (0);
    801 	}
    802 
    803 	return (1);
    804 }
    805 
    806 static int
    807 get_ip6addr(char **cpp, struct in6_addr *addr, struct in6_addr *mask)
    808 {
    809 	char w[MAX_WORD], *prefix;
    810 	u_char *cp;
    811 	int len;
    812 
    813 	*addr = in6addr_any;  /* set all 0 */
    814 	*mask = in6addr_any;  /* set all 0 */
    815 
    816 	if (!next_word(cpp, w))
    817 		return (0);
    818 
    819 	if (EQUAL(w, "0"))
    820 		/* abbreviation of a wildcard (::0) */
    821 		return (1);
    822 
    823 	if ((prefix = strchr(w, '/')) != NULL) {
    824 		/* address has prefix length */
    825 		*prefix++ = '\0';
    826 	}
    827 
    828 	if (inet_pton(AF_INET6, w, addr) != 1)
    829 		return (0);
    830 
    831 	if (IN6_IS_ADDR_UNSPECIFIED(addr) && prefix == NULL)
    832 		/* wildcard */
    833 		return (1);
    834 
    835 	/* convert address prefix length to address mask */
    836 	if (prefix != NULL) {
    837 		len = (int)strtol(prefix, NULL, 0);
    838 		if ((len < 0) || (len > 128))
    839 			return (0);
    840 		for (cp = (u_char *)mask; len > 7; len -= 8)
    841 			*cp++ = 0xff;
    842 		if (len > 0)
    843 			*cp = (0xff << (8 - len)) & 0xff;
    844 
    845 		IN6ADDR32(addr, 0) &= IN6ADDR32(mask, 0);
    846 		IN6ADDR32(addr, 1) &= IN6ADDR32(mask, 1);
    847 		IN6ADDR32(addr, 2) &= IN6ADDR32(mask, 2);
    848 		IN6ADDR32(addr, 3) &= IN6ADDR32(mask, 3);
    849 	} else
    850 		/* full mask */
    851 		memset(mask, 0xff, sizeof(struct in6_addr));
    852 
    853 	return (1);
    854 }
    855 
    856 #endif /* INET6 */
    857 
    858 static int
    859 ctl_parser(char *cmdbuf)
    860 {
    861 	char	w[MAX_WORD], *cp = cmdbuf;
    862 	char	*ifname;
    863 	int	state;
    864 	int	rval;
    865 
    866 	if (!get_ifname(&cp, &ifname)) {
    867 		printf("missing interface name in %s, line %d",
    868 		       altqconfigfile, line_no);
    869 		return (0);
    870 	}
    871 
    872 	if (!next_word(&cp, w)) {
    873 		state = is_q_enabled(ifname);
    874 		printf("altq %s on %s\n",
    875 		       state ? "enabled" : "disabled", ifname);
    876 		return (1);
    877 	}
    878 
    879 	if (EQUAL(w, "enable")) {
    880 		rval = qcmd_enable(ifname);
    881 		printf("altq %s on %s\n",
    882 		       (rval == 0) ? "enabled" : "enable failed!", ifname);
    883 	} else if (EQUAL(w, "disable")) {
    884 		rval = qcmd_disable(ifname);
    885 		printf("altq %s on %s\n",
    886 		       (rval == 0) ? "disabled" : "disable failed!", ifname);
    887 	} else if (EQUAL(w, "reload")) {
    888 		printf("reinitializing altq...\n");
    889 		qcmd_destroyall();
    890 		qcmd_init();
    891 	} else
    892 		return (0);
    893 	return (1);
    894 }
    895 
    896 static int
    897 delete_parser(char *cmdbuf)
    898 {
    899 	char	*cp = cmdbuf;
    900 	char	*ifname, class_name[MAX_WORD], filter_name[MAX_WORD];
    901 	int	ret;
    902 
    903 	if (!get_ifname(&cp, &ifname)) {
    904 		LOG(LOG_ERR, 0, "missing interface name");
    905 		return (0);
    906 	}
    907 
    908 	if (!next_word(&cp, class_name)) {
    909 		LOG(LOG_ERR, 0, "missing class name");
    910 		return (0);
    911 	}
    912 
    913 	/* check if filter is specified */
    914 	if (next_word(&cp, filter_name)) {
    915 		ret = qcmd_delete_filter(ifname, class_name, filter_name);
    916 		if (ret) {
    917 			LOG(LOG_ERR, 0,
    918 			    "can't delete filter '%s' on interface '%s'",
    919 			    filter_name, ifname);
    920 			return (0);
    921 		}
    922 		return (1);
    923 	}
    924 
    925 	ret = qcmd_delete_class(ifname, class_name);
    926 	if (ret) {
    927 		LOG(LOG_ERR, 0,
    928 		    "can't delete class '%s' on interface '%s'",
    929 		    class_name, ifname);
    930 		return (0);
    931 	}
    932 
    933 	return (1);
    934 }
    935 
    936 static int
    937 red_parser(char *cmdbuf)
    938 {
    939 	char	w[MAX_WORD], *cp = cmdbuf;
    940 	int th_min, th_max, inv_pmax;
    941 
    942 	if (!next_word(&cp, w))
    943 		goto bad;
    944 	th_min = (int)strtol(w, NULL, 0);
    945 
    946 	if (!next_word(&cp, w))
    947 		goto bad;
    948 	th_max = (int)strtol(w, NULL, 0);
    949 
    950 	if (!next_word(&cp, w))
    951 		goto bad;
    952 	inv_pmax = (int)strtol(w, NULL, 0);
    953 
    954 	if (qop_red_set_defaults(th_min, th_max, inv_pmax) != 0) {
    955 		LOG(LOG_ERR, 0, "can't set red default parameters");
    956 		return (0);
    957 	}
    958 
    959 	return (1);
    960 
    961  bad:
    962 	LOG(LOG_ERR, 0, "bad red parameter");
    963 	return (0);
    964 }
    965 
    966 static int
    967 rio_parser(char *cmdbuf)
    968 {
    969 	char	w[MAX_WORD], *cp = cmdbuf;
    970 	int	i;
    971 	struct redparams params[RIO_NDROPPREC];
    972 
    973 	for (i = 0; i < RIO_NDROPPREC; i++) {
    974 		if (!next_word(&cp, w))
    975 			goto bad;
    976 		params[i].th_min = (int)strtol(w, NULL, 0);
    977 
    978 		if (!next_word(&cp, w))
    979 			goto bad;
    980 		params[i].th_max = (int)strtol(w, NULL, 0);
    981 
    982 		if (!next_word(&cp, w))
    983 			goto bad;
    984 		params[i].inv_pmax = (int)strtol(w, NULL, 0);
    985 	}
    986 
    987 	if (qop_rio_set_defaults(&params[0]) != 0) {
    988 		LOG(LOG_ERR, 0, "can't set rio default parameters");
    989 		return (0);
    990 	}
    991 
    992 	return (1);
    993 
    994  bad:
    995 	LOG(LOG_ERR, 0, "bad rio parameter");
    996 	return (0);
    997 }
    998 
    999 static int
   1000 conditioner_parser(char *cmdbuf)
   1001 {
   1002 	char	cdnr_name[MAX_WORD], *cp = cmdbuf;
   1003 	char	*ifname;
   1004 	struct tc_action action[MAX_ACTIONS];
   1005 
   1006 	if (!get_ifname(&cp, &ifname)) {
   1007 		LOG(LOG_ERR, 0, "missing interface name");
   1008 		return (0);
   1009 	}
   1010 
   1011 	/* get conditioner name */
   1012 	if (!next_word(&cp, cdnr_name)) {
   1013 		LOG(LOG_ERR, 0, "missing cdnr name");
   1014 		return (0);
   1015 	}
   1016 
   1017 	if (tc_action_parser(ifname, &cp, &action[0]) == 0)
   1018 		return (0);
   1019 
   1020 	if (qcmd_cdnr_add_element(NULL, ifname, cdnr_name, &action[0]) != 0)
   1021 		return (0);
   1022 	return (1);
   1023 }
   1024 
   1025 /*
   1026  * recursively parse '<'tc_action'>'
   1027  * note that array "action" grows during recursive parse.
   1028  */
   1029 static int
   1030 tc_action_parser(char *ifname, char **cpp, struct tc_action *action)
   1031 {
   1032 	char	*cp, *start, *end;
   1033 	char	type[MAX_WORD], w[MAX_WORD];
   1034 	int	depth, i;
   1035 	struct tb_profile profile[2];
   1036 
   1037 	/*
   1038 	 * find a possibly nested pair of '<' and '>',
   1039 	 * make them pointed by 'start' and 'end'.
   1040 	 */
   1041 	start = strchr(*cpp, '<');
   1042 	if (start == NULL) {
   1043 		LOG(LOG_ERR, 0, "conditioner action missing");
   1044 		return (0);
   1045 	}
   1046 	depth = 1;
   1047 	cp = start + 1;
   1048 	do {
   1049 		end = strpbrk(cp, "<>");
   1050 		if (end == NULL) {
   1051 			LOG(LOG_ERR, 0,
   1052 			    "conditioner action delimiter mismatch");
   1053 			return (0);
   1054 		}
   1055 		if (*end == '<')
   1056 			depth++;
   1057 		else if (*end == '>')
   1058 			depth--;
   1059 		cp = end + 1;
   1060 	} while (depth > 0);
   1061 	*end = '\0';
   1062 	*cpp = end + 1;
   1063 	cp = start + 1;
   1064 
   1065 	if (IsDebug(DEBUG_ALTQ)) {
   1066 		printf("tc_action_parser: [%s]\n", cp);
   1067 	}
   1068 
   1069 	if (!next_word(&cp, type)) {
   1070 		LOG(LOG_ERR, 0, "missing conditioner action type");
   1071 		return (0);
   1072 	}
   1073 
   1074 	/*
   1075 	 * action type specific process
   1076 	 */
   1077 	if (EQUAL(type, "conditioner")) {
   1078 		if (!next_word(&cp, w)) {
   1079 			LOG(LOG_ERR, 0,
   1080 			    "missing conditioner name");
   1081 			return (0);
   1082 		}
   1083 		action->tca_code = TCACODE_HANDLE;
   1084 		action->tca_handle = cdnr_name2handle(ifname, w);
   1085 		if (action->tca_handle == CDNR_NULL_HANDLE) {
   1086 			LOG(LOG_ERR, 0,
   1087 			    "wrong conditioner name %s", w);
   1088 			return (0);
   1089 		}
   1090 	} else if (EQUAL(type, "pass")) {
   1091 		action->tca_code = TCACODE_PASS;
   1092 	} else if (EQUAL(type, "drop")) {
   1093 		action->tca_code = TCACODE_DROP;
   1094 	} else if (EQUAL(type, "mark")) {
   1095 		if (!next_word(&cp, w)) {
   1096 			LOG(LOG_ERR, 0, "missing dscp");
   1097 			return (0);
   1098 		}
   1099 		action->tca_code = TCACODE_MARK;
   1100 		action->tca_dscp = (u_int8_t)strtol(w, NULL, 0);
   1101 	} else if (EQUAL(type, "tbmeter")) {
   1102 		if (!next_word(&cp, w)) {
   1103 			LOG(LOG_ERR, 0, "missing tb profile");
   1104 			return (0);
   1105 		}
   1106 		profile[0].rate = atobps(w);
   1107 		if (!next_word(&cp, w)) {
   1108 			LOG(LOG_ERR, 0, "missing tb profile");
   1109 			return (0);
   1110 		}
   1111 		profile[0].depth = atobytes(w);
   1112 		if (tc_action_parser(ifname, &cp, &action[1]) == 0)
   1113 			return (0);
   1114 		if (tc_action_parser(ifname, &cp, &action[2]) == 0)
   1115 			return (0);
   1116 
   1117 		if (qcmd_cdnr_add_tbmeter(action, ifname, NULL, &profile[0],
   1118 					  &action[1], &action[2]) != 0)
   1119 			return (0);
   1120 	} else if (EQUAL(type, "trtcm")) {
   1121 		int coloraware = 0;	/* default is color-blind */
   1122 
   1123 		for (i=0; i<2; i++) {
   1124 			if (!next_word(&cp, w)) {
   1125 				LOG(LOG_ERR, 0, "missing tb profile");
   1126 				return (0);
   1127 			}
   1128 			profile[i].rate = atobps(w);
   1129 			if (!next_word(&cp, w)) {
   1130 				LOG(LOG_ERR, 0, "missing tb profile");
   1131 				return (0);
   1132 			}
   1133 			profile[i].depth = atobytes(w);
   1134 		}
   1135 		if (tc_action_parser(ifname, &cp, &action[1]) == 0)
   1136 			return (0);
   1137 		if (tc_action_parser(ifname, &cp, &action[2]) == 0)
   1138 			return (0);
   1139 		if (tc_action_parser(ifname, &cp, &action[3]) == 0)
   1140 			return (0);
   1141 		if (next_word(&cp, w)) {
   1142 			if (EQUAL(w, "coloraware"))
   1143 				coloraware = 1;
   1144 			else if (EQUAL(w, "colorblind"))
   1145 				coloraware = 0;
   1146 		}
   1147 
   1148 		if (qcmd_cdnr_add_trtcm(action, ifname, NULL,
   1149 					&profile[0], &profile[1],
   1150 					&action[1], &action[2], &action[3],
   1151 					coloraware) != 0)
   1152 			return (0);
   1153 	} else if (EQUAL(type, "tswtcm")) {
   1154 		u_int32_t cmtd_rate, peak_rate, avg_interval;
   1155 
   1156 		if (!next_word(&cp, w)) {
   1157 			LOG(LOG_ERR, 0, "missing cmtd rate");
   1158 			return (0);
   1159 		}
   1160 		cmtd_rate = atobps(w);
   1161 
   1162 		if (!next_word(&cp, w)) {
   1163 			LOG(LOG_ERR, 0, "missing peak rate");
   1164 			return (0);
   1165 		}
   1166 		peak_rate = atobps(w);
   1167 
   1168 		if (!next_word(&cp, w)) {
   1169 			LOG(LOG_ERR, 0, "missing avg interval");
   1170 			return (0);
   1171 		}
   1172 		avg_interval = (u_int32_t)strtoul(w, NULL, 0);
   1173 
   1174 		if (tc_action_parser(ifname, &cp, &action[1]) == 0)
   1175 			return (0);
   1176 		if (tc_action_parser(ifname, &cp, &action[2]) == 0)
   1177 			return (0);
   1178 		if (tc_action_parser(ifname, &cp, &action[3]) == 0)
   1179 			return (0);
   1180 
   1181 		if (qcmd_cdnr_add_tswtcm(action, ifname, NULL,
   1182 					 cmtd_rate, peak_rate, avg_interval,
   1183 					 &action[1], &action[2], &action[3])
   1184 		    != 0)
   1185 			return (0);
   1186 	} else {
   1187 		LOG(LOG_ERR, 0, "unknown action type %s");
   1188 		return (0);
   1189 	}
   1190 
   1191 	*end = '>';	/* restore the end delimiter */
   1192 
   1193 	return (1);
   1194 }
   1195