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(¶ms[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