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