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