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