Home | History | Annotate | Line # | Download | only in libaltq
parser.c revision 1.6
      1  1.6   itojun /*	$NetBSD: parser.c,v 1.6 2001/08/22 08:52:36 itojun Exp $	*/
      2  1.6   itojun /*	$KAME: parser.c,v 1.12 2001/08/16 10:39:13 kjc Exp $	*/
      3  1.1  thorpej /*******************************************************************
      4  1.1  thorpej 
      5  1.1  thorpej   Copyright (c) 1996 by the University of Southern California
      6  1.1  thorpej   All rights reserved.
      7  1.1  thorpej 
      8  1.1  thorpej   Permission to use, copy, modify, and distribute this software and its
      9  1.1  thorpej   documentation in source and binary forms for any purpose and without
     10  1.1  thorpej   fee is hereby granted, provided that both the above copyright notice
     11  1.1  thorpej   and this permission notice appear in all copies. and that any
     12  1.1  thorpej   documentation, advertising materials, and other materials related to
     13  1.1  thorpej   such distribution and use acknowledge that the software was developed
     14  1.1  thorpej   in part by the University of Southern California, Information
     15  1.1  thorpej   Sciences Institute.  The name of the University may not be used to
     16  1.1  thorpej   endorse or promote products derived from this software without
     17  1.1  thorpej   specific prior written permission.
     18  1.1  thorpej 
     19  1.1  thorpej   THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
     20  1.1  thorpej   the suitability of this software for any purpose.  THIS SOFTWARE IS
     21  1.1  thorpej   PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
     22  1.1  thorpej   INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     23  1.1  thorpej   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     24  1.1  thorpej 
     25  1.1  thorpej   Other copyrights might apply to parts of this software and are so
     26  1.1  thorpej   noted when applicable.
     27  1.1  thorpej 
     28  1.1  thorpej ********************************************************************/
     29  1.1  thorpej 
     30  1.1  thorpej 
     31  1.1  thorpej #include <stdio.h>
     32  1.1  thorpej #include <stdlib.h>
     33  1.1  thorpej #include <unistd.h>
     34  1.1  thorpej #include <stddef.h>
     35  1.1  thorpej #include <string.h>
     36  1.1  thorpej #include <ctype.h>
     37  1.1  thorpej #include <errno.h>
     38  1.1  thorpej #include <syslog.h>
     39  1.1  thorpej #include <sys/socket.h>
     40  1.1  thorpej #include <netdb.h>
     41  1.1  thorpej #include <net/if.h>
     42  1.1  thorpej #include <netinet/in.h>
     43  1.1  thorpej #include <arpa/inet.h>
     44  1.1  thorpej 
     45  1.1  thorpej #include <altq/altq.h>
     46  1.1  thorpej #include <altq/altq_cdnr.h>
     47  1.1  thorpej #include <altq/altq_red.h>
     48  1.1  thorpej #include <altq/altq_rio.h>
     49  1.1  thorpej #include "altq_qop.h"
     50  1.1  thorpej #include "qop_cdnr.h"
     51  1.1  thorpej 
     52  1.1  thorpej #define show_help(op)  printf(cmd_tab[op].cmd_help)
     53  1.1  thorpej 
     54  1.1  thorpej /*
     55  1.1  thorpej  * Forward & External Declarations
     56  1.1  thorpej  */
     57  1.4   itojun static int is_qdisc_name(const char *);
     58  1.4   itojun static int qdisc_interface_parser(const char *, const char *, int, char **);
     59  1.4   itojun static int qdisc_class_parser(const char *, const char *, const char *,
     60  1.4   itojun 	const char *, int, char **);
     61  1.4   itojun 
     62  1.4   itojun static int pfxcmp(const char *, const char *);
     63  1.4   itojun static int next_word(char **, char *);
     64  1.4   itojun 
     65  1.4   itojun static int do_cmd(int, char *);
     66  1.4   itojun static int get_ifname(char **, char **);
     67  1.4   itojun static int get_addr(char **, struct in_addr *, struct in_addr *);
     68  1.4   itojun static int get_port(const char *, u_int16_t *);
     69  1.4   itojun static int get_proto(const char *, int *);
     70  1.4   itojun static int get_fltr_opts(char **, char *, size_t, int *);
     71  1.4   itojun static int interface_parser(char *);
     72  1.4   itojun static int class_parser(char *) ;
     73  1.4   itojun static int filter_parser(char *);
     74  1.1  thorpej #ifdef INET6
     75  1.4   itojun static int filter6_parser(char *);
     76  1.4   itojun static int get_ip6addr(char **, struct in6_addr *, struct in6_addr *);
     77  1.1  thorpej #endif
     78  1.4   itojun static int ctl_parser(char *);
     79  1.4   itojun static int delete_parser(char *);
     80  1.4   itojun static int red_parser(char *);
     81  1.4   itojun static int rio_parser(char *);
     82  1.4   itojun static int conditioner_parser(char *);
     83  1.4   itojun static int tc_action_parser(char *, char **, struct tc_action *);
     84  1.1  thorpej 
     85  1.1  thorpej /*
     86  1.1  thorpej  * Globals
     87  1.1  thorpej  */
     88  1.1  thorpej #define MAX_NFLWDS      64
     89  1.1  thorpej #define MAX_T           64
     90  1.1  thorpej 
     91  1.1  thorpej int             TNO = 1;  	/* Current Thread number */
     92  1.1  thorpej int		line_no = 0;
     93  1.1  thorpej int		filter_dontwarn;
     94  1.1  thorpej 
     95  1.1  thorpej static char	if_names[MAX_T][IFNAMSIZ];
     96  1.1  thorpej static struct if_nameindex *if_namelist = NULL;
     97  1.1  thorpej 
     98  1.1  thorpej #ifndef MAX
     99  1.1  thorpej #define MAX(a,b) (((a)>(b))?(a):(b))
    100  1.1  thorpej #endif
    101  1.1  thorpej #ifndef MIN
    102  1.1  thorpej #define MIN(a,b) (((a)<(b))?(a):(b))
    103  1.1  thorpej #endif
    104  1.1  thorpej 
    105  1.1  thorpej enum op_codes {
    106  1.1  thorpej         /* order must be same as entries cmd_tab[].cmd_op below!! */
    107  1.1  thorpej         OP_HELP = 1, 	OP_QUIT,
    108  1.1  thorpej 	OP_IFACE,	OP_CLASS,	OP_FILTER,
    109  1.1  thorpej 	OP_ALTQ,		OP_DEL,
    110  1.1  thorpej #ifdef INET6
    111  1.1  thorpej 	OP_FILTER6,
    112  1.1  thorpej #endif
    113  1.1  thorpej 	OP_RED,		OP_RIO,
    114  1.1  thorpej 	OP_CDNR,
    115  1.1  thorpej         OP_NULL, 	OP_BUG
    116  1.1  thorpej };
    117  1.1  thorpej 
    118  1.1  thorpej /*	Following table MUST match enum order of op_codes !
    119  1.1  thorpej  */
    120  1.1  thorpej struct cmds {
    121  1.1  thorpej 	char           *cmd_verb;
    122  1.1  thorpej 	int             cmd_op;
    123  1.1  thorpej 	char           *cmd_help;
    124  1.1  thorpej }		cmd_tab[] = {
    125  1.1  thorpej 
    126  1.1  thorpej   	{ "?",		OP_HELP, 	"Commands are:\n" },
    127  1.1  thorpej 	{ "help",	OP_HELP, 	" help | ?\n" },
    128  1.1  thorpej 	{ "quit",	OP_QUIT, 	" quit\n" },
    129  1.1  thorpej 	{ "interface",	OP_IFACE,	" interface if_name [bandwidth bps] [cbq|hfsc]\n" },
    130  1.1  thorpej 	{ "class",	OP_CLASS,	" class discipline if_name class_name [parent]\n" },
    131  1.1  thorpej 	{ "filter",	OP_FILTER,	" filter if_name class_name [name filt_name] dst [netmask #] dport src [netmask #] sport proto [tos # [tosmask #] [gpi #] [dontwarn]\n" },
    132  1.1  thorpej 	{ "altq",	OP_ALTQ,	" disc if_name {enable|disable}\n" },
    133  1.1  thorpej 	{ "delete",	OP_DEL,		" delete if_name class_name\n" },
    134  1.1  thorpej #ifdef INET6
    135  1.1  thorpej 	{ "filter6",	OP_FILTER6,	" filter6 if_name class_name [name filt_name] dst[/prefix] dport src[/prefix] sport proto [flowlabel #][tclass # [tclassmask #]][gpi #] [dontwarn]\n" },
    136  1.1  thorpej #endif
    137  1.1  thorpej 	{ "red", 	OP_RED,		" red th_min th_max inv_pmax\n" },
    138  1.1  thorpej 	{ "rio", 	OP_RIO,		" 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\n" },
    139  1.1  thorpej 	{ "conditioner", OP_CDNR,	" conditioner if_name cdnr_name <tc_action>\n" },
    140  1.1  thorpej 	{ "bug",	OP_BUG,		" bug (On/Off)\n" },
    141  1.1  thorpej 	{ "",		OP_NULL,	"" } /* MUST BE LAST IN CMD TABLE */
    142  1.1  thorpej };
    143  1.1  thorpej 
    144  1.1  thorpej static int
    145  1.1  thorpej is_qdisc_name(const char *qname)
    146  1.1  thorpej {
    147  1.1  thorpej 	struct qdisc_parser *qp;
    148  1.1  thorpej 
    149  1.1  thorpej 	for (qp = qdisc_parser; qp->qname != NULL; qp++)
    150  1.1  thorpej 		if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0)
    151  1.1  thorpej 			return (1);
    152  1.1  thorpej 	return (0);
    153  1.1  thorpej }
    154  1.1  thorpej 
    155  1.1  thorpej static int
    156  1.1  thorpej qdisc_interface_parser(const char * qname, const char *ifname,
    157  1.1  thorpej 		       int argc, char **argv)
    158  1.1  thorpej {
    159  1.1  thorpej 	struct qdisc_parser *qp;
    160  1.1  thorpej 
    161  1.1  thorpej 	for (qp = qdisc_parser; qp->qname != NULL; qp++)
    162  1.1  thorpej 		if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0)
    163  1.1  thorpej 			return (*qp->interface_parser)(ifname, argc, argv);
    164  1.1  thorpej 	return (0);
    165  1.1  thorpej }
    166  1.1  thorpej 
    167  1.1  thorpej static int
    168  1.1  thorpej qdisc_class_parser(const char *qname, const char *ifname,
    169  1.1  thorpej 		   const char *class_name, const char *parent_name,
    170  1.1  thorpej 		   int argc, char **argv)
    171  1.1  thorpej {
    172  1.1  thorpej 	struct qdisc_parser *qp;
    173  1.4   itojun 	struct ifinfo	*ifinfo;
    174  1.4   itojun 
    175  1.1  thorpej 	for (qp = qdisc_parser; qp->qname != NULL; qp++)
    176  1.1  thorpej 		if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0) {
    177  1.1  thorpej 			if (qp->class_parser == NULL) {
    178  1.1  thorpej 				LOG(LOG_ERR, 0,
    179  1.4   itojun 				    "class can't be specified for %s", qp->qname);
    180  1.4   itojun 				return (0);
    181  1.4   itojun 			}
    182  1.4   itojun 			if ((ifinfo = ifname2ifinfo(ifname)) == NULL) {
    183  1.4   itojun 				LOG(LOG_ERR, 0,
    184  1.6   itojun 				    "no such interface, line %d", line_no);
    185  1.4   itojun 				return (0);
    186  1.4   itojun 			}
    187  1.4   itojun 			if (strncmp(ifinfo->qdisc->qname, qname,
    188  1.4   itojun 				    strlen(ifinfo->qdisc->qname)) != 0) {
    189  1.4   itojun 				LOG(LOG_ERR, 0,
    190  1.6   itojun 				    "qname doesn't match the interface, line %d",
    191  1.4   itojun 				    line_no);
    192  1.1  thorpej 				return (0);
    193  1.1  thorpej 			}
    194  1.1  thorpej 			return (*qp->class_parser)(ifname, class_name,
    195  1.1  thorpej 						   parent_name, argc, argv);
    196  1.1  thorpej 		}
    197  1.1  thorpej 	return (0);
    198  1.1  thorpej }
    199  1.1  thorpej 
    200  1.1  thorpej 
    201  1.1  thorpej /*
    202  1.1  thorpej  * Read the config file to learn about tunnel vifs and non-default phyint
    203  1.1  thorpej  * parameters.
    204  1.1  thorpej  */
    205  1.1  thorpej int
    206  1.1  thorpej qcmd_config(void)
    207  1.1  thorpej {
    208  1.1  thorpej 	FILE		*f;
    209  1.1  thorpej 	int		i, rc = 1;
    210  1.1  thorpej 
    211  1.1  thorpej 	if (if_namelist != NULL)
    212  1.1  thorpej 		if_freenameindex(if_namelist);
    213  1.1  thorpej 	if_namelist = if_nameindex();
    214  1.1  thorpej 
    215  1.1  thorpej 	for (i = 0; i < MAX_T; i++)
    216  1.1  thorpej 		if_names[i][0] = '\0';
    217  1.1  thorpej 
    218  1.6   itojun 	LOG(LOG_INFO, 0, "ALTQ config file is %s", altqconfigfile);
    219  1.1  thorpej 
    220  1.1  thorpej 	f = fopen(altqconfigfile, "r");
    221  1.1  thorpej 	if (f == NULL) {
    222  1.6   itojun 		LOG(LOG_ERR, errno, "can't open %s", altqconfigfile, 0);
    223  1.1  thorpej 		return (QOPERR_INVAL);
    224  1.1  thorpej 	}
    225  1.1  thorpej 	line_no = 0;
    226  1.1  thorpej 	while (rc)
    227  1.1  thorpej 		rc = DoCommand(altqconfigfile, f);
    228  1.1  thorpej 
    229  1.1  thorpej 	(void) fclose(f);
    230  1.1  thorpej 	line_no = 0;
    231  1.1  thorpej 	return (0);
    232  1.1  thorpej }
    233  1.1  thorpej 
    234  1.1  thorpej /*
    235  1.1  thorpej  *  Do_Command(): Top-level routine to read the next line from a given
    236  1.1  thorpej  *	file and execute the command it contains.
    237  1.1  thorpej  *	returns 1 if OK, 0 if EOF.
    238  1.1  thorpej  */
    239  1.1  thorpej int
    240  1.1  thorpej DoCommand(char *infile, FILE *infp)
    241  1.1  thorpej {
    242  1.1  thorpej 	char	cmd_line[256], cmd_op[80];
    243  1.1  thorpej 	struct	cmds *cmdp;
    244  1.1  thorpej 	char	*cp;
    245  1.1  thorpej 	int	rc;
    246  1.1  thorpej 
    247  1.1  thorpej 	if (fgets(cmd_line, sizeof(cmd_line), infp) == NULL)
    248  1.1  thorpej 		/* EOF */
    249  1.1  thorpej 		return(0);
    250  1.1  thorpej 	line_no++;
    251  1.1  thorpej 
    252  1.1  thorpej 	/* check escaped newline */
    253  1.1  thorpej 	while ((cp = strrchr(cmd_line, '\\')) != NULL && cp[1] == '\n') {
    254  1.1  thorpej 		if (fgets(cp, &cmd_line[256] - cp, infp) != NULL)
    255  1.1  thorpej 			line_no++;
    256  1.1  thorpej 	}
    257  1.1  thorpej 
    258  1.1  thorpej 	/* remove trailing NL */
    259  1.1  thorpej 	cp = cmd_line + strlen(cmd_line) - 1;
    260  1.1  thorpej 	if (*cp == '\n')
    261  1.1  thorpej 		*cp = '\0';
    262  1.1  thorpej 	else if (!feof(infp)) {
    263  1.1  thorpej 		printf("LINE %d > 255 CHARS: %s.\n", line_no, cmd_line);
    264  1.1  thorpej 		exit(1);
    265  1.1  thorpej 	}
    266  1.1  thorpej 	/*** printf("DoCommand: %s\n", cmd_line); ***/
    267  1.1  thorpej 
    268  1.1  thorpej 	if (cmd_line[0] == '#') {	/* Comment, skip this line */
    269  1.1  thorpej 		return(1);
    270  1.1  thorpej 	}
    271  1.1  thorpej 	cp = cmd_line;
    272  1.1  thorpej 	if (!next_word(&cp, cmd_op))
    273  1.1  thorpej 		return(1);
    274  1.1  thorpej 	if (cmd_op[0] == 'T') {
    275  1.1  thorpej 		TNO = atoi(&cmd_op[1]);
    276  1.1  thorpej 		if (!next_word(&cp, cmd_op))
    277  1.1  thorpej 			return(1);
    278  1.1  thorpej 	}
    279  1.1  thorpej 	cmdp = cmd_tab;
    280  1.1  thorpej 	while ((cmdp->cmd_op != OP_NULL) && pfxcmp(cmd_op, cmdp->cmd_verb))
    281  1.1  thorpej 		cmdp++;
    282  1.1  thorpej 
    283  1.1  thorpej 	if (cmdp->cmd_op == OP_NULL) {
    284  1.1  thorpej 		if (cmd_op[0])
    285  1.1  thorpej 			printf(" ?? %s\n", cmd_op);
    286  1.1  thorpej 		return(1);
    287  1.1  thorpej 	}
    288  1.1  thorpej 	rc = do_cmd(cmdp->cmd_op, cp);
    289  1.1  thorpej 	if (rc == 0) {
    290  1.1  thorpej 		if (infile) {
    291  1.1  thorpej 			/* error in the config file.  cleanup and exit. */
    292  1.6   itojun 			LOG(LOG_ERR, 0, "config failed. exiting...");
    293  1.1  thorpej 			(void) qcmd_destroyall();
    294  1.1  thorpej 			(void) fclose(infp);
    295  1.1  thorpej 			exit(1);
    296  1.1  thorpej 		} else {
    297  1.1  thorpej 			/* interactive mode */
    298  1.1  thorpej 			printf("error: usage :");
    299  1.1  thorpej 			show_help(cmdp->cmd_op);
    300  1.1  thorpej 		}
    301  1.1  thorpej 	}
    302  1.1  thorpej 	return(1);
    303  1.1  thorpej }
    304  1.1  thorpej 
    305  1.1  thorpej 
    306  1.1  thorpej /*
    307  1.1  thorpej  * Prefix string comparison: Return 0 if s1 string is prefix of s2 string, 1
    308  1.1  thorpej  * otherwise.
    309  1.1  thorpej  */
    310  1.1  thorpej static int
    311  1.1  thorpej pfxcmp(const char *s1, const char *s2)
    312  1.1  thorpej {
    313  1.1  thorpej 	while (*s1)
    314  1.1  thorpej 		if (*s1++ != *s2++)
    315  1.1  thorpej 			return (1);
    316  1.1  thorpej 	return (0);
    317  1.1  thorpej }
    318  1.1  thorpej 
    319  1.1  thorpej /*
    320  1.1  thorpej  * Skip leading blanks, then copy next word (delimited by blank or zero, but
    321  1.1  thorpej  * no longer than 63 bytes) into buffer b, set scan pointer to following
    322  1.1  thorpej  * non-blank (or end of string), and return 1.  If there is no non-blank text,
    323  1.1  thorpej  * set scan ptr to point to 0 byte and return 0.
    324  1.1  thorpej  */
    325  1.1  thorpej static int
    326  1.1  thorpej next_word(char **cpp, char *b)
    327  1.1  thorpej {
    328  1.1  thorpej 	char           *tp;
    329  1.1  thorpej 	size_t		L;
    330  1.1  thorpej 
    331  1.1  thorpej 	*cpp += strspn(*cpp, " \t");
    332  1.1  thorpej 	if (**cpp == '\0' || **cpp == '\n' || **cpp == '#')
    333  1.1  thorpej 		return(0);
    334  1.1  thorpej 
    335  1.1  thorpej 	tp = strpbrk(*cpp, " \t\n#");
    336  1.1  thorpej 	L = MIN((tp)?(tp-*cpp):strlen(*cpp), 63);
    337  1.1  thorpej 	strncpy(b, *cpp, L);
    338  1.1  thorpej 	*(b + L) = '\0';
    339  1.1  thorpej 	*cpp += L;
    340  1.1  thorpej 	*cpp += strspn(*cpp, " \t");
    341  1.1  thorpej 	return (1);
    342  1.1  thorpej }
    343  1.1  thorpej 
    344  1.1  thorpej /*
    345  1.1  thorpej  * do_cmd executes a command input.
    346  1.1  thorpej  * returns 1 if OK, 0 if an error occurs.
    347  1.1  thorpej  */
    348  1.1  thorpej static int
    349  1.1  thorpej do_cmd(int op, char *cmdbuf)
    350  1.1  thorpej {
    351  1.1  thorpej 	int i, rval = 0;
    352  1.1  thorpej 
    353  1.1  thorpej 	switch (op) {
    354  1.1  thorpej 	case OP_HELP:
    355  1.1  thorpej 		for (i = 0; i < OP_NULL; i++)
    356  1.1  thorpej 			show_help(i);
    357  1.1  thorpej 		rval = 1;
    358  1.1  thorpej 		break;
    359  1.1  thorpej 	case OP_QUIT:
    360  1.1  thorpej 		qcmd_destroyall();
    361  1.1  thorpej 		exit(0);
    362  1.1  thorpej 		break;
    363  1.1  thorpej 	case OP_IFACE:
    364  1.1  thorpej 		rval = interface_parser(cmdbuf);
    365  1.1  thorpej 		break;
    366  1.1  thorpej 	case OP_CLASS:
    367  1.1  thorpej 		rval = class_parser(cmdbuf);
    368  1.1  thorpej 		break;
    369  1.1  thorpej 	case OP_FILTER:
    370  1.1  thorpej 		rval = filter_parser(cmdbuf);
    371  1.1  thorpej 		break;
    372  1.1  thorpej 	case OP_ALTQ:
    373  1.1  thorpej 		rval = ctl_parser(cmdbuf);
    374  1.1  thorpej 		break;
    375  1.1  thorpej 	case OP_DEL:
    376  1.1  thorpej 		rval = delete_parser(cmdbuf);
    377  1.1  thorpej 		break;
    378  1.1  thorpej #ifdef INET6
    379  1.1  thorpej 	case OP_FILTER6:
    380  1.1  thorpej 		rval = filter6_parser(cmdbuf);
    381  1.1  thorpej 		break;
    382  1.1  thorpej #endif
    383  1.1  thorpej 	case OP_RED:
    384  1.1  thorpej 		rval = red_parser(cmdbuf);
    385  1.1  thorpej 		break;
    386  1.1  thorpej 	case OP_RIO:
    387  1.1  thorpej 		rval = rio_parser(cmdbuf);
    388  1.1  thorpej 		break;
    389  1.1  thorpej 	case OP_CDNR:
    390  1.1  thorpej 		rval = conditioner_parser(cmdbuf);
    391  1.1  thorpej 		break;
    392  1.1  thorpej 	case OP_BUG:
    393  1.1  thorpej 		if (m_debug & DEBUG_ALTQ) {
    394  1.1  thorpej 			/* turn off verbose */
    395  1.1  thorpej 			l_debug = LOG_INFO;
    396  1.1  thorpej 			m_debug &= ~DEBUG_ALTQ;
    397  1.1  thorpej 		} else {
    398  1.1  thorpej 			/* turn on verbose */
    399  1.1  thorpej 			l_debug = LOG_DEBUG;
    400  1.1  thorpej 			m_debug |= DEBUG_ALTQ;
    401  1.1  thorpej 		}
    402  1.1  thorpej 		break;
    403  1.1  thorpej 	default:
    404  1.1  thorpej 		printf("command %d not supported\n", op);
    405  1.1  thorpej 		rval = 0;
    406  1.1  thorpej 		break;
    407  1.1  thorpej 	}
    408  1.1  thorpej 	return(rval);
    409  1.1  thorpej }
    410  1.1  thorpej 
    411  1.1  thorpej #define EQUAL(s1, s2)	(strcmp((s1), (s2)) == 0)
    412  1.1  thorpej 
    413  1.1  thorpej char *cur_ifname(void)
    414  1.1  thorpej {
    415  1.1  thorpej 	return (if_names[TNO]);
    416  1.1  thorpej }
    417  1.1  thorpej 
    418  1.1  thorpej u_int
    419  1.1  thorpej get_ifindex(const char *ifname)
    420  1.1  thorpej {
    421  1.1  thorpej 	struct if_nameindex *ifnp;
    422  1.1  thorpej 
    423  1.1  thorpej 	for (ifnp = if_namelist; ifnp->if_name != NULL; ifnp++)
    424  1.1  thorpej 		if (strcmp(ifname, ifnp->if_name) == 0)
    425  1.1  thorpej 			return (ifnp->if_index);
    426  1.1  thorpej 	return (0);
    427  1.1  thorpej }
    428  1.1  thorpej 
    429  1.1  thorpej static int
    430  1.1  thorpej get_ifname(char **cpp, char **ifnamep)
    431  1.1  thorpej {
    432  1.1  thorpej 	char w[128], *ocp;
    433  1.1  thorpej 	struct if_nameindex *ifnp;
    434  1.1  thorpej 
    435  1.1  thorpej 	ocp = *cpp;
    436  1.1  thorpej 	if (next_word(&ocp, w) && if_namelist != NULL)
    437  1.1  thorpej 		for (ifnp = if_namelist; ifnp->if_name != NULL; ifnp++)
    438  1.1  thorpej 			if (strcmp(w, ifnp->if_name) == 0) {
    439  1.1  thorpej 				/* if_name found. advance the word pointer */
    440  1.1  thorpej 				*cpp = ocp;
    441  1.4   itojun 				strlcpy(if_names[TNO], w, sizeof(if_names[TNO]));
    442  1.1  thorpej 				*ifnamep = if_names[TNO];
    443  1.1  thorpej 				return (1);
    444  1.1  thorpej 			}
    445  1.1  thorpej 
    446  1.1  thorpej 	/* this is not interface name. use one in the context. */
    447  1.1  thorpej 	if (if_names[TNO][0] == 0)
    448  1.1  thorpej 		return (0);
    449  1.1  thorpej 	*ifnamep = if_names[TNO];
    450  1.1  thorpej 	return (1);
    451  1.1  thorpej }
    452  1.1  thorpej 
    453  1.1  thorpej /* set address and netmask in network byte order */
    454  1.1  thorpej static int
    455  1.1  thorpej get_addr(char **cpp, struct in_addr *addr, struct in_addr *mask)
    456  1.1  thorpej {
    457  1.1  thorpej 	char w[128], *ocp;
    458  1.3   itojun 	struct in_addr tmp;
    459  1.1  thorpej 
    460  1.1  thorpej 	addr->s_addr = 0;
    461  1.1  thorpej 	mask->s_addr = 0xffffffff;
    462  1.1  thorpej 
    463  1.1  thorpej 	if (!next_word(cpp, w))
    464  1.1  thorpej 		return (0);
    465  1.1  thorpej 
    466  1.3   itojun 	if (inet_aton((char *)w, &tmp) != 1) {
    467  1.1  thorpej 		/* try gethostbyname */
    468  1.1  thorpej 		struct hostent *h;
    469  1.1  thorpej 
    470  1.1  thorpej 		if ((h = gethostbyname(w)) == NULL
    471  1.1  thorpej 		    || h->h_addrtype != AF_INET || h->h_length != 4)
    472  1.1  thorpej 			return (0);
    473  1.1  thorpej 
    474  1.1  thorpej 		bcopy(h->h_addr, &tmp, (size_t)h->h_length);
    475  1.1  thorpej 	}
    476  1.1  thorpej 
    477  1.3   itojun 	addr->s_addr = tmp.s_addr;
    478  1.1  thorpej 
    479  1.1  thorpej 	/* check if netmask option is present */
    480  1.1  thorpej 	ocp = *cpp;
    481  1.1  thorpej 	if (next_word(&ocp, w) && EQUAL(w, "netmask")) {
    482  1.1  thorpej 		if (!next_word(&ocp, w))
    483  1.1  thorpej 			return (0);
    484  1.1  thorpej 
    485  1.3   itojun 		if (inet_aton((char *)w, (struct in_addr *)&tmp) != 1)
    486  1.1  thorpej 			return (0);
    487  1.1  thorpej 
    488  1.3   itojun 		mask->s_addr = tmp.s_addr;
    489  1.1  thorpej 		*cpp = ocp;
    490  1.1  thorpej 		return (1);
    491  1.1  thorpej 	}
    492  1.1  thorpej 	/* no netmask option */
    493  1.1  thorpej 	return (1);
    494  1.1  thorpej }
    495  1.1  thorpej 
    496  1.1  thorpej /* returns service number in network byte order */
    497  1.1  thorpej static int
    498  1.1  thorpej get_port(const char *name, u_int16_t *port_no)
    499  1.1  thorpej {
    500  1.1  thorpej 	struct servent *s;
    501  1.1  thorpej 	u_int16_t num;
    502  1.1  thorpej 
    503  1.1  thorpej 	if (isdigit(name[0])) {
    504  1.1  thorpej 		num = (u_int16_t)strtol(name, NULL, 0);
    505  1.1  thorpej 		*port_no = htons(num);
    506  1.1  thorpej 		return (1);
    507  1.1  thorpej 	}
    508  1.1  thorpej 
    509  1.1  thorpej 	if ((s = getservbyname(name, 0)) == NULL)
    510  1.1  thorpej 		return (0);
    511  1.1  thorpej 
    512  1.1  thorpej 	*port_no = (u_int16_t)s->s_port;
    513  1.1  thorpej 	return (1);
    514  1.1  thorpej }
    515  1.1  thorpej 
    516  1.1  thorpej static int
    517  1.1  thorpej get_proto(const char *name, int *proto_no)
    518  1.1  thorpej {
    519  1.1  thorpej 	struct protoent *p;
    520  1.1  thorpej 
    521  1.1  thorpej 	if (isdigit(name[0])) {
    522  1.1  thorpej 		*proto_no = (int)strtol(name, NULL, 0);
    523  1.1  thorpej 		return (1);
    524  1.1  thorpej 	}
    525  1.1  thorpej 
    526  1.1  thorpej 	if ((p = getprotobyname(name)) == NULL)
    527  1.1  thorpej 		return (0);
    528  1.1  thorpej 
    529  1.1  thorpej 	*proto_no = p->p_proto;
    530  1.1  thorpej 	return (1);
    531  1.1  thorpej }
    532  1.1  thorpej 
    533  1.1  thorpej static int
    534  1.4   itojun get_fltr_opts(char **cpp, char *fltr_name, size_t len, int *ruleno)
    535  1.1  thorpej {
    536  1.1  thorpej 	char w[128], *ocp;
    537  1.1  thorpej 
    538  1.1  thorpej 	ocp = *cpp;
    539  1.1  thorpej 	while (next_word(&ocp, w)) {
    540  1.1  thorpej 		if (EQUAL(w, "name")) {
    541  1.1  thorpej 			if (!next_word(&ocp, w))
    542  1.1  thorpej 				return (0);
    543  1.4   itojun 			strlcpy(fltr_name, w, len);
    544  1.1  thorpej 			*cpp = ocp;
    545  1.1  thorpej 		} else if (EQUAL(w, "ruleno")) {
    546  1.1  thorpej 			if (!next_word(&ocp, w))
    547  1.1  thorpej 				return (0);
    548  1.1  thorpej 			*ruleno = (int)strtol(w, NULL, 0);
    549  1.1  thorpej 			*cpp = ocp;
    550  1.1  thorpej 		} else
    551  1.1  thorpej 			break;
    552  1.1  thorpej 	}
    553  1.1  thorpej 	return (1);
    554  1.1  thorpej }
    555  1.1  thorpej 
    556  1.1  thorpej 
    557  1.1  thorpej #define	DISCIPLINE_NONE		0
    558  1.1  thorpej 
    559  1.1  thorpej static int
    560  1.1  thorpej interface_parser(char *cmdbuf)
    561  1.1  thorpej {
    562  1.1  thorpej 	char	w[256], *ap, *cp = cmdbuf;
    563  1.1  thorpej 	char	*ifname, *argv[64], qdisc_name[64];
    564  1.1  thorpej 	int     argc, rval;
    565  1.1  thorpej 
    566  1.1  thorpej 	if (!get_ifname(&cp, &ifname)) {
    567  1.6   itojun 		LOG(LOG_ERR, 0, "missing interface name in %s, line %d",
    568  1.1  thorpej 		    altqconfigfile, line_no);
    569  1.1  thorpej 		return (0);
    570  1.1  thorpej 	}
    571  1.1  thorpej 
    572  1.1  thorpej 	/*
    573  1.1  thorpej 	 * Create argment list & look for scheduling discipline options.
    574  1.1  thorpej 	 */
    575  1.3   itojun 	snprintf(qdisc_name, sizeof(qdisc_name), "null");
    576  1.1  thorpej 	argc = 0;
    577  1.1  thorpej 	ap = w;
    578  1.1  thorpej 	while (next_word(&cp, ap)) {
    579  1.1  thorpej 		if (is_qdisc_name(ap))
    580  1.4   itojun 			strlcpy(qdisc_name, ap, sizeof(qdisc_name));
    581  1.1  thorpej 
    582  1.1  thorpej 		argv[argc] = ap;
    583  1.1  thorpej 		ap += strlen(ap) + 1;
    584  1.1  thorpej 		argc++;
    585  1.1  thorpej 	}
    586  1.1  thorpej 
    587  1.1  thorpej 	rval = qdisc_interface_parser(qdisc_name, ifname, argc, argv);
    588  1.1  thorpej 	if (rval == 0) {
    589  1.6   itojun 		LOG(LOG_ERR, 0, "Error in %s, line %d",
    590  1.1  thorpej 		    altqconfigfile, line_no);
    591  1.1  thorpej 		return (0);
    592  1.1  thorpej 	}
    593  1.1  thorpej 	return (1);
    594  1.1  thorpej }
    595  1.1  thorpej 
    596  1.1  thorpej static int
    597  1.1  thorpej class_parser(char *cmdbuf)
    598  1.1  thorpej {
    599  1.1  thorpej 	char	w[256], *cp = cmdbuf;
    600  1.1  thorpej 	char 	*ifname, qdisc_name[128], class_name[128], parent_name[128];
    601  1.1  thorpej 	char	*clname = class_name;
    602  1.1  thorpej 	char	*parent = NULL;
    603  1.1  thorpej 	char	*argv[64], *ap;
    604  1.1  thorpej 	int	argc, rval;
    605  1.1  thorpej 
    606  1.1  thorpej 	/* get scheduling class */
    607  1.1  thorpej 	if (!next_word(&cp, qdisc_name)) {
    608  1.6   itojun 		LOG(LOG_ERR, 0, "missing scheduling discipline in %s, line %d",
    609  1.1  thorpej 		    altqconfigfile, line_no);
    610  1.1  thorpej 		return (0);
    611  1.1  thorpej 	}
    612  1.1  thorpej 	if (!is_qdisc_name(qdisc_name)) {
    613  1.1  thorpej 		LOG(LOG_ERR, 0,
    614  1.6   itojun 		    "unknown scheduling discipline '%s' in %s, line %d",
    615  1.1  thorpej 		    qdisc_name, altqconfigfile, line_no);
    616  1.1  thorpej 		return (0);
    617  1.1  thorpej 	}
    618  1.1  thorpej 
    619  1.1  thorpej 	/* get interface name */
    620  1.1  thorpej 	if (!get_ifname(&cp, &ifname)) {
    621  1.6   itojun 		LOG(LOG_ERR, 0, "missing interface name in %s, line %d",
    622  1.1  thorpej 		    altqconfigfile, line_no);
    623  1.1  thorpej 		return (0);
    624  1.1  thorpej 	}
    625  1.1  thorpej 
    626  1.1  thorpej 	/* get class name */
    627  1.1  thorpej 	if (!next_word(&cp, class_name)) {
    628  1.6   itojun 		LOG(LOG_ERR, 0, "missing class name in %s, line %d",
    629  1.1  thorpej 		    altqconfigfile, line_no);
    630  1.1  thorpej 		return (0);
    631  1.1  thorpej 	}
    632  1.1  thorpej 
    633  1.1  thorpej 	/* get parent name */
    634  1.1  thorpej 	if (!next_word(&cp, parent_name)) {
    635  1.6   itojun 		LOG(LOG_ERR, 0, "missing parent class in %s, line %d",
    636  1.1  thorpej 		    altqconfigfile, line_no);
    637  1.1  thorpej 		return (0);
    638  1.1  thorpej 	}
    639  1.1  thorpej 	if (!EQUAL(parent_name, "null") && !EQUAL(parent_name, "NULL")) {
    640  1.1  thorpej 		parent = parent_name;
    641  1.1  thorpej 	} else {
    642  1.1  thorpej 		parent = NULL;
    643  1.1  thorpej 	}
    644  1.1  thorpej 
    645  1.1  thorpej 	ap = w;
    646  1.1  thorpej 	argc = 0;
    647  1.1  thorpej 	while (next_word(&cp, ap)) {
    648  1.1  thorpej 		argv[argc] = ap;
    649  1.1  thorpej 		ap += strlen(ap) + 1;
    650  1.1  thorpej 		argc++;
    651  1.1  thorpej 	}
    652  1.1  thorpej 
    653  1.1  thorpej 	rval = qdisc_class_parser(qdisc_name, ifname, clname, parent,
    654  1.1  thorpej 				 argc, argv);
    655  1.1  thorpej     	if (rval == 0) {
    656  1.6   itojun 		LOG(LOG_ERR, 0, "can't add class '%s' on interface '%s'",
    657  1.1  thorpej 		    clname, ifname);
    658  1.1  thorpej 		return (0);
    659  1.1  thorpej 	}
    660  1.1  thorpej 
    661  1.1  thorpej 	return (1);
    662  1.1  thorpej }
    663  1.1  thorpej 
    664  1.1  thorpej static int
    665  1.1  thorpej filter_parser(char *cmdbuf)
    666  1.1  thorpej {
    667  1.1  thorpej 	char 	w[128], *cp = cmdbuf;
    668  1.1  thorpej 	char 	*ifname, class_name[64], fltr_name[64], *flname = NULL;
    669  1.1  thorpej 	struct flow_filter	sfilt;
    670  1.1  thorpej 	int	protocol;
    671  1.1  thorpej 	u_char	tos, tosmask;
    672  1.1  thorpej 	int	ruleno;
    673  1.1  thorpej 	int	dontwarn = 0;
    674  1.1  thorpej 	int	error;
    675  1.1  thorpej 
    676  1.1  thorpej 	memset(&sfilt, 0, sizeof(sfilt));
    677  1.1  thorpej 	sfilt.ff_flow.fi_family = AF_INET;
    678  1.1  thorpej 
    679  1.1  thorpej 	if (!get_ifname(&cp, &ifname)) {
    680  1.6   itojun 		LOG(LOG_ERR, 0, "missing interface name in %s, line %d",
    681  1.1  thorpej 		    altqconfigfile, line_no);
    682  1.1  thorpej 		return (0);
    683  1.1  thorpej 	}
    684  1.1  thorpej 
    685  1.1  thorpej 	if (!next_word(&cp, class_name)) {
    686  1.1  thorpej 		LOG(LOG_ERR, 0,
    687  1.6   itojun 		    "missing class name in %s, line %d",
    688  1.1  thorpej 		    altqconfigfile, line_no);
    689  1.1  thorpej 		return (0);
    690  1.1  thorpej 	}
    691  1.1  thorpej 
    692  1.1  thorpej 	fltr_name[0] = '\0';
    693  1.1  thorpej 	ruleno = 0;
    694  1.4   itojun 	if (!get_fltr_opts(&cp, &fltr_name[0], sizeof(fltr_name), &ruleno)) {
    695  1.1  thorpej 		LOG(LOG_ERR, 0,
    696  1.6   itojun 		    "bad filter option in %s, line %d",
    697  1.1  thorpej 		    altqconfigfile, line_no);
    698  1.1  thorpej 		return (0);
    699  1.1  thorpej 	}
    700  1.1  thorpej 	if (fltr_name[0] != '\0')
    701  1.1  thorpej 		flname = fltr_name;
    702  1.1  thorpej 	sfilt.ff_ruleno = ruleno;
    703  1.1  thorpej 
    704  1.1  thorpej 	/* get filter destination Address */
    705  1.1  thorpej 	if (!get_addr(&cp, &sfilt.ff_flow.fi_dst, &sfilt.ff_mask.mask_dst)) {
    706  1.1  thorpej 		LOG(LOG_ERR, 0,
    707  1.6   itojun 		    "bad filter destination address in %s, line %d",
    708  1.1  thorpej 		    altqconfigfile, line_no);
    709  1.1  thorpej 		return (0);
    710  1.1  thorpej 	}
    711  1.1  thorpej 
    712  1.1  thorpej 	/* get filter destination port */
    713  1.1  thorpej 	if (!next_word(&cp, w)) {
    714  1.1  thorpej 		LOG(LOG_ERR, 0,
    715  1.6   itojun 		    "missing filter destination port in %s, line %d",
    716  1.1  thorpej 		    altqconfigfile, line_no);
    717  1.1  thorpej 		return (0);
    718  1.1  thorpej 	}
    719  1.1  thorpej 	if (!get_port(w, &sfilt.ff_flow.fi_dport)) {
    720  1.6   itojun 		LOG(LOG_ERR, 0, "bad filter destination port in %s, line %d",
    721  1.1  thorpej 		    altqconfigfile, line_no);
    722  1.1  thorpej 		return (0);
    723  1.1  thorpej 	}
    724  1.1  thorpej 
    725  1.1  thorpej 	/* get filter source address */
    726  1.1  thorpej 	if (!get_addr(&cp, &sfilt.ff_flow.fi_src, &sfilt.ff_mask.mask_src)) {
    727  1.6   itojun 		LOG(LOG_ERR, 0, "bad filter source address in %s, line %d",
    728  1.1  thorpej 		    altqconfigfile, line_no);
    729  1.1  thorpej 		return (0);
    730  1.1  thorpej 	}
    731  1.1  thorpej 
    732  1.1  thorpej 	/* get filter source port */
    733  1.1  thorpej 	if (!next_word(&cp, w)) {
    734  1.6   itojun 		LOG(LOG_ERR, 0, "missing filter source port in %s, line %d",
    735  1.1  thorpej 		    altqconfigfile, line_no);
    736  1.1  thorpej 		return (0);
    737  1.1  thorpej 	}
    738  1.1  thorpej 	if (!get_port(w, &sfilt.ff_flow.fi_sport)) {
    739  1.6   itojun 		LOG(LOG_ERR, 0, "bad filter source port in %s, line %d",
    740  1.1  thorpej 		    altqconfigfile, line_no);
    741  1.1  thorpej 		return (0);
    742  1.1  thorpej 	}
    743  1.1  thorpej 
    744  1.1  thorpej 	/* get filter protocol id */
    745  1.1  thorpej 	if (!next_word(&cp, w)) {
    746  1.6   itojun 		LOG(LOG_ERR, 0, "missing filter protocol id in %s, line %d",
    747  1.1  thorpej 		    altqconfigfile, line_no);
    748  1.1  thorpej 		return (0);
    749  1.1  thorpej 	}
    750  1.1  thorpej 	if (!get_proto(w, &protocol)) {
    751  1.6   itojun 		LOG(LOG_ERR, 0, "bad protocol in %s, line %d",
    752  1.1  thorpej 		    altqconfigfile, line_no);
    753  1.1  thorpej 		return (0);
    754  1.1  thorpej 	}
    755  1.1  thorpej 	sfilt.ff_flow.fi_proto = protocol;
    756  1.1  thorpej 
    757  1.1  thorpej 	while (next_word(&cp, w)) {
    758  1.1  thorpej 		if (EQUAL(w, "tos")) {
    759  1.1  thorpej 			tos = 0;
    760  1.1  thorpej 			tosmask = 0xff;
    761  1.1  thorpej 
    762  1.1  thorpej 			if (next_word(&cp, w)) {
    763  1.1  thorpej 				tos = (u_char)strtol(w, NULL, 0);
    764  1.1  thorpej 				if (next_word(&cp, w)) {
    765  1.1  thorpej 					if (EQUAL(w, "tosmask")) {
    766  1.1  thorpej 						next_word(&cp, w);
    767  1.1  thorpej 						tosmask = (u_char)strtol(w, NULL, 0);
    768  1.1  thorpej 					}
    769  1.1  thorpej 				}
    770  1.1  thorpej 			}
    771  1.1  thorpej 			sfilt.ff_flow.fi_tos = tos;
    772  1.1  thorpej 			sfilt.ff_mask.mask_tos = tosmask;
    773  1.1  thorpej 		} else if (EQUAL(w, "gpi")) {
    774  1.1  thorpej 			if (next_word(&cp, w)) {
    775  1.1  thorpej 				sfilt.ff_flow.fi_gpi =
    776  1.1  thorpej 					(u_int32_t)strtoul(w, NULL, 0);
    777  1.1  thorpej 				sfilt.ff_flow.fi_gpi =
    778  1.1  thorpej 					htonl(sfilt.ff_flow.fi_gpi);
    779  1.1  thorpej 			}
    780  1.1  thorpej 		} else if (EQUAL(w, "dontwarn"))
    781  1.1  thorpej 			dontwarn = 1;
    782  1.1  thorpej 	}
    783  1.1  thorpej 
    784  1.1  thorpej 	/*
    785  1.1  thorpej 	 * Add the filter.
    786  1.1  thorpej 	 */
    787  1.1  thorpej 	filter_dontwarn = dontwarn;	/* XXX */
    788  1.1  thorpej 	error = qcmd_add_filter(ifname, class_name, flname, &sfilt);
    789  1.1  thorpej 	filter_dontwarn = 0;		/* XXX */
    790  1.1  thorpej 	if (error) {
    791  1.1  thorpej 		LOG(LOG_ERR, 0,
    792  1.6   itojun 		    "can't add filter to class '%s' on interface '%s'",
    793  1.1  thorpej 		    class_name, ifname);
    794  1.1  thorpej 		return (0);
    795  1.1  thorpej 	}
    796  1.1  thorpej 
    797  1.1  thorpej 	return (1);
    798  1.1  thorpej }
    799  1.1  thorpej 
    800  1.1  thorpej #ifdef INET6
    801  1.1  thorpej static int
    802  1.1  thorpej filter6_parser(char *cmdbuf)
    803  1.1  thorpej {
    804  1.1  thorpej 	char 	w[128], *cp = cmdbuf;
    805  1.1  thorpej 	char 	*ifname, class_name[128], fltr_name[64], *flname = NULL;
    806  1.1  thorpej 	struct flow_filter6	sfilt;
    807  1.1  thorpej 	int	protocol;
    808  1.1  thorpej 	u_char	tclass, tclassmask;
    809  1.1  thorpej 	int	ruleno;
    810  1.1  thorpej 	int	dontwarn = 0;
    811  1.1  thorpej 	int	ret;
    812  1.1  thorpej 
    813  1.1  thorpej 	memset(&sfilt, 0, sizeof(sfilt));
    814  1.1  thorpej 	sfilt.ff_flow6.fi6_family = AF_INET6;
    815  1.1  thorpej 
    816  1.1  thorpej 	if (!get_ifname(&cp, &ifname)) {
    817  1.6   itojun 		LOG(LOG_ERR, 0, "missing interface name in %s, line %d",
    818  1.1  thorpej 		    altqconfigfile, line_no);
    819  1.1  thorpej 		return (0);
    820  1.1  thorpej 	}
    821  1.1  thorpej 
    822  1.1  thorpej 	if (!next_word(&cp, class_name)) {
    823  1.6   itojun 		LOG(LOG_ERR, 0, "missing class name in %s, line %d",
    824  1.1  thorpej 		    altqconfigfile, line_no);
    825  1.1  thorpej 		return (0);
    826  1.1  thorpej 	}
    827  1.1  thorpej 
    828  1.1  thorpej 	fltr_name[0] = '\0';
    829  1.1  thorpej 	ruleno = 0;
    830  1.4   itojun 	if (!get_fltr_opts(&cp, &fltr_name[0], sizeof(fltr_name), &ruleno)) {
    831  1.1  thorpej 		LOG(LOG_ERR, 0,
    832  1.6   itojun 		    "bad filter option in %s, line %d",
    833  1.1  thorpej 		    altqconfigfile, line_no);
    834  1.1  thorpej 		return (0);
    835  1.1  thorpej 	}
    836  1.1  thorpej 	if (fltr_name[0] != '\0')
    837  1.1  thorpej 		flname = fltr_name;
    838  1.1  thorpej 	sfilt.ff_ruleno = ruleno;
    839  1.1  thorpej 
    840  1.1  thorpej 	/* get filter destination address */
    841  1.1  thorpej 	if (!get_ip6addr(&cp, &sfilt.ff_flow6.fi6_dst,
    842  1.1  thorpej 			 &sfilt.ff_mask6.mask6_dst)) {
    843  1.6   itojun 		LOG(LOG_ERR, 0, "bad destination address in %s, line %d",
    844  1.1  thorpej 		    altqconfigfile, line_no);
    845  1.1  thorpej 		return (0);
    846  1.1  thorpej 	}
    847  1.6   itojun 
    848  1.1  thorpej 	/* get filter destination port */
    849  1.1  thorpej 	if (!next_word(&cp, w)) {
    850  1.1  thorpej 		LOG(LOG_ERR, 0,
    851  1.6   itojun 		    "missing filter destination port in %s, line %d",
    852  1.1  thorpej 		    altqconfigfile, line_no);
    853  1.1  thorpej 		return (0);
    854  1.1  thorpej 	}
    855  1.1  thorpej 	if (!get_port(w, &sfilt.ff_flow6.fi6_dport)) {
    856  1.6   itojun 		LOG(LOG_ERR, 0, "bad filter destination port in %s, line %d",
    857  1.1  thorpej 		    altqconfigfile, line_no);
    858  1.1  thorpej 		return (0);
    859  1.1  thorpej 	}
    860  1.6   itojun 
    861  1.1  thorpej 	/* get filter source address */
    862  1.1  thorpej 	if (!get_ip6addr(&cp, &sfilt.ff_flow6.fi6_src,
    863  1.1  thorpej 			 &sfilt.ff_mask6.mask6_src)) {
    864  1.6   itojun 		LOG(LOG_ERR, 0, "bad source address in %s, line %d",
    865  1.1  thorpej 		    altqconfigfile, line_no);
    866  1.1  thorpej 		return (0);
    867  1.1  thorpej 	}
    868  1.1  thorpej 
    869  1.1  thorpej 	/* get filter source port */
    870  1.1  thorpej 	if (!next_word(&cp, w)) {
    871  1.6   itojun 		LOG(LOG_ERR, 0, "missing filter source port in %s, line %d",
    872  1.1  thorpej 		    altqconfigfile, line_no);
    873  1.1  thorpej 		return (0);
    874  1.1  thorpej 	}
    875  1.1  thorpej 	if (!get_port(w, &sfilt.ff_flow6.fi6_sport)) {
    876  1.6   itojun 		LOG(LOG_ERR, 0, "bad filter source port in %s, line %d",
    877  1.1  thorpej 		    altqconfigfile, line_no);
    878  1.1  thorpej 		return (0);
    879  1.1  thorpej 	}
    880  1.1  thorpej 
    881  1.1  thorpej 	/* get filter protocol id */
    882  1.1  thorpej 	if (!next_word(&cp, w)) {
    883  1.6   itojun 		LOG(LOG_ERR, 0, "missing filter protocol id in %s, line %d",
    884  1.1  thorpej 		    altqconfigfile, line_no);
    885  1.1  thorpej 		return (0);
    886  1.1  thorpej 	}
    887  1.1  thorpej 	if (!get_proto(w, &protocol)) {
    888  1.6   itojun 		LOG(LOG_ERR, 0, "bad protocol in %s, line %d",
    889  1.1  thorpej 		    altqconfigfile, line_no);
    890  1.1  thorpej 		return (0);
    891  1.1  thorpej 	}
    892  1.1  thorpej 	sfilt.ff_flow6.fi6_proto = protocol;
    893  1.1  thorpej 
    894  1.1  thorpej 	while (next_word(&cp, w)) {
    895  1.1  thorpej 		if (EQUAL(w, "tclass")) {
    896  1.1  thorpej 			tclass = 0;
    897  1.1  thorpej 			tclassmask = 0xff;
    898  1.1  thorpej 
    899  1.1  thorpej 			if (next_word(&cp, w)) {
    900  1.1  thorpej 				tclass = (u_char)strtol(w, NULL, 0);
    901  1.1  thorpej 				if (next_word(&cp, w)) {
    902  1.1  thorpej 					if (EQUAL(w, "tclassmask")) {
    903  1.1  thorpej 						next_word(&cp, w);
    904  1.1  thorpej 						tclassmask =
    905  1.1  thorpej 						    (u_char)strtol(w, NULL, 0);
    906  1.1  thorpej 					}
    907  1.1  thorpej 				}
    908  1.1  thorpej 			}
    909  1.6   itojun 			sfilt.ff_flow6.fi6_tclass = tclass;
    910  1.6   itojun 			sfilt.ff_mask6.mask6_tclass = tclassmask;
    911  1.1  thorpej 		} else if (EQUAL(w, "gpi")) {
    912  1.1  thorpej 			if (next_word(&cp, w)) {
    913  1.1  thorpej 				sfilt.ff_flow6.fi6_gpi =
    914  1.1  thorpej 					(u_int32_t)strtoul(w, NULL, 0);
    915  1.1  thorpej 				sfilt.ff_flow6.fi6_gpi =
    916  1.1  thorpej 					htonl(sfilt.ff_flow6.fi6_gpi);
    917  1.1  thorpej 			}
    918  1.1  thorpej 		} else if (EQUAL(w, "flowlabel")) {
    919  1.1  thorpej 			if (next_word(&cp, w)) {
    920  1.1  thorpej 				sfilt.ff_flow6.fi6_flowlabel =
    921  1.1  thorpej 				   (u_int32_t)strtoul(w, NULL, 0) & 0x000fffff;
    922  1.1  thorpej 				sfilt.ff_flow6.fi6_flowlabel =
    923  1.1  thorpej 					htonl(sfilt.ff_flow6.fi6_flowlabel);
    924  1.1  thorpej 			}
    925  1.1  thorpej 		} else if (EQUAL(w, "dontwarn"))
    926  1.1  thorpej 			dontwarn = 1;
    927  1.1  thorpej 	}
    928  1.1  thorpej 
    929  1.1  thorpej 	/*
    930  1.1  thorpej 	 * Add the filter.
    931  1.1  thorpej 	 */
    932  1.1  thorpej 	filter_dontwarn = dontwarn;	/* XXX */
    933  1.1  thorpej 	ret = qcmd_add_filter(ifname, class_name, flname,
    934  1.1  thorpej 			      (struct flow_filter *)&sfilt);
    935  1.1  thorpej 	filter_dontwarn = 0;		/* XXX */
    936  1.1  thorpej 	if (ret) {
    937  1.1  thorpej 		LOG(LOG_ERR, 0,
    938  1.6   itojun 		    "can't add filter to class '%s' on interface '%s'",
    939  1.1  thorpej 		    class_name, ifname);
    940  1.1  thorpej 		return (0);
    941  1.1  thorpej 	}
    942  1.1  thorpej 
    943  1.1  thorpej 	return (1);
    944  1.1  thorpej }
    945  1.1  thorpej 
    946  1.1  thorpej static int
    947  1.1  thorpej get_ip6addr(char **cpp, struct in6_addr *addr, struct in6_addr *mask)
    948  1.1  thorpej {
    949  1.1  thorpej 	char w[128], *prefix;
    950  1.1  thorpej 	u_char *cp;
    951  1.1  thorpej 	int len;
    952  1.1  thorpej 
    953  1.1  thorpej 	*addr = in6addr_any;  /* set all 0 */
    954  1.1  thorpej 	*mask = in6addr_any;  /* set all 0 */
    955  1.1  thorpej 
    956  1.1  thorpej 	if (!next_word(cpp, w))
    957  1.1  thorpej 		return (0);
    958  1.1  thorpej 
    959  1.1  thorpej 	if (EQUAL(w, "0"))
    960  1.1  thorpej 		/* abbreviation of a wildcard (::0) */
    961  1.1  thorpej 		return (1);
    962  1.1  thorpej 
    963  1.1  thorpej 	if ((prefix = strchr(w, '/')) != NULL) {
    964  1.1  thorpej 		/* address has prefix length */
    965  1.1  thorpej 		*prefix++ = '\0';
    966  1.1  thorpej 	}
    967  1.1  thorpej 
    968  1.3   itojun 	if (inet_pton(AF_INET6, w, addr) != 1)
    969  1.1  thorpej 		return (0);
    970  1.1  thorpej 
    971  1.1  thorpej 	if (IN6_IS_ADDR_UNSPECIFIED(addr) && prefix == NULL)
    972  1.1  thorpej 		/* wildcard */
    973  1.1  thorpej 		return (1);
    974  1.1  thorpej 
    975  1.1  thorpej 	/* convert address prefix length to address mask */
    976  1.1  thorpej 	if (prefix != NULL) {
    977  1.1  thorpej 		len = (int)strtol(prefix, NULL, 0);
    978  1.1  thorpej 		if ((len < 0) || (len > 128))
    979  1.1  thorpej 			return (0);
    980  1.1  thorpej 		for (cp = (u_char *)mask; len > 7; len -= 8)
    981  1.1  thorpej 			*cp++ = 0xff;
    982  1.1  thorpej 		if (len > 0)
    983  1.1  thorpej 			*cp = (0xff << (8 - len)) & 0xff;
    984  1.1  thorpej 
    985  1.1  thorpej 		IN6ADDR32(addr, 0) &= IN6ADDR32(mask, 0);
    986  1.1  thorpej 		IN6ADDR32(addr, 1) &= IN6ADDR32(mask, 1);
    987  1.1  thorpej 		IN6ADDR32(addr, 2) &= IN6ADDR32(mask, 2);
    988  1.1  thorpej 		IN6ADDR32(addr, 3) &= IN6ADDR32(mask, 3);
    989  1.1  thorpej 	} else
    990  1.1  thorpej 		/* full mask */
    991  1.1  thorpej 		memset(mask, 0xff, sizeof(struct in6_addr));
    992  1.1  thorpej 
    993  1.1  thorpej 	return (1);
    994  1.1  thorpej }
    995  1.1  thorpej 
    996  1.1  thorpej #endif /* INET6 */
    997  1.1  thorpej 
    998  1.1  thorpej static int
    999  1.1  thorpej ctl_parser(char *cmdbuf)
   1000  1.1  thorpej {
   1001  1.1  thorpej 	char	w[128], *cp = cmdbuf;
   1002  1.1  thorpej 	char	*ifname;
   1003  1.1  thorpej 	int	state;
   1004  1.1  thorpej 	int	rval;
   1005  1.1  thorpej 
   1006  1.1  thorpej 	if (!get_ifname(&cp, &ifname)) {
   1007  1.1  thorpej 		printf("missing interface name in %s, line %d",
   1008  1.1  thorpej 		       altqconfigfile, line_no);
   1009  1.1  thorpej 		return (0);
   1010  1.1  thorpej 	}
   1011  1.1  thorpej 
   1012  1.1  thorpej 	if (!next_word(&cp, w)) {
   1013  1.1  thorpej 		state = is_q_enabled(ifname);
   1014  1.1  thorpej 		printf("altq %s on %s\n",
   1015  1.1  thorpej 		       state ? "enabled" : "disabled", ifname);
   1016  1.1  thorpej 		return (1);
   1017  1.1  thorpej 	}
   1018  1.6   itojun 
   1019  1.1  thorpej 	if (EQUAL(w, "enable")) {
   1020  1.1  thorpej 		rval = qcmd_enable(ifname);
   1021  1.1  thorpej 		printf("altq %s on %s\n",
   1022  1.1  thorpej 		       (rval == 0) ? "enabled" : "enable failed!", ifname);
   1023  1.1  thorpej 	} else if (EQUAL(w, "disable")) {
   1024  1.1  thorpej 		rval = qcmd_disable(ifname);
   1025  1.1  thorpej 		printf("altq %s on %s\n",
   1026  1.1  thorpej 		       (rval == 0) ? "disabled" : "disable failed!", ifname);
   1027  1.1  thorpej 	} else if (EQUAL(w, "reload")) {
   1028  1.1  thorpej 		printf("reinitializing altq...\n");
   1029  1.1  thorpej 		qcmd_destroyall();
   1030  1.1  thorpej 		qcmd_init();
   1031  1.1  thorpej 	} else
   1032  1.1  thorpej 		return (0);
   1033  1.1  thorpej 	return (1);
   1034  1.1  thorpej }
   1035  1.1  thorpej 
   1036  1.1  thorpej 
   1037  1.1  thorpej static int
   1038  1.1  thorpej delete_parser(char *cmdbuf)
   1039  1.1  thorpej {
   1040  1.1  thorpej 	char	*cp = cmdbuf;
   1041  1.1  thorpej 	char	*ifname, class_name[128];
   1042  1.1  thorpej 	int	ret;
   1043  1.1  thorpej 
   1044  1.1  thorpej 	if (!get_ifname(&cp, &ifname)) {
   1045  1.1  thorpej 		printf("missing interface name in %s, line %d",
   1046  1.1  thorpej 		       altqconfigfile, line_no);
   1047  1.1  thorpej 		return (0);
   1048  1.1  thorpej 	}
   1049  1.1  thorpej 
   1050  1.1  thorpej 	if (!next_word(&cp, class_name)) {
   1051  1.1  thorpej 		LOG(LOG_ERR, 0,
   1052  1.6   itojun 		    "missing class name in %s, line %d",
   1053  1.1  thorpej 		    altqconfigfile, line_no);
   1054  1.1  thorpej 		return (0);
   1055  1.1  thorpej 	}
   1056  1.1  thorpej 
   1057  1.1  thorpej 	ret = qcmd_delete_class(ifname, class_name);
   1058  1.1  thorpej 	if (ret) {
   1059  1.1  thorpej 		LOG(LOG_ERR, 0,
   1060  1.6   itojun 		    "can't delete class '%s' on interface '%s'",
   1061  1.1  thorpej 		    class_name, ifname);
   1062  1.1  thorpej 		return (0);
   1063  1.1  thorpej 	}
   1064  1.1  thorpej 
   1065  1.1  thorpej 	return (1);
   1066  1.1  thorpej }
   1067  1.1  thorpej 
   1068  1.1  thorpej static int
   1069  1.1  thorpej red_parser(char *cmdbuf)
   1070  1.1  thorpej {
   1071  1.1  thorpej 	char	w[128], *cp = cmdbuf;
   1072  1.1  thorpej 	int th_min, th_max, inv_pmax;
   1073  1.1  thorpej 
   1074  1.1  thorpej 	if (!next_word(&cp, w))
   1075  1.1  thorpej 		goto bad;
   1076  1.1  thorpej 	th_min = (int)strtol(w, NULL, 0);
   1077  1.1  thorpej 
   1078  1.1  thorpej 	if (!next_word(&cp, w))
   1079  1.1  thorpej 		goto bad;
   1080  1.1  thorpej 	th_max = (int)strtol(w, NULL, 0);
   1081  1.1  thorpej 
   1082  1.1  thorpej 	if (!next_word(&cp, w))
   1083  1.1  thorpej 		goto bad;
   1084  1.1  thorpej 	inv_pmax = (int)strtol(w, NULL, 0);
   1085  1.1  thorpej 
   1086  1.1  thorpej 	if (qop_red_set_defaults(th_min, th_max, inv_pmax) != 0) {
   1087  1.6   itojun 		LOG(LOG_ERR, 0, "can't set red default parameters");
   1088  1.1  thorpej 		return (0);
   1089  1.1  thorpej 	}
   1090  1.1  thorpej 
   1091  1.1  thorpej 	return (1);
   1092  1.1  thorpej 
   1093  1.1  thorpej  bad:
   1094  1.6   itojun 	LOG(LOG_ERR, 0, "bad red parameter in %s, line %d",
   1095  1.1  thorpej 	    altqconfigfile, line_no);
   1096  1.1  thorpej 	return (0);
   1097  1.1  thorpej }
   1098  1.1  thorpej 
   1099  1.1  thorpej static int
   1100  1.1  thorpej rio_parser(char *cmdbuf)
   1101  1.1  thorpej {
   1102  1.1  thorpej 	char	w[128], *cp = cmdbuf;
   1103  1.1  thorpej 	int	i;
   1104  1.1  thorpej 	struct redparams params[RIO_NDROPPREC];
   1105  1.1  thorpej 
   1106  1.1  thorpej 	for (i = 0; i < RIO_NDROPPREC; i++) {
   1107  1.1  thorpej 		if (!next_word(&cp, w))
   1108  1.1  thorpej 			goto bad;
   1109  1.1  thorpej 		params[i].th_min = (int)strtol(w, NULL, 0);
   1110  1.1  thorpej 
   1111  1.1  thorpej 		if (!next_word(&cp, w))
   1112  1.1  thorpej 			goto bad;
   1113  1.1  thorpej 		params[i].th_max = (int)strtol(w, NULL, 0);
   1114  1.1  thorpej 
   1115  1.1  thorpej 		if (!next_word(&cp, w))
   1116  1.1  thorpej 			goto bad;
   1117  1.1  thorpej 		params[i].inv_pmax = (int)strtol(w, NULL, 0);
   1118  1.1  thorpej 	}
   1119  1.1  thorpej 
   1120  1.1  thorpej 	if (qop_rio_set_defaults(&params[0]) != 0) {
   1121  1.6   itojun 		LOG(LOG_ERR, 0, "can't set rio default parameters");
   1122  1.1  thorpej 		return (0);
   1123  1.1  thorpej 	}
   1124  1.1  thorpej 
   1125  1.1  thorpej 	return (1);
   1126  1.1  thorpej 
   1127  1.1  thorpej  bad:
   1128  1.6   itojun 	LOG(LOG_ERR, 0, "bad rio parameter in %s, line %d",
   1129  1.1  thorpej 	    altqconfigfile, line_no);
   1130  1.1  thorpej 	return (0);
   1131  1.1  thorpej }
   1132  1.1  thorpej 
   1133  1.1  thorpej static int
   1134  1.1  thorpej conditioner_parser(char *cmdbuf)
   1135  1.1  thorpej {
   1136  1.1  thorpej 	char	cdnr_name[128], *cp = cmdbuf;
   1137  1.1  thorpej 	char	*ifname;
   1138  1.1  thorpej 	struct tc_action action[64];
   1139  1.1  thorpej 
   1140  1.1  thorpej 	if (!get_ifname(&cp, &ifname)) {
   1141  1.6   itojun 		LOG(LOG_ERR, 0, "missing interface name in %s, line %d",
   1142  1.1  thorpej 		    altqconfigfile, line_no);
   1143  1.1  thorpej 		return (0);
   1144  1.1  thorpej 	}
   1145  1.1  thorpej 
   1146  1.1  thorpej 	/* get conditioner name */
   1147  1.1  thorpej 	if (!next_word(&cp, cdnr_name)) {
   1148  1.6   itojun 		LOG(LOG_ERR, 0, "missing cdnr name in %s, line %d",
   1149  1.1  thorpej 		    altqconfigfile, line_no);
   1150  1.1  thorpej 		return (0);
   1151  1.1  thorpej 	}
   1152  1.1  thorpej 
   1153  1.1  thorpej 	if (tc_action_parser(ifname, &cp, &action[0]) == 0)
   1154  1.1  thorpej 		return (0);
   1155  1.1  thorpej 
   1156  1.1  thorpej 	if (qcmd_cdnr_add_element(NULL, ifname, cdnr_name, &action[0]) != 0)
   1157  1.1  thorpej 		return (0);
   1158  1.1  thorpej 	return (1);
   1159  1.1  thorpej }
   1160  1.1  thorpej 
   1161  1.1  thorpej /*
   1162  1.1  thorpej  * recursively parse '<'tc_action'>'
   1163  1.1  thorpej  * note that array "action" grows during recursive parse.
   1164  1.1  thorpej  */
   1165  1.1  thorpej static int
   1166  1.1  thorpej tc_action_parser(char *ifname, char **cpp, struct tc_action *action)
   1167  1.1  thorpej {
   1168  1.1  thorpej 	char	*cp, *start, *end;
   1169  1.1  thorpej 	char	type[128], w[128];
   1170  1.1  thorpej 	int	depth, i;
   1171  1.1  thorpej 	struct tb_profile profile[2];
   1172  1.6   itojun 
   1173  1.1  thorpej 	/*
   1174  1.1  thorpej 	 * find a possibly nested pair of '<' and '>',
   1175  1.1  thorpej 	 * make them pointed by 'start' and 'end'.
   1176  1.1  thorpej 	 */
   1177  1.1  thorpej 	start = strchr(*cpp, '<');
   1178  1.1  thorpej 	if (start == NULL) {
   1179  1.6   itojun 		LOG(LOG_ERR, 0, "conditioner action missing in %s, line %d",
   1180  1.1  thorpej 		    altqconfigfile, line_no);
   1181  1.1  thorpej 		return (0);
   1182  1.1  thorpej 	}
   1183  1.1  thorpej 	depth = 1;
   1184  1.1  thorpej 	cp = start + 1;
   1185  1.1  thorpej 	do {
   1186  1.1  thorpej 		end = strpbrk(cp, "<>");
   1187  1.1  thorpej 		if (end == NULL) {
   1188  1.1  thorpej 			LOG(LOG_ERR, 0,
   1189  1.6   itojun 			    "conditioner action delimiter mismatch in %s, line %d",
   1190  1.1  thorpej 			    altqconfigfile, line_no);
   1191  1.1  thorpej 			return (0);
   1192  1.1  thorpej 		}
   1193  1.1  thorpej 		if (*end == '<')
   1194  1.1  thorpej 			depth++;
   1195  1.1  thorpej 		else if (*end == '>')
   1196  1.1  thorpej 			depth--;
   1197  1.1  thorpej 		cp = end + 1;
   1198  1.1  thorpej 	} while (depth > 0);
   1199  1.1  thorpej 	*end = '\0';
   1200  1.1  thorpej 	*cpp = end + 1;
   1201  1.1  thorpej 	cp = start + 1;
   1202  1.1  thorpej 
   1203  1.1  thorpej 	if (IsDebug(DEBUG_ALTQ)) {
   1204  1.1  thorpej 		printf("tc_action_parser: [%s]\n", cp);
   1205  1.1  thorpej 	}
   1206  1.1  thorpej 
   1207  1.1  thorpej 	if (!next_word(&cp, type)) {
   1208  1.1  thorpej 		LOG(LOG_ERR, 0,
   1209  1.6   itojun 		    "missing conditioner action type in %s, line %d",
   1210  1.1  thorpej 		    altqconfigfile, line_no);
   1211  1.1  thorpej 		return (0);
   1212  1.1  thorpej 	}
   1213  1.6   itojun 
   1214  1.1  thorpej 	/*
   1215  1.1  thorpej 	 * action type specific process
   1216  1.1  thorpej 	 */
   1217  1.1  thorpej 	if (EQUAL(type, "conditioner")) {
   1218  1.1  thorpej 		if (!next_word(&cp, w)) {
   1219  1.1  thorpej 			LOG(LOG_ERR, 0,
   1220  1.6   itojun 			    "missing conditioner name in %s, line %d",
   1221  1.1  thorpej 			    altqconfigfile, line_no);
   1222  1.1  thorpej 			return (0);
   1223  1.1  thorpej 		}
   1224  1.1  thorpej 		action->tca_code = TCACODE_HANDLE;
   1225  1.1  thorpej 		action->tca_handle = cdnr_name2handle(ifname, w);
   1226  1.1  thorpej 		if (action->tca_handle == CDNR_NULL_HANDLE) {
   1227  1.1  thorpej 			LOG(LOG_ERR, 0,
   1228  1.6   itojun 			    "wrong conditioner name %s in %s, line %d",
   1229  1.1  thorpej 			    w, altqconfigfile, line_no);
   1230  1.1  thorpej 			return (0);
   1231  1.1  thorpej 		}
   1232  1.1  thorpej 	} else if (EQUAL(type, "pass")) {
   1233  1.1  thorpej 		action->tca_code = TCACODE_PASS;
   1234  1.1  thorpej 	} else if (EQUAL(type, "drop")) {
   1235  1.1  thorpej 		action->tca_code = TCACODE_DROP;
   1236  1.1  thorpej 	} else if (EQUAL(type, "mark")) {
   1237  1.1  thorpej 		if (!next_word(&cp, w)) {
   1238  1.6   itojun 			LOG(LOG_ERR, 0, "missing dscp in %s, line %d",
   1239  1.1  thorpej 			    altqconfigfile, line_no);
   1240  1.1  thorpej 			return (0);
   1241  1.1  thorpej 		}
   1242  1.1  thorpej 		action->tca_code = TCACODE_MARK;
   1243  1.1  thorpej 		action->tca_dscp = (u_int8_t)strtol(w, NULL, 0);
   1244  1.1  thorpej 	} else if (EQUAL(type, "tbmeter")) {
   1245  1.1  thorpej 		if (!next_word(&cp, w)) {
   1246  1.6   itojun 			LOG(LOG_ERR, 0, "missing tb profile in %s, line %d",
   1247  1.1  thorpej 			    altqconfigfile, line_no);
   1248  1.1  thorpej 			return (0);
   1249  1.1  thorpej 		}
   1250  1.1  thorpej 		profile[0].rate = atobps(w);
   1251  1.1  thorpej 		if (!next_word(&cp, w)) {
   1252  1.6   itojun 			LOG(LOG_ERR, 0, "missing tb profile in %s, line %d",
   1253  1.1  thorpej 			    altqconfigfile, line_no);
   1254  1.1  thorpej 			return (0);
   1255  1.1  thorpej 		}
   1256  1.1  thorpej 		profile[0].depth = atobytes(w);
   1257  1.1  thorpej 		if (tc_action_parser(ifname, &cp, &action[1]) == 0)
   1258  1.1  thorpej 			return (0);
   1259  1.1  thorpej 		if (tc_action_parser(ifname, &cp, &action[2]) == 0)
   1260  1.1  thorpej 			return (0);
   1261  1.1  thorpej 
   1262  1.1  thorpej 		if (qcmd_cdnr_add_tbmeter(action, ifname, NULL, &profile[0],
   1263  1.1  thorpej 					  &action[1], &action[2]) != 0)
   1264  1.1  thorpej 			return (0);
   1265  1.1  thorpej 	} else if (EQUAL(type, "trtcm")) {
   1266  1.1  thorpej 		int coloraware = 0;	/* default is color-blind */
   1267  1.1  thorpej 
   1268  1.1  thorpej 		for (i=0; i<2; i++) {
   1269  1.1  thorpej 			if (!next_word(&cp, w)) {
   1270  1.1  thorpej 				LOG(LOG_ERR, 0,
   1271  1.6   itojun 				    "missing tb profile in %s, line %d",
   1272  1.1  thorpej 				    altqconfigfile, line_no);
   1273  1.1  thorpej 				return (0);
   1274  1.1  thorpej 			}
   1275  1.1  thorpej 			profile[i].rate = atobps(w);
   1276  1.1  thorpej 			if (!next_word(&cp, w)) {
   1277  1.1  thorpej 				LOG(LOG_ERR, 0,
   1278  1.6   itojun 				    "missing tb profile in %s, line %d",
   1279  1.1  thorpej 				    altqconfigfile, line_no);
   1280  1.1  thorpej 				return (0);
   1281  1.1  thorpej 			}
   1282  1.1  thorpej 			profile[i].depth = atobytes(w);
   1283  1.1  thorpej 		}
   1284  1.1  thorpej 		if (tc_action_parser(ifname, &cp, &action[1]) == 0)
   1285  1.1  thorpej 			return (0);
   1286  1.1  thorpej 		if (tc_action_parser(ifname, &cp, &action[2]) == 0)
   1287  1.1  thorpej 			return (0);
   1288  1.1  thorpej 		if (tc_action_parser(ifname, &cp, &action[3]) == 0)
   1289  1.1  thorpej 			return (0);
   1290  1.1  thorpej 		if (next_word(&cp, w)) {
   1291  1.1  thorpej 			if (EQUAL(w, "coloraware"))
   1292  1.1  thorpej 				coloraware = 1;
   1293  1.1  thorpej 			else if (EQUAL(w, "colorblind"))
   1294  1.1  thorpej 				coloraware = 0;
   1295  1.1  thorpej 		}
   1296  1.1  thorpej 
   1297  1.1  thorpej 		if (qcmd_cdnr_add_trtcm(action, ifname, NULL,
   1298  1.1  thorpej 					&profile[0], &profile[1],
   1299  1.1  thorpej 					&action[1], &action[2], &action[3],
   1300  1.1  thorpej 					coloraware) != 0)
   1301  1.1  thorpej 			return (0);
   1302  1.1  thorpej 	} else if (EQUAL(type, "tswtcm")) {
   1303  1.1  thorpej 		u_int32_t cmtd_rate, peak_rate, avg_interval;
   1304  1.1  thorpej 
   1305  1.1  thorpej 		if (!next_word(&cp, w)) {
   1306  1.6   itojun 			LOG(LOG_ERR, 0, "missing cmtd rate in %s, line %d",
   1307  1.1  thorpej 			    altqconfigfile, line_no);
   1308  1.1  thorpej 			return (0);
   1309  1.1  thorpej 		}
   1310  1.1  thorpej 		cmtd_rate = atobps(w);
   1311  1.1  thorpej 
   1312  1.1  thorpej 		if (!next_word(&cp, w)) {
   1313  1.6   itojun 			LOG(LOG_ERR, 0, "missing peak rate in %s, line %d",
   1314  1.1  thorpej 			    altqconfigfile, line_no);
   1315  1.1  thorpej 			return (0);
   1316  1.1  thorpej 		}
   1317  1.1  thorpej 		peak_rate = atobps(w);
   1318  1.1  thorpej 
   1319  1.1  thorpej 		if (!next_word(&cp, w)) {
   1320  1.6   itojun 			LOG(LOG_ERR, 0, "missing avg interval in %s, line %d",
   1321  1.1  thorpej 			    altqconfigfile, line_no);
   1322  1.1  thorpej 			return (0);
   1323  1.1  thorpej 		}
   1324  1.1  thorpej 		avg_interval = (u_int32_t)strtoul(w, NULL, 0);
   1325  1.1  thorpej 
   1326  1.1  thorpej 		if (tc_action_parser(ifname, &cp, &action[1]) == 0)
   1327  1.1  thorpej 			return (0);
   1328  1.1  thorpej 		if (tc_action_parser(ifname, &cp, &action[2]) == 0)
   1329  1.1  thorpej 			return (0);
   1330  1.1  thorpej 		if (tc_action_parser(ifname, &cp, &action[3]) == 0)
   1331  1.1  thorpej 			return (0);
   1332  1.1  thorpej 
   1333  1.1  thorpej 		if (qcmd_cdnr_add_tswtcm(action, ifname, NULL,
   1334  1.1  thorpej 					 cmtd_rate, peak_rate, avg_interval,
   1335  1.1  thorpej 					 &action[1], &action[2], &action[3])
   1336  1.1  thorpej 		    != 0)
   1337  1.1  thorpej 			return (0);
   1338  1.1  thorpej 	} else {
   1339  1.1  thorpej 		LOG(LOG_ERR, 0,
   1340  1.6   itojun 		    "Unkown action type %s in %s, line %d",
   1341  1.1  thorpej 		    type, altqconfigfile, line_no);
   1342  1.1  thorpej 		return (0);
   1343  1.1  thorpej 	}
   1344  1.6   itojun 
   1345  1.1  thorpej 	*end = '>';	/* restore the end delimiter */
   1346  1.1  thorpej 
   1347  1.1  thorpej 	return (1);
   1348  1.1  thorpej }
   1349  1.1  thorpej 
   1350