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