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