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