parser.c revision 1.4 1 1.4 itojun /* $KAME: parser.c,v 1.10 2001/08/15 12:51:57 kjc Exp $ */
2 1.1 thorpej /*******************************************************************
3 1.1 thorpej
4 1.1 thorpej Copyright (c) 1996 by the University of Southern California
5 1.1 thorpej All rights reserved.
6 1.1 thorpej
7 1.1 thorpej Permission to use, copy, modify, and distribute this software and its
8 1.1 thorpej documentation in source and binary forms for any purpose and without
9 1.1 thorpej fee is hereby granted, provided that both the above copyright notice
10 1.1 thorpej and this permission notice appear in all copies. and that any
11 1.1 thorpej documentation, advertising materials, and other materials related to
12 1.1 thorpej such distribution and use acknowledge that the software was developed
13 1.1 thorpej in part by the University of Southern California, Information
14 1.1 thorpej Sciences Institute. The name of the University may not be used to
15 1.1 thorpej endorse or promote products derived from this software without
16 1.1 thorpej specific prior written permission.
17 1.1 thorpej
18 1.1 thorpej THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
19 1.1 thorpej the suitability of this software for any purpose. THIS SOFTWARE IS
20 1.1 thorpej PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
21 1.1 thorpej INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22 1.1 thorpej MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 1.1 thorpej
24 1.1 thorpej Other copyrights might apply to parts of this software and are so
25 1.1 thorpej noted when applicable.
26 1.1 thorpej
27 1.1 thorpej ********************************************************************/
28 1.1 thorpej
29 1.1 thorpej
30 1.1 thorpej #include <stdio.h>
31 1.1 thorpej #include <stdlib.h>
32 1.1 thorpej #include <unistd.h>
33 1.1 thorpej #include <stddef.h>
34 1.1 thorpej #include <string.h>
35 1.1 thorpej #include <ctype.h>
36 1.1 thorpej #include <errno.h>
37 1.1 thorpej #include <syslog.h>
38 1.1 thorpej #include <sys/socket.h>
39 1.1 thorpej #include <netdb.h>
40 1.1 thorpej #include <net/if.h>
41 1.1 thorpej #include <netinet/in.h>
42 1.1 thorpej #include <arpa/inet.h>
43 1.1 thorpej
44 1.1 thorpej #include <altq/altq.h>
45 1.1 thorpej #include <altq/altq_cdnr.h>
46 1.1 thorpej #include <altq/altq_red.h>
47 1.1 thorpej #include <altq/altq_rio.h>
48 1.1 thorpej #include "altq_qop.h"
49 1.1 thorpej #include "qop_cdnr.h"
50 1.1 thorpej
51 1.1 thorpej #define show_help(op) printf(cmd_tab[op].cmd_help)
52 1.1 thorpej
53 1.1 thorpej /*
54 1.1 thorpej * Forward & External Declarations
55 1.1 thorpej */
56 1.4 itojun static int is_qdisc_name(const char *);
57 1.4 itojun static int qdisc_interface_parser(const char *, const char *, int, char **);
58 1.4 itojun static int qdisc_class_parser(const char *, const char *, const char *,
59 1.4 itojun const char *, int, char **);
60 1.4 itojun
61 1.4 itojun static int pfxcmp(const char *, const char *);
62 1.4 itojun static int next_word(char **, char *);
63 1.4 itojun
64 1.4 itojun static int do_cmd(int, char *);
65 1.4 itojun static int get_ifname(char **, char **);
66 1.4 itojun static int get_addr(char **, struct in_addr *, struct in_addr *);
67 1.4 itojun static int get_port(const char *, u_int16_t *);
68 1.4 itojun static int get_proto(const char *, int *);
69 1.4 itojun static int get_fltr_opts(char **, char *, size_t, int *);
70 1.4 itojun static int interface_parser(char *);
71 1.4 itojun static int class_parser(char *) ;
72 1.4 itojun static int filter_parser(char *);
73 1.1 thorpej #ifdef INET6
74 1.4 itojun static int filter6_parser(char *);
75 1.4 itojun static int get_ip6addr(char **, struct in6_addr *, struct in6_addr *);
76 1.1 thorpej #endif
77 1.4 itojun static int ctl_parser(char *);
78 1.4 itojun static int delete_parser(char *);
79 1.4 itojun static int red_parser(char *);
80 1.4 itojun static int rio_parser(char *);
81 1.4 itojun static int conditioner_parser(char *);
82 1.4 itojun static int tc_action_parser(char *, char **, struct tc_action *);
83 1.1 thorpej
84 1.1 thorpej /*
85 1.1 thorpej * Globals
86 1.1 thorpej */
87 1.1 thorpej #define MAX_NFLWDS 64
88 1.1 thorpej #define MAX_T 64
89 1.1 thorpej
90 1.1 thorpej int TNO = 1; /* Current Thread number */
91 1.1 thorpej int line_no = 0;
92 1.1 thorpej int filter_dontwarn;
93 1.1 thorpej
94 1.1 thorpej static char if_names[MAX_T][IFNAMSIZ];
95 1.1 thorpej static struct if_nameindex *if_namelist = NULL;
96 1.1 thorpej
97 1.1 thorpej #ifndef MAX
98 1.1 thorpej #define MAX(a,b) (((a)>(b))?(a):(b))
99 1.1 thorpej #endif
100 1.1 thorpej #ifndef MIN
101 1.1 thorpej #define MIN(a,b) (((a)<(b))?(a):(b))
102 1.1 thorpej #endif
103 1.1 thorpej
104 1.1 thorpej enum op_codes {
105 1.1 thorpej /* order must be same as entries cmd_tab[].cmd_op below!! */
106 1.1 thorpej OP_HELP = 1, OP_QUIT,
107 1.1 thorpej OP_IFACE, OP_CLASS, OP_FILTER,
108 1.1 thorpej OP_ALTQ, OP_DEL,
109 1.1 thorpej #ifdef INET6
110 1.1 thorpej OP_FILTER6,
111 1.1 thorpej #endif
112 1.1 thorpej OP_RED, OP_RIO,
113 1.1 thorpej OP_CDNR,
114 1.1 thorpej OP_NULL, OP_BUG
115 1.1 thorpej };
116 1.1 thorpej
117 1.1 thorpej /* Following table MUST match enum order of op_codes !
118 1.1 thorpej */
119 1.1 thorpej struct cmds {
120 1.1 thorpej char *cmd_verb;
121 1.1 thorpej int cmd_op;
122 1.1 thorpej char *cmd_help;
123 1.1 thorpej } cmd_tab[] = {
124 1.1 thorpej
125 1.1 thorpej { "?", OP_HELP, "Commands are:\n" },
126 1.1 thorpej { "help", OP_HELP, " help | ?\n" },
127 1.1 thorpej { "quit", OP_QUIT, " quit\n" },
128 1.1 thorpej { "interface", OP_IFACE, " interface if_name [bandwidth bps] [cbq|hfsc]\n" },
129 1.1 thorpej { "class", OP_CLASS, " class discipline if_name class_name [parent]\n" },
130 1.1 thorpej { "filter", OP_FILTER, " filter if_name class_name [name filt_name] dst [netmask #] dport src [netmask #] sport proto [tos # [tosmask #] [gpi #] [dontwarn]\n" },
131 1.1 thorpej { "altq", OP_ALTQ, " disc if_name {enable|disable}\n" },
132 1.1 thorpej { "delete", OP_DEL, " delete if_name class_name\n" },
133 1.1 thorpej #ifdef INET6
134 1.1 thorpej { "filter6", OP_FILTER6, " filter6 if_name class_name [name filt_name] dst[/prefix] dport src[/prefix] sport proto [flowlabel #][tclass # [tclassmask #]][gpi #] [dontwarn]\n" },
135 1.1 thorpej #endif
136 1.1 thorpej { "red", OP_RED, " red th_min th_max inv_pmax\n" },
137 1.1 thorpej { "rio", OP_RIO, " 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\n" },
138 1.1 thorpej { "conditioner", OP_CDNR, " conditioner if_name cdnr_name <tc_action>\n" },
139 1.1 thorpej { "bug", OP_BUG, " bug (On/Off)\n" },
140 1.1 thorpej { "", OP_NULL, "" } /* MUST BE LAST IN CMD TABLE */
141 1.1 thorpej };
142 1.1 thorpej
143 1.1 thorpej static int
144 1.1 thorpej is_qdisc_name(const char *qname)
145 1.1 thorpej {
146 1.1 thorpej struct qdisc_parser *qp;
147 1.1 thorpej
148 1.1 thorpej for (qp = qdisc_parser; qp->qname != NULL; qp++)
149 1.1 thorpej if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0)
150 1.1 thorpej return (1);
151 1.1 thorpej return (0);
152 1.1 thorpej }
153 1.1 thorpej
154 1.1 thorpej static int
155 1.1 thorpej qdisc_interface_parser(const char * qname, const char *ifname,
156 1.1 thorpej int argc, char **argv)
157 1.1 thorpej {
158 1.1 thorpej struct qdisc_parser *qp;
159 1.1 thorpej
160 1.1 thorpej for (qp = qdisc_parser; qp->qname != NULL; qp++)
161 1.1 thorpej if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0)
162 1.1 thorpej return (*qp->interface_parser)(ifname, argc, argv);
163 1.1 thorpej return (0);
164 1.1 thorpej }
165 1.1 thorpej
166 1.1 thorpej static int
167 1.1 thorpej qdisc_class_parser(const char *qname, const char *ifname,
168 1.1 thorpej const char *class_name, const char *parent_name,
169 1.1 thorpej int argc, char **argv)
170 1.1 thorpej {
171 1.1 thorpej struct qdisc_parser *qp;
172 1.4 itojun struct ifinfo *ifinfo;
173 1.4 itojun
174 1.1 thorpej for (qp = qdisc_parser; qp->qname != NULL; qp++)
175 1.1 thorpej if (strncmp(qp->qname, qname, strlen(qp->qname)) == 0) {
176 1.1 thorpej if (qp->class_parser == NULL) {
177 1.1 thorpej LOG(LOG_ERR, 0,
178 1.4 itojun "class can't be specified for %s", qp->qname);
179 1.4 itojun return (0);
180 1.4 itojun }
181 1.4 itojun if ((ifinfo = ifname2ifinfo(ifname)) == NULL) {
182 1.4 itojun LOG(LOG_ERR, 0,
183 1.4 itojun "no such interface, line %d\n", line_no);
184 1.4 itojun return (0);
185 1.4 itojun }
186 1.4 itojun if (strncmp(ifinfo->qdisc->qname, qname,
187 1.4 itojun strlen(ifinfo->qdisc->qname)) != 0) {
188 1.4 itojun LOG(LOG_ERR, 0,
189 1.4 itojun "qname doesn't match the interface, line %d\n",
190 1.4 itojun line_no);
191 1.1 thorpej return (0);
192 1.1 thorpej }
193 1.1 thorpej return (*qp->class_parser)(ifname, class_name,
194 1.1 thorpej parent_name, argc, argv);
195 1.1 thorpej }
196 1.1 thorpej return (0);
197 1.1 thorpej }
198 1.1 thorpej
199 1.1 thorpej
200 1.1 thorpej /*
201 1.1 thorpej * Read the config file to learn about tunnel vifs and non-default phyint
202 1.1 thorpej * parameters.
203 1.1 thorpej */
204 1.1 thorpej int
205 1.1 thorpej qcmd_config(void)
206 1.1 thorpej {
207 1.1 thorpej FILE *f;
208 1.1 thorpej int i, rc = 1;
209 1.1 thorpej
210 1.1 thorpej if (if_namelist != NULL)
211 1.1 thorpej if_freenameindex(if_namelist);
212 1.1 thorpej if_namelist = if_nameindex();
213 1.1 thorpej
214 1.1 thorpej for (i = 0; i < MAX_T; i++)
215 1.1 thorpej if_names[i][0] = '\0';
216 1.1 thorpej
217 1.1 thorpej LOG(LOG_INFO, 0, "ALTQ config file is %s\n", altqconfigfile);
218 1.1 thorpej
219 1.1 thorpej f = fopen(altqconfigfile, "r");
220 1.1 thorpej if (f == NULL) {
221 1.1 thorpej LOG(LOG_ERR, errno, "Can't open %s", altqconfigfile, 0);
222 1.1 thorpej return (QOPERR_INVAL);
223 1.1 thorpej }
224 1.1 thorpej line_no = 0;
225 1.1 thorpej while (rc)
226 1.1 thorpej rc = DoCommand(altqconfigfile, f);
227 1.1 thorpej
228 1.1 thorpej (void) fclose(f);
229 1.1 thorpej line_no = 0;
230 1.1 thorpej return (0);
231 1.1 thorpej }
232 1.1 thorpej
233 1.1 thorpej /*
234 1.1 thorpej * Do_Command(): Top-level routine to read the next line from a given
235 1.1 thorpej * file and execute the command it contains.
236 1.1 thorpej * returns 1 if OK, 0 if EOF.
237 1.1 thorpej */
238 1.1 thorpej int
239 1.1 thorpej DoCommand(char *infile, FILE *infp)
240 1.1 thorpej {
241 1.1 thorpej char cmd_line[256], cmd_op[80];
242 1.1 thorpej struct cmds *cmdp;
243 1.1 thorpej char *cp;
244 1.1 thorpej int rc;
245 1.1 thorpej
246 1.1 thorpej if (fgets(cmd_line, sizeof(cmd_line), infp) == NULL)
247 1.1 thorpej /* EOF */
248 1.1 thorpej return(0);
249 1.1 thorpej line_no++;
250 1.1 thorpej
251 1.1 thorpej /* check escaped newline */
252 1.1 thorpej while ((cp = strrchr(cmd_line, '\\')) != NULL && cp[1] == '\n') {
253 1.1 thorpej if (fgets(cp, &cmd_line[256] - cp, infp) != NULL)
254 1.1 thorpej line_no++;
255 1.1 thorpej }
256 1.1 thorpej
257 1.1 thorpej /* remove trailing NL */
258 1.1 thorpej cp = cmd_line + strlen(cmd_line) - 1;
259 1.1 thorpej if (*cp == '\n')
260 1.1 thorpej *cp = '\0';
261 1.1 thorpej else if (!feof(infp)) {
262 1.1 thorpej printf("LINE %d > 255 CHARS: %s.\n", line_no, cmd_line);
263 1.1 thorpej exit(1);
264 1.1 thorpej }
265 1.1 thorpej /*** printf("DoCommand: %s\n", cmd_line); ***/
266 1.1 thorpej
267 1.1 thorpej if (cmd_line[0] == '#') { /* Comment, skip this line */
268 1.1 thorpej return(1);
269 1.1 thorpej }
270 1.1 thorpej cp = cmd_line;
271 1.1 thorpej if (!next_word(&cp, cmd_op))
272 1.1 thorpej return(1);
273 1.1 thorpej if (cmd_op[0] == 'T') {
274 1.1 thorpej TNO = atoi(&cmd_op[1]);
275 1.1 thorpej if (!next_word(&cp, cmd_op))
276 1.1 thorpej return(1);
277 1.1 thorpej }
278 1.1 thorpej cmdp = cmd_tab;
279 1.1 thorpej while ((cmdp->cmd_op != OP_NULL) && pfxcmp(cmd_op, cmdp->cmd_verb))
280 1.1 thorpej cmdp++;
281 1.1 thorpej
282 1.1 thorpej if (cmdp->cmd_op == OP_NULL) {
283 1.1 thorpej if (cmd_op[0])
284 1.1 thorpej printf(" ?? %s\n", cmd_op);
285 1.1 thorpej return(1);
286 1.1 thorpej }
287 1.1 thorpej rc = do_cmd(cmdp->cmd_op, cp);
288 1.1 thorpej if (rc == 0) {
289 1.1 thorpej if (infile) {
290 1.1 thorpej /* error in the config file. cleanup and exit. */
291 1.1 thorpej LOG(LOG_ERR, 0, "Config failed. Exiting.\n");
292 1.1 thorpej (void) qcmd_destroyall();
293 1.1 thorpej (void) fclose(infp);
294 1.1 thorpej exit(1);
295 1.1 thorpej } else {
296 1.1 thorpej /* interactive mode */
297 1.1 thorpej printf("error: usage :");
298 1.1 thorpej show_help(cmdp->cmd_op);
299 1.1 thorpej }
300 1.1 thorpej }
301 1.1 thorpej return(1);
302 1.1 thorpej }
303 1.1 thorpej
304 1.1 thorpej
305 1.1 thorpej /*
306 1.1 thorpej * Prefix string comparison: Return 0 if s1 string is prefix of s2 string, 1
307 1.1 thorpej * otherwise.
308 1.1 thorpej */
309 1.1 thorpej static int
310 1.1 thorpej pfxcmp(const char *s1, const char *s2)
311 1.1 thorpej {
312 1.1 thorpej while (*s1)
313 1.1 thorpej if (*s1++ != *s2++)
314 1.1 thorpej return (1);
315 1.1 thorpej return (0);
316 1.1 thorpej }
317 1.1 thorpej
318 1.1 thorpej /*
319 1.1 thorpej * Skip leading blanks, then copy next word (delimited by blank or zero, but
320 1.1 thorpej * no longer than 63 bytes) into buffer b, set scan pointer to following
321 1.1 thorpej * non-blank (or end of string), and return 1. If there is no non-blank text,
322 1.1 thorpej * set scan ptr to point to 0 byte and return 0.
323 1.1 thorpej */
324 1.1 thorpej static int
325 1.1 thorpej next_word(char **cpp, char *b)
326 1.1 thorpej {
327 1.1 thorpej char *tp;
328 1.1 thorpej size_t L;
329 1.1 thorpej
330 1.1 thorpej *cpp += strspn(*cpp, " \t");
331 1.1 thorpej if (**cpp == '\0' || **cpp == '\n' || **cpp == '#')
332 1.1 thorpej return(0);
333 1.1 thorpej
334 1.1 thorpej tp = strpbrk(*cpp, " \t\n#");
335 1.1 thorpej L = MIN((tp)?(tp-*cpp):strlen(*cpp), 63);
336 1.1 thorpej strncpy(b, *cpp, L);
337 1.1 thorpej *(b + L) = '\0';
338 1.1 thorpej *cpp += L;
339 1.1 thorpej *cpp += strspn(*cpp, " \t");
340 1.1 thorpej return (1);
341 1.1 thorpej }
342 1.1 thorpej
343 1.1 thorpej /*
344 1.1 thorpej * do_cmd executes a command input.
345 1.1 thorpej * returns 1 if OK, 0 if an error occurs.
346 1.1 thorpej */
347 1.1 thorpej static int
348 1.1 thorpej do_cmd(int op, char *cmdbuf)
349 1.1 thorpej {
350 1.1 thorpej int i, rval = 0;
351 1.1 thorpej
352 1.1 thorpej switch (op) {
353 1.1 thorpej case OP_HELP:
354 1.1 thorpej for (i = 0; i < OP_NULL; i++)
355 1.1 thorpej show_help(i);
356 1.1 thorpej rval = 1;
357 1.1 thorpej break;
358 1.1 thorpej case OP_QUIT:
359 1.1 thorpej qcmd_destroyall();
360 1.1 thorpej exit(0);
361 1.1 thorpej break;
362 1.1 thorpej case OP_IFACE:
363 1.1 thorpej rval = interface_parser(cmdbuf);
364 1.1 thorpej break;
365 1.1 thorpej case OP_CLASS:
366 1.1 thorpej rval = class_parser(cmdbuf);
367 1.1 thorpej break;
368 1.1 thorpej case OP_FILTER:
369 1.1 thorpej rval = filter_parser(cmdbuf);
370 1.1 thorpej break;
371 1.1 thorpej case OP_ALTQ:
372 1.1 thorpej rval = ctl_parser(cmdbuf);
373 1.1 thorpej break;
374 1.1 thorpej case OP_DEL:
375 1.1 thorpej rval = delete_parser(cmdbuf);
376 1.1 thorpej break;
377 1.1 thorpej #ifdef INET6
378 1.1 thorpej case OP_FILTER6:
379 1.1 thorpej rval = filter6_parser(cmdbuf);
380 1.1 thorpej break;
381 1.1 thorpej #endif
382 1.1 thorpej case OP_RED:
383 1.1 thorpej rval = red_parser(cmdbuf);
384 1.1 thorpej break;
385 1.1 thorpej case OP_RIO:
386 1.1 thorpej rval = rio_parser(cmdbuf);
387 1.1 thorpej break;
388 1.1 thorpej case OP_CDNR:
389 1.1 thorpej rval = conditioner_parser(cmdbuf);
390 1.1 thorpej break;
391 1.1 thorpej case OP_BUG:
392 1.1 thorpej if (m_debug & DEBUG_ALTQ) {
393 1.1 thorpej /* turn off verbose */
394 1.1 thorpej l_debug = LOG_INFO;
395 1.1 thorpej m_debug &= ~DEBUG_ALTQ;
396 1.1 thorpej } else {
397 1.1 thorpej /* turn on verbose */
398 1.1 thorpej l_debug = LOG_DEBUG;
399 1.1 thorpej m_debug |= DEBUG_ALTQ;
400 1.1 thorpej }
401 1.1 thorpej break;
402 1.1 thorpej default:
403 1.1 thorpej printf("command %d not supported\n", op);
404 1.1 thorpej rval = 0;
405 1.1 thorpej break;
406 1.1 thorpej }
407 1.1 thorpej return(rval);
408 1.1 thorpej }
409 1.1 thorpej
410 1.1 thorpej #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
411 1.1 thorpej
412 1.1 thorpej char *cur_ifname(void)
413 1.1 thorpej {
414 1.1 thorpej return (if_names[TNO]);
415 1.1 thorpej }
416 1.1 thorpej
417 1.1 thorpej u_int
418 1.1 thorpej get_ifindex(const char *ifname)
419 1.1 thorpej {
420 1.1 thorpej struct if_nameindex *ifnp;
421 1.1 thorpej
422 1.1 thorpej for (ifnp = if_namelist; ifnp->if_name != NULL; ifnp++)
423 1.1 thorpej if (strcmp(ifname, ifnp->if_name) == 0)
424 1.1 thorpej return (ifnp->if_index);
425 1.1 thorpej return (0);
426 1.1 thorpej }
427 1.1 thorpej
428 1.1 thorpej static int
429 1.1 thorpej get_ifname(char **cpp, char **ifnamep)
430 1.1 thorpej {
431 1.1 thorpej char w[128], *ocp;
432 1.1 thorpej struct if_nameindex *ifnp;
433 1.1 thorpej
434 1.1 thorpej ocp = *cpp;
435 1.1 thorpej if (next_word(&ocp, w) && if_namelist != NULL)
436 1.1 thorpej for (ifnp = if_namelist; ifnp->if_name != NULL; ifnp++)
437 1.1 thorpej if (strcmp(w, ifnp->if_name) == 0) {
438 1.1 thorpej /* if_name found. advance the word pointer */
439 1.1 thorpej *cpp = ocp;
440 1.4 itojun strlcpy(if_names[TNO], w, sizeof(if_names[TNO]));
441 1.1 thorpej *ifnamep = if_names[TNO];
442 1.1 thorpej return (1);
443 1.1 thorpej }
444 1.1 thorpej
445 1.1 thorpej /* this is not interface name. use one in the context. */
446 1.1 thorpej if (if_names[TNO][0] == 0)
447 1.1 thorpej return (0);
448 1.1 thorpej *ifnamep = if_names[TNO];
449 1.1 thorpej return (1);
450 1.1 thorpej }
451 1.1 thorpej
452 1.1 thorpej /* set address and netmask in network byte order */
453 1.1 thorpej static int
454 1.1 thorpej get_addr(char **cpp, struct in_addr *addr, struct in_addr *mask)
455 1.1 thorpej {
456 1.1 thorpej char w[128], *ocp;
457 1.3 itojun struct in_addr tmp;
458 1.1 thorpej
459 1.1 thorpej addr->s_addr = 0;
460 1.1 thorpej mask->s_addr = 0xffffffff;
461 1.1 thorpej
462 1.1 thorpej if (!next_word(cpp, w))
463 1.1 thorpej return (0);
464 1.1 thorpej
465 1.3 itojun if (inet_aton((char *)w, &tmp) != 1) {
466 1.1 thorpej /* try gethostbyname */
467 1.1 thorpej struct hostent *h;
468 1.1 thorpej
469 1.1 thorpej if ((h = gethostbyname(w)) == NULL
470 1.1 thorpej || h->h_addrtype != AF_INET || h->h_length != 4)
471 1.1 thorpej return (0);
472 1.1 thorpej
473 1.1 thorpej bcopy(h->h_addr, &tmp, (size_t)h->h_length);
474 1.1 thorpej }
475 1.1 thorpej
476 1.3 itojun addr->s_addr = tmp.s_addr;
477 1.1 thorpej
478 1.1 thorpej /* check if netmask option is present */
479 1.1 thorpej ocp = *cpp;
480 1.1 thorpej if (next_word(&ocp, w) && EQUAL(w, "netmask")) {
481 1.1 thorpej if (!next_word(&ocp, w))
482 1.1 thorpej return (0);
483 1.1 thorpej
484 1.3 itojun if (inet_aton((char *)w, (struct in_addr *)&tmp) != 1)
485 1.1 thorpej return (0);
486 1.1 thorpej
487 1.3 itojun mask->s_addr = tmp.s_addr;
488 1.1 thorpej *cpp = ocp;
489 1.1 thorpej return (1);
490 1.1 thorpej }
491 1.1 thorpej /* no netmask option */
492 1.1 thorpej return (1);
493 1.1 thorpej }
494 1.1 thorpej
495 1.1 thorpej /* returns service number in network byte order */
496 1.1 thorpej static int
497 1.1 thorpej get_port(const char *name, u_int16_t *port_no)
498 1.1 thorpej {
499 1.1 thorpej struct servent *s;
500 1.1 thorpej u_int16_t num;
501 1.1 thorpej
502 1.1 thorpej if (isdigit(name[0])) {
503 1.1 thorpej num = (u_int16_t)strtol(name, NULL, 0);
504 1.1 thorpej *port_no = htons(num);
505 1.1 thorpej return (1);
506 1.1 thorpej }
507 1.1 thorpej
508 1.1 thorpej if ((s = getservbyname(name, 0)) == NULL)
509 1.1 thorpej return (0);
510 1.1 thorpej
511 1.1 thorpej *port_no = (u_int16_t)s->s_port;
512 1.1 thorpej return (1);
513 1.1 thorpej }
514 1.1 thorpej
515 1.1 thorpej static int
516 1.1 thorpej get_proto(const char *name, int *proto_no)
517 1.1 thorpej {
518 1.1 thorpej struct protoent *p;
519 1.1 thorpej
520 1.1 thorpej if (isdigit(name[0])) {
521 1.1 thorpej *proto_no = (int)strtol(name, NULL, 0);
522 1.1 thorpej return (1);
523 1.1 thorpej }
524 1.1 thorpej
525 1.1 thorpej if ((p = getprotobyname(name)) == NULL)
526 1.1 thorpej return (0);
527 1.1 thorpej
528 1.1 thorpej *proto_no = p->p_proto;
529 1.1 thorpej return (1);
530 1.1 thorpej }
531 1.1 thorpej
532 1.1 thorpej static int
533 1.4 itojun get_fltr_opts(char **cpp, char *fltr_name, size_t len, int *ruleno)
534 1.1 thorpej {
535 1.1 thorpej char w[128], *ocp;
536 1.1 thorpej
537 1.1 thorpej ocp = *cpp;
538 1.1 thorpej while (next_word(&ocp, w)) {
539 1.1 thorpej if (EQUAL(w, "name")) {
540 1.1 thorpej if (!next_word(&ocp, w))
541 1.1 thorpej return (0);
542 1.4 itojun strlcpy(fltr_name, w, len);
543 1.1 thorpej *cpp = ocp;
544 1.1 thorpej } else if (EQUAL(w, "ruleno")) {
545 1.1 thorpej if (!next_word(&ocp, w))
546 1.1 thorpej return (0);
547 1.1 thorpej *ruleno = (int)strtol(w, NULL, 0);
548 1.1 thorpej *cpp = ocp;
549 1.1 thorpej } else
550 1.1 thorpej break;
551 1.1 thorpej }
552 1.1 thorpej return (1);
553 1.1 thorpej }
554 1.1 thorpej
555 1.1 thorpej
556 1.1 thorpej #define DISCIPLINE_NONE 0
557 1.1 thorpej
558 1.1 thorpej static int
559 1.1 thorpej interface_parser(char *cmdbuf)
560 1.1 thorpej {
561 1.1 thorpej char w[256], *ap, *cp = cmdbuf;
562 1.1 thorpej char *ifname, *argv[64], qdisc_name[64];
563 1.1 thorpej int argc, rval;
564 1.1 thorpej
565 1.1 thorpej if (!get_ifname(&cp, &ifname)) {
566 1.1 thorpej LOG(LOG_ERR, 0, "missing interface name in %s, line %d\n",
567 1.1 thorpej altqconfigfile, line_no);
568 1.1 thorpej return (0);
569 1.1 thorpej }
570 1.1 thorpej
571 1.1 thorpej /*
572 1.1 thorpej * Create argment list & look for scheduling discipline options.
573 1.1 thorpej */
574 1.3 itojun snprintf(qdisc_name, sizeof(qdisc_name), "null");
575 1.1 thorpej argc = 0;
576 1.1 thorpej ap = w;
577 1.1 thorpej while (next_word(&cp, ap)) {
578 1.1 thorpej if (is_qdisc_name(ap))
579 1.4 itojun strlcpy(qdisc_name, ap, sizeof(qdisc_name));
580 1.1 thorpej
581 1.1 thorpej argv[argc] = ap;
582 1.1 thorpej ap += strlen(ap) + 1;
583 1.1 thorpej argc++;
584 1.1 thorpej }
585 1.1 thorpej
586 1.1 thorpej rval = qdisc_interface_parser(qdisc_name, ifname, argc, argv);
587 1.1 thorpej if (rval == 0) {
588 1.1 thorpej LOG(LOG_ERR, 0, "Error in %s, line %d\n",
589 1.1 thorpej altqconfigfile, line_no);
590 1.1 thorpej return (0);
591 1.1 thorpej }
592 1.1 thorpej return (1);
593 1.1 thorpej }
594 1.1 thorpej
595 1.1 thorpej static int
596 1.1 thorpej class_parser(char *cmdbuf)
597 1.1 thorpej {
598 1.1 thorpej char w[256], *cp = cmdbuf;
599 1.1 thorpej char *ifname, qdisc_name[128], class_name[128], parent_name[128];
600 1.1 thorpej char *clname = class_name;
601 1.1 thorpej char *parent = NULL;
602 1.1 thorpej char *argv[64], *ap;
603 1.1 thorpej int argc, rval;
604 1.1 thorpej
605 1.1 thorpej /* get scheduling class */
606 1.1 thorpej if (!next_word(&cp, qdisc_name)) {
607 1.1 thorpej LOG(LOG_ERR, 0, "missing scheduling discipline in %s, line %d\n",
608 1.1 thorpej altqconfigfile, line_no);
609 1.1 thorpej return (0);
610 1.1 thorpej }
611 1.1 thorpej if (!is_qdisc_name(qdisc_name)) {
612 1.1 thorpej LOG(LOG_ERR, 0,
613 1.1 thorpej "unknown scheduling discipline '%s' in %s, line %d\n",
614 1.1 thorpej qdisc_name, altqconfigfile, line_no);
615 1.1 thorpej return (0);
616 1.1 thorpej }
617 1.1 thorpej
618 1.1 thorpej /* get interface name */
619 1.1 thorpej if (!get_ifname(&cp, &ifname)) {
620 1.1 thorpej LOG(LOG_ERR, 0, "missing interface name in %s, line %d\n",
621 1.1 thorpej altqconfigfile, line_no);
622 1.1 thorpej return (0);
623 1.1 thorpej }
624 1.1 thorpej
625 1.1 thorpej /* get class name */
626 1.1 thorpej if (!next_word(&cp, class_name)) {
627 1.1 thorpej LOG(LOG_ERR, 0, "missing class name in %s, line %d\n",
628 1.1 thorpej altqconfigfile, line_no);
629 1.1 thorpej return (0);
630 1.1 thorpej }
631 1.1 thorpej
632 1.1 thorpej /* get parent name */
633 1.1 thorpej if (!next_word(&cp, parent_name)) {
634 1.1 thorpej LOG(LOG_ERR, 0, "missing parent class in %s, line %d\n",
635 1.1 thorpej altqconfigfile, line_no);
636 1.1 thorpej return (0);
637 1.1 thorpej }
638 1.1 thorpej if (!EQUAL(parent_name, "null") && !EQUAL(parent_name, "NULL")) {
639 1.1 thorpej parent = parent_name;
640 1.1 thorpej } else {
641 1.1 thorpej parent = NULL;
642 1.1 thorpej }
643 1.1 thorpej
644 1.1 thorpej ap = w;
645 1.1 thorpej argc = 0;
646 1.1 thorpej while (next_word(&cp, ap)) {
647 1.1 thorpej argv[argc] = ap;
648 1.1 thorpej ap += strlen(ap) + 1;
649 1.1 thorpej argc++;
650 1.1 thorpej }
651 1.1 thorpej
652 1.1 thorpej rval = qdisc_class_parser(qdisc_name, ifname, clname, parent,
653 1.1 thorpej argc, argv);
654 1.1 thorpej if (rval == 0) {
655 1.1 thorpej LOG(LOG_ERR, 0, "can't add class '%s' on interface '%s'\n",
656 1.1 thorpej clname, ifname);
657 1.1 thorpej return (0);
658 1.1 thorpej }
659 1.1 thorpej
660 1.1 thorpej return (1);
661 1.1 thorpej }
662 1.1 thorpej
663 1.1 thorpej static int
664 1.1 thorpej filter_parser(char *cmdbuf)
665 1.1 thorpej {
666 1.1 thorpej char w[128], *cp = cmdbuf;
667 1.1 thorpej char *ifname, class_name[64], fltr_name[64], *flname = NULL;
668 1.1 thorpej struct flow_filter sfilt;
669 1.1 thorpej int protocol;
670 1.1 thorpej u_char tos, tosmask;
671 1.1 thorpej int ruleno;
672 1.1 thorpej int dontwarn = 0;
673 1.1 thorpej int error;
674 1.1 thorpej
675 1.1 thorpej memset(&sfilt, 0, sizeof(sfilt));
676 1.1 thorpej sfilt.ff_flow.fi_family = AF_INET;
677 1.1 thorpej
678 1.1 thorpej if (!get_ifname(&cp, &ifname)) {
679 1.1 thorpej LOG(LOG_ERR, 0, "missing interface name in %s, line %d\n",
680 1.1 thorpej altqconfigfile, line_no);
681 1.1 thorpej return (0);
682 1.1 thorpej }
683 1.1 thorpej
684 1.1 thorpej if (!next_word(&cp, class_name)) {
685 1.1 thorpej LOG(LOG_ERR, 0,
686 1.1 thorpej "missing class name in %s, line %d\n",
687 1.1 thorpej altqconfigfile, line_no);
688 1.1 thorpej return (0);
689 1.1 thorpej }
690 1.1 thorpej
691 1.1 thorpej fltr_name[0] = '\0';
692 1.1 thorpej ruleno = 0;
693 1.4 itojun if (!get_fltr_opts(&cp, &fltr_name[0], sizeof(fltr_name), &ruleno)) {
694 1.1 thorpej LOG(LOG_ERR, 0,
695 1.1 thorpej "bad filter option in %s, line %d\n",
696 1.1 thorpej altqconfigfile, line_no);
697 1.1 thorpej return (0);
698 1.1 thorpej }
699 1.1 thorpej if (fltr_name[0] != '\0')
700 1.1 thorpej flname = fltr_name;
701 1.1 thorpej sfilt.ff_ruleno = ruleno;
702 1.1 thorpej
703 1.1 thorpej /* get filter destination Address */
704 1.1 thorpej if (!get_addr(&cp, &sfilt.ff_flow.fi_dst, &sfilt.ff_mask.mask_dst)) {
705 1.1 thorpej LOG(LOG_ERR, 0,
706 1.1 thorpej "bad filter destination address in %s, line %d\n",
707 1.1 thorpej altqconfigfile, line_no);
708 1.1 thorpej return (0);
709 1.1 thorpej }
710 1.1 thorpej
711 1.1 thorpej /* get filter destination port */
712 1.1 thorpej if (!next_word(&cp, w)) {
713 1.1 thorpej LOG(LOG_ERR, 0,
714 1.1 thorpej "missing filter destination port in %s, line %d\n",
715 1.1 thorpej altqconfigfile, line_no);
716 1.1 thorpej return (0);
717 1.1 thorpej }
718 1.1 thorpej if (!get_port(w, &sfilt.ff_flow.fi_dport)) {
719 1.1 thorpej LOG(LOG_ERR, 0, "bad filter destination port in %s, line %d\n",
720 1.1 thorpej altqconfigfile, line_no);
721 1.1 thorpej return (0);
722 1.1 thorpej }
723 1.1 thorpej
724 1.1 thorpej /* get filter source address */
725 1.1 thorpej if (!get_addr(&cp, &sfilt.ff_flow.fi_src, &sfilt.ff_mask.mask_src)) {
726 1.1 thorpej LOG(LOG_ERR, 0, "bad filter source address in %s, line %d\n",
727 1.1 thorpej altqconfigfile, line_no);
728 1.1 thorpej return (0);
729 1.1 thorpej }
730 1.1 thorpej
731 1.1 thorpej /* get filter source port */
732 1.1 thorpej if (!next_word(&cp, w)) {
733 1.1 thorpej LOG(LOG_ERR, 0, "missing filter source port in %s, line %d\n",
734 1.1 thorpej altqconfigfile, line_no);
735 1.1 thorpej return (0);
736 1.1 thorpej }
737 1.1 thorpej if (!get_port(w, &sfilt.ff_flow.fi_sport)) {
738 1.1 thorpej LOG(LOG_ERR, 0, "bad filter source port in %s, line %d\n",
739 1.1 thorpej altqconfigfile, line_no);
740 1.1 thorpej return (0);
741 1.1 thorpej }
742 1.1 thorpej
743 1.1 thorpej /* get filter protocol id */
744 1.1 thorpej if (!next_word(&cp, w)) {
745 1.1 thorpej LOG(LOG_ERR, 0, "missing filter protocol id in %s, line %d\n",
746 1.1 thorpej altqconfigfile, line_no);
747 1.1 thorpej return (0);
748 1.1 thorpej }
749 1.1 thorpej if (!get_proto(w, &protocol)) {
750 1.1 thorpej LOG(LOG_ERR, 0, "bad protocol in %s, line %d\n",
751 1.1 thorpej altqconfigfile, line_no);
752 1.1 thorpej return (0);
753 1.1 thorpej }
754 1.1 thorpej sfilt.ff_flow.fi_proto = protocol;
755 1.1 thorpej
756 1.1 thorpej while (next_word(&cp, w)) {
757 1.1 thorpej if (EQUAL(w, "tos")) {
758 1.1 thorpej tos = 0;
759 1.1 thorpej tosmask = 0xff;
760 1.1 thorpej
761 1.1 thorpej if (next_word(&cp, w)) {
762 1.1 thorpej tos = (u_char)strtol(w, NULL, 0);
763 1.1 thorpej if (next_word(&cp, w)) {
764 1.1 thorpej if (EQUAL(w, "tosmask")) {
765 1.1 thorpej next_word(&cp, w);
766 1.1 thorpej tosmask = (u_char)strtol(w, NULL, 0);
767 1.1 thorpej }
768 1.1 thorpej }
769 1.1 thorpej }
770 1.1 thorpej sfilt.ff_flow.fi_tos = tos;
771 1.1 thorpej sfilt.ff_mask.mask_tos = tosmask;
772 1.1 thorpej } else if (EQUAL(w, "gpi")) {
773 1.1 thorpej if (next_word(&cp, w)) {
774 1.1 thorpej sfilt.ff_flow.fi_gpi =
775 1.1 thorpej (u_int32_t)strtoul(w, NULL, 0);
776 1.1 thorpej sfilt.ff_flow.fi_gpi =
777 1.1 thorpej htonl(sfilt.ff_flow.fi_gpi);
778 1.1 thorpej }
779 1.1 thorpej } else if (EQUAL(w, "dontwarn"))
780 1.1 thorpej dontwarn = 1;
781 1.1 thorpej }
782 1.1 thorpej
783 1.1 thorpej /*
784 1.1 thorpej * Add the filter.
785 1.1 thorpej */
786 1.1 thorpej filter_dontwarn = dontwarn; /* XXX */
787 1.1 thorpej error = qcmd_add_filter(ifname, class_name, flname, &sfilt);
788 1.1 thorpej filter_dontwarn = 0; /* XXX */
789 1.1 thorpej if (error) {
790 1.1 thorpej LOG(LOG_ERR, 0,
791 1.1 thorpej "can't add filter to class '%s' on interface '%s'\n",
792 1.1 thorpej class_name, ifname);
793 1.1 thorpej return (0);
794 1.1 thorpej }
795 1.1 thorpej
796 1.1 thorpej return (1);
797 1.1 thorpej }
798 1.1 thorpej
799 1.1 thorpej #ifdef INET6
800 1.1 thorpej static int
801 1.1 thorpej filter6_parser(char *cmdbuf)
802 1.1 thorpej {
803 1.1 thorpej char w[128], *cp = cmdbuf;
804 1.1 thorpej char *ifname, class_name[128], fltr_name[64], *flname = NULL;
805 1.1 thorpej struct flow_filter6 sfilt;
806 1.1 thorpej int protocol;
807 1.1 thorpej u_char tclass, tclassmask;
808 1.1 thorpej int ruleno;
809 1.1 thorpej int dontwarn = 0;
810 1.1 thorpej int ret;
811 1.1 thorpej
812 1.1 thorpej memset(&sfilt, 0, sizeof(sfilt));
813 1.1 thorpej sfilt.ff_flow6.fi6_family = AF_INET6;
814 1.1 thorpej
815 1.1 thorpej if (!get_ifname(&cp, &ifname)) {
816 1.1 thorpej LOG(LOG_ERR, 0, "missing interface name in %s, line %d\n",
817 1.1 thorpej altqconfigfile, line_no);
818 1.1 thorpej return (0);
819 1.1 thorpej }
820 1.1 thorpej
821 1.1 thorpej if (!next_word(&cp, class_name)) {
822 1.1 thorpej LOG(LOG_ERR, 0, "missing class name in %s, line %d\n",
823 1.1 thorpej altqconfigfile, line_no);
824 1.1 thorpej return (0);
825 1.1 thorpej }
826 1.1 thorpej
827 1.1 thorpej fltr_name[0] = '\0';
828 1.1 thorpej ruleno = 0;
829 1.4 itojun if (!get_fltr_opts(&cp, &fltr_name[0], sizeof(fltr_name), &ruleno)) {
830 1.1 thorpej LOG(LOG_ERR, 0,
831 1.1 thorpej "bad filter option in %s, line %d\n",
832 1.1 thorpej altqconfigfile, line_no);
833 1.1 thorpej return (0);
834 1.1 thorpej }
835 1.1 thorpej if (fltr_name[0] != '\0')
836 1.1 thorpej flname = fltr_name;
837 1.1 thorpej sfilt.ff_ruleno = ruleno;
838 1.1 thorpej
839 1.1 thorpej /* get filter destination address */
840 1.1 thorpej if (!get_ip6addr(&cp, &sfilt.ff_flow6.fi6_dst,
841 1.1 thorpej &sfilt.ff_mask6.mask6_dst)) {
842 1.1 thorpej LOG(LOG_ERR, 0, "bad destination address in %s, line %d\n",
843 1.1 thorpej altqconfigfile, line_no);
844 1.1 thorpej return (0);
845 1.1 thorpej }
846 1.1 thorpej
847 1.1 thorpej /* get filter destination port */
848 1.1 thorpej if (!next_word(&cp, w)) {
849 1.1 thorpej LOG(LOG_ERR, 0,
850 1.1 thorpej "missing filter destination port in %s, line %d\n",
851 1.1 thorpej altqconfigfile, line_no);
852 1.1 thorpej return (0);
853 1.1 thorpej }
854 1.1 thorpej if (!get_port(w, &sfilt.ff_flow6.fi6_dport)) {
855 1.1 thorpej LOG(LOG_ERR, 0, "bad filter destination port in %s, line %d\n",
856 1.1 thorpej altqconfigfile, line_no);
857 1.1 thorpej return (0);
858 1.1 thorpej }
859 1.1 thorpej
860 1.1 thorpej /* get filter source address */
861 1.1 thorpej if (!get_ip6addr(&cp, &sfilt.ff_flow6.fi6_src,
862 1.1 thorpej &sfilt.ff_mask6.mask6_src)) {
863 1.1 thorpej LOG(LOG_ERR, 0, "bad source address in %s, line %d\n",
864 1.1 thorpej altqconfigfile, line_no);
865 1.1 thorpej return (0);
866 1.1 thorpej }
867 1.1 thorpej
868 1.1 thorpej /* get filter source port */
869 1.1 thorpej if (!next_word(&cp, w)) {
870 1.1 thorpej LOG(LOG_ERR, 0, "missing filter source port in %s, line %d\n",
871 1.1 thorpej altqconfigfile, line_no);
872 1.1 thorpej return (0);
873 1.1 thorpej }
874 1.1 thorpej if (!get_port(w, &sfilt.ff_flow6.fi6_sport)) {
875 1.1 thorpej LOG(LOG_ERR, 0, "bad filter source port in %s, line %d\n",
876 1.1 thorpej altqconfigfile, line_no);
877 1.1 thorpej return (0);
878 1.1 thorpej }
879 1.1 thorpej
880 1.1 thorpej /* get filter protocol id */
881 1.1 thorpej if (!next_word(&cp, w)) {
882 1.1 thorpej LOG(LOG_ERR, 0, "missing filter protocol id in %s, line %d\n",
883 1.1 thorpej altqconfigfile, line_no);
884 1.1 thorpej return (0);
885 1.1 thorpej }
886 1.1 thorpej if (!get_proto(w, &protocol)) {
887 1.1 thorpej LOG(LOG_ERR, 0, "bad protocol in %s, line %d\n",
888 1.1 thorpej altqconfigfile, line_no);
889 1.1 thorpej return (0);
890 1.1 thorpej }
891 1.1 thorpej sfilt.ff_flow6.fi6_proto = protocol;
892 1.1 thorpej
893 1.1 thorpej while (next_word(&cp, w)) {
894 1.1 thorpej if (EQUAL(w, "tclass")) {
895 1.1 thorpej tclass = 0;
896 1.1 thorpej tclassmask = 0xff;
897 1.1 thorpej
898 1.1 thorpej if (next_word(&cp, w)) {
899 1.1 thorpej tclass = (u_char)strtol(w, NULL, 0);
900 1.1 thorpej if (next_word(&cp, w)) {
901 1.1 thorpej if (EQUAL(w, "tclassmask")) {
902 1.1 thorpej next_word(&cp, w);
903 1.1 thorpej tclassmask =
904 1.1 thorpej (u_char)strtol(w, NULL, 0);
905 1.1 thorpej }
906 1.1 thorpej }
907 1.1 thorpej }
908 1.1 thorpej sfilt.ff_flow6.fi6_tclass = tclass;
909 1.1 thorpej sfilt.ff_mask6.mask6_tclass = tclassmask;
910 1.1 thorpej } else if (EQUAL(w, "gpi")) {
911 1.1 thorpej if (next_word(&cp, w)) {
912 1.1 thorpej sfilt.ff_flow6.fi6_gpi =
913 1.1 thorpej (u_int32_t)strtoul(w, NULL, 0);
914 1.1 thorpej sfilt.ff_flow6.fi6_gpi =
915 1.1 thorpej htonl(sfilt.ff_flow6.fi6_gpi);
916 1.1 thorpej }
917 1.1 thorpej } else if (EQUAL(w, "flowlabel")) {
918 1.1 thorpej if (next_word(&cp, w)) {
919 1.1 thorpej sfilt.ff_flow6.fi6_flowlabel =
920 1.1 thorpej (u_int32_t)strtoul(w, NULL, 0) & 0x000fffff;
921 1.1 thorpej sfilt.ff_flow6.fi6_flowlabel =
922 1.1 thorpej htonl(sfilt.ff_flow6.fi6_flowlabel);
923 1.1 thorpej }
924 1.1 thorpej } else if (EQUAL(w, "dontwarn"))
925 1.1 thorpej dontwarn = 1;
926 1.1 thorpej }
927 1.1 thorpej
928 1.1 thorpej /*
929 1.1 thorpej * Add the filter.
930 1.1 thorpej */
931 1.1 thorpej filter_dontwarn = dontwarn; /* XXX */
932 1.1 thorpej ret = qcmd_add_filter(ifname, class_name, flname,
933 1.1 thorpej (struct flow_filter *)&sfilt);
934 1.1 thorpej filter_dontwarn = 0; /* XXX */
935 1.1 thorpej if (ret) {
936 1.1 thorpej LOG(LOG_ERR, 0,
937 1.1 thorpej "can't add filter to class '%s' on interface '%s'\n",
938 1.1 thorpej class_name, ifname);
939 1.1 thorpej return (0);
940 1.1 thorpej }
941 1.1 thorpej
942 1.1 thorpej return (1);
943 1.1 thorpej }
944 1.1 thorpej
945 1.1 thorpej static int
946 1.1 thorpej get_ip6addr(char **cpp, struct in6_addr *addr, struct in6_addr *mask)
947 1.1 thorpej {
948 1.1 thorpej char w[128], *prefix;
949 1.1 thorpej u_char *cp;
950 1.1 thorpej int len;
951 1.1 thorpej
952 1.1 thorpej *addr = in6addr_any; /* set all 0 */
953 1.1 thorpej *mask = in6addr_any; /* set all 0 */
954 1.1 thorpej
955 1.1 thorpej if (!next_word(cpp, w))
956 1.1 thorpej return (0);
957 1.1 thorpej
958 1.1 thorpej if (EQUAL(w, "0"))
959 1.1 thorpej /* abbreviation of a wildcard (::0) */
960 1.1 thorpej return (1);
961 1.1 thorpej
962 1.1 thorpej if ((prefix = strchr(w, '/')) != NULL) {
963 1.1 thorpej /* address has prefix length */
964 1.1 thorpej *prefix++ = '\0';
965 1.1 thorpej }
966 1.1 thorpej
967 1.3 itojun if (inet_pton(AF_INET6, w, addr) != 1)
968 1.1 thorpej return (0);
969 1.1 thorpej
970 1.1 thorpej if (IN6_IS_ADDR_UNSPECIFIED(addr) && prefix == NULL)
971 1.1 thorpej /* wildcard */
972 1.1 thorpej return (1);
973 1.1 thorpej
974 1.1 thorpej /* convert address prefix length to address mask */
975 1.1 thorpej if (prefix != NULL) {
976 1.1 thorpej len = (int)strtol(prefix, NULL, 0);
977 1.1 thorpej if ((len < 0) || (len > 128))
978 1.1 thorpej return (0);
979 1.1 thorpej for (cp = (u_char *)mask; len > 7; len -= 8)
980 1.1 thorpej *cp++ = 0xff;
981 1.1 thorpej if (len > 0)
982 1.1 thorpej *cp = (0xff << (8 - len)) & 0xff;
983 1.1 thorpej
984 1.1 thorpej IN6ADDR32(addr, 0) &= IN6ADDR32(mask, 0);
985 1.1 thorpej IN6ADDR32(addr, 1) &= IN6ADDR32(mask, 1);
986 1.1 thorpej IN6ADDR32(addr, 2) &= IN6ADDR32(mask, 2);
987 1.1 thorpej IN6ADDR32(addr, 3) &= IN6ADDR32(mask, 3);
988 1.1 thorpej } else
989 1.1 thorpej /* full mask */
990 1.1 thorpej memset(mask, 0xff, sizeof(struct in6_addr));
991 1.1 thorpej
992 1.1 thorpej return (1);
993 1.1 thorpej }
994 1.1 thorpej
995 1.1 thorpej #endif /* INET6 */
996 1.1 thorpej
997 1.1 thorpej static int
998 1.1 thorpej ctl_parser(char *cmdbuf)
999 1.1 thorpej {
1000 1.1 thorpej char w[128], *cp = cmdbuf;
1001 1.1 thorpej char *ifname;
1002 1.1 thorpej int state;
1003 1.1 thorpej int rval;
1004 1.1 thorpej
1005 1.1 thorpej if (!get_ifname(&cp, &ifname)) {
1006 1.1 thorpej printf("missing interface name in %s, line %d",
1007 1.1 thorpej altqconfigfile, line_no);
1008 1.1 thorpej return (0);
1009 1.1 thorpej }
1010 1.1 thorpej
1011 1.1 thorpej if (!next_word(&cp, w)) {
1012 1.1 thorpej state = is_q_enabled(ifname);
1013 1.1 thorpej printf("altq %s on %s\n",
1014 1.1 thorpej state ? "enabled" : "disabled", ifname);
1015 1.1 thorpej return (1);
1016 1.1 thorpej }
1017 1.1 thorpej
1018 1.1 thorpej if (EQUAL(w, "enable")) {
1019 1.1 thorpej rval = qcmd_enable(ifname);
1020 1.1 thorpej printf("altq %s on %s\n",
1021 1.1 thorpej (rval == 0) ? "enabled" : "enable failed!", ifname);
1022 1.1 thorpej } else if (EQUAL(w, "disable")) {
1023 1.1 thorpej rval = qcmd_disable(ifname);
1024 1.1 thorpej printf("altq %s on %s\n",
1025 1.1 thorpej (rval == 0) ? "disabled" : "disable failed!", ifname);
1026 1.1 thorpej } else if (EQUAL(w, "reload")) {
1027 1.1 thorpej printf("reinitializing altq...\n");
1028 1.1 thorpej qcmd_destroyall();
1029 1.1 thorpej qcmd_init();
1030 1.1 thorpej } else
1031 1.1 thorpej return (0);
1032 1.1 thorpej return (1);
1033 1.1 thorpej }
1034 1.1 thorpej
1035 1.1 thorpej
1036 1.1 thorpej static int
1037 1.1 thorpej delete_parser(char *cmdbuf)
1038 1.1 thorpej {
1039 1.1 thorpej char *cp = cmdbuf;
1040 1.1 thorpej char *ifname, class_name[128];
1041 1.1 thorpej int ret;
1042 1.1 thorpej
1043 1.1 thorpej if (!get_ifname(&cp, &ifname)) {
1044 1.1 thorpej printf("missing interface name in %s, line %d",
1045 1.1 thorpej altqconfigfile, line_no);
1046 1.1 thorpej return (0);
1047 1.1 thorpej }
1048 1.1 thorpej
1049 1.1 thorpej if (!next_word(&cp, class_name)) {
1050 1.1 thorpej LOG(LOG_ERR, 0,
1051 1.1 thorpej "missing class name in %s, line %d\n",
1052 1.1 thorpej altqconfigfile, line_no);
1053 1.1 thorpej return (0);
1054 1.1 thorpej }
1055 1.1 thorpej
1056 1.1 thorpej ret = qcmd_delete_class(ifname, class_name);
1057 1.1 thorpej if (ret) {
1058 1.1 thorpej LOG(LOG_ERR, 0,
1059 1.1 thorpej "can't delete class '%s' on interface '%s'\n",
1060 1.1 thorpej class_name, ifname);
1061 1.1 thorpej return (0);
1062 1.1 thorpej }
1063 1.1 thorpej
1064 1.1 thorpej return (1);
1065 1.1 thorpej }
1066 1.1 thorpej
1067 1.1 thorpej static int
1068 1.1 thorpej red_parser(char *cmdbuf)
1069 1.1 thorpej {
1070 1.1 thorpej char w[128], *cp = cmdbuf;
1071 1.1 thorpej int th_min, th_max, inv_pmax;
1072 1.1 thorpej
1073 1.1 thorpej if (!next_word(&cp, w))
1074 1.1 thorpej goto bad;
1075 1.1 thorpej th_min = (int)strtol(w, NULL, 0);
1076 1.1 thorpej
1077 1.1 thorpej if (!next_word(&cp, w))
1078 1.1 thorpej goto bad;
1079 1.1 thorpej th_max = (int)strtol(w, NULL, 0);
1080 1.1 thorpej
1081 1.1 thorpej if (!next_word(&cp, w))
1082 1.1 thorpej goto bad;
1083 1.1 thorpej inv_pmax = (int)strtol(w, NULL, 0);
1084 1.1 thorpej
1085 1.1 thorpej if (qop_red_set_defaults(th_min, th_max, inv_pmax) != 0) {
1086 1.1 thorpej LOG(LOG_ERR, 0, "can't set red default parameters\n");
1087 1.1 thorpej return (0);
1088 1.1 thorpej }
1089 1.1 thorpej
1090 1.1 thorpej return (1);
1091 1.1 thorpej
1092 1.1 thorpej bad:
1093 1.1 thorpej LOG(LOG_ERR, 0, "bad red parameter in %s, line %d\n",
1094 1.1 thorpej altqconfigfile, line_no);
1095 1.1 thorpej return (0);
1096 1.1 thorpej }
1097 1.1 thorpej
1098 1.1 thorpej static int
1099 1.1 thorpej rio_parser(char *cmdbuf)
1100 1.1 thorpej {
1101 1.1 thorpej char w[128], *cp = cmdbuf;
1102 1.1 thorpej int i;
1103 1.1 thorpej struct redparams params[RIO_NDROPPREC];
1104 1.1 thorpej
1105 1.1 thorpej for (i = 0; i < RIO_NDROPPREC; i++) {
1106 1.1 thorpej if (!next_word(&cp, w))
1107 1.1 thorpej goto bad;
1108 1.1 thorpej params[i].th_min = (int)strtol(w, NULL, 0);
1109 1.1 thorpej
1110 1.1 thorpej if (!next_word(&cp, w))
1111 1.1 thorpej goto bad;
1112 1.1 thorpej params[i].th_max = (int)strtol(w, NULL, 0);
1113 1.1 thorpej
1114 1.1 thorpej if (!next_word(&cp, w))
1115 1.1 thorpej goto bad;
1116 1.1 thorpej params[i].inv_pmax = (int)strtol(w, NULL, 0);
1117 1.1 thorpej }
1118 1.1 thorpej
1119 1.1 thorpej if (qop_rio_set_defaults(¶ms[0]) != 0) {
1120 1.1 thorpej LOG(LOG_ERR, 0, "can't set rio default parameters\n");
1121 1.1 thorpej return (0);
1122 1.1 thorpej }
1123 1.1 thorpej
1124 1.1 thorpej return (1);
1125 1.1 thorpej
1126 1.1 thorpej bad:
1127 1.1 thorpej LOG(LOG_ERR, 0, "bad rio parameter in %s, line %d\n",
1128 1.1 thorpej altqconfigfile, line_no);
1129 1.1 thorpej return (0);
1130 1.1 thorpej }
1131 1.1 thorpej
1132 1.1 thorpej static int
1133 1.1 thorpej conditioner_parser(char *cmdbuf)
1134 1.1 thorpej {
1135 1.1 thorpej char cdnr_name[128], *cp = cmdbuf;
1136 1.1 thorpej char *ifname;
1137 1.1 thorpej struct tc_action action[64];
1138 1.1 thorpej
1139 1.1 thorpej if (!get_ifname(&cp, &ifname)) {
1140 1.1 thorpej LOG(LOG_ERR, 0, "missing interface name in %s, line %d\n",
1141 1.1 thorpej altqconfigfile, line_no);
1142 1.1 thorpej return (0);
1143 1.1 thorpej }
1144 1.1 thorpej
1145 1.1 thorpej /* get conditioner name */
1146 1.1 thorpej if (!next_word(&cp, cdnr_name)) {
1147 1.1 thorpej LOG(LOG_ERR, 0, "missing cdnr name in %s, line %d\n",
1148 1.1 thorpej altqconfigfile, line_no);
1149 1.1 thorpej return (0);
1150 1.1 thorpej }
1151 1.1 thorpej
1152 1.1 thorpej if (tc_action_parser(ifname, &cp, &action[0]) == 0)
1153 1.1 thorpej return (0);
1154 1.1 thorpej
1155 1.1 thorpej if (qcmd_cdnr_add_element(NULL, ifname, cdnr_name, &action[0]) != 0)
1156 1.1 thorpej return (0);
1157 1.1 thorpej return (1);
1158 1.1 thorpej }
1159 1.1 thorpej
1160 1.1 thorpej /*
1161 1.1 thorpej * recursively parse '<'tc_action'>'
1162 1.1 thorpej * note that array "action" grows during recursive parse.
1163 1.1 thorpej */
1164 1.1 thorpej static int
1165 1.1 thorpej tc_action_parser(char *ifname, char **cpp, struct tc_action *action)
1166 1.1 thorpej {
1167 1.1 thorpej char *cp, *start, *end;
1168 1.1 thorpej char type[128], w[128];
1169 1.1 thorpej int depth, i;
1170 1.1 thorpej struct tb_profile profile[2];
1171 1.1 thorpej
1172 1.1 thorpej /*
1173 1.1 thorpej * find a possibly nested pair of '<' and '>',
1174 1.1 thorpej * make them pointed by 'start' and 'end'.
1175 1.1 thorpej */
1176 1.1 thorpej start = strchr(*cpp, '<');
1177 1.1 thorpej if (start == NULL) {
1178 1.1 thorpej LOG(LOG_ERR, 0, "conditioner action missing in %s, line %d\n",
1179 1.1 thorpej altqconfigfile, line_no);
1180 1.1 thorpej return (0);
1181 1.1 thorpej }
1182 1.1 thorpej depth = 1;
1183 1.1 thorpej cp = start + 1;
1184 1.1 thorpej do {
1185 1.1 thorpej end = strpbrk(cp, "<>");
1186 1.1 thorpej if (end == NULL) {
1187 1.1 thorpej LOG(LOG_ERR, 0,
1188 1.1 thorpej "conditioner action delimiter mismatch in %s, line %d\n",
1189 1.1 thorpej altqconfigfile, line_no);
1190 1.1 thorpej return (0);
1191 1.1 thorpej }
1192 1.1 thorpej if (*end == '<')
1193 1.1 thorpej depth++;
1194 1.1 thorpej else if (*end == '>')
1195 1.1 thorpej depth--;
1196 1.1 thorpej cp = end + 1;
1197 1.1 thorpej } while (depth > 0);
1198 1.1 thorpej *end = '\0';
1199 1.1 thorpej *cpp = end + 1;
1200 1.1 thorpej cp = start + 1;
1201 1.1 thorpej
1202 1.1 thorpej if (IsDebug(DEBUG_ALTQ)) {
1203 1.1 thorpej printf("tc_action_parser: [%s]\n", cp);
1204 1.1 thorpej }
1205 1.1 thorpej
1206 1.1 thorpej if (!next_word(&cp, type)) {
1207 1.1 thorpej LOG(LOG_ERR, 0,
1208 1.1 thorpej "missing conditioner action type in %s, line %d\n",
1209 1.1 thorpej altqconfigfile, line_no);
1210 1.1 thorpej return (0);
1211 1.1 thorpej }
1212 1.1 thorpej
1213 1.1 thorpej /*
1214 1.1 thorpej * action type specific process
1215 1.1 thorpej */
1216 1.1 thorpej if (EQUAL(type, "conditioner")) {
1217 1.1 thorpej if (!next_word(&cp, w)) {
1218 1.1 thorpej LOG(LOG_ERR, 0,
1219 1.1 thorpej "missing conditioner name in %s, line %d\n",
1220 1.1 thorpej altqconfigfile, line_no);
1221 1.1 thorpej return (0);
1222 1.1 thorpej }
1223 1.1 thorpej action->tca_code = TCACODE_HANDLE;
1224 1.1 thorpej action->tca_handle = cdnr_name2handle(ifname, w);
1225 1.1 thorpej if (action->tca_handle == CDNR_NULL_HANDLE) {
1226 1.1 thorpej LOG(LOG_ERR, 0,
1227 1.1 thorpej "wrong conditioner name %s in %s, line %d\n",
1228 1.1 thorpej w, altqconfigfile, line_no);
1229 1.1 thorpej return (0);
1230 1.1 thorpej }
1231 1.1 thorpej } else if (EQUAL(type, "pass")) {
1232 1.1 thorpej action->tca_code = TCACODE_PASS;
1233 1.1 thorpej } else if (EQUAL(type, "drop")) {
1234 1.1 thorpej action->tca_code = TCACODE_DROP;
1235 1.1 thorpej } else if (EQUAL(type, "mark")) {
1236 1.1 thorpej if (!next_word(&cp, w)) {
1237 1.1 thorpej LOG(LOG_ERR, 0, "missing dscp in %s, line %d\n",
1238 1.1 thorpej altqconfigfile, line_no);
1239 1.1 thorpej return (0);
1240 1.1 thorpej }
1241 1.1 thorpej action->tca_code = TCACODE_MARK;
1242 1.1 thorpej action->tca_dscp = (u_int8_t)strtol(w, NULL, 0);
1243 1.1 thorpej } else if (EQUAL(type, "tbmeter")) {
1244 1.1 thorpej if (!next_word(&cp, w)) {
1245 1.1 thorpej LOG(LOG_ERR, 0, "missing tb profile in %s, line %d\n",
1246 1.1 thorpej altqconfigfile, line_no);
1247 1.1 thorpej return (0);
1248 1.1 thorpej }
1249 1.1 thorpej profile[0].rate = atobps(w);
1250 1.1 thorpej if (!next_word(&cp, w)) {
1251 1.1 thorpej LOG(LOG_ERR, 0, "missing tb profile in %s, line %d\n",
1252 1.1 thorpej altqconfigfile, line_no);
1253 1.1 thorpej return (0);
1254 1.1 thorpej }
1255 1.1 thorpej profile[0].depth = atobytes(w);
1256 1.1 thorpej if (tc_action_parser(ifname, &cp, &action[1]) == 0)
1257 1.1 thorpej return (0);
1258 1.1 thorpej if (tc_action_parser(ifname, &cp, &action[2]) == 0)
1259 1.1 thorpej return (0);
1260 1.1 thorpej
1261 1.1 thorpej if (qcmd_cdnr_add_tbmeter(action, ifname, NULL, &profile[0],
1262 1.1 thorpej &action[1], &action[2]) != 0)
1263 1.1 thorpej return (0);
1264 1.1 thorpej } else if (EQUAL(type, "trtcm")) {
1265 1.1 thorpej int coloraware = 0; /* default is color-blind */
1266 1.1 thorpej
1267 1.1 thorpej for (i=0; i<2; i++) {
1268 1.1 thorpej if (!next_word(&cp, w)) {
1269 1.1 thorpej LOG(LOG_ERR, 0,
1270 1.1 thorpej "missing tb profile in %s, line %d\n",
1271 1.1 thorpej altqconfigfile, line_no);
1272 1.1 thorpej return (0);
1273 1.1 thorpej }
1274 1.1 thorpej profile[i].rate = atobps(w);
1275 1.1 thorpej if (!next_word(&cp, w)) {
1276 1.1 thorpej LOG(LOG_ERR, 0,
1277 1.1 thorpej "missing tb profile in %s, line %d\n",
1278 1.1 thorpej altqconfigfile, line_no);
1279 1.1 thorpej return (0);
1280 1.1 thorpej }
1281 1.1 thorpej profile[i].depth = atobytes(w);
1282 1.1 thorpej }
1283 1.1 thorpej if (tc_action_parser(ifname, &cp, &action[1]) == 0)
1284 1.1 thorpej return (0);
1285 1.1 thorpej if (tc_action_parser(ifname, &cp, &action[2]) == 0)
1286 1.1 thorpej return (0);
1287 1.1 thorpej if (tc_action_parser(ifname, &cp, &action[3]) == 0)
1288 1.1 thorpej return (0);
1289 1.1 thorpej if (next_word(&cp, w)) {
1290 1.1 thorpej if (EQUAL(w, "coloraware"))
1291 1.1 thorpej coloraware = 1;
1292 1.1 thorpej else if (EQUAL(w, "colorblind"))
1293 1.1 thorpej coloraware = 0;
1294 1.1 thorpej }
1295 1.1 thorpej
1296 1.1 thorpej if (qcmd_cdnr_add_trtcm(action, ifname, NULL,
1297 1.1 thorpej &profile[0], &profile[1],
1298 1.1 thorpej &action[1], &action[2], &action[3],
1299 1.1 thorpej coloraware) != 0)
1300 1.1 thorpej return (0);
1301 1.1 thorpej } else if (EQUAL(type, "tswtcm")) {
1302 1.1 thorpej u_int32_t cmtd_rate, peak_rate, avg_interval;
1303 1.1 thorpej
1304 1.1 thorpej if (!next_word(&cp, w)) {
1305 1.1 thorpej LOG(LOG_ERR, 0, "missing cmtd rate in %s, line %d\n",
1306 1.1 thorpej altqconfigfile, line_no);
1307 1.1 thorpej return (0);
1308 1.1 thorpej }
1309 1.1 thorpej cmtd_rate = atobps(w);
1310 1.1 thorpej
1311 1.1 thorpej if (!next_word(&cp, w)) {
1312 1.1 thorpej LOG(LOG_ERR, 0, "missing peak rate in %s, line %d\n",
1313 1.1 thorpej altqconfigfile, line_no);
1314 1.1 thorpej return (0);
1315 1.1 thorpej }
1316 1.1 thorpej peak_rate = atobps(w);
1317 1.1 thorpej
1318 1.1 thorpej if (!next_word(&cp, w)) {
1319 1.1 thorpej LOG(LOG_ERR, 0, "missing avg interval in %s, line %d\n",
1320 1.1 thorpej altqconfigfile, line_no);
1321 1.1 thorpej return (0);
1322 1.1 thorpej }
1323 1.1 thorpej avg_interval = (u_int32_t)strtoul(w, NULL, 0);
1324 1.1 thorpej
1325 1.1 thorpej if (tc_action_parser(ifname, &cp, &action[1]) == 0)
1326 1.1 thorpej return (0);
1327 1.1 thorpej if (tc_action_parser(ifname, &cp, &action[2]) == 0)
1328 1.1 thorpej return (0);
1329 1.1 thorpej if (tc_action_parser(ifname, &cp, &action[3]) == 0)
1330 1.1 thorpej return (0);
1331 1.1 thorpej
1332 1.1 thorpej if (qcmd_cdnr_add_tswtcm(action, ifname, NULL,
1333 1.1 thorpej cmtd_rate, peak_rate, avg_interval,
1334 1.1 thorpej &action[1], &action[2], &action[3])
1335 1.1 thorpej != 0)
1336 1.1 thorpej return (0);
1337 1.1 thorpej } else {
1338 1.1 thorpej LOG(LOG_ERR, 0,
1339 1.1 thorpej "Unkown action type %s in %s, line %d\n",
1340 1.1 thorpej type, altqconfigfile, line_no);
1341 1.1 thorpej return (0);
1342 1.1 thorpej }
1343 1.1 thorpej
1344 1.1 thorpej *end = '>'; /* restore the end delimiter */
1345 1.1 thorpej
1346 1.1 thorpej return (1);
1347 1.1 thorpej }
1348 1.1 thorpej
1349