1*915340d5Sandvar /* $NetBSD: parser.c,v 1.13 2024/01/15 19:44:07 andvar Exp $ */
269881cf6Sitojun /* $KAME: parser.c,v 1.16 2002/02/20 10:40:39 kjc Exp $ */
369881cf6Sitojun /*
469881cf6Sitojun * Copyright (C) 1999-2002
569881cf6Sitojun * Sony Computer Science Laboratories, Inc. All rights reserved.
669881cf6Sitojun *
769881cf6Sitojun * Redistribution and use in source and binary forms, with or without
869881cf6Sitojun * modification, are permitted provided that the following conditions
969881cf6Sitojun * are met:
1069881cf6Sitojun * 1. Redistributions of source code must retain the above copyright
1169881cf6Sitojun * notice, this list of conditions and the following disclaimer.
1269881cf6Sitojun * 2. Redistributions in binary form must reproduce the above copyright
1369881cf6Sitojun * notice, this list of conditions and the following disclaimer in the
1469881cf6Sitojun * documentation and/or other materials provided with the distribution.
1569881cf6Sitojun *
1669881cf6Sitojun * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
1769881cf6Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1869881cf6Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1969881cf6Sitojun * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
2069881cf6Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2169881cf6Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2269881cf6Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2369881cf6Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2469881cf6Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2569881cf6Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2669881cf6Sitojun * SUCH DAMAGE.
2769881cf6Sitojun */
2895a65560Sthorpej
2969881cf6Sitojun #include <sys/param.h>
3069881cf6Sitojun #include <sys/socket.h>
3169881cf6Sitojun #include <net/if.h>
3269881cf6Sitojun #include <netinet/in.h>
3369881cf6Sitojun #include <arpa/inet.h>
3495a65560Sthorpej
3595a65560Sthorpej #include <stdio.h>
3695a65560Sthorpej #include <stdlib.h>
3795a65560Sthorpej #include <unistd.h>
3895a65560Sthorpej #include <stddef.h>
3995a65560Sthorpej #include <string.h>
4095a65560Sthorpej #include <ctype.h>
4195a65560Sthorpej #include <errno.h>
4295a65560Sthorpej #include <syslog.h>
4395a65560Sthorpej #include <netdb.h>
4469881cf6Sitojun #include <err.h>
4595a65560Sthorpej
4695a65560Sthorpej #include <altq/altq.h>
4795a65560Sthorpej #include <altq/altq_cdnr.h>
4895a65560Sthorpej #include <altq/altq_red.h>
4995a65560Sthorpej #include <altq/altq_rio.h>
5095a65560Sthorpej #include "altq_qop.h"
5195a65560Sthorpej #include "qop_cdnr.h"
5295a65560Sthorpej
538b8734d2Sitojun static int is_qdisc_name(const char *);
548b8734d2Sitojun static int qdisc_interface_parser(const char *, const char *, int, char **);
558b8734d2Sitojun static int qdisc_class_parser(const char *, const char *, const char *,
568b8734d2Sitojun const char *, int, char **);
578b8734d2Sitojun static int next_word(char **, char *);
5895a65560Sthorpej
598b8734d2Sitojun static int get_ifname(char **, char **);
608b8734d2Sitojun static int get_addr(char **, struct in_addr *, struct in_addr *);
618b8734d2Sitojun static int get_port(const char *, u_int16_t *);
628b8734d2Sitojun static int get_proto(const char *, int *);
638b8734d2Sitojun static int get_fltr_opts(char **, char *, size_t, int *);
648b8734d2Sitojun static int interface_parser(char *);
658b8734d2Sitojun static int class_parser(char *) ;
668b8734d2Sitojun static int filter_parser(char *);
6795a65560Sthorpej #ifdef INET6
688b8734d2Sitojun static int filter6_parser(char *);
698b8734d2Sitojun static int get_ip6addr(char **, struct in6_addr *, struct in6_addr *);
7095a65560Sthorpej #endif
718b8734d2Sitojun static int ctl_parser(char *);
728b8734d2Sitojun static int delete_parser(char *);
738b8734d2Sitojun static int red_parser(char *);
748b8734d2Sitojun static int rio_parser(char *);
758b8734d2Sitojun static int conditioner_parser(char *);
768b8734d2Sitojun static int tc_action_parser(char *, char **, struct tc_action *);
7795a65560Sthorpej
7869881cf6Sitojun #define MAX_LINE 1024
79aeaca9dbSozaki-r #define MAX_WORD 128
8069881cf6Sitojun #define MAX_ARGS 64
8169881cf6Sitojun #define MAX_ACTIONS 16
8295a65560Sthorpej
8395a65560Sthorpej #ifndef MAX
8495a65560Sthorpej #define MAX(a,b) (((a)>(b))?(a):(b))
8595a65560Sthorpej #endif
8695a65560Sthorpej #ifndef MIN
8795a65560Sthorpej #define MIN(a,b) (((a)<(b))?(a):(b))
8895a65560Sthorpej #endif
8969881cf6Sitojun #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
9095a65560Sthorpej
9169881cf6Sitojun int line_no = 0;
9269881cf6Sitojun int filter_dontwarn;
9395a65560Sthorpej
9469881cf6Sitojun static char curifname[IFNAMSIZ];
9569881cf6Sitojun static struct if_nameindex *if_namelist = NULL;
9669881cf6Sitojun
9769881cf6Sitojun struct cmd_tab {
9869881cf6Sitojun const char *cmd;
9969881cf6Sitojun int (*parser)(char *);
10069881cf6Sitojun const char *help;
10195a65560Sthorpej } cmd_tab[] = {
102b7e50f13Swiz {"?", NULL, "?"},
103b7e50f13Swiz {"help", NULL, "help"},
10469881cf6Sitojun {"quit", NULL, "quit"},
10569881cf6Sitojun {"interface", interface_parser, "interface if_name [bandwidth bps] [cbq|hfsc]"},
10669881cf6Sitojun {"class", class_parser, "class discipline if_name class_name [parent]"},
10769881cf6Sitojun {"filter", filter_parser, "filter if_name class_name [name filt_name] dst [netmask #] dport src [netmask #] sport proto [tos # [tosmask #] [gpi #] [dontwarn]"},
10869881cf6Sitojun {"altq", ctl_parser, "altq if_name {enable|disable}"},
10969881cf6Sitojun {"delete", delete_parser, "delete if_name class_name [filter_name]"},
11095a65560Sthorpej #ifdef INET6
11169881cf6Sitojun {"filter6", filter6_parser, "filter6 if_name class_name [name filt_name] dst[/prefix] dport src[/prefix] sport proto [flowlabel #][tclass # [tclassmask #]][gpi #] [dontwarn]"},
11295a65560Sthorpej #endif
11369881cf6Sitojun {"red", red_parser, "red th_min th_max inv_pmax"},
11469881cf6Sitojun {"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"},
11569881cf6Sitojun {"conditioner", conditioner_parser, "conditioner if_name cdnr_name <tc_action>"},
11669881cf6Sitojun {"debug", NULL, "debug"},
11769881cf6Sitojun {NULL, NULL, NULL} /* termination */
11895a65560Sthorpej };
11995a65560Sthorpej
12069881cf6Sitojun /*
12169881cf6Sitojun * read one line from the specified stream. if it's a command,
12269881cf6Sitojun * execute the command.
12369881cf6Sitojun * returns 1 if OK, 0 if error or EOF.
12469881cf6Sitojun */
12569881cf6Sitojun int
do_command(FILE * fp)12669881cf6Sitojun do_command(FILE *fp)
12769881cf6Sitojun {
12869881cf6Sitojun char cmd_line[MAX_LINE], cmd[MAX_WORD], *cp;
12969881cf6Sitojun struct cmd_tab *tp;
13069881cf6Sitojun int len, rval;
13169881cf6Sitojun
13269881cf6Sitojun /*
13369881cf6Sitojun * read a line from the stream and make it a null-terminated string
13469881cf6Sitojun */
13569881cf6Sitojun cp = cmd_line;
13669881cf6Sitojun read_line:
13769881cf6Sitojun if (fgets(cp, &cmd_line[MAX_LINE] - cp, fp) == NULL)
13869881cf6Sitojun /* EOF or error */
13969881cf6Sitojun return(0);
14069881cf6Sitojun line_no++;
14169881cf6Sitojun
14269881cf6Sitojun /* null-terminate the line */
14369881cf6Sitojun if ((len = strlen(cmd_line)) > 0) {
14469881cf6Sitojun cp = cmd_line + len - 1;
14569881cf6Sitojun if (*cp == '\n') {
14669881cf6Sitojun /* if escaped newline, read next line */
14769881cf6Sitojun if (len > 1 && *(cp - 1) == '\\')
14869881cf6Sitojun goto read_line;
14969881cf6Sitojun *cp = '\0';
15069881cf6Sitojun } else if (!feof(fp))
15169881cf6Sitojun err(1, "LINE %d too long!", line_no);
15269881cf6Sitojun }
15369881cf6Sitojun /* trim comments */
15469881cf6Sitojun if ((cp = strchr(cmd_line, '#')) != NULL)
15569881cf6Sitojun *cp = '\0';
15669881cf6Sitojun
15769881cf6Sitojun cp = cmd_line;
15869881cf6Sitojun if ((len = next_word(&cp, cmd)) == 0)
15969881cf6Sitojun /* no command in this line */
16069881cf6Sitojun return (1);
16169881cf6Sitojun
16269881cf6Sitojun /* fnind the corresponding parser */
16369881cf6Sitojun rval = 0;
16469881cf6Sitojun for (tp = cmd_tab; tp->cmd != NULL; tp++)
16569881cf6Sitojun if (strncmp(cmd, tp->cmd, len) == 0)
16669881cf6Sitojun break;
16769881cf6Sitojun
16869881cf6Sitojun if (tp->cmd == NULL) {
16969881cf6Sitojun if (fp == stdin) {
17069881cf6Sitojun printf(" ?? %s\n", cmd);
17169881cf6Sitojun rval = 1;
17269881cf6Sitojun } else
17369881cf6Sitojun LOG(LOG_ERR, 0, "unknown command: %s", cmd);
17469881cf6Sitojun return (rval);
17569881cf6Sitojun }
17669881cf6Sitojun
17769881cf6Sitojun if (tp->parser != NULL)
17869881cf6Sitojun rval = (*tp->parser)(cp);
17969881cf6Sitojun else {
18069881cf6Sitojun /* handle other commands */
18169881cf6Sitojun if (strcmp(tp->cmd, "quit") == 0)
18269881cf6Sitojun rval = 0;
18369881cf6Sitojun else if (strcmp(tp->cmd, "help") == 0 ||
18469881cf6Sitojun strcmp(tp->cmd, "?") == 0) {
18569881cf6Sitojun for (tp = cmd_tab; tp->cmd != NULL; tp++)
18669881cf6Sitojun printf("%s\n", tp->help);
18769881cf6Sitojun rval = 1;
18869881cf6Sitojun } else if (strcmp(tp->cmd, "debug") == 0) {
18969881cf6Sitojun if (m_debug & DEBUG_ALTQ) {
19069881cf6Sitojun /* turn off verbose */
19169881cf6Sitojun l_debug = LOG_INFO;
19269881cf6Sitojun m_debug &= ~DEBUG_ALTQ;
19369881cf6Sitojun } else {
19469881cf6Sitojun /* turn on verbose */
19569881cf6Sitojun l_debug = LOG_DEBUG;
19669881cf6Sitojun m_debug |= DEBUG_ALTQ;
19769881cf6Sitojun }
19869881cf6Sitojun rval = 1;
19969881cf6Sitojun }
20069881cf6Sitojun }
20169881cf6Sitojun return (rval);
20269881cf6Sitojun }
20369881cf6Sitojun
20495a65560Sthorpej static int
is_qdisc_name(const char * qname)20595a65560Sthorpej is_qdisc_name(const char *qname)
20695a65560Sthorpej {
20795a65560Sthorpej struct qdisc_parser *qp;
20895a65560Sthorpej
20995a65560Sthorpej for (qp = qdisc_parser; qp->qname != NULL; qp++)
21095a65560Sthorpej if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0)
21195a65560Sthorpej return (1);
21295a65560Sthorpej return (0);
21395a65560Sthorpej }
21495a65560Sthorpej
21595a65560Sthorpej static int
qdisc_interface_parser(const char * qname,const char * ifname,int argc,char ** argv)21695a65560Sthorpej qdisc_interface_parser(const char * qname, const char *ifname,
21795a65560Sthorpej int argc, char **argv)
21895a65560Sthorpej {
21995a65560Sthorpej struct qdisc_parser *qp;
22095a65560Sthorpej
22195a65560Sthorpej for (qp = qdisc_parser; qp->qname != NULL; qp++)
22295a65560Sthorpej if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0)
22395a65560Sthorpej return (*qp->interface_parser)(ifname, argc, argv);
22495a65560Sthorpej return (0);
22595a65560Sthorpej }
22695a65560Sthorpej
22795a65560Sthorpej static int
qdisc_class_parser(const char * qname,const char * ifname,const char * class_name,const char * parent_name,int argc,char ** argv)22895a65560Sthorpej qdisc_class_parser(const char *qname, const char *ifname,
22995a65560Sthorpej const char *class_name, const char *parent_name,
23095a65560Sthorpej int argc, char **argv)
23195a65560Sthorpej {
23295a65560Sthorpej struct qdisc_parser *qp;
2338b8734d2Sitojun struct ifinfo *ifinfo;
23495a65560Sthorpej
23595a65560Sthorpej for (qp = qdisc_parser; qp->qname != NULL; qp++)
23695a65560Sthorpej if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0) {
23795a65560Sthorpej if (qp->class_parser == NULL) {
23895a65560Sthorpej LOG(LOG_ERR, 0,
2398b8734d2Sitojun "class can't be specified for %s", qp->qname);
2408b8734d2Sitojun return (0);
2418b8734d2Sitojun }
2428b8734d2Sitojun if ((ifinfo = ifname2ifinfo(ifname)) == NULL) {
24369881cf6Sitojun LOG(LOG_ERR, 0, "no such interface");
2448b8734d2Sitojun return (0);
2458b8734d2Sitojun }
2468b8734d2Sitojun if (strncmp(ifinfo->qdisc->qname, qname,
2478b8734d2Sitojun strlen(ifinfo->qdisc->qname)) != 0) {
2488b8734d2Sitojun LOG(LOG_ERR, 0,
24969881cf6Sitojun "qname doesn't match the interface");
25095a65560Sthorpej return (0);
25195a65560Sthorpej }
25295a65560Sthorpej return (*qp->class_parser)(ifname, class_name,
25395a65560Sthorpej parent_name, argc, argv);
25495a65560Sthorpej }
25595a65560Sthorpej return (0);
25695a65560Sthorpej }
25795a65560Sthorpej
25895a65560Sthorpej /*
25969881cf6Sitojun * read the config file
26095a65560Sthorpej */
26195a65560Sthorpej int
qcmd_config(void)26295a65560Sthorpej qcmd_config(void)
26395a65560Sthorpej {
26469881cf6Sitojun FILE *fp;
26569881cf6Sitojun int rval;
26695a65560Sthorpej
26795a65560Sthorpej if (if_namelist != NULL)
26895a65560Sthorpej if_freenameindex(if_namelist);
26995a65560Sthorpej if_namelist = if_nameindex();
27069881cf6Sitojun curifname[0] = '\0';
27195a65560Sthorpej
272d5e1f166Sitojun LOG(LOG_INFO, 0, "ALTQ config file is %s", altqconfigfile);
27395a65560Sthorpej
27469881cf6Sitojun fp = fopen(altqconfigfile, "r");
27569881cf6Sitojun if (fp == NULL) {
276d5e1f166Sitojun LOG(LOG_ERR, errno, "can't open %s", altqconfigfile, 0);
27795a65560Sthorpej return (QOPERR_INVAL);
27895a65560Sthorpej }
27995a65560Sthorpej line_no = 0;
28095a65560Sthorpej rval = 1;
28169881cf6Sitojun while (rval)
28269881cf6Sitojun rval = do_command(fp);
28369881cf6Sitojun
28469881cf6Sitojun if (!feof(fp)) {
28569881cf6Sitojun LOG(LOG_ERR, 0, "Error in %s, line %d. config failed.",
28669881cf6Sitojun altqconfigfile, line_no);
28769881cf6Sitojun (void) qcmd_destroyall();
28869881cf6Sitojun rval = QOPERR_INVAL;
28969881cf6Sitojun } else
29095a65560Sthorpej rval = 0;
29169881cf6Sitojun
29269881cf6Sitojun (void)fclose(fp);
29369881cf6Sitojun line_no = 0;
29495a65560Sthorpej return (rval);
29595a65560Sthorpej }
29695a65560Sthorpej
29769881cf6Sitojun static int
next_word(char ** cpp,char * b)29869881cf6Sitojun next_word(char **cpp, char *b)
29995a65560Sthorpej {
30069881cf6Sitojun char *cp;
30169881cf6Sitojun int i;
30269881cf6Sitojun
30369881cf6Sitojun cp = *cpp;
30469881cf6Sitojun while (*cp == ' ' || *cp == '\t')
30569881cf6Sitojun cp++;
30669881cf6Sitojun for (i = 0; i < MAX_WORD - 1; i++) {
30769881cf6Sitojun if (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\0')
30869881cf6Sitojun break;
30969881cf6Sitojun *b++ = *cp++;
31069881cf6Sitojun }
31169881cf6Sitojun *b = '\0';
31269881cf6Sitojun *cpp = cp;
31369881cf6Sitojun return (i);
31469881cf6Sitojun }
31569881cf6Sitojun
31669881cf6Sitojun char *
cur_ifname(void)31769881cf6Sitojun cur_ifname(void)
31869881cf6Sitojun {
31969881cf6Sitojun return (curifname);
32095a65560Sthorpej }
32195a65560Sthorpej
32295a65560Sthorpej u_int
get_ifindex(const char * ifname)32395a65560Sthorpej get_ifindex(const char *ifname)
32495a65560Sthorpej {
32595a65560Sthorpej struct if_nameindex *ifnp;
32695a65560Sthorpej
32795a65560Sthorpej for (ifnp = if_namelist; ifnp->if_name != NULL; ifnp++)
32895a65560Sthorpej if (strcmp(ifname, ifnp->if_name) == 0)
32995a65560Sthorpej return (ifnp->if_index);
33095a65560Sthorpej return (0);
33195a65560Sthorpej }
33295a65560Sthorpej
33395a65560Sthorpej static int
get_ifname(char ** cpp,char ** ifnamep)33495a65560Sthorpej get_ifname(char **cpp, char **ifnamep)
33595a65560Sthorpej {
33669881cf6Sitojun char w[MAX_WORD], *ocp;
33795a65560Sthorpej struct if_nameindex *ifnp;
33895a65560Sthorpej
33995a65560Sthorpej ocp = *cpp;
34095a65560Sthorpej if (next_word(&ocp, w) && if_namelist != NULL)
34195a65560Sthorpej for (ifnp = if_namelist; ifnp->if_name != NULL; ifnp++)
34295a65560Sthorpej if (strcmp(w, ifnp->if_name) == 0) {
34395a65560Sthorpej /* if_name found. advance the word pointer */
34495a65560Sthorpej *cpp = ocp;
34569881cf6Sitojun strlcpy(curifname, w, sizeof(curifname));
34669881cf6Sitojun *ifnamep = curifname;
34795a65560Sthorpej return (1);
34895a65560Sthorpej }
34995a65560Sthorpej
35095a65560Sthorpej /* this is not interface name. use one in the context. */
35169881cf6Sitojun if (curifname[0] == '\0')
35295a65560Sthorpej return (0);
35369881cf6Sitojun *ifnamep = curifname;
35495a65560Sthorpej return (1);
35595a65560Sthorpej }
35695a65560Sthorpej
35795a65560Sthorpej /* set address and netmask in network byte order */
35895a65560Sthorpej static int
get_addr(char ** cpp,struct in_addr * addr,struct in_addr * mask)35995a65560Sthorpej get_addr(char **cpp, struct in_addr *addr, struct in_addr *mask)
36095a65560Sthorpej {
36169881cf6Sitojun char w[MAX_WORD], *ocp;
36292b62a25Sitojun struct in_addr tmp;
36395a65560Sthorpej
36495a65560Sthorpej addr->s_addr = 0;
36595a65560Sthorpej mask->s_addr = 0xffffffff;
36695a65560Sthorpej
36795a65560Sthorpej if (!next_word(cpp, w))
36895a65560Sthorpej return (0);
36995a65560Sthorpej
37092b62a25Sitojun if (inet_aton((char *)w, &tmp) != 1) {
37195a65560Sthorpej /* try gethostbyname */
37295a65560Sthorpej struct hostent *h;
37395a65560Sthorpej
37469881cf6Sitojun if ((h = gethostbyname(w)) == NULL ||
37569881cf6Sitojun h->h_addrtype != AF_INET || h->h_length != 4)
37695a65560Sthorpej return (0);
37795a65560Sthorpej bcopy(h->h_addr, &tmp, (size_t)h->h_length);
37895a65560Sthorpej }
37992b62a25Sitojun addr->s_addr = tmp.s_addr;
38095a65560Sthorpej
38195a65560Sthorpej /* check if netmask option is present */
38295a65560Sthorpej ocp = *cpp;
38395a65560Sthorpej if (next_word(&ocp, w) && EQUAL(w, "netmask")) {
38495a65560Sthorpej if (!next_word(&ocp, w))
38595a65560Sthorpej return (0);
38692b62a25Sitojun if (inet_aton((char *)w, (struct in_addr *)&tmp) != 1)
38795a65560Sthorpej return (0);
38895a65560Sthorpej
38992b62a25Sitojun mask->s_addr = tmp.s_addr;
39095a65560Sthorpej *cpp = ocp;
39195a65560Sthorpej return (1);
39295a65560Sthorpej }
39395a65560Sthorpej /* no netmask option */
39495a65560Sthorpej return (1);
39595a65560Sthorpej }
39695a65560Sthorpej
39795a65560Sthorpej /* returns service number in network byte order */
39895a65560Sthorpej static int
get_port(const char * name,u_int16_t * port_no)39995a65560Sthorpej get_port(const char *name, u_int16_t *port_no)
40095a65560Sthorpej {
40195a65560Sthorpej struct servent *s;
40295a65560Sthorpej u_int16_t num;
40395a65560Sthorpej
404238960afSdsl if (isdigit((unsigned char)name[0])) {
40595a65560Sthorpej num = (u_int16_t)strtol(name, NULL, 0);
40695a65560Sthorpej *port_no = htons(num);
40795a65560Sthorpej return (1);
40895a65560Sthorpej }
40995a65560Sthorpej
41095a65560Sthorpej if ((s = getservbyname(name, 0)) == NULL)
41195a65560Sthorpej return (0);
41295a65560Sthorpej
41395a65560Sthorpej *port_no = (u_int16_t)s->s_port;
41495a65560Sthorpej return (1);
41595a65560Sthorpej }
41695a65560Sthorpej
41795a65560Sthorpej static int
get_proto(const char * name,int * proto_no)41895a65560Sthorpej get_proto(const char *name, int *proto_no)
41995a65560Sthorpej {
42095a65560Sthorpej struct protoent *p;
42195a65560Sthorpej
422238960afSdsl if (isdigit((unsigned char)name[0])) {
42395a65560Sthorpej *proto_no = (int)strtol(name, NULL, 0);
42495a65560Sthorpej return (1);
42595a65560Sthorpej }
42695a65560Sthorpej
42795a65560Sthorpej if ((p = getprotobyname(name)) == NULL)
42895a65560Sthorpej return (0);
42995a65560Sthorpej
43095a65560Sthorpej *proto_no = p->p_proto;
43195a65560Sthorpej return (1);
43295a65560Sthorpej }
43395a65560Sthorpej
43495a65560Sthorpej static int
get_fltr_opts(char ** cpp,char * fltr_name,size_t len,int * ruleno)4358b8734d2Sitojun get_fltr_opts(char **cpp, char *fltr_name, size_t len, int *ruleno)
43695a65560Sthorpej {
43769881cf6Sitojun char w[MAX_WORD], *ocp;
43895a65560Sthorpej
43995a65560Sthorpej ocp = *cpp;
44095a65560Sthorpej while (next_word(&ocp, w)) {
44195a65560Sthorpej if (EQUAL(w, "name")) {
44295a65560Sthorpej if (!next_word(&ocp, w))
44395a65560Sthorpej return (0);
4448b8734d2Sitojun strlcpy(fltr_name, w, len);
44595a65560Sthorpej *cpp = ocp;
44695a65560Sthorpej } else if (EQUAL(w, "ruleno")) {
44795a65560Sthorpej if (!next_word(&ocp, w))
44895a65560Sthorpej return (0);
44995a65560Sthorpej *ruleno = (int)strtol(w, NULL, 0);
45095a65560Sthorpej *cpp = ocp;
45195a65560Sthorpej } else
45295a65560Sthorpej break;
45395a65560Sthorpej }
45495a65560Sthorpej return (1);
45595a65560Sthorpej }
45695a65560Sthorpej
45795a65560Sthorpej
45895a65560Sthorpej #define DISCIPLINE_NONE 0
45995a65560Sthorpej
46095a65560Sthorpej static int
interface_parser(char * cmdbuf)46195a65560Sthorpej interface_parser(char *cmdbuf)
46295a65560Sthorpej {
46369881cf6Sitojun char w[MAX_WORD], *ap, *cp = cmdbuf;
46469881cf6Sitojun char *ifname, *argv[MAX_ARGS], qdisc_name[MAX_WORD];
46569881cf6Sitojun int argc;
46695a65560Sthorpej
46795a65560Sthorpej if (!get_ifname(&cp, &ifname)) {
46869881cf6Sitojun LOG(LOG_ERR, 0, "missing interface name");
46995a65560Sthorpej return (0);
47095a65560Sthorpej }
47195a65560Sthorpej
472*915340d5Sandvar /* create argument list & look for scheduling discipline options. */
47369881cf6Sitojun snprintf(qdisc_name, sizeof qdisc_name, "null");
47495a65560Sthorpej argc = 0;
47595a65560Sthorpej ap = w;
47695a65560Sthorpej while (next_word(&cp, ap)) {
47795a65560Sthorpej if (is_qdisc_name(ap))
47869881cf6Sitojun strlcpy(qdisc_name, ap, sizeof qdisc_name);
47995a65560Sthorpej
48095a65560Sthorpej argv[argc] = ap;
48195a65560Sthorpej ap += strlen(ap) + 1;
48295a65560Sthorpej argc++;
48369881cf6Sitojun if (argc >= MAX_ARGS) {
48469881cf6Sitojun LOG(LOG_ERR, 0, "too many args");
48595a65560Sthorpej return (0);
48695a65560Sthorpej }
48795a65560Sthorpej }
48895a65560Sthorpej
48969881cf6Sitojun return qdisc_interface_parser(qdisc_name, ifname, argc, argv);
49069881cf6Sitojun }
49169881cf6Sitojun
49269881cf6Sitojun
49395a65560Sthorpej static int
class_parser(char * cmdbuf)49495a65560Sthorpej class_parser(char *cmdbuf)
49595a65560Sthorpej {
49669881cf6Sitojun char w[MAX_WORD], *cp = cmdbuf;
49769881cf6Sitojun char *ifname, qdisc_name[MAX_WORD];
49869881cf6Sitojun char class_name[MAX_WORD], parent_name[MAX_WORD];
49995a65560Sthorpej char *clname = class_name;
50095a65560Sthorpej char *parent = NULL;
50169881cf6Sitojun char *argv[MAX_ARGS], *ap;
50269881cf6Sitojun int argc;
50395a65560Sthorpej
50495a65560Sthorpej /* get scheduling class */
50595a65560Sthorpej if (!next_word(&cp, qdisc_name)) {
50669881cf6Sitojun LOG(LOG_ERR, 0, "missing discipline");
50795a65560Sthorpej return (0);
50895a65560Sthorpej }
50995a65560Sthorpej if (!is_qdisc_name(qdisc_name)) {
51069881cf6Sitojun LOG(LOG_ERR, 0, "unknown discipline '%s'", qdisc_name);
51195a65560Sthorpej return (0);
51295a65560Sthorpej }
51395a65560Sthorpej
51495a65560Sthorpej /* get interface name */
51595a65560Sthorpej if (!get_ifname(&cp, &ifname)) {
51669881cf6Sitojun LOG(LOG_ERR, 0, "missing interface name");
51795a65560Sthorpej return (0);
51895a65560Sthorpej }
51995a65560Sthorpej
52095a65560Sthorpej /* get class name */
52195a65560Sthorpej if (!next_word(&cp, class_name)) {
52269881cf6Sitojun LOG(LOG_ERR, 0, "missing class name");
52395a65560Sthorpej return (0);
52495a65560Sthorpej }
52595a65560Sthorpej
52695a65560Sthorpej /* get parent name */
52795a65560Sthorpej if (!next_word(&cp, parent_name)) {
52869881cf6Sitojun LOG(LOG_ERR, 0, "missing parent class");
52995a65560Sthorpej return (0);
53095a65560Sthorpej }
53169881cf6Sitojun if (!EQUAL(parent_name, "null") && !EQUAL(parent_name, "NULL"))
53295a65560Sthorpej parent = parent_name;
53369881cf6Sitojun else
53495a65560Sthorpej parent = NULL;
53595a65560Sthorpej
53695a65560Sthorpej ap = w;
53795a65560Sthorpej argc = 0;
53895a65560Sthorpej while (next_word(&cp, ap)) {
53995a65560Sthorpej argv[argc] = ap;
54095a65560Sthorpej ap += strlen(ap) + 1;
54195a65560Sthorpej argc++;
54269881cf6Sitojun if (argc >= MAX_ARGS) {
54369881cf6Sitojun LOG(LOG_ERR, 0, "too many args");
54495a65560Sthorpej return (0);
54595a65560Sthorpej }
54669881cf6Sitojun }
54795a65560Sthorpej
54869881cf6Sitojun return qdisc_class_parser(qdisc_name, ifname, clname, parent,
54969881cf6Sitojun argc, argv);
55095a65560Sthorpej }
55195a65560Sthorpej
55295a65560Sthorpej static int
filter_parser(char * cmdbuf)55395a65560Sthorpej filter_parser(char *cmdbuf)
55495a65560Sthorpej {
55569881cf6Sitojun char w[MAX_WORD], *cp = cmdbuf;
55669881cf6Sitojun char *ifname, class_name[MAX_WORD], fltr_name[MAX_WORD];
55769881cf6Sitojun char *flname = NULL;
55895a65560Sthorpej struct flow_filter sfilt;
55995a65560Sthorpej int protocol;
56095a65560Sthorpej u_char tos, tosmask;
56195a65560Sthorpej int ruleno;
56295a65560Sthorpej int dontwarn = 0;
56395a65560Sthorpej int error;
56495a65560Sthorpej
56595a65560Sthorpej memset(&sfilt, 0, sizeof(sfilt));
56695a65560Sthorpej sfilt.ff_flow.fi_family = AF_INET;
56795a65560Sthorpej
56895a65560Sthorpej if (!get_ifname(&cp, &ifname)) {
56969881cf6Sitojun LOG(LOG_ERR, 0, "missing interface name in filter command");
57095a65560Sthorpej return (0);
57195a65560Sthorpej }
57295a65560Sthorpej
57395a65560Sthorpej if (!next_word(&cp, class_name)) {
57469881cf6Sitojun LOG(LOG_ERR, 0, "missing class name in filter command");
57595a65560Sthorpej return (0);
57695a65560Sthorpej }
57795a65560Sthorpej
57895a65560Sthorpej fltr_name[0] = '\0';
57995a65560Sthorpej ruleno = 0;
5808b8734d2Sitojun if (!get_fltr_opts(&cp, &fltr_name[0], sizeof(fltr_name), &ruleno)) {
58169881cf6Sitojun LOG(LOG_ERR, 0, "bad filter option");
58295a65560Sthorpej return (0);
58395a65560Sthorpej }
58495a65560Sthorpej if (fltr_name[0] != '\0')
58595a65560Sthorpej flname = fltr_name;
58695a65560Sthorpej sfilt.ff_ruleno = ruleno;
58795a65560Sthorpej
58895a65560Sthorpej /* get filter destination Address */
58995a65560Sthorpej if (!get_addr(&cp, &sfilt.ff_flow.fi_dst, &sfilt.ff_mask.mask_dst)) {
59069881cf6Sitojun LOG(LOG_ERR, 0, "bad filter destination address");
59195a65560Sthorpej return (0);
59295a65560Sthorpej }
59395a65560Sthorpej
59495a65560Sthorpej /* get filter destination port */
59595a65560Sthorpej if (!next_word(&cp, w)) {
59669881cf6Sitojun LOG(LOG_ERR, 0, "missing filter destination port");
59795a65560Sthorpej return (0);
59895a65560Sthorpej }
59995a65560Sthorpej if (!get_port(w, &sfilt.ff_flow.fi_dport)) {
60069881cf6Sitojun LOG(LOG_ERR, 0, "bad filter destination port");
60195a65560Sthorpej return (0);
60295a65560Sthorpej }
60395a65560Sthorpej
60495a65560Sthorpej /* get filter source address */
60595a65560Sthorpej if (!get_addr(&cp, &sfilt.ff_flow.fi_src, &sfilt.ff_mask.mask_src)) {
60669881cf6Sitojun LOG(LOG_ERR, 0, "bad filter source address");
60795a65560Sthorpej return (0);
60895a65560Sthorpej }
60995a65560Sthorpej
61095a65560Sthorpej /* get filter source port */
61195a65560Sthorpej if (!next_word(&cp, w)) {
61269881cf6Sitojun LOG(LOG_ERR, 0, "missing filter source port");
61395a65560Sthorpej return (0);
61495a65560Sthorpej }
61595a65560Sthorpej if (!get_port(w, &sfilt.ff_flow.fi_sport)) {
61669881cf6Sitojun LOG(LOG_ERR, 0, "bad filter source port");
61795a65560Sthorpej return (0);
61895a65560Sthorpej }
61995a65560Sthorpej
62095a65560Sthorpej /* get filter protocol id */
62195a65560Sthorpej if (!next_word(&cp, w)) {
62269881cf6Sitojun LOG(LOG_ERR, 0, "missing filter protocol");
62395a65560Sthorpej return (0);
62495a65560Sthorpej }
62595a65560Sthorpej if (!get_proto(w, &protocol)) {
62669881cf6Sitojun LOG(LOG_ERR, 0, "bad protocol");
62795a65560Sthorpej return (0);
62895a65560Sthorpej }
62995a65560Sthorpej sfilt.ff_flow.fi_proto = protocol;
63095a65560Sthorpej
63195a65560Sthorpej while (next_word(&cp, w)) {
63295a65560Sthorpej if (EQUAL(w, "tos")) {
63395a65560Sthorpej tos = 0;
63495a65560Sthorpej tosmask = 0xff;
63595a65560Sthorpej
63695a65560Sthorpej if (next_word(&cp, w)) {
63795a65560Sthorpej tos = (u_char)strtol(w, NULL, 0);
63895a65560Sthorpej if (next_word(&cp, w)) {
63995a65560Sthorpej if (EQUAL(w, "tosmask")) {
64095a65560Sthorpej next_word(&cp, w);
64195a65560Sthorpej tosmask = (u_char)strtol(w, NULL, 0);
64295a65560Sthorpej }
64395a65560Sthorpej }
64495a65560Sthorpej }
64595a65560Sthorpej sfilt.ff_flow.fi_tos = tos;
64695a65560Sthorpej sfilt.ff_mask.mask_tos = tosmask;
64795a65560Sthorpej } else if (EQUAL(w, "gpi")) {
64895a65560Sthorpej if (next_word(&cp, w)) {
64995a65560Sthorpej sfilt.ff_flow.fi_gpi =
65095a65560Sthorpej (u_int32_t)strtoul(w, NULL, 0);
65195a65560Sthorpej sfilt.ff_flow.fi_gpi =
65295a65560Sthorpej htonl(sfilt.ff_flow.fi_gpi);
65395a65560Sthorpej }
65495a65560Sthorpej } else if (EQUAL(w, "dontwarn"))
65595a65560Sthorpej dontwarn = 1;
65695a65560Sthorpej }
65795a65560Sthorpej
65895a65560Sthorpej /*
65995a65560Sthorpej * Add the filter.
66095a65560Sthorpej */
66195a65560Sthorpej filter_dontwarn = dontwarn; /* XXX */
66295a65560Sthorpej error = qcmd_add_filter(ifname, class_name, flname, &sfilt);
66395a65560Sthorpej filter_dontwarn = 0; /* XXX */
66495a65560Sthorpej if (error) {
66595a65560Sthorpej LOG(LOG_ERR, 0,
666d5e1f166Sitojun "can't add filter to class '%s' on interface '%s'",
66795a65560Sthorpej class_name, ifname);
66895a65560Sthorpej return (0);
66995a65560Sthorpej }
67095a65560Sthorpej return (1);
67195a65560Sthorpej }
67295a65560Sthorpej
67395a65560Sthorpej #ifdef INET6
67495a65560Sthorpej static int
filter6_parser(char * cmdbuf)67595a65560Sthorpej filter6_parser(char *cmdbuf)
67695a65560Sthorpej {
67769881cf6Sitojun char w[MAX_WORD], *cp = cmdbuf;
67869881cf6Sitojun char *ifname, class_name[MAX_WORD], fltr_name[MAX_WORD];
67969881cf6Sitojun char *flname = NULL;
68095a65560Sthorpej struct flow_filter6 sfilt;
68195a65560Sthorpej int protocol;
68295a65560Sthorpej u_char tclass, tclassmask;
68395a65560Sthorpej int ruleno;
68495a65560Sthorpej int dontwarn = 0;
68595a65560Sthorpej int ret;
68695a65560Sthorpej
68795a65560Sthorpej memset(&sfilt, 0, sizeof(sfilt));
68895a65560Sthorpej sfilt.ff_flow6.fi6_family = AF_INET6;
68995a65560Sthorpej
69095a65560Sthorpej if (!get_ifname(&cp, &ifname)) {
69169881cf6Sitojun LOG(LOG_ERR, 0, "missing interface name");
69295a65560Sthorpej return (0);
69395a65560Sthorpej }
69495a65560Sthorpej
69595a65560Sthorpej if (!next_word(&cp, class_name)) {
69669881cf6Sitojun LOG(LOG_ERR, 0, "missing class name");
69795a65560Sthorpej return (0);
69895a65560Sthorpej }
69995a65560Sthorpej
70095a65560Sthorpej fltr_name[0] = '\0';
70195a65560Sthorpej ruleno = 0;
7028b8734d2Sitojun if (!get_fltr_opts(&cp, &fltr_name[0], sizeof(fltr_name), &ruleno)) {
70369881cf6Sitojun LOG(LOG_ERR, 0, "bad filter option");
70495a65560Sthorpej return (0);
70595a65560Sthorpej }
70695a65560Sthorpej if (fltr_name[0] != '\0')
70795a65560Sthorpej flname = fltr_name;
70895a65560Sthorpej sfilt.ff_ruleno = ruleno;
70995a65560Sthorpej
71095a65560Sthorpej /* get filter destination address */
71195a65560Sthorpej if (!get_ip6addr(&cp, &sfilt.ff_flow6.fi6_dst,
71295a65560Sthorpej &sfilt.ff_mask6.mask6_dst)) {
71369881cf6Sitojun LOG(LOG_ERR, 0, "bad destination address");
71495a65560Sthorpej return (0);
71595a65560Sthorpej }
71695a65560Sthorpej
71795a65560Sthorpej /* get filter destination port */
71895a65560Sthorpej if (!next_word(&cp, w)) {
71969881cf6Sitojun LOG(LOG_ERR, 0, "missing filter destination port");
72095a65560Sthorpej return (0);
72195a65560Sthorpej }
72295a65560Sthorpej if (!get_port(w, &sfilt.ff_flow6.fi6_dport)) {
72369881cf6Sitojun LOG(LOG_ERR, 0, "bad filter destination port");
72495a65560Sthorpej return (0);
72595a65560Sthorpej }
72695a65560Sthorpej
72795a65560Sthorpej /* get filter source address */
72895a65560Sthorpej if (!get_ip6addr(&cp, &sfilt.ff_flow6.fi6_src,
72995a65560Sthorpej &sfilt.ff_mask6.mask6_src)) {
73069881cf6Sitojun LOG(LOG_ERR, 0, "bad source address");
73195a65560Sthorpej return (0);
73295a65560Sthorpej }
73395a65560Sthorpej
73495a65560Sthorpej /* get filter source port */
73595a65560Sthorpej if (!next_word(&cp, w)) {
73669881cf6Sitojun LOG(LOG_ERR, 0, "missing filter source port");
73795a65560Sthorpej return (0);
73895a65560Sthorpej }
73995a65560Sthorpej if (!get_port(w, &sfilt.ff_flow6.fi6_sport)) {
74069881cf6Sitojun LOG(LOG_ERR, 0, "bad filter source port");
74195a65560Sthorpej return (0);
74295a65560Sthorpej }
74395a65560Sthorpej
74495a65560Sthorpej /* get filter protocol id */
74595a65560Sthorpej if (!next_word(&cp, w)) {
74669881cf6Sitojun LOG(LOG_ERR, 0, "missing filter protocol");
74795a65560Sthorpej return (0);
74895a65560Sthorpej }
74995a65560Sthorpej if (!get_proto(w, &protocol)) {
75069881cf6Sitojun LOG(LOG_ERR, 0, "bad protocol");
75195a65560Sthorpej return (0);
75295a65560Sthorpej }
75395a65560Sthorpej sfilt.ff_flow6.fi6_proto = protocol;
75495a65560Sthorpej
75595a65560Sthorpej while (next_word(&cp, w)) {
75695a65560Sthorpej if (EQUAL(w, "tclass")) {
75795a65560Sthorpej tclass = 0;
75895a65560Sthorpej tclassmask = 0xff;
75995a65560Sthorpej
76095a65560Sthorpej if (next_word(&cp, w)) {
76195a65560Sthorpej tclass = (u_char)strtol(w, NULL, 0);
76295a65560Sthorpej if (next_word(&cp, w)) {
76395a65560Sthorpej if (EQUAL(w, "tclassmask")) {
76495a65560Sthorpej next_word(&cp, w);
76595a65560Sthorpej tclassmask =
76695a65560Sthorpej (u_char)strtol(w, NULL, 0);
76795a65560Sthorpej }
76895a65560Sthorpej }
76995a65560Sthorpej }
77095a65560Sthorpej sfilt.ff_flow6.fi6_tclass = tclass;
77195a65560Sthorpej sfilt.ff_mask6.mask6_tclass = tclassmask;
77295a65560Sthorpej } else if (EQUAL(w, "gpi")) {
77395a65560Sthorpej if (next_word(&cp, w)) {
77495a65560Sthorpej sfilt.ff_flow6.fi6_gpi =
77595a65560Sthorpej (u_int32_t)strtoul(w, NULL, 0);
77695a65560Sthorpej sfilt.ff_flow6.fi6_gpi =
77795a65560Sthorpej htonl(sfilt.ff_flow6.fi6_gpi);
77895a65560Sthorpej }
77995a65560Sthorpej } else if (EQUAL(w, "flowlabel")) {
78095a65560Sthorpej if (next_word(&cp, w)) {
78195a65560Sthorpej sfilt.ff_flow6.fi6_flowlabel =
78295a65560Sthorpej (u_int32_t)strtoul(w, NULL, 0) & 0x000fffff;
78395a65560Sthorpej sfilt.ff_flow6.fi6_flowlabel =
78495a65560Sthorpej htonl(sfilt.ff_flow6.fi6_flowlabel);
78595a65560Sthorpej }
78695a65560Sthorpej } else if (EQUAL(w, "dontwarn"))
78795a65560Sthorpej dontwarn = 1;
78895a65560Sthorpej }
78995a65560Sthorpej
79095a65560Sthorpej /*
79195a65560Sthorpej * Add the filter.
79295a65560Sthorpej */
79395a65560Sthorpej filter_dontwarn = dontwarn; /* XXX */
79495a65560Sthorpej ret = qcmd_add_filter(ifname, class_name, flname,
79595a65560Sthorpej (struct flow_filter *)&sfilt);
79695a65560Sthorpej filter_dontwarn = 0; /* XXX */
79795a65560Sthorpej if (ret) {
79895a65560Sthorpej LOG(LOG_ERR, 0,
799d5e1f166Sitojun "can't add filter to class '%s' on interface '%s'",
80095a65560Sthorpej class_name, ifname);
80195a65560Sthorpej return (0);
80295a65560Sthorpej }
80395a65560Sthorpej
80495a65560Sthorpej return (1);
80595a65560Sthorpej }
80695a65560Sthorpej
80795a65560Sthorpej static int
get_ip6addr(char ** cpp,struct in6_addr * addr,struct in6_addr * mask)80895a65560Sthorpej get_ip6addr(char **cpp, struct in6_addr *addr, struct in6_addr *mask)
80995a65560Sthorpej {
81069881cf6Sitojun char w[MAX_WORD], *prefix;
81195a65560Sthorpej u_char *cp;
81295a65560Sthorpej int len;
81395a65560Sthorpej
81495a65560Sthorpej *addr = in6addr_any; /* set all 0 */
81595a65560Sthorpej *mask = in6addr_any; /* set all 0 */
81695a65560Sthorpej
81795a65560Sthorpej if (!next_word(cpp, w))
81895a65560Sthorpej return (0);
81995a65560Sthorpej
82095a65560Sthorpej if (EQUAL(w, "0"))
82195a65560Sthorpej /* abbreviation of a wildcard (::0) */
82295a65560Sthorpej return (1);
82395a65560Sthorpej
82495a65560Sthorpej if ((prefix = strchr(w, '/')) != NULL) {
82595a65560Sthorpej /* address has prefix length */
82695a65560Sthorpej *prefix++ = '\0';
82795a65560Sthorpej }
82895a65560Sthorpej
82992b62a25Sitojun if (inet_pton(AF_INET6, w, addr) != 1)
83095a65560Sthorpej return (0);
83195a65560Sthorpej
83295a65560Sthorpej if (IN6_IS_ADDR_UNSPECIFIED(addr) && prefix == NULL)
83395a65560Sthorpej /* wildcard */
83495a65560Sthorpej return (1);
83595a65560Sthorpej
83695a65560Sthorpej /* convert address prefix length to address mask */
83795a65560Sthorpej if (prefix != NULL) {
83895a65560Sthorpej len = (int)strtol(prefix, NULL, 0);
83995a65560Sthorpej if ((len < 0) || (len > 128))
84095a65560Sthorpej return (0);
84195a65560Sthorpej for (cp = (u_char *)mask; len > 7; len -= 8)
84295a65560Sthorpej *cp++ = 0xff;
84395a65560Sthorpej if (len > 0)
84495a65560Sthorpej *cp = (0xff << (8 - len)) & 0xff;
84595a65560Sthorpej
8460d33c75cSchristos IN6ADDR32_SET(addr, 0, IN6ADDR32_GET(mask, 0) &
8470d33c75cSchristos IN6ADDR32_GET(addr, 0));
8480d33c75cSchristos IN6ADDR32_SET(addr, 1, IN6ADDR32_GET(mask, 1) &
8490d33c75cSchristos IN6ADDR32_GET(addr, 1));
8500d33c75cSchristos IN6ADDR32_SET(addr, 2, IN6ADDR32_GET(mask, 2) &
8510d33c75cSchristos IN6ADDR32_GET(addr, 2));
8520d33c75cSchristos IN6ADDR32_SET(addr, 3, IN6ADDR32_GET(mask, 3) &
8530d33c75cSchristos IN6ADDR32_GET(addr, 3));
85495a65560Sthorpej } else
85595a65560Sthorpej /* full mask */
85695a65560Sthorpej memset(mask, 0xff, sizeof(struct in6_addr));
85795a65560Sthorpej
85895a65560Sthorpej return (1);
85995a65560Sthorpej }
86095a65560Sthorpej
86195a65560Sthorpej #endif /* INET6 */
86295a65560Sthorpej
86395a65560Sthorpej static int
ctl_parser(char * cmdbuf)86495a65560Sthorpej ctl_parser(char *cmdbuf)
86595a65560Sthorpej {
86669881cf6Sitojun char w[MAX_WORD], *cp = cmdbuf;
86795a65560Sthorpej char *ifname;
86895a65560Sthorpej int state;
86995a65560Sthorpej int rval;
87095a65560Sthorpej
87195a65560Sthorpej if (!get_ifname(&cp, &ifname)) {
87295a65560Sthorpej printf("missing interface name in %s, line %d",
87395a65560Sthorpej altqconfigfile, line_no);
87495a65560Sthorpej return (0);
87595a65560Sthorpej }
87695a65560Sthorpej
87795a65560Sthorpej if (!next_word(&cp, w)) {
87895a65560Sthorpej state = is_q_enabled(ifname);
87995a65560Sthorpej printf("altq %s on %s\n",
88095a65560Sthorpej state ? "enabled" : "disabled", ifname);
88195a65560Sthorpej return (1);
88295a65560Sthorpej }
88395a65560Sthorpej
88495a65560Sthorpej if (EQUAL(w, "enable")) {
88595a65560Sthorpej rval = qcmd_enable(ifname);
88695a65560Sthorpej printf("altq %s on %s\n",
88795a65560Sthorpej (rval == 0) ? "enabled" : "enable failed!", ifname);
88895a65560Sthorpej } else if (EQUAL(w, "disable")) {
88995a65560Sthorpej rval = qcmd_disable(ifname);
89095a65560Sthorpej printf("altq %s on %s\n",
89195a65560Sthorpej (rval == 0) ? "disabled" : "disable failed!", ifname);
89295a65560Sthorpej } else if (EQUAL(w, "reload")) {
89395a65560Sthorpej printf("reinitializing altq...\n");
89495a65560Sthorpej qcmd_destroyall();
89595a65560Sthorpej qcmd_init();
89695a65560Sthorpej } else
89795a65560Sthorpej return (0);
89895a65560Sthorpej return (1);
89995a65560Sthorpej }
90095a65560Sthorpej
90195a65560Sthorpej static int
delete_parser(char * cmdbuf)90295a65560Sthorpej delete_parser(char *cmdbuf)
90395a65560Sthorpej {
90495a65560Sthorpej char *cp = cmdbuf;
90569881cf6Sitojun char *ifname, class_name[MAX_WORD], filter_name[MAX_WORD];
90695a65560Sthorpej int ret;
90795a65560Sthorpej
90895a65560Sthorpej if (!get_ifname(&cp, &ifname)) {
90969881cf6Sitojun LOG(LOG_ERR, 0, "missing interface name");
91095a65560Sthorpej return (0);
91195a65560Sthorpej }
91295a65560Sthorpej
91395a65560Sthorpej if (!next_word(&cp, class_name)) {
91469881cf6Sitojun LOG(LOG_ERR, 0, "missing class name");
91595a65560Sthorpej return (0);
91695a65560Sthorpej }
91795a65560Sthorpej
91869881cf6Sitojun /* check if filter is specified */
91969881cf6Sitojun if (next_word(&cp, filter_name)) {
92069881cf6Sitojun ret = qcmd_delete_filter(ifname, class_name, filter_name);
92169881cf6Sitojun if (ret) {
92269881cf6Sitojun LOG(LOG_ERR, 0,
92369881cf6Sitojun "can't delete filter '%s' on interface '%s'",
92469881cf6Sitojun filter_name, ifname);
92569881cf6Sitojun return (0);
92669881cf6Sitojun }
92769881cf6Sitojun return (1);
92869881cf6Sitojun }
92969881cf6Sitojun
93095a65560Sthorpej ret = qcmd_delete_class(ifname, class_name);
93195a65560Sthorpej if (ret) {
93295a65560Sthorpej LOG(LOG_ERR, 0,
933d5e1f166Sitojun "can't delete class '%s' on interface '%s'",
93495a65560Sthorpej class_name, ifname);
93595a65560Sthorpej return (0);
93695a65560Sthorpej }
93795a65560Sthorpej
93895a65560Sthorpej return (1);
93995a65560Sthorpej }
94095a65560Sthorpej
94195a65560Sthorpej static int
red_parser(char * cmdbuf)94295a65560Sthorpej red_parser(char *cmdbuf)
94395a65560Sthorpej {
94469881cf6Sitojun char w[MAX_WORD], *cp = cmdbuf;
94595a65560Sthorpej int th_min, th_max, inv_pmax;
94695a65560Sthorpej
94795a65560Sthorpej if (!next_word(&cp, w))
94895a65560Sthorpej goto bad;
94995a65560Sthorpej th_min = (int)strtol(w, NULL, 0);
95095a65560Sthorpej
95195a65560Sthorpej if (!next_word(&cp, w))
95295a65560Sthorpej goto bad;
95395a65560Sthorpej th_max = (int)strtol(w, NULL, 0);
95495a65560Sthorpej
95595a65560Sthorpej if (!next_word(&cp, w))
95695a65560Sthorpej goto bad;
95795a65560Sthorpej inv_pmax = (int)strtol(w, NULL, 0);
95895a65560Sthorpej
95995a65560Sthorpej if (qop_red_set_defaults(th_min, th_max, inv_pmax) != 0) {
960d5e1f166Sitojun LOG(LOG_ERR, 0, "can't set red default parameters");
96195a65560Sthorpej return (0);
96295a65560Sthorpej }
96395a65560Sthorpej
96495a65560Sthorpej return (1);
96595a65560Sthorpej
96695a65560Sthorpej bad:
96769881cf6Sitojun LOG(LOG_ERR, 0, "bad red parameter");
96895a65560Sthorpej return (0);
96995a65560Sthorpej }
97095a65560Sthorpej
97195a65560Sthorpej static int
rio_parser(char * cmdbuf)97295a65560Sthorpej rio_parser(char *cmdbuf)
97395a65560Sthorpej {
97469881cf6Sitojun char w[MAX_WORD], *cp = cmdbuf;
97595a65560Sthorpej int i;
97695a65560Sthorpej struct redparams params[RIO_NDROPPREC];
97795a65560Sthorpej
97895a65560Sthorpej for (i = 0; i < RIO_NDROPPREC; i++) {
97995a65560Sthorpej if (!next_word(&cp, w))
98095a65560Sthorpej goto bad;
98195a65560Sthorpej params[i].th_min = (int)strtol(w, NULL, 0);
98295a65560Sthorpej
98395a65560Sthorpej if (!next_word(&cp, w))
98495a65560Sthorpej goto bad;
98595a65560Sthorpej params[i].th_max = (int)strtol(w, NULL, 0);
98695a65560Sthorpej
98795a65560Sthorpej if (!next_word(&cp, w))
98895a65560Sthorpej goto bad;
98995a65560Sthorpej params[i].inv_pmax = (int)strtol(w, NULL, 0);
99095a65560Sthorpej }
99195a65560Sthorpej
99295a65560Sthorpej if (qop_rio_set_defaults(¶ms[0]) != 0) {
993d5e1f166Sitojun LOG(LOG_ERR, 0, "can't set rio default parameters");
99495a65560Sthorpej return (0);
99595a65560Sthorpej }
99695a65560Sthorpej
99795a65560Sthorpej return (1);
99895a65560Sthorpej
99995a65560Sthorpej bad:
100069881cf6Sitojun LOG(LOG_ERR, 0, "bad rio parameter");
100195a65560Sthorpej return (0);
100295a65560Sthorpej }
100395a65560Sthorpej
100495a65560Sthorpej static int
conditioner_parser(char * cmdbuf)100595a65560Sthorpej conditioner_parser(char *cmdbuf)
100695a65560Sthorpej {
100769881cf6Sitojun char cdnr_name[MAX_WORD], *cp = cmdbuf;
100895a65560Sthorpej char *ifname;
100969881cf6Sitojun struct tc_action action[MAX_ACTIONS];
101095a65560Sthorpej
101195a65560Sthorpej if (!get_ifname(&cp, &ifname)) {
101269881cf6Sitojun LOG(LOG_ERR, 0, "missing interface name");
101395a65560Sthorpej return (0);
101495a65560Sthorpej }
101595a65560Sthorpej
101695a65560Sthorpej /* get conditioner name */
101795a65560Sthorpej if (!next_word(&cp, cdnr_name)) {
101869881cf6Sitojun LOG(LOG_ERR, 0, "missing cdnr name");
101995a65560Sthorpej return (0);
102095a65560Sthorpej }
102195a65560Sthorpej
102295a65560Sthorpej if (tc_action_parser(ifname, &cp, &action[0]) == 0)
102395a65560Sthorpej return (0);
102495a65560Sthorpej
102595a65560Sthorpej if (qcmd_cdnr_add_element(NULL, ifname, cdnr_name, &action[0]) != 0)
102695a65560Sthorpej return (0);
102795a65560Sthorpej return (1);
102895a65560Sthorpej }
102995a65560Sthorpej
103095a65560Sthorpej /*
103195a65560Sthorpej * recursively parse '<'tc_action'>'
103295a65560Sthorpej * note that array "action" grows during recursive parse.
103395a65560Sthorpej */
103495a65560Sthorpej static int
tc_action_parser(char * ifname,char ** cpp,struct tc_action * action)103595a65560Sthorpej tc_action_parser(char *ifname, char **cpp, struct tc_action *action)
103695a65560Sthorpej {
103795a65560Sthorpej char *cp, *start, *end;
103869881cf6Sitojun char type[MAX_WORD], w[MAX_WORD];
103995a65560Sthorpej int depth, i;
104095a65560Sthorpej struct tb_profile profile[2];
104195a65560Sthorpej
104295a65560Sthorpej /*
104395a65560Sthorpej * find a possibly nested pair of '<' and '>',
104495a65560Sthorpej * make them pointed by 'start' and 'end'.
104595a65560Sthorpej */
104695a65560Sthorpej start = strchr(*cpp, '<');
104795a65560Sthorpej if (start == NULL) {
104869881cf6Sitojun LOG(LOG_ERR, 0, "conditioner action missing");
104995a65560Sthorpej return (0);
105095a65560Sthorpej }
105195a65560Sthorpej depth = 1;
105295a65560Sthorpej cp = start + 1;
105395a65560Sthorpej do {
105495a65560Sthorpej end = strpbrk(cp, "<>");
105595a65560Sthorpej if (end == NULL) {
105695a65560Sthorpej LOG(LOG_ERR, 0,
105769881cf6Sitojun "conditioner action delimiter mismatch");
105895a65560Sthorpej return (0);
105995a65560Sthorpej }
106095a65560Sthorpej if (*end == '<')
106195a65560Sthorpej depth++;
106295a65560Sthorpej else if (*end == '>')
106395a65560Sthorpej depth--;
106495a65560Sthorpej cp = end + 1;
106595a65560Sthorpej } while (depth > 0);
106695a65560Sthorpej *end = '\0';
106795a65560Sthorpej *cpp = end + 1;
106895a65560Sthorpej cp = start + 1;
106995a65560Sthorpej
107095a65560Sthorpej if (IsDebug(DEBUG_ALTQ)) {
107195a65560Sthorpej printf("tc_action_parser: [%s]\n", cp);
107295a65560Sthorpej }
107395a65560Sthorpej
107495a65560Sthorpej if (!next_word(&cp, type)) {
107569881cf6Sitojun LOG(LOG_ERR, 0, "missing conditioner action type");
107695a65560Sthorpej return (0);
107795a65560Sthorpej }
107895a65560Sthorpej
107995a65560Sthorpej /*
108095a65560Sthorpej * action type specific process
108195a65560Sthorpej */
108295a65560Sthorpej if (EQUAL(type, "conditioner")) {
108395a65560Sthorpej if (!next_word(&cp, w)) {
108495a65560Sthorpej LOG(LOG_ERR, 0,
108569881cf6Sitojun "missing conditioner name");
108695a65560Sthorpej return (0);
108795a65560Sthorpej }
108895a65560Sthorpej action->tca_code = TCACODE_HANDLE;
108995a65560Sthorpej action->tca_handle = cdnr_name2handle(ifname, w);
109095a65560Sthorpej if (action->tca_handle == CDNR_NULL_HANDLE) {
109195a65560Sthorpej LOG(LOG_ERR, 0,
109269881cf6Sitojun "wrong conditioner name %s", w);
109395a65560Sthorpej return (0);
109495a65560Sthorpej }
109595a65560Sthorpej } else if (EQUAL(type, "pass")) {
109695a65560Sthorpej action->tca_code = TCACODE_PASS;
109795a65560Sthorpej } else if (EQUAL(type, "drop")) {
109895a65560Sthorpej action->tca_code = TCACODE_DROP;
109995a65560Sthorpej } else if (EQUAL(type, "mark")) {
110095a65560Sthorpej if (!next_word(&cp, w)) {
110169881cf6Sitojun LOG(LOG_ERR, 0, "missing dscp");
110295a65560Sthorpej return (0);
110395a65560Sthorpej }
110495a65560Sthorpej action->tca_code = TCACODE_MARK;
110595a65560Sthorpej action->tca_dscp = (u_int8_t)strtol(w, NULL, 0);
110695a65560Sthorpej } else if (EQUAL(type, "tbmeter")) {
110795a65560Sthorpej if (!next_word(&cp, w)) {
110869881cf6Sitojun LOG(LOG_ERR, 0, "missing tb profile");
110995a65560Sthorpej return (0);
111095a65560Sthorpej }
111195a65560Sthorpej profile[0].rate = atobps(w);
111295a65560Sthorpej if (!next_word(&cp, w)) {
111369881cf6Sitojun LOG(LOG_ERR, 0, "missing tb profile");
111495a65560Sthorpej return (0);
111595a65560Sthorpej }
111695a65560Sthorpej profile[0].depth = atobytes(w);
111795a65560Sthorpej if (tc_action_parser(ifname, &cp, &action[1]) == 0)
111895a65560Sthorpej return (0);
111995a65560Sthorpej if (tc_action_parser(ifname, &cp, &action[2]) == 0)
112095a65560Sthorpej return (0);
112195a65560Sthorpej
112295a65560Sthorpej if (qcmd_cdnr_add_tbmeter(action, ifname, NULL, &profile[0],
112395a65560Sthorpej &action[1], &action[2]) != 0)
112495a65560Sthorpej return (0);
112595a65560Sthorpej } else if (EQUAL(type, "trtcm")) {
112695a65560Sthorpej int coloraware = 0; /* default is color-blind */
112795a65560Sthorpej
112895a65560Sthorpej for (i=0; i<2; i++) {
112995a65560Sthorpej if (!next_word(&cp, w)) {
113069881cf6Sitojun LOG(LOG_ERR, 0, "missing tb profile");
113195a65560Sthorpej return (0);
113295a65560Sthorpej }
113395a65560Sthorpej profile[i].rate = atobps(w);
113495a65560Sthorpej if (!next_word(&cp, w)) {
113569881cf6Sitojun LOG(LOG_ERR, 0, "missing tb profile");
113695a65560Sthorpej return (0);
113795a65560Sthorpej }
113895a65560Sthorpej profile[i].depth = atobytes(w);
113995a65560Sthorpej }
114095a65560Sthorpej if (tc_action_parser(ifname, &cp, &action[1]) == 0)
114195a65560Sthorpej return (0);
114295a65560Sthorpej if (tc_action_parser(ifname, &cp, &action[2]) == 0)
114395a65560Sthorpej return (0);
114495a65560Sthorpej if (tc_action_parser(ifname, &cp, &action[3]) == 0)
114595a65560Sthorpej return (0);
114695a65560Sthorpej if (next_word(&cp, w)) {
114795a65560Sthorpej if (EQUAL(w, "coloraware"))
114895a65560Sthorpej coloraware = 1;
114995a65560Sthorpej else if (EQUAL(w, "colorblind"))
115095a65560Sthorpej coloraware = 0;
115195a65560Sthorpej }
115295a65560Sthorpej
115395a65560Sthorpej if (qcmd_cdnr_add_trtcm(action, ifname, NULL,
115495a65560Sthorpej &profile[0], &profile[1],
115595a65560Sthorpej &action[1], &action[2], &action[3],
115695a65560Sthorpej coloraware) != 0)
115795a65560Sthorpej return (0);
115895a65560Sthorpej } else if (EQUAL(type, "tswtcm")) {
115995a65560Sthorpej u_int32_t cmtd_rate, peak_rate, avg_interval;
116095a65560Sthorpej
116195a65560Sthorpej if (!next_word(&cp, w)) {
116269881cf6Sitojun LOG(LOG_ERR, 0, "missing cmtd rate");
116395a65560Sthorpej return (0);
116495a65560Sthorpej }
116595a65560Sthorpej cmtd_rate = atobps(w);
116695a65560Sthorpej
116795a65560Sthorpej if (!next_word(&cp, w)) {
116869881cf6Sitojun LOG(LOG_ERR, 0, "missing peak rate");
116995a65560Sthorpej return (0);
117095a65560Sthorpej }
117195a65560Sthorpej peak_rate = atobps(w);
117295a65560Sthorpej
117395a65560Sthorpej if (!next_word(&cp, w)) {
117469881cf6Sitojun LOG(LOG_ERR, 0, "missing avg interval");
117595a65560Sthorpej return (0);
117695a65560Sthorpej }
117795a65560Sthorpej avg_interval = (u_int32_t)strtoul(w, NULL, 0);
117895a65560Sthorpej
117995a65560Sthorpej if (tc_action_parser(ifname, &cp, &action[1]) == 0)
118095a65560Sthorpej return (0);
118195a65560Sthorpej if (tc_action_parser(ifname, &cp, &action[2]) == 0)
118295a65560Sthorpej return (0);
118395a65560Sthorpej if (tc_action_parser(ifname, &cp, &action[3]) == 0)
118495a65560Sthorpej return (0);
118595a65560Sthorpej
118695a65560Sthorpej if (qcmd_cdnr_add_tswtcm(action, ifname, NULL,
118795a65560Sthorpej cmtd_rate, peak_rate, avg_interval,
118895a65560Sthorpej &action[1], &action[2], &action[3])
118995a65560Sthorpej != 0)
119095a65560Sthorpej return (0);
119195a65560Sthorpej } else {
11927bd6fd35Swiz LOG(LOG_ERR, 0, "unknown action type %s");
119395a65560Sthorpej return (0);
119495a65560Sthorpej }
119595a65560Sthorpej
119695a65560Sthorpej *end = '>'; /* restore the end delimiter */
119795a65560Sthorpej
119895a65560Sthorpej return (1);
119995a65560Sthorpej }
1200