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