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