Home | History | Annotate | Line # | Download | only in libaltq
      1  1.13    andvar /*	$NetBSD: parser.c,v 1.13 2024/01/15 19:44:07 andvar 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.12     ozaki #define MAX_WORD	128
     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.10       dsl 	if (isdigit((unsigned char)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.10       dsl 	if (isdigit((unsigned char)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.13    andvar 	/* create argument 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.11  christos 		IN6ADDR32_SET(addr, 0, IN6ADDR32_GET(mask, 0) &
    847  1.11  christos 		    IN6ADDR32_GET(addr, 0));
    848  1.11  christos 		IN6ADDR32_SET(addr, 1, IN6ADDR32_GET(mask, 1) &
    849  1.11  christos 		    IN6ADDR32_GET(addr, 1));
    850  1.11  christos 		IN6ADDR32_SET(addr, 2, IN6ADDR32_GET(mask, 2) &
    851  1.11  christos 		    IN6ADDR32_GET(addr, 2));
    852  1.11  christos 		IN6ADDR32_SET(addr, 3, IN6ADDR32_GET(mask, 3) &
    853  1.11  christos 		    IN6ADDR32_GET(addr, 3));
    854   1.1   thorpej 	} else
    855   1.1   thorpej 		/* full mask */
    856   1.1   thorpej 		memset(mask, 0xff, sizeof(struct in6_addr));
    857   1.1   thorpej 
    858   1.1   thorpej 	return (1);
    859   1.1   thorpej }
    860   1.1   thorpej 
    861   1.1   thorpej #endif /* INET6 */
    862   1.1   thorpej 
    863   1.1   thorpej static int
    864   1.1   thorpej ctl_parser(char *cmdbuf)
    865   1.1   thorpej {
    866   1.7    itojun 	char	w[MAX_WORD], *cp = cmdbuf;
    867   1.1   thorpej 	char	*ifname;
    868   1.1   thorpej 	int	state;
    869   1.1   thorpej 	int	rval;
    870   1.7    itojun 
    871   1.1   thorpej 	if (!get_ifname(&cp, &ifname)) {
    872   1.1   thorpej 		printf("missing interface name in %s, line %d",
    873   1.1   thorpej 		       altqconfigfile, line_no);
    874   1.1   thorpej 		return (0);
    875   1.1   thorpej 	}
    876   1.1   thorpej 
    877   1.1   thorpej 	if (!next_word(&cp, w)) {
    878   1.1   thorpej 		state = is_q_enabled(ifname);
    879   1.1   thorpej 		printf("altq %s on %s\n",
    880   1.1   thorpej 		       state ? "enabled" : "disabled", ifname);
    881   1.1   thorpej 		return (1);
    882   1.1   thorpej 	}
    883   1.6    itojun 
    884   1.1   thorpej 	if (EQUAL(w, "enable")) {
    885   1.1   thorpej 		rval = qcmd_enable(ifname);
    886   1.1   thorpej 		printf("altq %s on %s\n",
    887   1.1   thorpej 		       (rval == 0) ? "enabled" : "enable failed!", ifname);
    888   1.1   thorpej 	} else if (EQUAL(w, "disable")) {
    889   1.1   thorpej 		rval = qcmd_disable(ifname);
    890   1.1   thorpej 		printf("altq %s on %s\n",
    891   1.1   thorpej 		       (rval == 0) ? "disabled" : "disable failed!", ifname);
    892   1.1   thorpej 	} else if (EQUAL(w, "reload")) {
    893   1.1   thorpej 		printf("reinitializing altq...\n");
    894   1.1   thorpej 		qcmd_destroyall();
    895   1.1   thorpej 		qcmd_init();
    896   1.1   thorpej 	} else
    897   1.1   thorpej 		return (0);
    898   1.1   thorpej 	return (1);
    899   1.1   thorpej }
    900   1.1   thorpej 
    901   1.1   thorpej static int
    902   1.1   thorpej delete_parser(char *cmdbuf)
    903   1.1   thorpej {
    904   1.1   thorpej 	char	*cp = cmdbuf;
    905   1.7    itojun 	char	*ifname, class_name[MAX_WORD], filter_name[MAX_WORD];
    906   1.1   thorpej 	int	ret;
    907   1.7    itojun 
    908   1.1   thorpej 	if (!get_ifname(&cp, &ifname)) {
    909   1.7    itojun 		LOG(LOG_ERR, 0, "missing interface name");
    910   1.1   thorpej 		return (0);
    911   1.1   thorpej 	}
    912   1.1   thorpej 
    913   1.1   thorpej 	if (!next_word(&cp, class_name)) {
    914   1.7    itojun 		LOG(LOG_ERR, 0, "missing class name");
    915   1.1   thorpej 		return (0);
    916   1.1   thorpej 	}
    917   1.1   thorpej 
    918   1.7    itojun 	/* check if filter is specified */
    919   1.7    itojun 	if (next_word(&cp, filter_name)) {
    920   1.7    itojun 		ret = qcmd_delete_filter(ifname, class_name, filter_name);
    921   1.7    itojun 		if (ret) {
    922   1.7    itojun 			LOG(LOG_ERR, 0,
    923   1.7    itojun 			    "can't delete filter '%s' on interface '%s'",
    924   1.7    itojun 			    filter_name, ifname);
    925   1.7    itojun 			return (0);
    926   1.7    itojun 		}
    927   1.7    itojun 		return (1);
    928   1.7    itojun 	}
    929   1.7    itojun 
    930   1.1   thorpej 	ret = qcmd_delete_class(ifname, class_name);
    931   1.1   thorpej 	if (ret) {
    932   1.1   thorpej 		LOG(LOG_ERR, 0,
    933   1.6    itojun 		    "can't delete class '%s' on interface '%s'",
    934   1.1   thorpej 		    class_name, ifname);
    935   1.1   thorpej 		return (0);
    936   1.1   thorpej 	}
    937   1.1   thorpej 
    938   1.1   thorpej 	return (1);
    939   1.1   thorpej }
    940   1.1   thorpej 
    941   1.1   thorpej static int
    942   1.1   thorpej red_parser(char *cmdbuf)
    943   1.1   thorpej {
    944   1.7    itojun 	char	w[MAX_WORD], *cp = cmdbuf;
    945   1.1   thorpej 	int th_min, th_max, inv_pmax;
    946   1.1   thorpej 
    947   1.1   thorpej 	if (!next_word(&cp, w))
    948   1.1   thorpej 		goto bad;
    949   1.1   thorpej 	th_min = (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 	th_max = (int)strtol(w, NULL, 0);
    954   1.1   thorpej 
    955   1.1   thorpej 	if (!next_word(&cp, w))
    956   1.1   thorpej 		goto bad;
    957   1.1   thorpej 	inv_pmax = (int)strtol(w, NULL, 0);
    958   1.1   thorpej 
    959   1.1   thorpej 	if (qop_red_set_defaults(th_min, th_max, inv_pmax) != 0) {
    960   1.6    itojun 		LOG(LOG_ERR, 0, "can't set red default parameters");
    961   1.1   thorpej 		return (0);
    962   1.1   thorpej 	}
    963   1.1   thorpej 
    964   1.1   thorpej 	return (1);
    965   1.1   thorpej 
    966   1.1   thorpej  bad:
    967   1.7    itojun 	LOG(LOG_ERR, 0, "bad red parameter");
    968   1.1   thorpej 	return (0);
    969   1.1   thorpej }
    970   1.1   thorpej 
    971   1.1   thorpej static int
    972   1.1   thorpej rio_parser(char *cmdbuf)
    973   1.1   thorpej {
    974   1.7    itojun 	char	w[MAX_WORD], *cp = cmdbuf;
    975   1.1   thorpej 	int	i;
    976   1.1   thorpej 	struct redparams params[RIO_NDROPPREC];
    977   1.1   thorpej 
    978   1.1   thorpej 	for (i = 0; i < RIO_NDROPPREC; i++) {
    979   1.1   thorpej 		if (!next_word(&cp, w))
    980   1.1   thorpej 			goto bad;
    981   1.1   thorpej 		params[i].th_min = (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].th_max = (int)strtol(w, NULL, 0);
    986   1.1   thorpej 
    987   1.1   thorpej 		if (!next_word(&cp, w))
    988   1.1   thorpej 			goto bad;
    989   1.1   thorpej 		params[i].inv_pmax = (int)strtol(w, NULL, 0);
    990   1.1   thorpej 	}
    991   1.1   thorpej 
    992   1.1   thorpej 	if (qop_rio_set_defaults(&params[0]) != 0) {
    993   1.6    itojun 		LOG(LOG_ERR, 0, "can't set rio default parameters");
    994   1.1   thorpej 		return (0);
    995   1.1   thorpej 	}
    996   1.1   thorpej 
    997   1.1   thorpej 	return (1);
    998   1.1   thorpej 
    999   1.1   thorpej  bad:
   1000   1.7    itojun 	LOG(LOG_ERR, 0, "bad rio parameter");
   1001   1.1   thorpej 	return (0);
   1002   1.1   thorpej }
   1003   1.1   thorpej 
   1004   1.1   thorpej static int
   1005   1.1   thorpej conditioner_parser(char *cmdbuf)
   1006   1.1   thorpej {
   1007   1.7    itojun 	char	cdnr_name[MAX_WORD], *cp = cmdbuf;
   1008   1.1   thorpej 	char	*ifname;
   1009   1.7    itojun 	struct tc_action action[MAX_ACTIONS];
   1010   1.7    itojun 
   1011   1.1   thorpej 	if (!get_ifname(&cp, &ifname)) {
   1012   1.7    itojun 		LOG(LOG_ERR, 0, "missing interface name");
   1013   1.1   thorpej 		return (0);
   1014   1.1   thorpej 	}
   1015   1.1   thorpej 
   1016   1.1   thorpej 	/* get conditioner name */
   1017   1.1   thorpej 	if (!next_word(&cp, cdnr_name)) {
   1018   1.7    itojun 		LOG(LOG_ERR, 0, "missing cdnr name");
   1019   1.1   thorpej 		return (0);
   1020   1.1   thorpej 	}
   1021   1.1   thorpej 
   1022   1.1   thorpej 	if (tc_action_parser(ifname, &cp, &action[0]) == 0)
   1023   1.1   thorpej 		return (0);
   1024   1.1   thorpej 
   1025   1.1   thorpej 	if (qcmd_cdnr_add_element(NULL, ifname, cdnr_name, &action[0]) != 0)
   1026   1.1   thorpej 		return (0);
   1027   1.1   thorpej 	return (1);
   1028   1.1   thorpej }
   1029   1.1   thorpej 
   1030   1.1   thorpej /*
   1031   1.1   thorpej  * recursively parse '<'tc_action'>'
   1032   1.1   thorpej  * note that array "action" grows during recursive parse.
   1033   1.1   thorpej  */
   1034   1.1   thorpej static int
   1035   1.1   thorpej tc_action_parser(char *ifname, char **cpp, struct tc_action *action)
   1036   1.1   thorpej {
   1037   1.1   thorpej 	char	*cp, *start, *end;
   1038   1.7    itojun 	char	type[MAX_WORD], w[MAX_WORD];
   1039   1.1   thorpej 	int	depth, i;
   1040   1.1   thorpej 	struct tb_profile profile[2];
   1041   1.6    itojun 
   1042   1.1   thorpej 	/*
   1043   1.1   thorpej 	 * find a possibly nested pair of '<' and '>',
   1044   1.1   thorpej 	 * make them pointed by 'start' and 'end'.
   1045   1.1   thorpej 	 */
   1046   1.1   thorpej 	start = strchr(*cpp, '<');
   1047   1.1   thorpej 	if (start == NULL) {
   1048   1.7    itojun 		LOG(LOG_ERR, 0, "conditioner action missing");
   1049   1.1   thorpej 		return (0);
   1050   1.1   thorpej 	}
   1051   1.1   thorpej 	depth = 1;
   1052   1.1   thorpej 	cp = start + 1;
   1053   1.1   thorpej 	do {
   1054   1.1   thorpej 		end = strpbrk(cp, "<>");
   1055   1.1   thorpej 		if (end == NULL) {
   1056   1.1   thorpej 			LOG(LOG_ERR, 0,
   1057   1.7    itojun 			    "conditioner action delimiter mismatch");
   1058   1.1   thorpej 			return (0);
   1059   1.1   thorpej 		}
   1060   1.1   thorpej 		if (*end == '<')
   1061   1.1   thorpej 			depth++;
   1062   1.1   thorpej 		else if (*end == '>')
   1063   1.1   thorpej 			depth--;
   1064   1.1   thorpej 		cp = end + 1;
   1065   1.1   thorpej 	} while (depth > 0);
   1066   1.1   thorpej 	*end = '\0';
   1067   1.1   thorpej 	*cpp = end + 1;
   1068   1.1   thorpej 	cp = start + 1;
   1069   1.1   thorpej 
   1070   1.1   thorpej 	if (IsDebug(DEBUG_ALTQ)) {
   1071   1.1   thorpej 		printf("tc_action_parser: [%s]\n", cp);
   1072   1.1   thorpej 	}
   1073   1.1   thorpej 
   1074   1.1   thorpej 	if (!next_word(&cp, type)) {
   1075   1.7    itojun 		LOG(LOG_ERR, 0, "missing conditioner action type");
   1076   1.1   thorpej 		return (0);
   1077   1.1   thorpej 	}
   1078   1.6    itojun 
   1079   1.1   thorpej 	/*
   1080   1.1   thorpej 	 * action type specific process
   1081   1.1   thorpej 	 */
   1082   1.1   thorpej 	if (EQUAL(type, "conditioner")) {
   1083   1.1   thorpej 		if (!next_word(&cp, w)) {
   1084   1.1   thorpej 			LOG(LOG_ERR, 0,
   1085   1.7    itojun 			    "missing conditioner name");
   1086   1.1   thorpej 			return (0);
   1087   1.1   thorpej 		}
   1088   1.1   thorpej 		action->tca_code = TCACODE_HANDLE;
   1089   1.1   thorpej 		action->tca_handle = cdnr_name2handle(ifname, w);
   1090   1.1   thorpej 		if (action->tca_handle == CDNR_NULL_HANDLE) {
   1091   1.1   thorpej 			LOG(LOG_ERR, 0,
   1092   1.7    itojun 			    "wrong conditioner name %s", w);
   1093   1.1   thorpej 			return (0);
   1094   1.1   thorpej 		}
   1095   1.1   thorpej 	} else if (EQUAL(type, "pass")) {
   1096   1.1   thorpej 		action->tca_code = TCACODE_PASS;
   1097   1.1   thorpej 	} else if (EQUAL(type, "drop")) {
   1098   1.1   thorpej 		action->tca_code = TCACODE_DROP;
   1099   1.1   thorpej 	} else if (EQUAL(type, "mark")) {
   1100   1.1   thorpej 		if (!next_word(&cp, w)) {
   1101   1.7    itojun 			LOG(LOG_ERR, 0, "missing dscp");
   1102   1.1   thorpej 			return (0);
   1103   1.1   thorpej 		}
   1104   1.1   thorpej 		action->tca_code = TCACODE_MARK;
   1105   1.1   thorpej 		action->tca_dscp = (u_int8_t)strtol(w, NULL, 0);
   1106   1.1   thorpej 	} else if (EQUAL(type, "tbmeter")) {
   1107   1.1   thorpej 		if (!next_word(&cp, w)) {
   1108   1.7    itojun 			LOG(LOG_ERR, 0, "missing tb profile");
   1109   1.1   thorpej 			return (0);
   1110   1.1   thorpej 		}
   1111   1.1   thorpej 		profile[0].rate = atobps(w);
   1112   1.1   thorpej 		if (!next_word(&cp, w)) {
   1113   1.7    itojun 			LOG(LOG_ERR, 0, "missing tb profile");
   1114   1.1   thorpej 			return (0);
   1115   1.1   thorpej 		}
   1116   1.1   thorpej 		profile[0].depth = atobytes(w);
   1117   1.1   thorpej 		if (tc_action_parser(ifname, &cp, &action[1]) == 0)
   1118   1.1   thorpej 			return (0);
   1119   1.1   thorpej 		if (tc_action_parser(ifname, &cp, &action[2]) == 0)
   1120   1.1   thorpej 			return (0);
   1121   1.1   thorpej 
   1122   1.1   thorpej 		if (qcmd_cdnr_add_tbmeter(action, ifname, NULL, &profile[0],
   1123   1.1   thorpej 					  &action[1], &action[2]) != 0)
   1124   1.1   thorpej 			return (0);
   1125   1.1   thorpej 	} else if (EQUAL(type, "trtcm")) {
   1126   1.1   thorpej 		int coloraware = 0;	/* default is color-blind */
   1127   1.1   thorpej 
   1128   1.1   thorpej 		for (i=0; i<2; i++) {
   1129   1.1   thorpej 			if (!next_word(&cp, w)) {
   1130   1.7    itojun 				LOG(LOG_ERR, 0, "missing tb profile");
   1131   1.1   thorpej 				return (0);
   1132   1.1   thorpej 			}
   1133   1.1   thorpej 			profile[i].rate = atobps(w);
   1134   1.1   thorpej 			if (!next_word(&cp, w)) {
   1135   1.7    itojun 				LOG(LOG_ERR, 0, "missing tb profile");
   1136   1.1   thorpej 				return (0);
   1137   1.1   thorpej 			}
   1138   1.1   thorpej 			profile[i].depth = atobytes(w);
   1139   1.1   thorpej 		}
   1140   1.1   thorpej 		if (tc_action_parser(ifname, &cp, &action[1]) == 0)
   1141   1.1   thorpej 			return (0);
   1142   1.1   thorpej 		if (tc_action_parser(ifname, &cp, &action[2]) == 0)
   1143   1.1   thorpej 			return (0);
   1144   1.1   thorpej 		if (tc_action_parser(ifname, &cp, &action[3]) == 0)
   1145   1.1   thorpej 			return (0);
   1146   1.1   thorpej 		if (next_word(&cp, w)) {
   1147   1.1   thorpej 			if (EQUAL(w, "coloraware"))
   1148   1.1   thorpej 				coloraware = 1;
   1149   1.1   thorpej 			else if (EQUAL(w, "colorblind"))
   1150   1.1   thorpej 				coloraware = 0;
   1151   1.1   thorpej 		}
   1152   1.1   thorpej 
   1153   1.1   thorpej 		if (qcmd_cdnr_add_trtcm(action, ifname, NULL,
   1154   1.1   thorpej 					&profile[0], &profile[1],
   1155   1.1   thorpej 					&action[1], &action[2], &action[3],
   1156   1.1   thorpej 					coloraware) != 0)
   1157   1.1   thorpej 			return (0);
   1158   1.1   thorpej 	} else if (EQUAL(type, "tswtcm")) {
   1159   1.1   thorpej 		u_int32_t cmtd_rate, peak_rate, avg_interval;
   1160   1.7    itojun 
   1161   1.1   thorpej 		if (!next_word(&cp, w)) {
   1162   1.7    itojun 			LOG(LOG_ERR, 0, "missing cmtd rate");
   1163   1.1   thorpej 			return (0);
   1164   1.1   thorpej 		}
   1165   1.1   thorpej 		cmtd_rate = atobps(w);
   1166   1.1   thorpej 
   1167   1.1   thorpej 		if (!next_word(&cp, w)) {
   1168   1.7    itojun 			LOG(LOG_ERR, 0, "missing peak rate");
   1169   1.1   thorpej 			return (0);
   1170   1.1   thorpej 		}
   1171   1.1   thorpej 		peak_rate = atobps(w);
   1172   1.1   thorpej 
   1173   1.1   thorpej 		if (!next_word(&cp, w)) {
   1174   1.7    itojun 			LOG(LOG_ERR, 0, "missing avg interval");
   1175   1.1   thorpej 			return (0);
   1176   1.1   thorpej 		}
   1177   1.1   thorpej 		avg_interval = (u_int32_t)strtoul(w, NULL, 0);
   1178   1.1   thorpej 
   1179   1.1   thorpej 		if (tc_action_parser(ifname, &cp, &action[1]) == 0)
   1180   1.1   thorpej 			return (0);
   1181   1.1   thorpej 		if (tc_action_parser(ifname, &cp, &action[2]) == 0)
   1182   1.1   thorpej 			return (0);
   1183   1.1   thorpej 		if (tc_action_parser(ifname, &cp, &action[3]) == 0)
   1184   1.1   thorpej 			return (0);
   1185   1.1   thorpej 
   1186   1.1   thorpej 		if (qcmd_cdnr_add_tswtcm(action, ifname, NULL,
   1187   1.1   thorpej 					 cmtd_rate, peak_rate, avg_interval,
   1188   1.1   thorpej 					 &action[1], &action[2], &action[3])
   1189   1.1   thorpej 		    != 0)
   1190   1.1   thorpej 			return (0);
   1191   1.1   thorpej 	} else {
   1192   1.8       wiz 		LOG(LOG_ERR, 0, "unknown action type %s");
   1193   1.1   thorpej 		return (0);
   1194   1.1   thorpej 	}
   1195   1.6    itojun 
   1196   1.1   thorpej 	*end = '>';	/* restore the end delimiter */
   1197   1.1   thorpej 
   1198   1.1   thorpej 	return (1);
   1199   1.1   thorpej }
   1200