Print this page
patch tsoome-feedback
patch cleanup
6659 nvlist_free(NULL) is a no-op
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/cmd-inet/usr.sbin/ipqosconf/ipqosconf.c
+++ new/usr/src/cmd/cmd-inet/usr.sbin/ipqosconf/ipqosconf.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 -#pragma ident "%Z%%M% %I% %E% SMI"
28 -
29 27 /* enable debug output and some debug asserts */
30 28 #undef _IPQOS_CONF_DEBUG
31 29
32 30 #include <stdlib.h>
33 31 #include <unistd.h>
34 32 #include <libintl.h>
35 33 #include <signal.h>
36 34 #include <strings.h>
37 35 #include <sys/nvpair.h>
38 36 #include <stdio.h>
39 37 #include <netinet/in.h>
40 38 #include <arpa/inet.h>
41 39 #include <ctype.h>
42 40 #include <sys/socket.h>
43 41 #include <limits.h>
44 42 #include <netdb.h>
45 43 #include <fcntl.h>
46 44 #include <sys/types.h>
47 45 #include <sys/stat.h>
48 46 #include <errno.h>
49 47 #include <libipp.h>
50 48 #include <ipp/ipp_config.h>
51 49 #include <ipp/ipgpc/ipgpc.h>
52 50 #include <ipp/ipp.h>
53 51 #ifdef _IPQOS_CONF_DEBUG
54 52 #include <assert.h>
55 53 #endif
56 54 #include <sys/sockio.h>
57 55 #include <syslog.h>
58 56 #include <stdarg.h>
59 57 #include <libintl.h>
60 58 #include <locale.h>
61 59 #include <pwd.h>
62 60 #include "ipqosconf.h"
63 61
64 62 #if defined(_IPQOS_CONF_DEBUG)
65 63
66 64 /* debug level */
67 65 static int ipqosconf_dbg_flgs =
68 66 /*
69 67 */
70 68 RBK |
71 69 MHME |
72 70 KRET |
73 71 DIFF |
74 72 APPLY |
75 73 L2 |
76 74 L1 |
77 75 L0 |
78 76 0;
79 77
80 78
81 79
82 80 #define IPQOSCDBG0(lvl, x)\
83 81 if (lvl & ipqosconf_dbg_flgs)\
84 82 (void) fprintf(stderr, x)
85 83
86 84 #define IPQOSCDBG1(lvl, x, y)\
87 85 if (lvl & ipqosconf_dbg_flgs)\
88 86 (void) fprintf(stderr, x, y)
89 87
90 88 #define IPQOSCDBG2(lvl, x, y, z)\
91 89 if (lvl & ipqosconf_dbg_flgs)\
92 90 (void) fprintf(stderr, x, y, z)
93 91
94 92 #define IPQOSCDBG3(lvl, x, y, z, a)\
95 93 if (lvl & ipqosconf_dbg_flgs)\
96 94 (void) fprintf(stderr, x, y, z, a)
97 95
98 96 #define IPQOSCDBG4(lvl, x, y, z, a, b)\
99 97 if (lvl & ipqosconf_dbg_flgs)\
100 98 (void) fprintf(stderr, x, y, z, a, b)
101 99
102 100 #define IPQOSCDBG5(lvl, x, y, z, a, b, c)\
103 101 if (lvl & ipqosconf_dbg_flgs)\
104 102 (void) fprintf(stderr, x, y, z, a, b, c)
105 103
106 104 #else /* defined(_IPQOS_CONF_DEBUG) && !defined(lint) */
107 105
108 106 #define IPQOSCDBG0(lvl, x)
109 107 #define IPQOSCDBG1(lvl, x, y)
110 108 #define IPQOSCDBG2(lvl, x, y, z)
111 109 #define IPQOSCDBG3(lvl, x, y, z, a)
112 110 #define IPQOSCDBG4(lvl, x, y, z, a, b)
113 111 #define IPQOSCDBG5(lvl, x, y, z, a, b, c)
114 112
115 113 #endif /* defined(_IPQOS_CONF_DEBUG) */
116 114
117 115
118 116
119 117 /* function prototypes */
120 118
121 119 static int modify_params(char *, nvlist_t **, int, boolean_t);
122 120 static int add_class(char *, char *, int, boolean_t, char *);
123 121 static int modify_class(char *, char *, int, boolean_t, char *,
124 122 enum ipp_flags);
125 123 static int remove_class(char *, char *, int, enum ipp_flags);
126 124 static int add_filter(char *, ipqos_conf_filter_t *, int);
127 125 static int modify_filter(char *, ipqos_conf_filter_t *, int);
128 126 static int remove_filter(char *, char *, int, int);
129 127 static boolean_t arrays_equal(int *, int *, uint32_t);
130 128 static int diffclass(ipqos_conf_class_t *, ipqos_conf_class_t *);
131 129 static int diffparams(ipqos_conf_params_t *, ipqos_conf_params_t *, char *);
132 130 static int difffilter(ipqos_conf_filter_t *, ipqos_conf_filter_t *, char *);
133 131 static int add_filters(ipqos_conf_filter_t *, char *, int, boolean_t);
134 132 static int add_classes(ipqos_conf_class_t *, char *, int, boolean_t);
135 133 static int modify_items(ipqos_conf_action_t *);
136 134 static int add_items(ipqos_conf_action_t *, boolean_t);
137 135 static int add_item(ipqos_conf_action_t *, boolean_t);
138 136 static int remove_items(ipqos_conf_action_t *, boolean_t);
139 137 static int remove_item(ipqos_conf_action_t *, boolean_t);
140 138 static int undo_modifys(ipqos_conf_action_t *, ipqos_conf_action_t *);
141 139 static int applydiff(ipqos_conf_action_t *, ipqos_conf_action_t *);
142 140 static int rollback(ipqos_conf_action_t *, ipqos_conf_action_t *);
143 141 static int rollback_recover(ipqos_conf_action_t *);
144 142 static ipqos_conf_class_t *classexist(char *, ipqos_conf_class_t *);
145 143 static ipqos_conf_filter_t *filterexist(char *, int, ipqos_conf_filter_t *);
146 144 static ipqos_conf_action_t *actionexist(char *, ipqos_conf_action_t *);
147 145 static int diffnvlists(nvlist_t *, nvlist_t *, char *, int *, place_t);
148 146 static int diffaction(ipqos_conf_action_t *, ipqos_conf_action_t *);
149 147 static int diffconf(ipqos_conf_action_t *, ipqos_conf_action_t *);
150 148 static int readllong(char *, long long *, char **);
151 149 static int readuint8(char *, uint8_t *, char **);
152 150 static int readuint16(char *, uint16_t *, char **);
153 151 static int readint16(char *, int16_t *, char **);
154 152 static int readint32(char *, int *, char **);
155 153 static int readuint32(char *, uint32_t *, char **);
156 154 static int readbool(char *, boolean_t *);
157 155 static void setmask(int, in6_addr_t *, int);
158 156 static int readtoken(FILE *, char **);
159 157 static nvpair_t *find_nvpair(nvlist_t *, char *);
160 158 static char *prepend_module_name(char *, char *);
161 159 static int readnvpair(FILE *, FILE *, nvlist_t **, nvpair_t **,
162 160 ipqos_nvtype_t *, place_t, char *);
163 161 static int add_aref(ipqos_conf_act_ref_t **, char *, char *);
164 162 static int readparams(FILE *, FILE *, char *, ipqos_conf_params_t *);
165 163 static int readclass(FILE *, char *, ipqos_conf_class_t **, char **, int);
166 164 static int readfilter(FILE *, FILE *, char *, ipqos_conf_filter_t **, char **,
167 165 int);
168 166 static FILE *validmod(char *, int *);
169 167 static int readaction(FILE *, ipqos_conf_action_t **);
170 168 static int actions_unique(ipqos_conf_action_t *, char **);
171 169 static int validconf(ipqos_conf_action_t *, int);
172 170 static int readconf(FILE *, ipqos_conf_action_t **);
173 171 static int flush(boolean_t *);
174 172 static int atomic_flush(boolean_t);
175 173 static int flushconf();
176 174 static int writeconf(ipqos_conf_action_t *, char *);
177 175 static int commitconf();
178 176 static int applyconf(char *ifile);
179 177 static int block_all_signals();
180 178 static int restore_all_signals();
181 179 static int unlock(int fd);
182 180 static int lock();
183 181 static int viewconf(int);
184 182 static void usage();
185 183 static int valid_name(char *);
186 184 static int in_cycle(ipqos_conf_action_t *);
187 185 static int readtype(FILE *, char *, char *, ipqos_nvtype_t *, str_val_nd_t **,
188 186 char *, boolean_t, place_t *);
189 187 static int read_int_array_info(char *, str_val_nd_t **, uint32_t *, int *,
190 188 int *, char *);
191 189 static str_val_nd_t *read_enum_nvs(char *, char *);
192 190 static int add_str_val_entry(str_val_nd_t **, char *, uint32_t);
193 191 static void free_str_val_entrys(str_val_nd_t *);
194 192 static void get_str_val_value_range(str_val_nd_t *, int *, int *);
195 193 static int read_enum_value(FILE *, char *, str_val_nd_t *, uint32_t *);
196 194 static int read_mapped_values(FILE *, nvlist_t **, char *, char *,
197 195 int);
198 196 static int read_int_array(FILE *, char *, int **, uint32_t, int, int,
199 197 str_val_nd_t *);
200 198 static int str_val_list_lookup(str_val_nd_t *, char *, uint32_t *);
201 199 static int parse_kparams(char *, ipqos_conf_params_t *, nvlist_t *);
202 200 static int parse_kclass(ipqos_conf_class_t *, nvlist_t *);
203 201 static int parse_kfilter(ipqos_conf_filter_t *, nvlist_t *);
204 202 static int parse_kaction(nvlist_t *, ipqos_actinfo_prm_t *);
205 203 static int readkconf(ipqos_conf_action_t **);
206 204 static void print_int_array(FILE *, int *, uint32_t, int, int, str_val_nd_t *,
207 205 int);
208 206 static void printrange(FILE *fp, uint32_t, uint32_t);
209 207 static void printenum(FILE *, uint32_t, str_val_nd_t *);
210 208 static void printproto(FILE *, uint8_t);
211 209 static void printport(FILE *, uint16_t);
212 210 static int printnvlist(FILE *, char *, nvlist_t *, int, ipqos_conf_filter_t *,
213 211 int, place_t);
214 212 static int virtual_action(char *);
215 213 static void free_arefs(ipqos_conf_act_ref_t *);
216 214 static void print_action_nm(FILE *, char *);
217 215 static int add_orig_ipqosconf(nvlist_t *);
218 216 static char *get_originator_nm(uint32_t);
219 217 static void mark_classes_filters_new(ipqos_conf_action_t *);
220 218 static void mark_classes_filters_del(ipqos_conf_action_t *);
221 219 static void mark_config_new(ipqos_conf_action_t *);
222 220 static int printifname(FILE *, int);
223 221 static int readifindex(char *, int *);
224 222 static void cleanup_string_table(char **, int);
225 223 static int domultihome(ipqos_conf_filter_t *, ipqos_conf_filter_t **,
226 224 boolean_t);
227 225 static int dup_filter(ipqos_conf_filter_t *, ipqos_conf_filter_t **, int, int,
228 226 void *, void *, int);
229 227 static void free_actions(ipqos_conf_action_t *);
230 228 static ipqos_conf_filter_t *alloc_filter();
231 229 static void free_filter(ipqos_conf_filter_t *);
232 230 static int read_curl_begin(FILE *);
233 231 static ipqos_conf_class_t *alloc_class(void);
234 232 static int diffclasses(ipqos_conf_action_t *old, ipqos_conf_action_t *new);
235 233 static int difffilters(ipqos_conf_action_t *old, ipqos_conf_action_t *new);
236 234 static int dup_class(ipqos_conf_class_t *src, ipqos_conf_class_t **dst);
237 235 static int add_action(ipqos_conf_action_t *act);
238 236 static int masktocidr(int af, in6_addr_t *mask);
239 237 static int read_perm_items(int, FILE *, char *, char ***, int *);
240 238 static int in_string_table(char *stable[], int size, char *string);
241 239 static void list_end(ipqos_list_el_t **listp, ipqos_list_el_t ***lendpp);
242 240 static void add_to_list(ipqos_list_el_t **listp, ipqos_list_el_t *el);
243 241 static int read_cfile_ver(FILE *, char *);
244 242 static char *quote_ws_string(const char *);
245 243 static int read_tfile_ver(FILE *, char *, char *);
246 244 static int ver_str_to_int(char *);
247 245 static void printuser(FILE *fp, uid_t uid);
248 246 static int readuser(char *str, uid_t *uid);
249 247
250 248 /*
251 249 * macros to call list functions with the more complex list element type
252 250 * cast to the skeletal type iqpos_list_el_t.
253 251 */
254 252 #define LIST_END(list, end)\
255 253 list_end((ipqos_list_el_t **)list, (ipqos_list_el_t ***)end)
256 254 #define ADD_TO_LIST(list, el)\
257 255 add_to_list((ipqos_list_el_t **)list, (ipqos_list_el_t *)el)
258 256
259 257 /*
260 258 * Macros to produce a quoted string containing the value of a
261 259 * preprocessor macro. For example, if SIZE is defined to be 256,
262 260 * VAL2STR(SIZE) is "256". This is used to construct format
263 261 * strings for scanf-family functions below.
264 262 */
265 263 #define QUOTE(x) #x
266 264 #define VAL2STR(x) QUOTE(x)
267 265
268 266
269 267 /* globals */
270 268
271 269 /* table of supported parameter types and enum value */
272 270 static str_val_t nv_types[] = {
273 271 {"uint8", IPQOS_DATA_TYPE_UINT8},
274 272 {"int16", IPQOS_DATA_TYPE_INT16},
275 273 {"uint16", IPQOS_DATA_TYPE_UINT16},
276 274 {"int32", IPQOS_DATA_TYPE_INT32},
277 275 {"uint32", IPQOS_DATA_TYPE_UINT32},
278 276 {"boolean", IPQOS_DATA_TYPE_BOOLEAN},
279 277 {"string", IPQOS_DATA_TYPE_STRING},
280 278 {"action", IPQOS_DATA_TYPE_ACTION},
281 279 {"address", IPQOS_DATA_TYPE_ADDRESS},
282 280 {"port", IPQOS_DATA_TYPE_PORT},
283 281 {"protocol", IPQOS_DATA_TYPE_PROTO},
284 282 {"enum", IPQOS_DATA_TYPE_ENUM},
285 283 {"ifname", IPQOS_DATA_TYPE_IFNAME},
286 284 {"mindex", IPQOS_DATA_TYPE_M_INDEX},
287 285 {"int_array", IPQOS_DATA_TYPE_INT_ARRAY},
288 286 {"user", IPQOS_DATA_TYPE_USER},
289 287 {"", 0}
290 288 };
291 289
292 290 /* table of name to id mappings for originator field */
293 291
294 292 static str_val_t originators[] = {
295 293 {IPP_CONFIG_NAME_PERMANENT, IPP_CONFIG_PERMANENT},
296 294 {IPP_CONFIG_NAME_IPQOSCONF, IPP_CONFIG_IPQOSCONF},
297 295 {IPP_CONFIG_NAME_FTPCL, IPP_CONFIG_FTPCL},
298 296 {"", -1}
299 297 };
300 298
301 299 /* current parse line */
302 300 static int lineno;
303 301
304 302 /* verbose output flag */
305 303 static int verbose;
306 304
307 305 /* use syslog for msg reporting flag */
308 306 static int use_syslog;
309 307
310 308 #ifdef _IPQOS_CONF_DEBUG
311 309 /*
312 310 * flag used to indicate that a rollback should be carried out regardless.
313 311 * Only settable during debug.
314 312 */
315 313 static int force_rback = 0;
316 314 #endif /* _IPQOS_CONF_DEBUG */
317 315
318 316 /*
319 317 * delivers messages to either syslog or stderr, dependant upon the
320 318 * the state of the flags use_syslog and verbose. The type
321 319 * of the msg as given in msg_type is indicated in the output msg.
322 320 *
323 321 * valid message types are:
324 322 * o MT_ERROR (standard error message)
325 323 * o MT_ENOSTR (error message with system error string appended)
326 324 * o MT_WARNING (warning message)
327 325 * o MT_LOG (logging message)
328 326 *
329 327 * Log messages only go to syslog. Warning messages only go to stderr
330 328 * and only when the verbose flag is set. All other messages go by default
331 329 * to the console; to syslog if syslog flag set, and to both if both
332 330 * syslog and verbose are set.
333 331 *
334 332 */
335 333 /*PRINTFLIKE2*/
336 334 static void
337 335 ipqos_msg(enum msg_type msgt, char *format, ...)
338 336 {
339 337 va_list ap;
340 338 char str_buf[IPQOS_MSG_BUF_SZ];
341 339 char fmt_buf[IPQOS_MSG_BUF_SZ];
342 340 char *cp;
343 341
344 342 IPQOSCDBG0(L1, "In ipqos_msg:\n");
345 343
346 344 va_start(ap, format);
347 345
348 346 /*
349 347 * send msgs to syslog if use_syslog set (except warning msgs),
350 348 * or a log msg.
351 349 */
352 350 if ((use_syslog && (msgt != MT_WARNING)) || msgt == MT_LOG) {
353 351
354 352 /* fill in format string */
355 353 (void) vsnprintf(str_buf, IPQOS_MSG_BUF_SZ, format, ap);
356 354
357 355 /*
358 356 * print message to syslog with appropriate severity
359 357 */
360 358 if (msgt == MT_ERROR) {
361 359 syslog(LOG_ERR, str_buf);
362 360 } else if (msgt == MT_LOG) {
363 361 syslog(LOG_INFO, str_buf);
364 362 /*
365 363 * for errno message type suffix with %m for syslog to
366 364 * interpret.
367 365 */
368 366 } else if (msgt == MT_ENOSTR) {
369 367 /*
370 368 * remove any newline in message parameter.
371 369 * syslog will reapply a newline for us later.
372 370 */
373 371 if ((cp = strchr(str_buf, '\n')) != NULL)
374 372 *cp = '\0';
375 373 (void) strlcat(str_buf, ": %m", IPQOS_MSG_BUF_SZ);
376 374 syslog(LOG_ERR, str_buf);
377 375 }
378 376 }
379 377
380 378 /*
381 379 * send msgs to stderr if use_syslog not set (except log msgs), or
382 380 * if verbose set.
383 381 */
384 382 if ((!use_syslog && (msgt != MT_LOG)) || (verbose)) {
385 383
386 384 /*
387 385 * prefix message with appropriate severity string
388 386 */
389 387 if (msgt == MT_ERROR) {
390 388 (void) strlcpy(fmt_buf, gettext("Error: "),
391 389 IPQOS_MSG_BUF_SZ);
392 390 } else if (msgt == MT_WARNING) {
393 391 if (!verbose) { /* don't show warn msg if !verbose */
394 392 va_end(ap);
395 393 return;
396 394 }
397 395 (void) strlcpy(fmt_buf, gettext("Warning: "),
398 396 IPQOS_MSG_BUF_SZ);
399 397 } else if (msgt == MT_ENOSTR) {
400 398 (void) strlcpy(fmt_buf, gettext("Error: "),
401 399 IPQOS_MSG_BUF_SZ);
402 400 } else if (msgt == MT_LOG) {
403 401 (void) strlcpy(fmt_buf, gettext("Notice: "),
404 402 IPQOS_MSG_BUF_SZ);
405 403 }
406 404 (void) strlcat(fmt_buf, format, IPQOS_MSG_BUF_SZ);
407 405
408 406 /*
409 407 * for errno message type suffix message with errno string
410 408 */
411 409 if (msgt == MT_ENOSTR) {
412 410 /*
413 411 * get rid of any newline in passed message.
414 412 * we'll apply another later.
415 413 */
416 414 if ((cp = strchr(fmt_buf, '\n')) != NULL)
417 415 *cp = '\0';
418 416 (void) strlcat(fmt_buf, ": ", IPQOS_MSG_BUF_SZ);
419 417 (void) strlcat(fmt_buf, strerror(errno),
420 418 IPQOS_MSG_BUF_SZ);
421 419 }
422 420
423 421 /*
424 422 * append a newline to message if not one already.
425 423 */
426 424 if ((cp = strchr(fmt_buf, '\n')) == NULL)
427 425 (void) strlcat(fmt_buf, "\n", IPQOS_MSG_BUF_SZ);
428 426
429 427 (void) vfprintf(stderr, fmt_buf, ap);
430 428 }
431 429
432 430 va_end(ap);
433 431 }
434 432
435 433 /* **************** kernel filter/class/params manipulation fns *********** */
436 434
437 435
438 436 /*
439 437 * modify the kernel parameters of the action action_nm using the nvlist
440 438 * parameter nvl and setting the stats according to stats_enable.
441 439 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
442 440 */
443 441
444 442 static int
445 443 modify_params(
446 444 char *action_name,
447 445 nvlist_t **nvl,
448 446 int module_version,
449 447 boolean_t stats_enable)
450 448 {
451 449
452 450 int res;
453 451 int created = 0;
454 452
455 453 IPQOSCDBG1(APPLY, "In modify_params: action: %s\n", action_name);
456 454
457 455 /* create nvlist if NULL */
458 456 if (*nvl == NULL) {
459 457 created++;
460 458 res = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
461 459 if (res != 0) {
462 460 ipqos_msg(MT_ENOSTR, "nvlist_alloc");
463 461 return (IPQOS_CONF_ERR);
464 462 }
465 463 }
466 464
467 465 /* add params modify config type */
468 466 res = nvlist_add_byte(*nvl, IPP_CONFIG_TYPE, IPP_SET);
469 467 if (res != 0) {
470 468 ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
471 469 goto fail;
472 470 }
473 471
474 472 /*
475 473 * add module version
476 474 */
477 475 if (nvlist_add_uint32(*nvl, IPP_MODULE_VERSION,
478 476 (uint32_t)module_version) != 0) {
479 477 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
480 478 goto fail;
481 479 }
482 480
483 481 /* add stats_enable */
484 482 res = nvlist_add_uint32(*nvl, IPP_ACTION_STATS_ENABLE,
485 483 (uint32_t)stats_enable);
486 484 if (res != 0) {
487 485 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
488 486 goto fail;
489 487 }
490 488
491 489 /* add ipqosconf as originator */
492 490 res = add_orig_ipqosconf(*nvl);
493 491 if (res != IPQOS_CONF_SUCCESS) {
494 492 goto fail;
495 493 }
496 494
497 495 /* call lib to do modify */
498 496 res = ipp_action_modify(action_name, nvl, 0);
499 497 if (res != 0) {
500 498
501 499 /* invalid parameters */
502 500
503 501 if (errno == EINVAL) {
504 502 ipqos_msg(MT_ERROR,
505 503 gettext("Invalid parameters for action %s.\n"),
506 504 action_name);
507 505
508 506
509 507 } else if (errno == ENOENT) {
510 508 ipqos_msg(MT_ERROR,
511 509 gettext("Mandatory parameter missing for "
512 510 "action %s.\n"), action_name);
513 511
514 512
515 513 } else { /* unexpected error */
516 514 ipqos_msg(MT_ERROR, gettext("Failed to modify action "
517 515 "%s parameters: %s.\n"), action_name,
518 516 strerror(errno));
519 517 }
520 518
521 519 goto fail;
522 520 }
523 521
524 522 return (IPQOS_CONF_SUCCESS);
525 523 fail:
526 524 if (created && *nvl != NULL) {
527 525 nvlist_free(*nvl);
528 526 *nvl = NULL;
529 527 }
530 528 return (IPQOS_CONF_ERR);
531 529 }
532 530
533 531 /*
534 532 * add a class to the kernel action action_name called class_name with
535 533 * stats set according to stats_enable and the first action set to
536 534 * first_action.
537 535 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
538 536 */
539 537 static int
540 538 add_class(
541 539 char *action_name,
542 540 char *class_name,
543 541 int module_version,
544 542 boolean_t stats_enable,
545 543 char *first_action)
546 544 {
547 545
548 546 nvlist_t *nvl;
549 547
550 548 IPQOSCDBG4(APPLY, "add_class: action: %s, class: %s, "
551 549 "first_action: %s, stats: %s\n", action_name, class_name,
552 550 first_action, (stats_enable == B_TRUE ? "true" : "false"));
553 551
554 552
555 553 /* create nvlist */
556 554 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
557 555 ipqos_msg(MT_ENOSTR, "nvlist_alloc");
558 556 return (IPQOS_CONF_ERR);
559 557 }
560 558
561 559 /* add 'add class' config type */
562 560 if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE, CLASSIFIER_ADD_CLASS) != 0) {
563 561 ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
564 562 goto fail;
565 563 }
566 564
567 565 /*
568 566 * add module version
569 567 */
570 568 if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
571 569 (uint32_t)module_version) != 0) {
572 570 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
573 571 goto fail;
574 572 }
575 573
576 574 /* add class name */
577 575 if (nvlist_add_string(nvl, CLASSIFIER_CLASS_NAME, class_name) != 0) {
578 576 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
579 577 goto fail;
580 578 }
581 579
582 580 /* add next action */
583 581 if (nvlist_add_string(nvl, CLASSIFIER_NEXT_ACTION, first_action) != 0) {
584 582 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
585 583 goto fail;
586 584 }
587 585
588 586 /* add stats_enable */
589 587 if (nvlist_add_uint32(nvl, CLASSIFIER_CLASS_STATS_ENABLE,
590 588 (uint32_t)stats_enable) != 0) {
591 589 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
592 590 goto fail;
593 591 }
594 592
595 593 /* add ipqosconf as originator */
596 594 if (add_orig_ipqosconf(nvl) != IPQOS_CONF_SUCCESS) {
597 595 goto fail;
598 596 }
599 597
600 598 /* call lib to do modify */
601 599 if (ipp_action_modify(action_name, &nvl, 0) != 0) {
602 600
603 601 /* ipgpc max classes */
604 602
605 603 if (errno == ENOSPC &&
606 604 strcmp(action_name, IPGPC_CLASSIFY) == 0) {
607 605 ipqos_msg(MT_ERROR,
608 606 gettext("Max number of classes reached in %s.\n"),
609 607 IPGPC_NAME);
610 608
611 609 /* other errors */
612 610
613 611 } else {
614 612 ipqos_msg(MT_ERROR,
↓ open down ↓ |
576 lines elided |
↑ open up ↑ |
615 613 gettext("Failed to create class %s in action "
616 614 "%s: %s.\n"), class_name, action_name,
617 615 strerror(errno));
618 616 }
619 617
620 618 goto fail;
621 619 }
622 620
623 621 return (IPQOS_CONF_SUCCESS);
624 622 fail:
625 - if (nvl != NULL)
626 - nvlist_free(nvl);
623 + nvlist_free(nvl);
627 624 return (IPQOS_CONF_ERR);
628 625 }
629 626
630 627
631 628 /*
632 629 * modify the class in the kernel action action_name called class_name with
633 630 * stats set according to stats_enable and the first action set to
634 631 * first_action.
635 632 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
636 633 */
637 634 static int
638 635 modify_class(
639 636 char *action_name,
640 637 char *class_name,
641 638 int module_version,
642 639 boolean_t stats_enable,
643 640 char *first_action,
644 641 enum ipp_flags flags)
645 642 {
646 643
647 644 nvlist_t *nvl;
648 645
649 646 IPQOSCDBG5(APPLY, "modify_class: action: %s, class: %s, first: %s, "
650 647 "stats: %s, flags: %x\n", action_name, class_name, first_action,
651 648 stats_enable == B_TRUE ? "true" : "false", flags);
652 649
653 650
654 651 /* create nvlist */
655 652 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
656 653 ipqos_msg(MT_ENOSTR, "nvlist_alloc");
657 654 return (IPQOS_CONF_ERR);
658 655 }
659 656
660 657 /* add 'modify class' config type */
661 658 if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE, CLASSIFIER_MODIFY_CLASS) !=
662 659 0) {
663 660 ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
664 661 goto fail;
665 662 }
666 663
667 664 /*
668 665 * add module version
669 666 */
670 667 if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
671 668 (uint32_t)module_version) != 0) {
672 669 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
673 670 goto fail;
674 671 }
675 672
676 673 /* add class name */
677 674 if (nvlist_add_string(nvl, CLASSIFIER_CLASS_NAME, class_name) != 0) {
678 675 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
679 676 goto fail;
680 677 }
681 678
682 679 /* add next action */
683 680 if (nvlist_add_string(nvl, CLASSIFIER_NEXT_ACTION, first_action) != 0) {
684 681 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
685 682 goto fail;
686 683 }
687 684
688 685 /* add stats enable */
689 686 if (nvlist_add_uint32(nvl, CLASSIFIER_CLASS_STATS_ENABLE,
690 687 (uint32_t)stats_enable) != 0) {
691 688 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
692 689 goto fail;
693 690 }
694 691
695 692 /* add originator ipqosconf */
696 693 if (add_orig_ipqosconf(nvl) != IPQOS_CONF_SUCCESS) {
697 694 goto fail;
698 695 }
699 696
700 697 /* call lib to do modify */
701 698 if (ipp_action_modify(action_name, &nvl, flags) != 0) {
702 699
703 700 /* generic error message */
↓ open down ↓ |
67 lines elided |
↑ open up ↑ |
704 701
705 702 ipqos_msg(MT_ERROR,
706 703 gettext("Modifying class %s in action %s failed: %s.\n"),
707 704 class_name, action_name, strerror(errno));
708 705
709 706 goto fail;
710 707 }
711 708
712 709 return (IPQOS_CONF_SUCCESS);
713 710 fail:
714 - if (nvl != NULL)
715 - nvlist_free(nvl);
711 + nvlist_free(nvl);
716 712 return (IPQOS_CONF_ERR);
717 713 }
718 714
719 715 /*
720 716 * removes the class class_name from the kernel action action_name. The
721 717 * flags argument can currently be set to IPP_ACTION_DESTROY which will
722 718 * result in the action this class references being destroyed.
723 719 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
724 720 */
725 721 static int
726 722 remove_class(
727 723 char *action_name,
728 724 char *class_name,
729 725 int module_version,
730 726 enum ipp_flags flags)
731 727 {
732 728
733 729 nvlist_t *nvl;
734 730
735 731 IPQOSCDBG3(APPLY, "remove_class: action: %s, class: %s, "
736 732 "flags: %x\n", action_name, class_name, flags);
737 733
738 734 /* allocate nvlist */
739 735 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
740 736 ipqos_msg(MT_ENOSTR, "nvlist_alloc");
741 737 return (IPQOS_CONF_ERR);
742 738 }
743 739
744 740 /* add 'remove class' config type */
745 741 if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE, CLASSIFIER_REMOVE_CLASS) !=
746 742 0) {
747 743 ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
748 744 goto fail;
749 745 }
750 746
751 747 /*
752 748 * add module version
753 749 */
754 750 if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
755 751 (uint32_t)module_version) != 0) {
756 752 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
757 753 goto fail;
758 754 }
759 755
760 756 /* add class name */
761 757 if (nvlist_add_string(nvl, CLASSIFIER_CLASS_NAME, class_name) != 0) {
762 758 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
763 759 goto fail;
764 760 }
765 761
766 762 if (ipp_action_modify(action_name, &nvl, flags) != 0) {
767 763
768 764 /* generic error message */
↓ open down ↓ |
43 lines elided |
↑ open up ↑ |
769 765
770 766 ipqos_msg(MT_ERROR,
771 767 gettext("Removing class %s in action %s failed: %s.\n"),
772 768 class_name, action_name, strerror(errno));
773 769
774 770 goto fail;
775 771 }
776 772
777 773 return (IPQOS_CONF_SUCCESS);
778 774 fail:
779 - if (nvl != NULL)
780 - nvlist_free(nvl);
775 + nvlist_free(nvl);
781 776 return (IPQOS_CONF_ERR);
782 777 }
783 778
784 779 /*
785 780 * add the filter flt to the kernel action named action_name.
786 781 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
787 782 */
788 783 static int
789 784 add_filter(
790 785 char *action_name,
791 786 ipqos_conf_filter_t *flt,
792 787 int module_version)
793 788 {
794 789
795 790 nvlist_t *nvl = flt->nvlist;
796 791 char ipvsbuf[IPQOS_INT_STR_LEN];
797 792
798 793 IPQOSCDBG4(APPLY, "add_filter: action: %s, filter: %s, "
799 794 "instance: %d, class: %s\n", action_name, flt->name,
800 795 flt->instance, flt->class_name);
801 796
802 797
803 798 /* add 'add filter' config type to filter nvlist */
804 799 if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE, CLASSIFIER_ADD_FILTER) != 0) {
805 800 ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
806 801 return (IPQOS_CONF_ERR);
807 802 }
808 803
809 804 /*
810 805 * add module version
811 806 */
812 807 if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
813 808 (uint32_t)module_version) != 0) {
814 809 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
815 810 return (IPQOS_CONF_ERR);
816 811 }
817 812
818 813 /* add filter name to nvlist */
819 814 if (nvlist_add_string(nvl, CLASSIFIER_FILTER_NAME, flt->name) != 0) {
820 815 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
821 816 return (IPQOS_CONF_ERR);
822 817 }
823 818
824 819 /* add class name to nvlist */
825 820 if (nvlist_add_string(nvl, CLASSIFIER_CLASS_NAME, flt->class_name) !=
826 821 0) {
827 822 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
828 823 return (IPQOS_CONF_ERR);
829 824 }
830 825
831 826 /* add ipqosconf as originator to nvlist */
832 827 if (add_orig_ipqosconf(nvl) != IPQOS_CONF_SUCCESS) {
833 828 return (IPQOS_CONF_ERR);
834 829 }
835 830
836 831 /* add ipgpc specific nv entrys */
837 832 if (strcmp(action_name, IPGPC_CLASSIFY) == 0) {
838 833
839 834 /* add src and dst nodes to nvlist if present */
840 835
841 836 if (flt->src_nd_name != NULL &&
842 837 nvlist_add_string(nvl, IPGPC_SADDR_HOSTNAME,
843 838 flt->src_nd_name) != 0) {
844 839 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
845 840 return (IPQOS_CONF_ERR);
846 841 }
847 842 if (flt->dst_nd_name != NULL &&
848 843 nvlist_add_string(nvl, IPGPC_DADDR_HOSTNAME,
849 844 flt->dst_nd_name) != 0) {
850 845 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
851 846 return (IPQOS_CONF_ERR);
852 847 }
853 848
854 849 /*
855 850 * add ip_version to private list element if present.
856 851 * NOTE: this value is of only real use to ipqosconf so
857 852 * it is placed in this opaque private field.
858 853 */
859 854 if (flt->ip_versions != 0) {
860 855 (void) sprintf(ipvsbuf, "%d", flt->ip_versions);
861 856 if (nvlist_add_string(nvl, IPGPC_FILTER_PRIVATE,
862 857 ipvsbuf) != 0) {
863 858 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
864 859 return (IPQOS_CONF_ERR);
865 860 }
866 861 }
867 862
868 863 /* add filter instance if present */
869 864
870 865 if (nvlist_add_int32(nvl, IPGPC_FILTER_INSTANCE,
871 866 flt->instance) != 0) {
872 867 ipqos_msg(MT_ENOSTR, "nvlist_add_int32");
873 868 return (IPQOS_CONF_ERR);
874 869 }
875 870 }
876 871
877 872 if (ipp_action_modify(action_name, &flt->nvlist, 0) != 0) {
878 873
879 874 /* invalid parameters */
880 875
881 876 if (errno == EINVAL) {
882 877 ipqos_msg(MT_ERROR,
883 878 gettext("Invalid/missing parameters for filter "
884 879 "%s in action %s.\n"), flt->name, action_name);
885 880
886 881 /* max ipgpc filters/classes */
887 882
888 883 } else if (errno == ENOSPC &&
889 884 strcmp(action_name, IPGPC_CLASSIFY) == 0) {
890 885 ipqos_msg(MT_ERROR, gettext("Max number of filters "
891 886 "reached in action %s.\n"), IPGPC_NAME);
892 887
893 888 /* anything other errnos */
894 889 } else {
895 890 ipqos_msg(MT_ERROR,
896 891 gettext("Failed to create filter %s in action "
897 892 "%s: %s.\n"), flt->name, action_name,
898 893 strerror(errno));
899 894 }
900 895
901 896 return (IPQOS_CONF_ERR);
902 897 }
903 898
904 899 return (IPQOS_CONF_SUCCESS);
905 900 }
906 901
907 902
908 903 /*
909 904 * modify the filter flt in the kernel action named action_name.
910 905 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
911 906 */
912 907 static int
913 908 modify_filter(
914 909 char *action_name,
915 910 ipqos_conf_filter_t *flt,
916 911 int module_version)
917 912 {
918 913
919 914 nvlist_t *nvl = flt->nvlist;
920 915 char ipvsbuf[IPQOS_INT_STR_LEN];
921 916
922 917 IPQOSCDBG4(APPLY, "modify_filter: action: %s, filter: %s, "
923 918 "instance: %d, class: %s\n", action_name, flt->name,
924 919 flt->instance, flt->class_name);
925 920
926 921 /* show src address and dst address if present */
927 922 #ifdef _IPQOS_CONF_DEBUG
928 923 if (ipqosconf_dbg_flgs & APPLY) {
929 924 uint_t tmp;
930 925 in6_addr_t *add;
931 926 char st[100];
932 927
933 928 if (nvlist_lookup_uint32_array(nvl, IPGPC_SADDR,
934 929 (uint32_t **)&add, &tmp) == 0) {
935 930 (void) fprintf(stderr, "saddr: %s\n",
936 931 inet_ntop(AF_INET6, add, st, 100));
937 932 }
938 933
939 934 if (nvlist_lookup_uint32_array(nvl, IPGPC_DADDR,
940 935 (uint32_t **)&add, &tmp) == 0) {
941 936 (void) fprintf(stderr, "daddr: %s\n",
942 937 inet_ntop(AF_INET6, add, st, 100));
943 938 }
944 939 }
945 940 #endif /* _IPQOS_CONF_DEBUG */
946 941
947 942 /* add 'modify filter' config type to filters nvlist */
948 943 if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE,
949 944 CLASSIFIER_MODIFY_FILTER) != 0) {
950 945 ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
951 946 return (IPQOS_CONF_ERR);
952 947 }
953 948
954 949 /*
955 950 * add module version
956 951 */
957 952 if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
958 953 (uint32_t)module_version) != 0) {
959 954 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
960 955 return (IPQOS_CONF_ERR);
961 956 }
962 957
963 958 /* add filter name to nvlist */
964 959 if (nvlist_add_string(nvl, CLASSIFIER_FILTER_NAME, flt->name) != 0) {
965 960 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
966 961 return (IPQOS_CONF_ERR);
967 962 }
968 963
969 964 /* add class name to nvlist */
970 965 if (nvlist_add_string(nvl, CLASSIFIER_CLASS_NAME, flt->class_name) !=
971 966 0) {
972 967 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
973 968 return (IPQOS_CONF_ERR);
974 969 }
975 970
976 971 /* add originator ipqosconf to nvlist */
977 972 if (add_orig_ipqosconf(nvl) != IPQOS_CONF_SUCCESS) {
978 973 return (IPQOS_CONF_ERR);
979 974 }
980 975
981 976 /* add ipgpc specific nvpairs */
982 977 if (strcmp(action_name, IPGPC_CLASSIFY) == 0) {
983 978
984 979 /* add src and dst nodes to nvlist if present */
985 980
986 981 if (flt->src_nd_name &&
987 982 nvlist_add_string(nvl, IPGPC_SADDR_HOSTNAME,
988 983 flt->src_nd_name) != 0) {
989 984 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
990 985 return (IPQOS_CONF_ERR);
991 986 }
992 987 if (flt->dst_nd_name &&
993 988 nvlist_add_string(nvl, IPGPC_DADDR_HOSTNAME,
994 989 flt->dst_nd_name) != 0) {
995 990 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
996 991 return (IPQOS_CONF_ERR);
997 992 }
998 993
999 994 /*
1000 995 * add ip_version to private list element if present.
1001 996 * NOTE: this value is of only real use to ipqosconf so
1002 997 * it is placed in this opaque private field.
1003 998 */
1004 999 if (flt->ip_versions != 0) {
1005 1000 (void) sprintf(ipvsbuf, "%d", flt->ip_versions);
1006 1001 if (nvlist_add_string(nvl, IPGPC_FILTER_PRIVATE,
1007 1002 ipvsbuf) != 0) {
1008 1003 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
1009 1004 return (IPQOS_CONF_ERR);
1010 1005 }
1011 1006 }
1012 1007
1013 1008 /* add filter instance if present */
1014 1009
1015 1010 if (nvlist_add_int32(nvl, IPGPC_FILTER_INSTANCE,
1016 1011 flt->instance) != 0) {
1017 1012 ipqos_msg(MT_ENOSTR, "nvlist_add_int32");
1018 1013 return (IPQOS_CONF_ERR);
1019 1014 }
1020 1015 }
1021 1016
1022 1017 if (ipp_action_modify(action_name, &flt->nvlist, 0) != 0) {
1023 1018
1024 1019 /* invalid parameters */
1025 1020
1026 1021 if (errno == EINVAL) {
1027 1022 ipqos_msg(MT_ERROR, gettext("Missing/Invalid "
1028 1023 "parameter for filter %s in action %s.\n"),
1029 1024 flt->name, action_name);
1030 1025
1031 1026 /* any other errnos */
1032 1027
1033 1028 } else {
1034 1029 ipqos_msg(MT_ERROR,
1035 1030 gettext("Failed to modify filter %s in action %s: "
1036 1031 "%s.\n"), flt->name, action_name, strerror(errno));
1037 1032 }
1038 1033
1039 1034 return (IPQOS_CONF_ERR);
1040 1035 }
1041 1036
1042 1037 return (IPQOS_CONF_SUCCESS);
1043 1038 }
1044 1039
1045 1040 /*
1046 1041 * remove the filter named filter_name instance number instance from the
1047 1042 * kernel action action_name.
1048 1043 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
1049 1044 */
1050 1045 static int
1051 1046 remove_filter(
1052 1047 char *action_name,
1053 1048 char *filter_name,
1054 1049 int instance,
1055 1050 int module_version)
1056 1051 {
1057 1052
1058 1053 nvlist_t *nvl;
1059 1054
1060 1055 IPQOSCDBG2(APPLY, "remove_filter: action: %s, filter: %s\n",
1061 1056 action_name, filter_name);
1062 1057
1063 1058 /* create nvlist */
1064 1059 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
1065 1060 ipqos_msg(MT_ENOSTR, "nvlist_alloc");
1066 1061 return (IPQOS_CONF_ERR);
1067 1062 }
1068 1063
1069 1064 /* add 'remove filter' config type to list */
1070 1065 if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE, CLASSIFIER_REMOVE_FILTER)
1071 1066 != 0) {
1072 1067 ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
1073 1068 return (IPQOS_CONF_ERR);
1074 1069 }
1075 1070
1076 1071 /*
1077 1072 * add module version
1078 1073 */
1079 1074 if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
1080 1075 (uint32_t)module_version) != 0) {
1081 1076 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
1082 1077 return (IPQOS_CONF_ERR);
1083 1078 }
1084 1079
1085 1080 /* add filter name to list */
1086 1081 if (nvlist_add_string(nvl, CLASSIFIER_FILTER_NAME, filter_name) != 0) {
1087 1082 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
1088 1083 return (IPQOS_CONF_ERR);
1089 1084 }
1090 1085
1091 1086 /* add instance number if part of multi-instance filter */
1092 1087 if (instance != -1 && nvlist_add_int32(nvl, IPGPC_FILTER_INSTANCE,
1093 1088 instance) != 0) {
1094 1089 ipqos_msg(MT_ENOSTR, "nvlist_add_int32");
1095 1090 return (IPQOS_CONF_ERR);
1096 1091 }
1097 1092
1098 1093 /* call into lib to remove */
1099 1094 if (ipp_action_modify(action_name, &nvl, 0) != 0) {
1100 1095
1101 1096 /* generic error message */
1102 1097
1103 1098 ipqos_msg(MT_ERROR,
1104 1099 gettext("Removing filter %s in action %s failed: %s.\n"),
1105 1100 filter_name, action_name, strerror(errno));
1106 1101
1107 1102 return (IPQOS_CONF_ERR);
1108 1103 }
1109 1104
1110 1105 return (IPQOS_CONF_SUCCESS);
1111 1106 }
1112 1107
1113 1108 /* ******************************************************************* */
1114 1109
1115 1110
1116 1111 /*
1117 1112 * add originator nvpair set to ipqosconf to nvl.
1118 1113 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
1119 1114 */
1120 1115 static int
1121 1116 add_orig_ipqosconf(nvlist_t *nvl)
1122 1117 {
1123 1118
1124 1119 if (nvlist_add_uint32(nvl, IPP_CONFIG_ORIGINATOR,
1125 1120 IPP_CONFIG_IPQOSCONF) != 0) {
1126 1121 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32: originator:");
1127 1122 return (IPQOS_CONF_ERR);
1128 1123 }
1129 1124
1130 1125 return (IPQOS_CONF_SUCCESS);
1131 1126 }
1132 1127
1133 1128 /* ************************* differencing functions ************************ */
1134 1129
1135 1130
1136 1131 /*
1137 1132 * compares the contents of arrays array1 and array2, both of size size, and
1138 1133 * returns B_TRUE or B_FALSE if they're equal or not respectively.
1139 1134 * RETURNS: B_TRUE if equal, else B_FALSE.
1140 1135 */
1141 1136 static boolean_t
1142 1137 arrays_equal(
1143 1138 int array1[],
1144 1139 int array2[],
1145 1140 uint32_t size)
1146 1141 {
1147 1142 int x;
1148 1143
1149 1144 for (x = 0; x < size; x++) {
1150 1145 if (array1[x] != array2[x])
1151 1146 return (B_FALSE);
1152 1147 }
1153 1148 return (B_TRUE);
1154 1149 }
1155 1150
1156 1151 /*
1157 1152 * difference class old against class new. It marks the new class as
1158 1153 * modified if it is different.
1159 1154 * RETURNS: IPQOS_CONF_SUCCESS.
1160 1155 */
1161 1156 static int
1162 1157 diffclass(
1163 1158 ipqos_conf_class_t *old,
1164 1159 ipqos_conf_class_t *new)
1165 1160 {
1166 1161
1167 1162 IPQOSCDBG0(L0, "In diffclass:\n");
1168 1163
1169 1164 /* two different spec'd actions */
1170 1165 if (strcmp(old->alist->name, new->alist->name) != 0) {
1171 1166 IPQOSCDBG1(DIFF, "marking class %s as modified\n", new->name);
1172 1167
1173 1168 new->modified = B_TRUE;
1174 1169 return (IPQOS_CONF_SUCCESS);
1175 1170 }
1176 1171
1177 1172 /* different stats values */
1178 1173 if (old->stats_enable != new->stats_enable) {
1179 1174 IPQOSCDBG1(DIFF, "marking class %s as modified\n", new->name);
1180 1175
1181 1176 new->modified = B_TRUE;
1182 1177 return (IPQOS_CONF_SUCCESS);
1183 1178 }
1184 1179
1185 1180 return (IPQOS_CONF_SUCCESS);
1186 1181 }
1187 1182
1188 1183 /*
1189 1184 * difference params set old against params set new of module module_name. It
1190 1185 * marks the new params as modified if different.
1191 1186 * RETURNS: if error IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
1192 1187 */
1193 1188 static int
1194 1189 diffparams(
1195 1190 ipqos_conf_params_t *old,
1196 1191 ipqos_conf_params_t *new,
1197 1192 char *module_name)
1198 1193 {
1199 1194
1200 1195 int diff;
1201 1196 int res;
1202 1197
1203 1198 IPQOSCDBG0(L0, "In diffparams\n");
1204 1199
1205 1200 /* diff stats */
1206 1201 if (old->stats_enable != new->stats_enable) {
1207 1202
1208 1203 new->modified = B_TRUE;
1209 1204 return (IPQOS_CONF_SUCCESS);
1210 1205 }
1211 1206
1212 1207 /* diff module specific params */
1213 1208 res = diffnvlists(old->nvlist, new->nvlist, module_name, &diff,
1214 1209 PL_PARAMS);
1215 1210 if (res != IPQOS_CONF_SUCCESS) {
1216 1211 return (res);
1217 1212 }
1218 1213 if (diff) {
1219 1214
1220 1215 new->modified = B_TRUE;
1221 1216 }
1222 1217
1223 1218 return (IPQOS_CONF_SUCCESS);
1224 1219 }
1225 1220
1226 1221 /*
1227 1222 * differences filter old against filter new of module module_name. It marks
1228 1223 * filter new as different if so.
1229 1224 * RETURNS: if error IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
1230 1225 */
1231 1226 static int
1232 1227 difffilter(
1233 1228 ipqos_conf_filter_t *old,
1234 1229 ipqos_conf_filter_t *new,
1235 1230 char *module_name)
1236 1231 {
1237 1232
1238 1233 int res;
1239 1234 int diff;
1240 1235
1241 1236 IPQOSCDBG0(L0, "In difffilter\n");
1242 1237
1243 1238 /* compare class name */
1244 1239
1245 1240 if (strcmp(old->class_name, new->class_name) != 0) {
1246 1241 IPQOSCDBG1(DIFF, "Marking filter %s as modified\n", new->name);
1247 1242
1248 1243 new->modified = B_TRUE;
1249 1244 return (IPQOS_CONF_SUCCESS);
1250 1245 }
1251 1246
1252 1247 /* compare module specific params */
1253 1248
1254 1249 res = diffnvlists(old->nvlist, new->nvlist, module_name, &diff,
1255 1250 PL_FILTER);
1256 1251 if (res != IPQOS_CONF_SUCCESS) {
1257 1252 return (res);
1258 1253 }
1259 1254
1260 1255 if (diff) {
1261 1256 IPQOSCDBG1(DIFF, "Marking filter %s as modified\n", new->name);
1262 1257 new->modified = B_TRUE;
1263 1258 }
1264 1259
1265 1260 return (IPQOS_CONF_SUCCESS);
1266 1261 }
1267 1262
1268 1263
1269 1264 /*
1270 1265 * mark all the filters and classes in parameter action either
1271 1266 * for deletion (if they are ipqosconf originated) or for modification.
1272 1267 */
1273 1268 static void
1274 1269 mark_classes_filters_del(ipqos_conf_action_t *action)
1275 1270 {
1276 1271
1277 1272 ipqos_conf_filter_t *flt;
1278 1273 ipqos_conf_class_t *cls;
1279 1274
1280 1275 IPQOSCDBG1(L1, "In mark_classes_filters_del: action: %s\n",
1281 1276 action->name);
1282 1277
1283 1278 /* mark all non-permanent filters for del and permanent to modify */
1284 1279 for (flt = action->filters; flt; flt = flt->next) {
1285 1280 if (flt->originator == IPP_CONFIG_PERMANENT) {
1286 1281 IPQOSCDBG1(DIFF, "Marking prm filter %s as modified.\n",
1287 1282 flt->name);
1288 1283
1289 1284 flt->modified = B_TRUE;
1290 1285 } else {
1291 1286 IPQOSCDBG1(DIFF, "Marking filter %s as del.\n",
1292 1287 flt->name);
1293 1288
1294 1289 flt->todel = B_TRUE;
1295 1290 }
1296 1291 }
1297 1292
1298 1293 /* mark all non-permanent classes for del and permanent to modify */
1299 1294 for (cls = action->classes; cls; cls = cls->next) {
1300 1295 if (cls->originator == IPP_CONFIG_PERMANENT) {
1301 1296 IPQOSCDBG1(DIFF, "Marking prm class %s as modified.\n",
1302 1297 cls->name);
1303 1298
1304 1299 cls->modified = B_TRUE;
1305 1300 } else {
1306 1301 IPQOSCDBG1(DIFF, "Marking class %s as del.\n",
1307 1302 cls->name);
1308 1303
1309 1304 cls->todel = B_TRUE;
1310 1305 }
1311 1306 }
1312 1307 }
1313 1308
1314 1309 /*
1315 1310 * mark all classes and filters either new (non-permanent) or modified.
1316 1311 */
1317 1312 static void
1318 1313 mark_classes_filters_new(ipqos_conf_action_t *action)
1319 1314 {
1320 1315
1321 1316 ipqos_conf_filter_t *flt;
1322 1317 ipqos_conf_class_t *cls;
1323 1318
1324 1319 IPQOSCDBG1(L1, "In mark_classes_filters_new: action: %s\n",
1325 1320 action->name);
1326 1321
1327 1322 /* mark all permanent filters as modified and all others new */
1328 1323
1329 1324 for (flt = action->filters; flt; flt = flt->next) {
1330 1325 if (flt->originator == IPP_CONFIG_PERMANENT) {
1331 1326 IPQOSCDBG1(DIFF, "Marking prm filter %s as modified.\n",
1332 1327 flt->name);
1333 1328
1334 1329 flt->modified = B_TRUE;
1335 1330 action->modified = B_TRUE;
1336 1331 } else {
1337 1332 IPQOSCDBG1(DIFF, "Marking filter %s as new.\n",
1338 1333 flt->name);
1339 1334
1340 1335 flt->new = B_TRUE;
1341 1336 }
1342 1337 }
1343 1338
1344 1339 /* mark all permanent classes as modified and all others new */
1345 1340 for (cls = action->classes; cls; cls = cls->next) {
1346 1341 if (cls->originator == IPP_CONFIG_PERMANENT) {
1347 1342 IPQOSCDBG1(DIFF, "Marking prm class %s as modified.\n",
1348 1343 cls->name);
1349 1344
1350 1345 cls->modified = B_TRUE;
1351 1346 action->modified = B_TRUE;
1352 1347 } else {
1353 1348 IPQOSCDBG1(DIFF, "Marking class %s as new.\n",
1354 1349 cls->name);
1355 1350
1356 1351 cls->new = B_TRUE;
1357 1352 }
1358 1353 }
1359 1354 }
1360 1355
1361 1356 /*
1362 1357 * Marks all the actions and their constituent elements in conf
1363 1358 * as new.
1364 1359 */
1365 1360 static void
1366 1361 mark_config_new(
1367 1362 ipqos_conf_action_t *conf)
1368 1363 {
1369 1364 while (conf != NULL) {
1370 1365 IPQOSCDBG1(DIFF, "Marking action %s as new\n", conf->name);
1371 1366 mark_classes_filters_new(conf);
1372 1367 conf->new = B_TRUE;
1373 1368 conf->visited = 0;
1374 1369 conf = conf->next;
1375 1370 }
1376 1371 }
1377 1372
1378 1373 /*
1379 1374 * differences the configuration in new against old marking the actions
1380 1375 * and their contents appropriately.
1381 1376 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
1382 1377 */
1383 1378 static int
1384 1379 diffconf(
1385 1380 ipqos_conf_action_t *old,
1386 1381 ipqos_conf_action_t *new)
1387 1382 {
1388 1383
1389 1384 int res;
1390 1385 ipqos_conf_action_t *act;
1391 1386 ipqos_conf_action_t *tmp;
1392 1387
1393 1388 IPQOSCDBG0((L0 | DIFF), "In diffconf\n");
1394 1389
1395 1390 /* check the new actions against the old */
1396 1391
1397 1392 for (act = new; act; act = act->next) {
1398 1393
1399 1394 /* if action not in old mark it and it's contents as new */
1400 1395
1401 1396 if ((tmp = actionexist(act->name, old)) == NULL) {
1402 1397 IPQOSCDBG1(DIFF, "marking act %s as new\n", act->name);
1403 1398
1404 1399 act->new = B_TRUE;
1405 1400 mark_classes_filters_new(act);
1406 1401 continue;
1407 1402 }
1408 1403
1409 1404 /* if action in old diff old against new */
1410 1405
1411 1406 res = diffaction(tmp, act);
1412 1407 if (res != IPQOS_CONF_SUCCESS) {
1413 1408 return (res);
1414 1409 }
1415 1410 }
1416 1411
1417 1412 /*
1418 1413 * mark actions, and their contents, in old but not new that were
1419 1414 * created by us for del.
1420 1415 */
1421 1416
1422 1417 for (act = old; act; act = act->next) {
1423 1418 if (act->params->originator == IPP_CONFIG_IPQOSCONF &&
1424 1419 actionexist(act->name, new) == NULL) {
1425 1420 IPQOSCDBG1(DIFF, "marking act %s for del\n", act->name);
1426 1421
1427 1422 act->todel = B_TRUE;
1428 1423 mark_classes_filters_del(act);
1429 1424 }
1430 1425 }
1431 1426
1432 1427 return (IPQOS_CONF_SUCCESS);
1433 1428 }
1434 1429
1435 1430 /*
1436 1431 * differences action old against action new, comparing its classes, filters
1437 1432 * and parameters. If it is different the new action is marked as modified
1438 1433 * and it's different sub-objects are also marked approriately.
1439 1434 * RETURNS: IPQOS_CONF_ERR if error, else IPQOS_CONF_SUCCESS.
1440 1435 */
1441 1436 static int
1442 1437 diffaction(
1443 1438 ipqos_conf_action_t *old,
1444 1439 ipqos_conf_action_t *new)
1445 1440 {
1446 1441
1447 1442 int res;
1448 1443
1449 1444 IPQOSCDBG0(L0, "In diffaction\n");
1450 1445
1451 1446 /* compare and mark classes */
1452 1447 res = diffclasses(old, new);
1453 1448 if (res != IPQOS_CONF_SUCCESS) {
1454 1449 return (res);
1455 1450 }
1456 1451
1457 1452 /* compare and mark filters */
1458 1453 res = difffilters(old, new);
1459 1454 if (res != IPQOS_CONF_SUCCESS) {
1460 1455 return (res);
1461 1456 }
1462 1457
1463 1458 /* compare and mark parameters */
1464 1459 res = diffparams(old->params, new->params, old->module);
1465 1460 if (res != IPQOS_CONF_SUCCESS) {
1466 1461 return (res);
1467 1462 }
1468 1463
1469 1464 /* mark action as modified if params are */
1470 1465 if (new->params->modified == B_TRUE) {
1471 1466 IPQOSCDBG1(DIFF, "Marking params for action %s modified\n",
1472 1467 new->name);
1473 1468
1474 1469 new->modified = B_TRUE;
1475 1470 }
1476 1471
1477 1472 return (IPQOS_CONF_SUCCESS);
1478 1473 }
1479 1474
1480 1475 /*
1481 1476 * differences the set of classes in new against those in old, marking any
1482 1477 * that are new/modified, approriately in the new class, and any removed
1483 1478 * in the old class appropriately. Also marks the action which has had an
1484 1479 * object within marked, as modified.
1485 1480 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
1486 1481 */
1487 1482
1488 1483 static int
1489 1484 diffclasses(
1490 1485 ipqos_conf_action_t *old,
1491 1486 ipqos_conf_action_t *new)
1492 1487 {
1493 1488
1494 1489
1495 1490 ipqos_conf_class_t *cls;
1496 1491 ipqos_conf_class_t *tmpc;
1497 1492 ipqos_conf_class_t *ncls;
1498 1493 int res;
1499 1494
1500 1495
1501 1496 /* loop through old classes checking for classes not present in new */
1502 1497
1503 1498 for (cls = old->classes; cls; cls = cls->next) {
1504 1499
1505 1500 if (classexist(cls->name, new->classes) == NULL) {
1506 1501
1507 1502 /* if we created original class mark for deletion */
1508 1503
1509 1504 if (cls->originator == IPP_CONFIG_IPQOSCONF) {
1510 1505 IPQOSCDBG1(DIFF, "marking class %s for del\n",
1511 1506 cls->name);
1512 1507
1513 1508 cls->todel = B_TRUE;
1514 1509
1515 1510 /* mark old action */
1516 1511 old->modified = B_TRUE;
1517 1512
1518 1513 /*
1519 1514 * if permanent class and next action created by us
1520 1515 * copy it, set it's next action to continue and
1521 1516 * add it to new action. This will cause the class
1522 1517 * to be marked as and modified. This returns the class
1523 1518 * to an assumed default state and prevents the
1524 1519 * case where the class is pointing at an action
1525 1520 * we want to remove and therefore couldn't without
1526 1521 * this forced modify.
1527 1522 */
1528 1523 } else if (cls->originator == IPP_CONFIG_PERMANENT &&
1529 1524 cls->alist->action && /* not virtual action */
1530 1525 cls->alist->action->params->originator ==
1531 1526 IPP_CONFIG_IPQOSCONF) {
1532 1527
1533 1528 /* copy class */
1534 1529
1535 1530 res = dup_class(cls, &ncls);
1536 1531 if (res != IPQOS_CONF_SUCCESS) {
1537 1532 return (IPQOS_CONF_ERR);
1538 1533 }
1539 1534
1540 1535 /* set next action to continue */
1541 1536
1542 1537 (void) strcpy(ncls->alist->name,
1543 1538 IPP_ANAME_CONT);
1544 1539
1545 1540 /* add to news classes to be diffed below */
1546 1541 ADD_TO_LIST(&new->classes, ncls);
1547 1542 }
1548 1543 }
1549 1544 }
1550 1545
1551 1546 /* loop through new classes checking for new / modified classes */
1552 1547
1553 1548 for (cls = new->classes; cls; cls = cls->next) {
1554 1549
1555 1550 /* new ipqosconf class */
1556 1551
1557 1552 if ((tmpc = classexist(cls->name, old->classes)) == NULL ||
1558 1553 (tmpc->originator != IPP_CONFIG_IPQOSCONF &&
1559 1554 tmpc->originator != IPP_CONFIG_PERMANENT)) {
1560 1555 IPQOSCDBG1(DIFF, "marking class %s new\n",
1561 1556 cls->name);
1562 1557
1563 1558 cls->new = B_TRUE;
1564 1559
1565 1560 new->modified = B_TRUE; /* mark new action */
1566 1561 continue;
1567 1562
1568 1563 /* existing ipqosconf/perm class */
1569 1564 } else {
1570 1565 res = diffclass(tmpc, cls);
1571 1566 if (res != IPQOS_CONF_SUCCESS) {
1572 1567 return (res);
1573 1568 }
1574 1569
1575 1570 if (cls->modified == B_TRUE) {
1576 1571 new->modified = B_TRUE;
1577 1572 }
1578 1573 }
1579 1574 }
1580 1575
1581 1576 return (IPQOS_CONF_SUCCESS);
1582 1577 }
1583 1578
1584 1579 /*
1585 1580 * differences the set of filters in new against those in old, marking any
1586 1581 * that are new/modified, approriately in the new filter/s, and any removed
1587 1582 * in the old filter appropriately. Also marks the action which has had an
1588 1583 * object within marked, as modified.
1589 1584 * RETURNS: IPQOS_CONF_SUCCESS (we return an int for symmetry with diffclasses
1590 1585 * and difffparams).
1591 1586 */
1592 1587 static int
1593 1588 difffilters(
1594 1589 ipqos_conf_action_t *old,
1595 1590 ipqos_conf_action_t *new)
1596 1591 {
1597 1592
1598 1593 ipqos_conf_filter_t *flt;
1599 1594 ipqos_conf_filter_t *tmpf;
1600 1595 int maxi;
1601 1596 int newi;
1602 1597 int res;
1603 1598
1604 1599 /* check for new/modified filters */
1605 1600
1606 1601 for (flt = new->filters; flt; flt = flt->next) {
1607 1602
1608 1603 /* new ipqosconf filter */
1609 1604
1610 1605 if ((tmpf = filterexist(flt->name, -1, old->filters)) == NULL) {
1611 1606
1612 1607 /* mark all instances of this filter as new */
1613 1608 for (;;) {
1614 1609 IPQOSCDBG1(DIFF, "Marking filter %s as "
1615 1610 "new\n", flt->name);
1616 1611
1617 1612 flt->new = B_TRUE;
1618 1613
1619 1614
1620 1615 if (flt->next == NULL ||
1621 1616 strcmp(flt->next->name, flt->name) != 0) {
1622 1617 break;
1623 1618 }
1624 1619 flt = flt->next;
1625 1620 }
1626 1621 new->modified = B_TRUE; /* mark new action */
1627 1622
1628 1623 /* ipqosconf/permanent filter existed */
1629 1624 } else {
1630 1625 /*
1631 1626 * if ip node name force filter refresh - ie. mark
1632 1627 * all old filter instances as todel and all new new.
1633 1628 */
1634 1629 if (tmpf->src_nd_name || tmpf->dst_nd_name ||
1635 1630 flt->src_nd_name || flt->dst_nd_name) {
1636 1631
1637 1632 /* init max previous filter instance */
1638 1633 maxi = tmpf->instance;
1639 1634
1640 1635 /* mark old instances for deletion */
1641 1636 do {
1642 1637 IPQOSCDBG2(DIFF, "Marking filter "
1643 1638 "%s, instance %d for del\n",
1644 1639 tmpf->name, tmpf->instance);
1645 1640
1646 1641 tmpf->todel = B_TRUE;
1647 1642
1648 1643 /*
1649 1644 * check and update previous instance
1650 1645 * max.
1651 1646 */
1652 1647 if (tmpf->instance > maxi) {
1653 1648 maxi = tmpf->instance;
1654 1649 }
1655 1650
1656 1651 tmpf = tmpf->next;
1657 1652 } while (tmpf != NULL &&
1658 1653 strcmp(tmpf->name, flt->name) == 0);
1659 1654
1660 1655 /*
1661 1656 * use the max previous instance + 1 for
1662 1657 * the start of the new instance numbers.
1663 1658 */
1664 1659 newi = (uint32_t)++maxi % INT_MAX;
1665 1660
1666 1661 /*
1667 1662 * mark new instances for addition and
1668 1663 * give new instance number.
1669 1664 */
1670 1665 for (;;) {
1671 1666 IPQOSCDBG2(DIFF, "Marking filter "
1672 1667 "%s, instance %d as new\n",
1673 1668 flt->name, newi);
1674 1669
1675 1670 flt->new = B_TRUE;
1676 1671 flt->instance = newi++;
1677 1672 if (flt->next == NULL ||
1678 1673 strcmp(flt->next->name,
1679 1674 flt->name) != 0) {
1680 1675 break;
1681 1676 }
1682 1677 flt = flt->next;
1683 1678 }
1684 1679 new->modified = B_TRUE; /* mark new action */
1685 1680
1686 1681 /* mark old action */
1687 1682 old->modified = B_TRUE;
1688 1683
1689 1684 /* non-node name filter */
1690 1685 } else {
1691 1686 /* compare and mark as modified if diff */
1692 1687
1693 1688 res = difffilter(tmpf, flt, new->module);
1694 1689 if (res != IPQOS_CONF_SUCCESS) {
1695 1690 return (res);
1696 1691 }
1697 1692 if (flt->modified == B_TRUE) {
1698 1693 /* mark action if diff */
1699 1694 new->modified = B_TRUE;
1700 1695 }
1701 1696 }
1702 1697 }
1703 1698 }
1704 1699
1705 1700 /*
1706 1701 * Check for deleted ipqosconf created filters and mark
1707 1702 * any found for deletion.
1708 1703 * For non-ipqosconf generated filters, including permanent
1709 1704 * ones (none of these exist at the moment) we just leave
1710 1705 * the filter unmarked.
1711 1706 */
1712 1707 for (flt = old->filters; flt; flt = flt->next) {
1713 1708
1714 1709 if (flt->originator == IPP_CONFIG_IPQOSCONF &&
1715 1710 filterexist(flt->name, -1, new->filters) == NULL) {
1716 1711
1717 1712 /* mark all old instances for deletions */
1718 1713 for (;;) {
1719 1714 IPQOSCDBG2(DIFF, "marking flt %s, inst %d "
1720 1715 "for del\n", flt->name, flt->instance);
1721 1716
1722 1717 flt->todel = B_TRUE;
1723 1718 old->modified = B_TRUE; /* mark old action */
1724 1719
1725 1720 if (flt->next == NULL ||
1726 1721 strcmp(flt->next->name, flt->name) != 0) {
1727 1722 break;
1728 1723 }
1729 1724 flt = flt->next;
1730 1725 }
1731 1726 }
1732 1727 }
1733 1728
1734 1729 return (IPQOS_CONF_SUCCESS);
1735 1730 }
1736 1731
1737 1732
1738 1733 /*
1739 1734 * differences the elements of nvlists old and new using the types file
1740 1735 * for module name to interpret the element types. It sets pdiff to either
1741 1736 * 0 or 1 if they are the same or different respectively.
1742 1737 * RETURNS: IPQOS_CONF_ERR if any errors, else IPQOS_CONF_SUCCESS.
1743 1738 */
1744 1739 static int
1745 1740 diffnvlists(
1746 1741 nvlist_t *old,
1747 1742 nvlist_t *new,
1748 1743 char *module_name,
1749 1744 int *pdiff,
1750 1745 place_t place)
1751 1746 {
1752 1747
1753 1748 int first_pass = 1;
1754 1749 nvlist_t *tmp;
1755 1750 int res;
1756 1751 nvpair_t *nvp;
1757 1752 FILE *tfp;
1758 1753 str_val_nd_t *enum_nvs;
1759 1754 char dfltst[IPQOS_VALST_MAXLEN+1] = "";
1760 1755 char *lo;
1761 1756 ipqos_nvtype_t type;
1762 1757 char *nme;
1763 1758 int diff;
1764 1759 int openerr;
1765 1760
1766 1761
1767 1762 IPQOSCDBG0(L0, "In diffnvlists\n");
1768 1763
1769 1764 /* open stream to types file */
1770 1765
1771 1766 tfp = validmod(module_name, &openerr);
1772 1767 if (tfp == NULL) {
1773 1768 if (openerr) {
1774 1769 ipqos_msg(MT_ENOSTR, "fopen");
1775 1770 }
1776 1771 return (IPQOS_CONF_ERR);
1777 1772 }
1778 1773 start:
1779 1774 /*
1780 1775 * loop through each of the elements of the new list comparing
1781 1776 * it with the old one if present. If the old one isn't present
1782 1777 * then it is compared with the default value for that type (if
1783 1778 * set). Any time the values are determined to be different
1784 1779 * or the default value is to be used but isn't present the diff
1785 1780 * param is set to 1 and we return.
1786 1781 *
1787 1782 * If the loop runs its course then the new and old nvlists are
1788 1783 * reversed and the loop is entered for a second time.
1789 1784 */
1790 1785 nvp = nvlist_next_nvpair(new, NULL);
1791 1786 while (nvp != NULL) {
1792 1787
1793 1788 /* get name */
1794 1789 nme = nvpair_name(nvp);
1795 1790
1796 1791 /*
1797 1792 * get type.
1798 1793 */
1799 1794 place = PL_ANY;
1800 1795 res = readtype(tfp, module_name, SHORT_NAME(nme), &type,
1801 1796 &enum_nvs, dfltst, B_TRUE, &place);
1802 1797 if (res != IPQOS_CONF_SUCCESS) {
1803 1798 return (res);
1804 1799 }
1805 1800
1806 1801 /* init diff to 1 */
1807 1802 diff = 1;
1808 1803
1809 1804 switch (type) {
1810 1805
1811 1806 /* interface name */
1812 1807 case IPQOS_DATA_TYPE_IFINDEX: {
1813 1808 uint32_t ifidx;
1814 1809 uint32_t oifidx;
1815 1810
1816 1811 /* get new value */
1817 1812 (void) nvpair_value_uint32(nvp, &ifidx);
1818 1813
1819 1814 /* compare against old if present */
1820 1815
1821 1816 res = nvlist_lookup_uint32(old, nme, &oifidx);
1822 1817 if (res == 0) {
1823 1818 /* diff values */
1824 1819 diff = (ifidx != oifidx);
1825 1820
1826 1821 /* not in old so see if new value is default */
1827 1822
1828 1823 } else {
1829 1824 diff = (ifidx != 0);
1830 1825 }
1831 1826 break;
1832 1827 }
1833 1828 /* protocol */
1834 1829 case IPQOS_DATA_TYPE_PROTO: {
1835 1830 uchar_t proto;
1836 1831 uchar_t oproto;
1837 1832
1838 1833 (void) nvpair_value_byte(nvp, &proto);
1839 1834
1840 1835 res = nvlist_lookup_byte(old, nme, &oproto);
1841 1836 if (res == 0) {
1842 1837 diff = (proto != oproto);
1843 1838 } else {
1844 1839 diff = (proto != 0);
1845 1840 }
1846 1841 break;
1847 1842 }
1848 1843 /* port */
1849 1844 case IPQOS_DATA_TYPE_PORT: {
1850 1845 uint16_t port;
1851 1846 uint16_t oport;
1852 1847
1853 1848 (void) nvpair_value_uint16(nvp, &port);
1854 1849 res = nvlist_lookup_uint16(old, nme, &oport);
1855 1850 if (res == 0) {
1856 1851 diff = (port != oport);
1857 1852 } else {
1858 1853 diff = (port != 0);
1859 1854 }
1860 1855 break;
1861 1856 }
1862 1857 /* action name / string */
1863 1858 case IPQOS_DATA_TYPE_ACTION:
1864 1859 case IPQOS_DATA_TYPE_STRING: {
1865 1860 char *str;
1866 1861 char *ostr;
1867 1862
1868 1863 (void) nvpair_value_string(nvp, &str);
1869 1864 res = nvlist_lookup_string(old, nme, &ostr);
1870 1865 if (res == 0) {
1871 1866 diff = strcmp(str, ostr);
1872 1867 } else if (*dfltst) {
1873 1868 diff = strcmp(str, dfltst);
1874 1869 }
1875 1870 break;
1876 1871 }
1877 1872 /* address mask / address */
1878 1873 case IPQOS_DATA_TYPE_ADDRESS_MASK:
1879 1874 case IPQOS_DATA_TYPE_ADDRESS: {
1880 1875 in6_addr_t *in6;
1881 1876 in6_addr_t *oin6;
1882 1877 uint_t x;
1883 1878
1884 1879 /*
1885 1880 * all addresses are stored as v6 addresses, so
1886 1881 * a uint32_t[4] array is used.
1887 1882 */
1888 1883
1889 1884 /* lookup new value */
1890 1885
1891 1886 (void) nvpair_value_uint32_array(nvp,
1892 1887 (uint32_t **)&in6, &x);
1893 1888
1894 1889 /* see if there's an old value and diff it */
1895 1890
1896 1891 res = nvlist_lookup_uint32_array(old, nme,
1897 1892 (uint32_t **)&oin6, &x);
1898 1893 if (res == 0) {
1899 1894 /* diff each of the 16 v6 address bytes */
1900 1895
1901 1896 for (x = 0; x < 16; x++) {
1902 1897 if (in6->s6_addr[x] !=
1903 1898 oin6->s6_addr[x]) {
1904 1899 diff++;
1905 1900 break;
1906 1901 }
1907 1902 }
1908 1903 }
1909 1904 break;
1910 1905 }
1911 1906 /* boolean */
1912 1907 case IPQOS_DATA_TYPE_BOOLEAN: {
1913 1908 boolean_t bl;
1914 1909 boolean_t obl;
1915 1910
1916 1911 (void) nvpair_value_uint32(nvp, (uint32_t *)&bl);
1917 1912
1918 1913 /* see if there's an old value and diff it */
1919 1914 res = nvlist_lookup_uint32(old, nme, (uint32_t *)&obl);
1920 1915 if (res == 0) {
1921 1916 diff = (bl != obl);
1922 1917
1923 1918 /* compare against default if present */
1924 1919 } else if (*dfltst) {
1925 1920 res = readbool(dfltst, &obl);
1926 1921 if (res == IPQOS_CONF_SUCCESS) {
1927 1922 diff = (bl != obl);
1928 1923 }
1929 1924 }
1930 1925 break;
1931 1926 }
1932 1927 /* uint 8 */
1933 1928 case IPQOS_DATA_TYPE_UINT8: {
1934 1929 uint8_t u8;
1935 1930 uint8_t ou8;
1936 1931
1937 1932 (void) nvpair_value_byte(nvp, (uchar_t *)&u8);
1938 1933 res = nvlist_lookup_byte(old, nme, (uchar_t *)&ou8);
1939 1934 if (res == 0) {
1940 1935 diff = (u8 != ou8);
1941 1936 } else if (*dfltst) {
1942 1937 res = readuint8(dfltst, &ou8, &lo);
1943 1938 if (res == IPQOS_CONF_SUCCESS) {
1944 1939 diff = (u8 != ou8);
1945 1940 }
1946 1941 }
1947 1942 break;
1948 1943 }
1949 1944 /* int 16 */
1950 1945 case IPQOS_DATA_TYPE_INT16: {
1951 1946 int16_t i16;
1952 1947 int16_t oi16;
1953 1948
1954 1949 (void) nvpair_value_int16(nvp, &i16);
1955 1950 res = nvlist_lookup_int16(old, nme, &oi16);
1956 1951 if (res == 0) {
1957 1952 diff = (i16 != oi16);
1958 1953 } else if (*dfltst) {
1959 1954 res = readint16(dfltst, &oi16, &lo);
1960 1955 if (res == IPQOS_CONF_SUCCESS) {
1961 1956 diff = (i16 != oi16);
1962 1957 }
1963 1958 }
1964 1959 break;
1965 1960 }
1966 1961 /* uint16 */
1967 1962 case IPQOS_DATA_TYPE_UINT16: {
1968 1963 uint16_t ui16;
1969 1964 uint16_t oui16;
1970 1965
1971 1966 (void) nvpair_value_uint16(nvp, &ui16);
1972 1967 res = nvlist_lookup_uint16(old, nme, &oui16);
1973 1968 if (res == 0) {
1974 1969 diff = (ui16 != oui16);
1975 1970 } else if (*dfltst) {
1976 1971 res = readuint16(dfltst, &oui16, &lo);
1977 1972 if (res == IPQOS_CONF_SUCCESS) {
1978 1973 diff = (ui16 != oui16);
1979 1974 }
1980 1975 }
1981 1976 break;
1982 1977 }
1983 1978 /*
1984 1979 * int32 and user.
1985 1980 * Since user uids are stored in an int32 nvpair we can use
1986 1981 * the same comparison code.
1987 1982 */
1988 1983 case IPQOS_DATA_TYPE_USER:
1989 1984 case IPQOS_DATA_TYPE_INT32: {
1990 1985 int32_t i32;
1991 1986 int32_t oi32;
1992 1987
1993 1988 (void) nvpair_value_int32(nvp, &i32);
1994 1989 res = nvlist_lookup_int32(old, nme, &oi32);
1995 1990 if (res == 0) {
1996 1991 diff = (i32 != oi32);
1997 1992 } else if (*dfltst) {
1998 1993 res = readint32(dfltst, &oi32, &lo);
1999 1994 if (res == IPQOS_CONF_SUCCESS) {
2000 1995 diff = (i32 != oi32);
2001 1996 }
2002 1997 }
2003 1998 break;
2004 1999 }
2005 2000 /* uint32 */
2006 2001 case IPQOS_DATA_TYPE_UINT32: {
2007 2002 uint32_t ui32;
2008 2003 uint32_t oui32;
2009 2004
2010 2005 (void) nvpair_value_uint32(nvp, &ui32);
2011 2006 res = nvlist_lookup_uint32(old, nme, &oui32);
2012 2007 if (res == 0) {
2013 2008 diff = (ui32 != oui32);
2014 2009 } else if (*dfltst) {
2015 2010 res = readuint32(dfltst, &oui32, &lo);
2016 2011 if (res == IPQOS_CONF_SUCCESS) {
2017 2012 diff = (ui32 != oui32);
2018 2013 }
2019 2014 }
2020 2015 break;
2021 2016 }
2022 2017 /* enumeration */
2023 2018 case IPQOS_DATA_TYPE_ENUM: {
2024 2019 uint32_t eval;
2025 2020 uint32_t oeval;
2026 2021
2027 2022 (void) nvpair_value_uint32(nvp, &eval);
2028 2023 res = nvlist_lookup_uint32(old, nme, &oeval);
2029 2024 if (res == 0) {
2030 2025 diff = (eval != oeval);
2031 2026 } else if (*dfltst) {
2032 2027 res = readuint32(dfltst, &oeval, &lo);
2033 2028 if (res == IPQOS_CONF_SUCCESS) {
2034 2029 diff = (eval != oeval);
2035 2030 }
2036 2031 }
2037 2032 break;
2038 2033 }
2039 2034 case IPQOS_DATA_TYPE_M_INDEX: {
2040 2035 uint8_t idx, oidx;
2041 2036
2042 2037 (void) nvpair_value_byte(nvp, &idx);
2043 2038 res = nvlist_lookup_byte(old, nme, &oidx);
2044 2039 if (res == 0)
2045 2040 diff = (idx != oidx);
2046 2041 break;
2047 2042 }
2048 2043 case IPQOS_DATA_TYPE_INT_ARRAY: {
2049 2044 int *oarr, *arr;
2050 2045 uint32_t osize, size;
2051 2046
2052 2047 (void) nvpair_value_int32_array(nvp, &arr, &size);
2053 2048 res = nvlist_lookup_int32_array(old, nme, &oarr,
2054 2049 &osize);
2055 2050 if (res == 0)
2056 2051 diff = (arrays_equal(arr, oarr, size) ==
2057 2052 B_FALSE);
2058 2053 break;
2059 2054 }
2060 2055 #ifdef _IPQOS_CONF_DEBUG
2061 2056 default: {
2062 2057 /* shouldn't get here as all types should be covered */
2063 2058 assert(1);
2064 2059 }
2065 2060 #endif
2066 2061 } /* switch */
2067 2062 if (diff != 0) {
2068 2063 IPQOSCDBG1(DIFF, "parameter %s different\n", nme);
2069 2064 *pdiff = 1;
2070 2065 (void) fclose(tfp);
2071 2066 return (IPQOS_CONF_SUCCESS);
2072 2067 }
2073 2068
2074 2069
2075 2070 nvp = nvlist_next_nvpair(new, nvp);
2076 2071
2077 2072 }
2078 2073
2079 2074 /* now compare all the stuff in the second list with the first */
2080 2075 if (first_pass) {
2081 2076 tmp = old;
2082 2077 old = new;
2083 2078 new = tmp;
2084 2079 first_pass = 0;
2085 2080 goto start;
2086 2081 }
2087 2082
2088 2083 (void) fclose(tfp);
2089 2084
2090 2085 *pdiff = 0;
2091 2086 return (IPQOS_CONF_SUCCESS);
2092 2087 }
2093 2088
2094 2089
2095 2090
2096 2091 /* ************************** difference application *********************** */
2097 2092
2098 2093
2099 2094
2100 2095 /*
2101 2096 * causes all items marked as requiring change in actions and old_actions
2102 2097 * to have the change applied.
2103 2098 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
2104 2099 */
2105 2100 static int
2106 2101 applydiff(
2107 2102 ipqos_conf_action_t *actions,
2108 2103 ipqos_conf_action_t *old_actions)
2109 2104 {
2110 2105
2111 2106 int res;
2112 2107
2113 2108 IPQOSCDBG0(L1, "In applydiff:\n");
2114 2109
2115 2110
2116 2111 /* add each item marked as new */
2117 2112
2118 2113 res = add_items(actions, B_FALSE);
2119 2114 if (res != IPQOS_CONF_SUCCESS) {
2120 2115 return (res);
2121 2116 }
2122 2117
2123 2118 /* modify items marked for modification */
2124 2119
2125 2120 res = modify_items(actions);
2126 2121 if (res != IPQOS_CONF_SUCCESS) {
2127 2122 return (res);
2128 2123 }
2129 2124
2130 2125 /* delete items marked for deletion */
2131 2126
2132 2127 res = remove_items(old_actions, B_FALSE);
2133 2128 if (res != IPQOS_CONF_SUCCESS) {
2134 2129 return (res);
2135 2130 }
2136 2131
2137 2132 return (IPQOS_CONF_SUCCESS);
2138 2133 }
2139 2134
2140 2135 static int
2141 2136 add_items(
2142 2137 ipqos_conf_action_t *actions,
2143 2138 boolean_t rem_undo)
2144 2139 {
2145 2140
2146 2141 int res;
2147 2142 ipqos_conf_action_t *act;
2148 2143
2149 2144 IPQOSCDBG1(L1, "In add_items, rem_undo: %u\n", rem_undo);
2150 2145
2151 2146 /*
2152 2147 * we need to create ipgpc action before any others as some actions
2153 2148 * such as ftpcl which make calls to it depend on it being there on
2154 2149 * their creation.
2155 2150 */
2156 2151 act = actionexist(IPGPC_CLASSIFY, actions);
2157 2152 if (act &&
2158 2153 (rem_undo == B_FALSE && act->new == B_TRUE ||
2159 2154 rem_undo == B_TRUE && act->deleted == B_TRUE)) {
2160 2155
2161 2156 res = add_action(act);
2162 2157 if (res != IPQOS_CONF_SUCCESS) {
2163 2158 return (res);
2164 2159 }
2165 2160 }
2166 2161
2167 2162 /*
2168 2163 * loop though action list and add any actions marked as
2169 2164 * new/modified action and apply any additions there, then return.
2170 2165 */
2171 2166
2172 2167 for (act = actions; act; act = act->next) {
2173 2168 res = add_item(act, rem_undo);
2174 2169 if (res != IPQOS_CONF_SUCCESS) {
2175 2170 return (IPQOS_CONF_ERR);
2176 2171 }
2177 2172 }
2178 2173
2179 2174 return (IPQOS_CONF_SUCCESS);
2180 2175 }
2181 2176
2182 2177
2183 2178 /*
2184 2179 *
2185 2180 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
2186 2181 */
2187 2182 static int
2188 2183 add_item(
2189 2184 ipqos_conf_action_t *actions,
2190 2185 boolean_t rem_undo)
2191 2186 {
2192 2187
2193 2188 ipqos_conf_action_t *act = actions;
2194 2189 int res;
2195 2190 ipqos_conf_class_t *cls;
2196 2191 ipqos_conf_act_ref_t *pact;
2197 2192
2198 2193 IPQOSCDBG2(L1, "In add_item: action: %s, rem_undo: %u\n",
2199 2194 actions->name, rem_undo);
2200 2195
2201 2196 /* if already visited return immediately */
2202 2197
2203 2198 if (act->visited == ADD_VISITED) {
2204 2199 IPQOSCDBG0(L1, "Early exit due to visited\n");
2205 2200 return (IPQOS_CONF_SUCCESS);
2206 2201 }
2207 2202 act->visited = ADD_VISITED;
2208 2203
2209 2204
2210 2205 /* recurse to last action in tree */
2211 2206
2212 2207 for (cls = act->classes; cls; cls = cls->next) {
2213 2208
2214 2209 /* if not virtual action */
2215 2210
2216 2211 if (cls->alist->action) {
2217 2212 res = add_item(cls->alist->action, rem_undo);
2218 2213 if (res != IPQOS_CONF_SUCCESS) {
2219 2214 return (res);
2220 2215 }
2221 2216 }
2222 2217 }
2223 2218
2224 2219 for (pact = act->params->actions; pact; pact = pact->next) {
2225 2220
2226 2221 /* if not virtual */
2227 2222
2228 2223 if (pact->action) {
2229 2224 res = add_item(pact->action, rem_undo);
2230 2225 if (res != IPQOS_CONF_SUCCESS) {
2231 2226 return (res);
2232 2227 }
2233 2228 }
2234 2229 }
2235 2230
2236 2231
2237 2232 /* if action marked as new and not ipgpc, create */
2238 2233
2239 2234 if (((rem_undo == B_FALSE && act->new == B_TRUE) ||
2240 2235 (rem_undo == B_TRUE && act->deleted == B_TRUE)) &&
2241 2236 strcmp(act->name, IPGPC_CLASSIFY) != 0) {
2242 2237 res = add_action(act);
2243 2238 if (res != IPQOS_CONF_SUCCESS) {
2244 2239 return (res);
2245 2240 }
2246 2241 }
2247 2242
2248 2243 /* add any classes and filters marked as new */
2249 2244
2250 2245 if (add_classes(act->classes, act->name, act->module_version,
2251 2246 rem_undo) != IPQOS_CONF_SUCCESS ||
2252 2247 add_filters(act->filters, act->name, act->module_version,
2253 2248 rem_undo) != IPQOS_CONF_SUCCESS) {
2254 2249 return (IPQOS_CONF_ERR);
2255 2250 }
2256 2251
2257 2252 return (IPQOS_CONF_SUCCESS);
2258 2253 }
2259 2254
2260 2255
2261 2256 /*
2262 2257 * Uses the contents of acts params nvlist and adds an originator
2263 2258 * element set to ipqosconf and the stats parameter. This list
2264 2259 * is then used as the parameter to a call to ipp_action_create to create
2265 2260 * this action in the kernel.
2266 2261 * RETURNS: IPQOS_CONF_ERR on err, else IPQOS_CONF_SUCCESS.
2267 2262 */
2268 2263 static int
2269 2264 add_action(ipqos_conf_action_t *act)
2270 2265 {
2271 2266
2272 2267 int res;
2273 2268 nvlist_t **nvl;
2274 2269
2275 2270 IPQOSCDBG2(APPLY, "add_action: action: %s, module: %s\n", act->name,
2276 2271 act->module);
2277 2272
2278 2273 nvl = &act->params->nvlist;
2279 2274
2280 2275 /* alloc params nvlist if not already one */
2281 2276
2282 2277 if (*nvl == NULL) {
2283 2278 res = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
2284 2279 if (res != 0) {
2285 2280 ipqos_msg(MT_ENOSTR, "nvlist_alloc");
2286 2281 return (IPQOS_CONF_ERR);
2287 2282 }
2288 2283 }
2289 2284
2290 2285 /*
2291 2286 * add module version
2292 2287 */
2293 2288 if (nvlist_add_uint32(*nvl, IPP_MODULE_VERSION,
2294 2289 (uint32_t)act->module_version) != 0) {
2295 2290 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
2296 2291 return (IPQOS_CONF_ERR);
2297 2292 }
2298 2293
2299 2294 /* add action stats */
2300 2295
2301 2296 if (nvlist_add_uint32(*nvl, IPP_ACTION_STATS_ENABLE,
2302 2297 (uint32_t)act->params->stats_enable) != 0) {
2303 2298 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32: action stats");
2304 2299 return (IPQOS_CONF_ERR);
2305 2300 }
2306 2301
2307 2302 /* add ipqosconf originator id */
2308 2303
2309 2304 if (add_orig_ipqosconf(*nvl) != IPQOS_CONF_SUCCESS) {
2310 2305 return (IPQOS_CONF_ERR);
2311 2306 }
2312 2307
2313 2308 /* call into lib to create action */
2314 2309
2315 2310 res = ipp_action_create(act->module, act->name, nvl, 0);
2316 2311 if (res != 0) {
2317 2312 IPQOSCDBG2(APPLY, "Create action %s, module %s failed\n",
2318 2313 act->name, act->module);
2319 2314
2320 2315 /* invalid params */
2321 2316
2322 2317 if (errno == EINVAL) {
2323 2318 ipqos_msg(MT_ERROR,
2324 2319 gettext("Invalid Parameters for action %s.\n"),
2325 2320 act->name);
2326 2321
2327 2322 } else if (errno == ENOENT) {
2328 2323 ipqos_msg(MT_ERROR,
2329 2324 gettext("Missing required parameter for action "
2330 2325 "%s.\n"), act->name);
2331 2326
2332 2327 } else { /* unexpected error */
2333 2328 ipqos_msg(MT_ERROR, gettext("Failed to create action "
2334 2329 "%s: %s.\n"), act->name, strerror(errno));
2335 2330 }
2336 2331
2337 2332 return (IPQOS_CONF_ERR);
2338 2333 }
2339 2334
2340 2335 /* mark action as created */
2341 2336 act->cr_mod = B_TRUE;
2342 2337
2343 2338 return (IPQOS_CONF_SUCCESS);
2344 2339 }
2345 2340
2346 2341 /*
2347 2342 * for each of the filters in parameter filters if rem_undo is false and
2348 2343 * the filter is marked as new or if rem_undo is true and the filter is
2349 2344 * marked as deleted then add the filter to the kernel action named by action
2350 2345 * and if successful mark as created.
2351 2346 * RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
2352 2347 */
2353 2348 static int
2354 2349 add_filters(
2355 2350 ipqos_conf_filter_t *filters,
2356 2351 char *action,
2357 2352 int module_version,
2358 2353 boolean_t rem_undo)
2359 2354 {
2360 2355
2361 2356 ipqos_conf_filter_t *flt;
2362 2357
2363 2358 IPQOSCDBG0(L1, "In add_filters\n");
2364 2359
2365 2360 /* loop through filters in filters param */
2366 2361 for (flt = filters; flt; flt = flt->next) {
2367 2362 /*
2368 2363 * skip filter if in normal mode and not new filter or
2369 2364 * if doing rollback and filter wasn't previously deleted.
2370 2365 */
2371 2366 if ((rem_undo == B_FALSE && flt->new == B_FALSE) ||
2372 2367 (rem_undo == B_TRUE && flt->deleted == B_FALSE)) {
2373 2368 continue;
2374 2369 }
2375 2370
2376 2371 /* add filter to action */
2377 2372 if (add_filter(action, flt, module_version) !=
2378 2373 IPQOS_CONF_SUCCESS) {
2379 2374 return (IPQOS_CONF_ERR);
2380 2375 }
2381 2376
2382 2377 /* mark as created */
2383 2378 flt->cr_mod = B_TRUE;
2384 2379 }
2385 2380
2386 2381 return (IPQOS_CONF_SUCCESS);
2387 2382 }
2388 2383
2389 2384 /*
2390 2385 * for each of the classes in parameter classes if rem_undo is false and
2391 2386 * the class is marked as new or if rem_undo is true and the class is
2392 2387 * marked as deleted then add the class to the kernel action named by action
2393 2388 * and if successful mark as created.
2394 2389 * RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
2395 2390 */
2396 2391 int
2397 2392 add_classes(
2398 2393 ipqos_conf_class_t *classes,
2399 2394 char *action,
2400 2395 int module_version,
2401 2396 boolean_t rem_undo) {
2402 2397
2403 2398 int res;
2404 2399 ipqos_conf_class_t *cls;
2405 2400
2406 2401 IPQOSCDBG0(L1, "In add_classes\n");
2407 2402
2408 2403 /* for each class */
2409 2404 for (cls = classes; cls; cls = cls->next) {
2410 2405 /*
2411 2406 * skip class if in normal mode and not new class or
2412 2407 * if doing rollback and class wasn't deleted.
2413 2408 */
2414 2409 if ((rem_undo == B_FALSE && cls->new == B_FALSE) ||
2415 2410 (rem_undo == B_TRUE && cls->deleted == B_FALSE)) {
2416 2411 continue;
2417 2412 }
2418 2413
2419 2414 /* add class to action */
2420 2415 res = add_class(action, cls->name, module_version,
2421 2416 cls->stats_enable, cls->alist->name);
2422 2417 if (res != IPQOS_CONF_SUCCESS) {
2423 2418 return (IPQOS_CONF_ERR);
2424 2419 }
2425 2420
2426 2421 /* mark class as created */
2427 2422 cls->cr_mod = B_TRUE;
2428 2423 }
2429 2424
2430 2425 return (IPQOS_CONF_SUCCESS);
2431 2426 }
2432 2427
2433 2428 /*
2434 2429 * For each of the actions in actions remove the action if marked as
2435 2430 * such or remove any objects within marked as such.
2436 2431 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
2437 2432 */
2438 2433 static int
2439 2434 remove_items(
2440 2435 ipqos_conf_action_t *actions,
2441 2436 boolean_t add_undo)
2442 2437 {
2443 2438
2444 2439 int res;
2445 2440 ipqos_conf_action_t *act;
2446 2441
2447 2442 IPQOSCDBG1(L0, "In remove_items, add_undo: %u\n", add_undo);
2448 2443
2449 2444 /*
2450 2445 * loop through actions removing any actions, or action contents
2451 2446 * that are marked as such.
2452 2447 */
2453 2448 for (act = actions; act; act = act->next) {
2454 2449 res = remove_item(act, add_undo);
2455 2450 if (res != IPQOS_CONF_SUCCESS) {
2456 2451 return (res);
2457 2452 }
2458 2453 }
2459 2454
2460 2455 return (IPQOS_CONF_SUCCESS);
2461 2456 }
2462 2457
2463 2458 /*
2464 2459 * Deletes this action if marked for deletion or any of it's contents marked
2465 2460 * for deletion. If the action is marked for deletion any actions referencing
2466 2461 * this action are destroyed first if marked or have their contents destroyed
2467 2462 * if marked. This is recursive.
2468 2463 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
2469 2464 */
2470 2465 static int
2471 2466 remove_item(
2472 2467 ipqos_conf_action_t *act,
2473 2468 boolean_t add_undo)
2474 2469 {
2475 2470
2476 2471 ipqos_conf_class_t *cls;
2477 2472 ipqos_conf_filter_t *flt;
2478 2473 ipqos_conf_act_ref_t *dep;
2479 2474 int res;
2480 2475
2481 2476 IPQOSCDBG3(L1, "In remove_item: action: %s, add_undo: %u, mod: %u\n",
2482 2477 act->name, add_undo, act->modified);
2483 2478
2484 2479
2485 2480 /* return immmediately if previously visited in remove phase */
2486 2481
2487 2482 if (act->visited == REM_VISITED) {
2488 2483 IPQOSCDBG0(L1, "Exit due to REM_VISITED set\n");
2489 2484 return (IPQOS_CONF_SUCCESS);
2490 2485 }
2491 2486 act->visited = REM_VISITED;
2492 2487
2493 2488
2494 2489 /* if this action is to be deleted */
2495 2490
2496 2491 if (add_undo == B_FALSE && act->todel == B_TRUE ||
2497 2492 add_undo == B_TRUE && act->new == B_TRUE &&
2498 2493 act->cr_mod == B_TRUE) {
2499 2494
2500 2495 /* modify parent actions first */
2501 2496
2502 2497 for (dep = act->dependencies; dep; dep = dep->next) {
2503 2498 res = remove_item(dep->action, add_undo);
2504 2499 if (res != IPQOS_CONF_SUCCESS) {
2505 2500 return (res);
2506 2501 }
2507 2502 }
2508 2503
2509 2504 /* delete this action */
2510 2505
2511 2506 IPQOSCDBG1(APPLY, "deleting action %s\n", act->name);
2512 2507 res = ipp_action_destroy(act->name, 0);
2513 2508 if (res != 0) {
2514 2509 IPQOSCDBG1(APPLY, "failed to destroy action %s\n",
2515 2510 act->name);
2516 2511 return (IPQOS_CONF_ERR);
2517 2512 }
2518 2513
2519 2514 /* flag as deleted */
2520 2515
2521 2516 act->deleted = B_TRUE;
2522 2517
2523 2518 /* if modified action */
2524 2519
2525 2520 } else if (act->modified == B_TRUE) {
2526 2521
2527 2522 /* loop through removing any filters marked for del */
2528 2523
2529 2524 for (flt = act->filters; flt; flt = flt->next) {
2530 2525 if ((add_undo == B_FALSE && flt->todel == B_TRUE) ||
2531 2526 (add_undo == B_TRUE && flt->new == B_TRUE &&
2532 2527 flt->cr_mod == B_TRUE)) {
2533 2528
2534 2529 /* do deletion */
2535 2530
2536 2531 res = remove_filter(act->name, flt->name,
2537 2532 flt->instance, act->module_version);
2538 2533 if (res != IPQOS_CONF_SUCCESS) {
2539 2534 IPQOSCDBG2(APPLY, "failed to destroy "
2540 2535 "filter %s, inst: %d\n", flt->name,
2541 2536 flt->instance);
2542 2537
2543 2538 return (IPQOS_CONF_ERR);
2544 2539 }
2545 2540
2546 2541 /* flag deleted */
2547 2542
2548 2543 flt->deleted = B_TRUE;
2549 2544 }
2550 2545 }
2551 2546
2552 2547 /* remove any classes marked for del */
2553 2548
2554 2549 for (cls = act->classes; cls; cls = cls->next) {
2555 2550 if ((add_undo == B_FALSE && cls->todel == B_TRUE) ||
2556 2551 (add_undo == B_TRUE && cls->new == B_TRUE &&
2557 2552 cls->cr_mod == B_TRUE)) {
2558 2553
2559 2554 /* do deletion */
2560 2555
2561 2556 res = remove_class(act->name, cls->name,
2562 2557 act->module_version, 0);
2563 2558 if (res != IPQOS_CONF_SUCCESS) {
2564 2559 IPQOSCDBG1(APPLY, "failed to destroy "
2565 2560 "class %s\n", cls->name);
2566 2561
2567 2562 return (IPQOS_CONF_ERR);
2568 2563 }
2569 2564
2570 2565 /* flag deleted */
2571 2566
2572 2567 cls->deleted = B_TRUE;
2573 2568 }
2574 2569 }
2575 2570
2576 2571 /* mark action as having been modified */
2577 2572
2578 2573 act->cr_mod = B_TRUE;
2579 2574 }
2580 2575
2581 2576 return (IPQOS_CONF_SUCCESS);
2582 2577 }
2583 2578
2584 2579 /*
2585 2580 * for each of the actions in parameter actions apply any objects marked as
2586 2581 * modified as a modification to the kernel action represented.
2587 2582 * RETURNS: IPQOS_CONF_ERR on err, else IPQOS_CONF_SUCCESS.
2588 2583 */
2589 2584 static int
2590 2585 modify_items(ipqos_conf_action_t *actions)
2591 2586 {
2592 2587
2593 2588 ipqos_conf_action_t *act;
2594 2589 int res;
2595 2590 ipqos_conf_filter_t *flt;
2596 2591 ipqos_conf_class_t *cls;
2597 2592
2598 2593
2599 2594 IPQOSCDBG0(L1, "In modify_items\n");
2600 2595
2601 2596 /* loop through actions in parameter actions */
2602 2597
2603 2598 for (act = actions; act; act = act->next) {
2604 2599
2605 2600 /* skip unchanged actions */
2606 2601
2607 2602 if (act->modified == B_FALSE) {
2608 2603 continue;
2609 2604 }
2610 2605
2611 2606 /* apply any parameter mods */
2612 2607
2613 2608 if (act->params->modified) {
2614 2609 res = modify_params(act->name,
2615 2610 &act->params->nvlist,
2616 2611 act->module_version, act->params->stats_enable);
2617 2612 if (res != IPQOS_CONF_SUCCESS) {
2618 2613 return (IPQOS_CONF_ERR);
2619 2614 }
2620 2615
2621 2616 act->params->cr_mod = B_TRUE;
2622 2617 }
2623 2618
2624 2619 /* apply any class mods */
2625 2620
2626 2621 for (cls = act->classes; cls; cls = cls->next) {
2627 2622 if (cls->modified) {
2628 2623 res = modify_class(act->name, cls->name,
2629 2624 act->module_version, cls->stats_enable,
2630 2625 cls->alist->name, 0);
2631 2626 if (res != IPQOS_CONF_SUCCESS) {
2632 2627 return (IPQOS_CONF_ERR);
2633 2628 }
2634 2629
2635 2630 /* mark modification done */
2636 2631 cls->cr_mod = B_TRUE;
2637 2632 }
2638 2633 }
2639 2634
2640 2635 /* apply any filter mods */
2641 2636
2642 2637 for (flt = act->filters; flt; flt = flt->next) {
2643 2638 if (flt->modified) {
2644 2639 res = modify_filter(act->name, flt,
2645 2640 act->module_version);
2646 2641 if (res != 0) {
2647 2642 return (IPQOS_CONF_ERR);
2648 2643 }
2649 2644
2650 2645 /* mark modification done */
2651 2646 flt->cr_mod = B_TRUE;
2652 2647 }
2653 2648 }
2654 2649
2655 2650 /* mark action modified */
2656 2651
2657 2652 act->cr_mod = B_TRUE;
2658 2653 }
2659 2654
2660 2655 return (IPQOS_CONF_SUCCESS);
2661 2656 }
2662 2657
2663 2658 /*
2664 2659 * For each of the objects of each of the actions in nactions that are
2665 2660 * marked as having been modified the object modification is done in
2666 2661 * reverse using the same named object from oactions.
2667 2662 * RETURNS: IPQOS_CONF_ERR on error, IPQOS_CONF_SUCCESS otherwise.
2668 2663 */
2669 2664 static int
2670 2665 undo_modifys(
2671 2666 ipqos_conf_action_t *oactions,
2672 2667 ipqos_conf_action_t *nactions)
2673 2668 {
2674 2669
2675 2670 ipqos_conf_filter_t *flt;
2676 2671 ipqos_conf_class_t *cls;
2677 2672 ipqos_conf_action_t *act;
2678 2673 ipqos_conf_action_t *oldact;
2679 2674 ipqos_conf_filter_t *oldflt;
2680 2675 ipqos_conf_class_t *oldcls;
2681 2676 int res;
2682 2677
2683 2678 IPQOSCDBG0(L1, "In undo_modifys:\n");
2684 2679
2685 2680 /* loop throught new actions */
2686 2681
2687 2682 for (act = nactions; act; act = act->next) {
2688 2683 oldact = actionexist(act->name, oactions);
2689 2684
2690 2685 /*
2691 2686 * if the action was new then it will be removed and
2692 2687 * any permamanent items that were marked for modify
2693 2688 * will dissappear, so ignore action.
2694 2689 */
2695 2690 if (oldact == NULL) {
2696 2691 continue;
2697 2692 }
2698 2693
2699 2694 /* if parameters were modified switch them back */
2700 2695
2701 2696 if (act->params->modified == B_TRUE &&
2702 2697 act->params->cr_mod == B_TRUE) {
2703 2698 res = modify_params(act->name,
2704 2699 &oldact->params->nvlist,
2705 2700 act->module_version, act->params->stats_enable);
2706 2701 if (res != IPQOS_CONF_SUCCESS) {
2707 2702 return (res);
2708 2703 }
2709 2704 }
2710 2705
2711 2706 /* for each filter in action if filter modified switch back */
2712 2707
2713 2708 for (flt = act->filters; flt; flt = flt->next) {
2714 2709 if (flt->modified == B_TRUE &&
2715 2710 flt->cr_mod == B_TRUE) {
2716 2711 oldflt = filterexist(flt->name, -1,
2717 2712 oldact->filters);
2718 2713 res = modify_filter(act->name, oldflt,
2719 2714 act->module_version);
2720 2715 if (res != IPQOS_CONF_SUCCESS) {
2721 2716 return (res);
2722 2717 }
2723 2718 }
2724 2719 }
2725 2720
2726 2721 /* for each class in action if class modified switch back */
2727 2722
2728 2723 for (cls = act->classes; cls; cls = cls->next) {
2729 2724 if (cls->modified == B_TRUE &&
2730 2725 cls->cr_mod == B_TRUE) {
2731 2726 oldcls = classexist(cls->name, oldact->classes);
2732 2727 if (oldcls->alist) {
2733 2728 res = modify_class(act->name,
2734 2729 cls->name, act->module_version,
2735 2730 oldcls->stats_enable,
2736 2731 oldcls->alist->name, 0);
2737 2732 }
2738 2733 if (res != IPQOS_CONF_SUCCESS) {
2739 2734 return (res);
2740 2735 }
2741 2736 }
2742 2737 }
2743 2738 }
2744 2739
2745 2740 /*
2746 2741 * Go through the old actions modifying perm filters and classes
2747 2742 * whose action was deleted.
2748 2743 *
2749 2744 */
2750 2745 for (act = oactions; act != NULL; act = act->next) {
2751 2746
2752 2747 if (act->deleted == B_FALSE) {
2753 2748 continue;
2754 2749 }
2755 2750
2756 2751 for (flt = act->filters; flt != NULL; flt = flt->next) {
2757 2752 if (flt->originator == IPP_CONFIG_PERMANENT) {
2758 2753 res = modify_filter(act->name, flt,
2759 2754 act->module_version);
2760 2755 if (res != IPQOS_CONF_SUCCESS) {
2761 2756 return (res);
2762 2757 }
2763 2758 }
2764 2759 }
2765 2760
2766 2761 for (cls = act->classes; cls != NULL; cls = cls->next) {
2767 2762 if (cls->originator == IPP_CONFIG_PERMANENT) {
2768 2763 res = modify_class(act->name, cls->name,
2769 2764 act->module_version, cls->stats_enable,
2770 2765 cls->alist->name, 0);
2771 2766 if (res != IPQOS_CONF_SUCCESS) {
2772 2767 return (res);
2773 2768 }
2774 2769 }
2775 2770
2776 2771 }
2777 2772 }
2778 2773
2779 2774 return (IPQOS_CONF_SUCCESS);
2780 2775 }
2781 2776
2782 2777
2783 2778 /*
2784 2779 * causes all changes marked as being done in actions and old_actions
2785 2780 * to be undone.
2786 2781 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
2787 2782 */
2788 2783 static int
2789 2784 rollback(
2790 2785 ipqos_conf_action_t *actions,
2791 2786 ipqos_conf_action_t *old_actions)
2792 2787 {
2793 2788
2794 2789 int res;
2795 2790
2796 2791 IPQOSCDBG0(RBK, "In rollback:\n");
2797 2792
2798 2793 /* re-add items that were deleted */
2799 2794
2800 2795 res = add_items(old_actions, B_TRUE);
2801 2796 if (res != IPQOS_CONF_SUCCESS) {
2802 2797 return (res);
2803 2798 }
2804 2799
2805 2800 /* change modified items back how they were */
2806 2801
2807 2802 res = undo_modifys(old_actions, actions);
2808 2803 if (res != IPQOS_CONF_SUCCESS) {
2809 2804 return (res);
2810 2805 }
2811 2806
2812 2807 /* remove new items that were added */
2813 2808
2814 2809 res = remove_items(actions, B_TRUE);
2815 2810 if (res != IPQOS_CONF_SUCCESS) {
2816 2811 return (res);
2817 2812 }
2818 2813
2819 2814 return (IPQOS_CONF_SUCCESS);
2820 2815 }
2821 2816
2822 2817 /* ******************************* print config **************************** */
2823 2818
2824 2819 /*
2825 2820 * Prints the username of the user with uid 'uid' to 'fp' if the uid belongs
2826 2821 * to a known user on the system, otherwise just print 'uid'.
2827 2822 */
2828 2823 static void
2829 2824 printuser(
2830 2825 FILE *fp,
2831 2826 uid_t uid)
2832 2827 {
2833 2828 struct passwd *pwd;
2834 2829
2835 2830 IPQOSCDBG0(L0, "In printuser\n");
2836 2831
2837 2832 pwd = getpwuid(uid);
2838 2833 if (pwd != NULL) {
2839 2834 (void) fprintf(fp, "%s\n", pwd->pw_name);
2840 2835 } else {
2841 2836 (void) fprintf(fp, "%u\n", (int)uid);
2842 2837 }
2843 2838 }
2844 2839
2845 2840 /*
2846 2841 * print either a single value of start to fp (if start equals end), else
2847 2842 * print start'-'end if start is the smaller of the two values, otherwise
2848 2843 * print end'-'start.
2849 2844 */
2850 2845 static void
2851 2846 printrange(
2852 2847 FILE *fp,
2853 2848 uint32_t start,
2854 2849 uint32_t end)
2855 2850 {
2856 2851 uint32_t tmp;
2857 2852
2858 2853 if (start > end) {
2859 2854 tmp = start;
2860 2855 start = end;
2861 2856 end = tmp;
2862 2857 }
2863 2858
2864 2859 (void) fprintf(fp, "%u", start);
2865 2860 if (end != start)
2866 2861 (void) fprintf(fp, "-%u", end);
2867 2862 }
2868 2863
2869 2864 /*
2870 2865 * print the contents of the array arr to fp in the form:
2871 2866 * {0-6:1;7-12:2;13:3.....} or {0-6:GREEN;7-12:YELLOW:...}
2872 2867 * dependant upon whether this is an integer or enumerated array resectively
2873 2868 * (if enum_nvs isn't set to NULL this is assumed to be an enumerated array);
2874 2869 * where 0-6 is the range of indexes with value 1 (or GREEN), 7-12 the range
2875 2870 * with value 2 (or YELLOW), and so forth. size is the array size and llimit
2876 2871 * and ulimit are the lower and upper limits of the array values printed
2877 2872 * respectively. For enumerated arrays enum_nvs carries the list of name
2878 2873 * and value pairs and ulimit and llimit parameters are ignored and instead
2879 2874 * determined from the enum_nvs list.
2880 2875 */
2881 2876 static void
2882 2877 print_int_array(
2883 2878 FILE *fp,
2884 2879 int arr[],
2885 2880 uint32_t size,
2886 2881 int llimit,
2887 2882 int ulimit,
2888 2883 str_val_nd_t *enum_nvs,
2889 2884 int tab_inserts)
2890 2885 {
2891 2886 int x, y;
2892 2887 uint32_t first, last;
2893 2888 boolean_t first_entry; /* first 'ranges:value' to be printed ? */
2894 2889 boolean_t first_range; /* first range for a value to be printed ? */
2895 2890 boolean_t found_range; /* did we find a range for this value ? */
2896 2891
2897 2892 IPQOSCDBG4(L0, "In print_int_array: size: %u, llimit: %u, ulimit: %u, "
2898 2893 "enum_nvs: %x \n", size, llimit, ulimit, enum_nvs);
2899 2894
2900 2895 /*
2901 2896 * if an enumeration retrieve value range.
2902 2897 */
2903 2898 if (enum_nvs != NULL)
2904 2899 get_str_val_value_range(enum_nvs, &llimit, &ulimit);
2905 2900
2906 2901 /*
2907 2902 * print opening curl.
2908 2903 */
2909 2904 (void) fprintf(fp, "%c\n", CURL_BEGIN);
2910 2905 PRINT_TABS(fp, tab_inserts + 1);
2911 2906
2912 2907 first_entry = B_TRUE;
2913 2908 /*
2914 2909 * for each value in range.
2915 2910 */
2916 2911 for (x = llimit; x <= ulimit; x++) {
2917 2912 found_range = B_FALSE;
2918 2913 first_range = B_TRUE;
2919 2914 y = 0;
2920 2915 /*
2921 2916 * scan array and print ranges of indexes with value x.
2922 2917 */
2923 2918 while (y < size) {
2924 2919 /*
2925 2920 * get first occurence of value for this range.
2926 2921 */
2927 2922 while ((arr[y] != x) && (y < size))
2928 2923 y++;
2929 2924 if (y == size) {
2930 2925 break;
2931 2926 } else {
2932 2927 found_range = B_TRUE;
2933 2928 }
2934 2929 first = y;
2935 2930
2936 2931 /*
2937 2932 * get last occurence of value for this range.
2938 2933 */
2939 2934 while ((arr[y] == x) && (y < size))
2940 2935 y++;
2941 2936 last = y - 1;
2942 2937
2943 2938 /*
2944 2939 * print entry delimiter (semi-colon)? It must be
2945 2940 * the first range for this value and this mustn't
2946 2941 * be the first 'ranges:value' entry.
2947 2942 */
2948 2943 if (!first_entry && first_range) {
2949 2944 (void) fprintf(fp, ";\n");
2950 2945 PRINT_TABS(fp, tab_inserts + 1);
2951 2946 } else {
2952 2947 first_entry = B_FALSE;
2953 2948 }
2954 2949
2955 2950 /*
2956 2951 * print comma (range delimeter) only if there was
2957 2952 * a previous range for this value.
2958 2953 */
2959 2954 if (!first_range) {
2960 2955 (void) fprintf(fp, ",");
2961 2956 } else {
2962 2957 first_range = B_FALSE;
2963 2958 }
2964 2959
2965 2960 /*
2966 2961 * print range.
2967 2962 */
2968 2963 printrange(fp, first, last);
2969 2964 }
2970 2965 /*
2971 2966 * only print a colon and value if we found a range with
2972 2967 * this value.
2973 2968 */
2974 2969 if (found_range) {
2975 2970 (void) fprintf(fp, ":");
2976 2971
2977 2972 /*
2978 2973 * print numeric/symbolic value.
2979 2974 */
2980 2975 if (enum_nvs) {
2981 2976 printenum(fp, x, enum_nvs);
2982 2977 } else {
2983 2978 (void) fprintf(fp, "%d", x);
2984 2979 }
2985 2980 }
2986 2981 }
2987 2982
2988 2983 /*
2989 2984 * print closing curl.
2990 2985 */
2991 2986 (void) fprintf(fp, "\n");
2992 2987 PRINT_TABS(fp, tab_inserts);
2993 2988 (void) fprintf(fp, "%c\n", CURL_END);
2994 2989 }
2995 2990
2996 2991 /* print the protocol name for proto, or if unknown protocol number proto. */
2997 2992 static void
2998 2993 printproto(
2999 2994 FILE *fp,
3000 2995 uint8_t proto)
3001 2996 {
3002 2997
3003 2998 struct protoent *pent;
3004 2999
3005 3000 pent = getprotobynumber(proto);
3006 3001 if (pent != NULL) {
3007 3002 (void) fprintf(fp, "%s\n", pent->p_name);
3008 3003 } else {
3009 3004 (void) fprintf(fp, "%u\n", proto);
3010 3005 }
3011 3006 }
3012 3007
3013 3008 /*
3014 3009 * prints the name associated with interface with index ifindex to fp.
3015 3010 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
3016 3011 */
3017 3012 static int
3018 3013 printifname(
3019 3014 FILE *fp,
3020 3015 int ifindex)
3021 3016 {
3022 3017
3023 3018 int s;
3024 3019 struct lifconf lc;
3025 3020 struct lifnum ln;
3026 3021 struct lifreq *lr;
3027 3022 char *buf;
3028 3023 int len;
3029 3024 char *cp;
3030 3025 int ret;
3031 3026 int x;
3032 3027 int idx;
3033 3028
3034 3029 /* open socket */
3035 3030
3036 3031 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
3037 3032 ipqos_msg(MT_ENOSTR, gettext("opening AF_INET socket"));
3038 3033 return (IPQOS_CONF_ERR);
3039 3034 }
3040 3035
3041 3036 /* get number of lifreq structs that need to be alloc'd for */
3042 3037
3043 3038 ln.lifn_family = AF_UNSPEC;
3044 3039 ln.lifn_flags = 0;
3045 3040 ret = ioctl(s, SIOCGLIFNUM, &ln);
3046 3041 if (ret < 0) {
3047 3042 ipqos_msg(MT_ENOSTR, "SIOCLIFNUM ioctl");
3048 3043 (void) close(s);
3049 3044 return (IPQOS_CONF_ERR);
3050 3045 }
3051 3046
3052 3047 /* allocate buffer for SIOGLIFCONF ioctl */
3053 3048
3054 3049 len = ln.lifn_count * sizeof (struct lifreq);
3055 3050 buf = malloc(len);
3056 3051 if (buf == NULL) {
3057 3052 ipqos_msg(MT_ENOSTR, "malloc");
3058 3053 (void) close(s);
3059 3054 return (IPQOS_CONF_ERR);
3060 3055 }
3061 3056
3062 3057 /* setup lifconf params for ioctl */
3063 3058
3064 3059 lc.lifc_family = AF_UNSPEC;
3065 3060 lc.lifc_flags = 0;
3066 3061 lc.lifc_len = len;
3067 3062 lc.lifc_buf = buf;
3068 3063
3069 3064 /* do SIOCGLIFCONF ioctl */
3070 3065
3071 3066 ret = ioctl(s, SIOCGLIFCONF, &lc);
3072 3067 if (ret < 0) {
3073 3068 ipqos_msg(MT_ENOSTR, "SIGLIFCONF");
3074 3069 (void) close(s);
3075 3070 free(buf);
3076 3071 return (IPQOS_CONF_ERR);
3077 3072 }
3078 3073 (void) close(s);
3079 3074
3080 3075 /*
3081 3076 * for each interface name given in the returned lifreq list get
3082 3077 * it's index and compare with ifindex param. Break if equal.
3083 3078 */
3084 3079 for (x = ln.lifn_count, lr = lc.lifc_req; x > 0; x--, lr++) {
3085 3080 ret = readifindex(lr->lifr_name, &idx);
3086 3081 if (ret != IPQOS_CONF_SUCCESS) {
3087 3082 free(buf);
3088 3083 return (IPQOS_CONF_ERR);
3089 3084 }
3090 3085 if (idx == ifindex) {
3091 3086 break;
3092 3087 }
3093 3088 }
3094 3089 free(buf);
3095 3090
3096 3091 if (x == 0) {
3097 3092 IPQOSCDBG1(L1, "Failed to find if index %u in returned "
3098 3093 "if list.\n", ifindex);
3099 3094 return (IPQOS_CONF_ERR);
3100 3095 }
3101 3096 /* truncate any logical suffix */
3102 3097
3103 3098 if ((cp = strchr(lr->lifr_name, '@')) != NULL) {
3104 3099 *cp = NULL;
3105 3100 }
3106 3101
3107 3102 /* print interface name */
3108 3103 (void) fprintf(fp, "%s\n", lr->lifr_name);
3109 3104
3110 3105 return (IPQOS_CONF_SUCCESS);
3111 3106 }
3112 3107
3113 3108 /*
3114 3109 * print to fp the enumeration clause evaluating to the value val using the
3115 3110 * names/values given in enum_nvs.
3116 3111 */
3117 3112 static void
3118 3113 printenum(
3119 3114 FILE *fp,
3120 3115 uint32_t val,
3121 3116 str_val_nd_t *enum_nvs)
3122 3117 {
3123 3118
3124 3119 boolean_t isfirstval = B_TRUE;
3125 3120 str_val_nd_t *name_val = enum_nvs;
3126 3121
3127 3122 /* for each value in enum_nvs if same bit set in val print name */
3128 3123
3129 3124 while (name_val) {
3130 3125 if ((name_val->sv.value & val) == name_val->sv.value) {
3131 3126 if (isfirstval == B_TRUE) {
3132 3127 (void) fprintf(fp, "%s", name_val->sv.string);
3133 3128 isfirstval = B_FALSE;
3134 3129 } else {
3135 3130 (void) fprintf(fp, ", %s", name_val->sv.string);
3136 3131 }
3137 3132 }
3138 3133 name_val = name_val->next;
3139 3134 }
3140 3135 }
3141 3136
3142 3137
3143 3138 /* prints the service name of port, or if unknown the number to fp. */
3144 3139 static void
3145 3140 printport(
3146 3141 FILE *fp,
3147 3142 uint16_t port)
3148 3143 {
3149 3144
3150 3145 struct servent *sent;
3151 3146
3152 3147 sent = getservbyport(port, NULL);
3153 3148 if (sent != NULL) {
3154 3149 (void) fprintf(fp, "%s\n", sent->s_name);
3155 3150 } else {
3156 3151 (void) fprintf(fp, "%u\n", ntohs(port));
3157 3152 }
3158 3153 }
3159 3154
3160 3155 /*
3161 3156 * prints tp fp the name and value of all user specifiable parameters in the
3162 3157 * nvlist.
3163 3158 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
3164 3159 */
3165 3160 static int
3166 3161 printnvlist(
3167 3162 FILE *fp,
3168 3163 char *module,
3169 3164 nvlist_t *nvl,
3170 3165 int printall, /* are we want ip addresses printing if node name */
3171 3166 ipqos_conf_filter_t *flt, /* used to determine if node name set */
3172 3167 int tab_inserts,
3173 3168 place_t place)
3174 3169 {
3175 3170 FILE *tfp;
3176 3171 nvpair_t *nvp;
3177 3172 char *name;
3178 3173 ipqos_nvtype_t type;
3179 3174 str_val_nd_t *enum_nvs;
3180 3175 int ret;
3181 3176 char dfltst[IPQOS_VALST_MAXLEN+1];
3182 3177 char *param;
3183 3178 int openerr;
3184 3179 int res;
3185 3180
3186 3181 IPQOSCDBG0(L1, "In printnvlist\n");
3187 3182
3188 3183
3189 3184 /* open stream to types file */
3190 3185
3191 3186 tfp = validmod(module, &openerr);
3192 3187 if (tfp == NULL) {
3193 3188 if (openerr) {
3194 3189 ipqos_msg(MT_ENOSTR, "fopen");
3195 3190 }
3196 3191 return (IPQOS_CONF_ERR);
3197 3192 }
3198 3193
3199 3194
3200 3195 /* go through list getting param name and type and printing it */
3201 3196
3202 3197 nvp = nvlist_next_nvpair(nvl, NULL);
3203 3198 while (nvp) {
3204 3199
3205 3200 /* get nvpair name */
3206 3201 name = nvpair_name(nvp);
3207 3202 IPQOSCDBG1(L0, "processing element %s.\n", name);
3208 3203
3209 3204 /* skip ipgpc params that are not explicitly user settable */
3210 3205
3211 3206 if (strcmp(name, IPGPC_FILTER_TYPE) == 0 ||
3212 3207 strcmp(name, IPGPC_SADDR_MASK) == 0 ||
3213 3208 strcmp(name, IPGPC_DADDR_MASK) == 0 ||
3214 3209 strcmp(name, IPGPC_SPORT_MASK) == 0 ||
3215 3210 strcmp(name, IPGPC_DPORT_MASK) == 0) {
3216 3211 nvp = nvlist_next_nvpair(nvl, nvp);
3217 3212 continue;
3218 3213 }
3219 3214
3220 3215 param = SHORT_NAME(name);
3221 3216
3222 3217 /*
3223 3218 * get parameter type from types file.
3224 3219 */
3225 3220 place = PL_ANY;
3226 3221 ret = readtype(tfp, module, param, &type, &enum_nvs, dfltst,
3227 3222 B_TRUE, &place);
3228 3223 if (ret != IPQOS_CONF_SUCCESS) {
3229 3224 return (ret);
3230 3225 }
3231 3226
3232 3227 /*
3233 3228 * for map entries we don't print the map value, only
3234 3229 * the index value it was derived from.
3235 3230 */
3236 3231 if (place == PL_MAP) {
3237 3232 nvp = nvlist_next_nvpair(nvl, nvp);
3238 3233 continue;
3239 3234 }
3240 3235
3241 3236 /*
3242 3237 * the ifindex is converted to the name and printed out
3243 3238 * so print the parameter name as ifname.
3244 3239 */
3245 3240 if (strcmp(name, IPGPC_IF_INDEX) == 0) {
3246 3241 PRINT_TABS(fp, tab_inserts);
3247 3242 (void) fprintf(fp, "%s ", IPQOS_IFNAME_STR);
3248 3243 /*
3249 3244 * we may not print the address due to us instead printing
3250 3245 * the node name in printfilter, therefore we leave the
3251 3246 * printing of the parameter in the addresses switch case code.
3252 3247 */
3253 3248 } else if ((strcmp(name, IPGPC_SADDR) != 0 &&
3254 3249 strcmp(name, IPGPC_DADDR) != 0)) {
3255 3250 PRINT_TABS(fp, tab_inserts);
3256 3251 (void) fprintf(fp, "%s ", param);
3257 3252 }
3258 3253
3259 3254 switch (type) {
3260 3255 case IPQOS_DATA_TYPE_IFINDEX: {
3261 3256 uint32_t ifidx;
3262 3257
3263 3258 (void) nvpair_value_uint32(nvp, &ifidx);
3264 3259 (void) printifname(fp, ifidx);
3265 3260 break;
3266 3261 }
3267 3262 case IPQOS_DATA_TYPE_BOOLEAN: {
3268 3263 boolean_t bl;
3269 3264
3270 3265 (void) nvpair_value_uint32(nvp,
3271 3266 (uint32_t *)&bl);
3272 3267 (void) fprintf(fp, "%s\n",
3273 3268 bl == B_TRUE ? "true" : "false");
3274 3269 break;
3275 3270 }
3276 3271 case IPQOS_DATA_TYPE_ACTION: {
3277 3272 char *strval;
3278 3273
3279 3274 (void) nvpair_value_string(nvp, &strval);
3280 3275 print_action_nm(fp, strval);
3281 3276 break;
3282 3277 }
3283 3278 case IPQOS_DATA_TYPE_STRING: {
3284 3279 char *strval;
3285 3280
3286 3281 (void) nvpair_value_string(nvp, &strval);
3287 3282 (void) fprintf(fp, "%s\n",
3288 3283 quote_ws_string(strval));
3289 3284 break;
3290 3285 }
3291 3286 case IPQOS_DATA_TYPE_ADDRESS: {
3292 3287 uint_t tmp;
3293 3288 in6_addr_t *addr;
3294 3289 char addrstr[INET6_ADDRSTRLEN];
3295 3290 uchar_t ftype;
3296 3291 int af;
3297 3292 in6_addr_t *mask;
3298 3293
3299 3294 /*
3300 3295 * skip addresses that have node names for
3301 3296 * non printall listings.
3302 3297 */
3303 3298 if (printall == 0 &&
3304 3299 (strcmp(nvpair_name(nvp), IPGPC_SADDR) ==
3305 3300 0 && flt->src_nd_name ||
3306 3301 strcmp(nvpair_name(nvp), IPGPC_DADDR) ==
3307 3302 0 && flt->dst_nd_name)) {
3308 3303 break;
3309 3304 }
3310 3305
3311 3306 /* we skipped this above */
3312 3307
3313 3308 PRINT_TABS(fp, tab_inserts);
3314 3309 (void) fprintf(fp, "%s ", param);
3315 3310
3316 3311 (void) nvpair_value_uint32_array(nvp,
3317 3312 (uint32_t **)&addr, &tmp);
3318 3313
3319 3314 /* get filter type */
3320 3315
3321 3316 (void) nvlist_lookup_byte(nvl,
3322 3317 IPGPC_FILTER_TYPE, &ftype);
3323 3318 if (ftype == IPGPC_V4_FLTR) {
3324 3319 af = AF_INET;
3325 3320 addr = (in6_addr_t *)
3326 3321 &V4_PART_OF_V6((*addr));
3327 3322 } else {
3328 3323 af = AF_INET6;
3329 3324 }
3330 3325 /* get mask */
3331 3326
3332 3327 if (strcmp(nvpair_name(nvp), IPGPC_SADDR) ==
3333 3328 0) {
3334 3329 ret = nvlist_lookup_uint32_array(nvl,
3335 3330 IPGPC_SADDR_MASK,
3336 3331 (uint32_t **)&mask, &tmp);
3337 3332 } else {
3338 3333 ret = nvlist_lookup_uint32_array(nvl,
3339 3334 IPGPC_DADDR_MASK,
3340 3335 (uint32_t **)&mask, &tmp);
3341 3336 }
3342 3337
3343 3338 /* print address/mask to fp */
3344 3339
3345 3340 (void) fprintf(fp, "%s/%u\n",
3346 3341 inet_ntop(af, addr, addrstr,
3347 3342 INET6_ADDRSTRLEN), masktocidr(af, mask));
3348 3343 break;
3349 3344 }
3350 3345 case IPQOS_DATA_TYPE_ENUM: {
3351 3346 uint32_t val;
3352 3347
3353 3348 (void) nvpair_value_uint32(nvp, &val);
3354 3349
3355 3350 /*
3356 3351 * print list of tokens resulting in val
3357 3352 */
3358 3353 (void) fprintf(fp, "{ ");
3359 3354 printenum(fp, val, enum_nvs);
3360 3355 (void) fprintf(fp, " }\n");
3361 3356 break;
3362 3357 }
3363 3358 case IPQOS_DATA_TYPE_PORT: {
3364 3359 uint16_t port;
3365 3360
3366 3361 (void) nvpair_value_uint16(nvp, &port);
3367 3362 printport(fp, port);
3368 3363 break;
3369 3364 }
3370 3365 case IPQOS_DATA_TYPE_PROTO: {
3371 3366 uint8_t proto;
3372 3367
3373 3368 (void) nvpair_value_byte(nvp, &proto);
3374 3369 printproto(fp, proto);
3375 3370 break;
3376 3371 }
3377 3372 case IPQOS_DATA_TYPE_M_INDEX:
3378 3373 case IPQOS_DATA_TYPE_UINT8: {
3379 3374 uchar_t u8;
3380 3375
3381 3376 (void) nvpair_value_byte(nvp, &u8);
3382 3377 (void) fprintf(fp, "%u\n", u8);
3383 3378 break;
3384 3379 }
3385 3380 case IPQOS_DATA_TYPE_UINT16: {
3386 3381 uint16_t u16;
3387 3382
3388 3383 (void) nvpair_value_uint16(nvp, &u16);
3389 3384 (void) fprintf(fp, "%u\n", u16);
3390 3385 break;
3391 3386 }
3392 3387 case IPQOS_DATA_TYPE_INT16: {
3393 3388 int16_t i16;
3394 3389
3395 3390 (void) nvpair_value_int16(nvp, &i16);
3396 3391 (void) fprintf(fp, "%d\n", i16);
3397 3392 break;
3398 3393 }
3399 3394 case IPQOS_DATA_TYPE_UINT32: {
3400 3395 uint32_t u32;
3401 3396
3402 3397 (void) nvpair_value_uint32(nvp, &u32);
3403 3398 (void) fprintf(fp, "%u\n", u32);
3404 3399 break;
3405 3400 }
3406 3401 case IPQOS_DATA_TYPE_INT32: {
3407 3402 int i32;
3408 3403
3409 3404 (void) nvpair_value_int32(nvp, &i32);
3410 3405 (void) fprintf(fp, "%d\n", i32);
3411 3406 break;
3412 3407 }
3413 3408 case IPQOS_DATA_TYPE_INT_ARRAY: {
3414 3409 str_val_nd_t *arr_enum_nvs = NULL;
3415 3410 uint32_t size;
3416 3411 int llimit, ulimit;
3417 3412 int *arr;
3418 3413
3419 3414 (void) nvpair_value_int32_array(nvp, &arr,
3420 3415 &size);
3421 3416
3422 3417 /*
3423 3418 * read array info from types file.
3424 3419 */
3425 3420 res = read_int_array_info(dfltst,
3426 3421 &arr_enum_nvs, &size, &llimit, &ulimit,
3427 3422 module);
3428 3423
3429 3424 /*
3430 3425 * print array with numbers, or symbols
3431 3426 * if enumerated.
3432 3427 */
3433 3428 if (res == IPQOS_CONF_SUCCESS) {
3434 3429 print_int_array(fp, arr, size,
3435 3430 llimit, ulimit, arr_enum_nvs,
3436 3431 tab_inserts);
3437 3432 if (arr_enum_nvs != NULL) {
3438 3433 free_str_val_entrys(
3439 3434 arr_enum_nvs);
3440 3435 }
3441 3436 }
3442 3437 break;
3443 3438 }
3444 3439 case IPQOS_DATA_TYPE_USER: {
3445 3440 uid_t uid;
3446 3441
3447 3442 (void) nvpair_value_int32(nvp, (int *)&uid);
3448 3443 printuser(fp, uid);
3449 3444 break;
3450 3445 }
3451 3446 #ifdef _IPQOS_CONF_DEBUG
3452 3447 default: {
3453 3448 /*
3454 3449 * we should have catered for all used data
3455 3450 * types that readtype returns.
3456 3451 */
3457 3452 assert(1);
3458 3453 }
3459 3454 #endif
3460 3455 }
3461 3456
3462 3457 nvp = nvlist_next_nvpair(nvl, nvp);
3463 3458 }
3464 3459
3465 3460 (void) fclose(tfp);
3466 3461 return (IPQOS_CONF_SUCCESS);
3467 3462 }
3468 3463
3469 3464 /*
3470 3465 * print a parameter clause for the parmeters given in params to fp.
3471 3466 * If printall is set, then the originator of the parameter object is printed.
3472 3467 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
3473 3468 */
3474 3469 static int
3475 3470 printparams(
3476 3471 FILE *fp,
3477 3472 char *module,
3478 3473 ipqos_conf_params_t *params,
3479 3474 int printall,
3480 3475 int tab_inserts)
3481 3476 {
3482 3477
3483 3478 int res;
3484 3479
3485 3480 /* print opening clause */
3486 3481
3487 3482 PRINT_TABS(fp, tab_inserts);
3488 3483 (void) fprintf(fp, IPQOS_CONF_PARAMS_STR " {\n");
3489 3484
3490 3485 /* print originator name if printall flag set */
3491 3486
3492 3487 if (printall) {
3493 3488 PRINT_TABS(fp, tab_inserts + 1);
3494 3489 (void) fprintf(stdout, "Originator %s\n",
3495 3490 quote_ws_string(get_originator_nm(params->originator)));
3496 3491 }
3497 3492
3498 3493 /* print global stats */
3499 3494
3500 3495 PRINT_TABS(fp, tab_inserts + 1);
3501 3496 (void) fprintf(fp, IPQOS_CONF_GLOBAL_STATS_STR " %s\n",
3502 3497 params->stats_enable == B_TRUE ? "true" : "false");
3503 3498
3504 3499 /* print module specific parameters */
3505 3500 res = printnvlist(fp, module, params->nvlist, printall, NULL,
3506 3501 tab_inserts + 1, PL_PARAMS);
3507 3502 if (res != IPQOS_CONF_SUCCESS) {
3508 3503 return (res);
3509 3504 }
3510 3505
3511 3506 PRINT_TABS(fp, tab_inserts);
3512 3507 (void) fprintf(fp, "}\n");
3513 3508
3514 3509 return (IPQOS_CONF_SUCCESS);
3515 3510 }
3516 3511
3517 3512 /*
3518 3513 * print the interpreted name of the action_nm parameter if it is a special
3519 3514 * action, else action_nm verbatim to fp parameter.
3520 3515 */
3521 3516 static void
3522 3517 print_action_nm(FILE *fp, char *action_nm)
3523 3518 {
3524 3519
3525 3520 if (strcmp(action_nm, IPP_ANAME_CONT) == 0) {
3526 3521 (void) fprintf(fp, IPQOS_CONF_CONT_STR "\n");
3527 3522 } else if (strcmp(action_nm, IPP_ANAME_DEFER) == 0) {
3528 3523 (void) fprintf(fp, IPQOS_CONF_DEFER_STR "\n");
3529 3524 } else if (strcmp(action_nm, IPP_ANAME_DROP) == 0) {
3530 3525 (void) fprintf(fp, IPQOS_CONF_DROP_STR "\n");
3531 3526 } else {
3532 3527 (void) fprintf(fp, "%s\n", quote_ws_string(action_nm));
3533 3528 }
3534 3529 }
3535 3530
3536 3531 /*
3537 3532 * print a class clause for class to fp. If printall is set the originator
3538 3533 * is printed.
3539 3534 */
3540 3535 static void
3541 3536 printclass(
3542 3537 FILE *fp,
3543 3538 ipqos_conf_class_t *class,
3544 3539 int printall,
3545 3540 int tab_inserts)
3546 3541 {
3547 3542
3548 3543 /* print opening clause */
3549 3544
3550 3545 PRINT_TABS(fp, tab_inserts);
3551 3546 (void) fprintf(fp, IPQOS_CONF_CLASS_STR " {\n");
3552 3547
3553 3548
3554 3549 /* if printall flag print originator name */
3555 3550
3556 3551 if (printall) {
3557 3552 PRINT_TABS(fp, tab_inserts + 1);
3558 3553 (void) fprintf(stdout, "Originator %s\n",
3559 3554 get_originator_nm(class->originator));
3560 3555 }
3561 3556
3562 3557 /* print name, next action and stats enable */
3563 3558
3564 3559 PRINT_TABS(fp, tab_inserts + 1);
3565 3560 (void) fprintf(fp, IPQOS_CONF_NAME_STR " %s\n",
3566 3561 quote_ws_string(class->name));
3567 3562 PRINT_TABS(fp, tab_inserts + 1);
3568 3563 (void) fprintf(fp, IPQOS_CONF_NEXT_ACTION_STR " ");
3569 3564 print_action_nm(fp, class->alist->name);
3570 3565 PRINT_TABS(fp, tab_inserts + 1);
3571 3566 (void) fprintf(fp, IPQOS_CONF_STATS_ENABLE_STR " %s\n",
3572 3567 class->stats_enable == B_TRUE ? "true" : "false");
3573 3568
3574 3569 PRINT_TABS(fp, tab_inserts);
3575 3570 (void) fprintf(fp, "}\n");
3576 3571 }
3577 3572
3578 3573 /*
3579 3574 * Returns a ptr to the originator name associated with origid. If unknown
3580 3575 * id returns ptr to "unknown".
3581 3576 * RETURNS: ptr to originator name, or if id not known "unknown".
3582 3577 */
3583 3578 static char *
3584 3579 get_originator_nm(uint32_t origid)
3585 3580 {
3586 3581
3587 3582 int x;
3588 3583
3589 3584 /* scan originators table for origid */
3590 3585
3591 3586 for (x = 0; originators[x].value != -1 &&
3592 3587 originators[x].value != origid; x++) {}
3593 3588
3594 3589 /* if we've reached end of array due to unknown type return "unknown" */
3595 3590
3596 3591 if (originators[x].value == -1) {
3597 3592 return ("unknown");
3598 3593 }
3599 3594
3600 3595 return (originators[x].string);
3601 3596 }
3602 3597
3603 3598 /*
3604 3599 * print a filter clause for filter pointed to by filter out to fp. If printall
3605 3600 * is set then the originator is printed, for filters with node names instance
3606 3601 * numbers are printed, and the filter pointer isn't advanced to point at the
3607 3602 * last instance of the printed filter.
3608 3603 * RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
3609 3604 */
3610 3605 static int
3611 3606 printfilter(
3612 3607 FILE *fp,
3613 3608 char *module,
3614 3609 ipqos_conf_filter_t **filter,
3615 3610 int printall,
3616 3611 int tab_inserts)
3617 3612 {
3618 3613
3619 3614 int res;
3620 3615
3621 3616 /* print opening clause */
3622 3617
3623 3618 PRINT_TABS(fp, tab_inserts);
3624 3619 (void) fprintf(fp, IPQOS_CONF_FILTER_STR " {\n");
3625 3620
3626 3621 /* print originator if printall flag set */
3627 3622
3628 3623 if (printall) {
3629 3624 PRINT_TABS(fp, tab_inserts + 1);
3630 3625 (void) fprintf(stdout, "Originator %s\n",
3631 3626 quote_ws_string(get_originator_nm((*filter)->originator)));
3632 3627 }
3633 3628
3634 3629 /* print name and class */
3635 3630
3636 3631 PRINT_TABS(fp, tab_inserts + 1);
3637 3632 (void) fprintf(fp, IPQOS_CONF_NAME_STR " %s\n",
3638 3633 quote_ws_string((*filter)->name));
3639 3634 PRINT_TABS(fp, tab_inserts + 1);
3640 3635 (void) fprintf(fp, IPQOS_CONF_CLASS_STR " %s\n",
3641 3636 quote_ws_string((*filter)->class_name));
3642 3637
3643 3638 /* print the instance if printall and potential mhomed addresses */
3644 3639
3645 3640 if (printall && ((*filter)->src_nd_name || (*filter)->dst_nd_name)) {
3646 3641 PRINT_TABS(fp, tab_inserts + 1);
3647 3642 (void) fprintf(fp, "Instance %u\n", (*filter)->instance);
3648 3643 }
3649 3644
3650 3645 /* print node names if any */
3651 3646
3652 3647 if ((*filter)->src_nd_name) {
3653 3648 PRINT_TABS(fp, tab_inserts + 1);
3654 3649 (void) fprintf(fp, "%s %s\n", strchr(IPGPC_SADDR, '.') + 1,
3655 3650 (*filter)->src_nd_name);
3656 3651 }
3657 3652 if ((*filter)->dst_nd_name) {
3658 3653 PRINT_TABS(fp, tab_inserts + 1);
3659 3654 (void) fprintf(fp, "%s %s\n", strchr(IPGPC_DADDR, '.') + 1,
3660 3655 (*filter)->dst_nd_name);
3661 3656 }
3662 3657
3663 3658 /* print ip_version enumeration if set */
3664 3659
3665 3660 if ((*filter)->ip_versions != 0) {
3666 3661 PRINT_TABS(fp, tab_inserts + 1);
3667 3662 (void) fprintf(fp, IPQOS_CONF_IP_VERSION_STR " {");
3668 3663 if (VERSION_IS_V4(*filter)) {
3669 3664 (void) fprintf(fp, " V4");
3670 3665 }
3671 3666 if (VERSION_IS_V6(*filter)) {
3672 3667 (void) fprintf(fp, " V6");
3673 3668 }
3674 3669 (void) fprintf(fp, " }\n");
3675 3670 }
3676 3671
3677 3672 /* print other module specific parameters parameters */
3678 3673
3679 3674 res = printnvlist(fp, module, (*filter)->nvlist, printall, *filter,
3680 3675 tab_inserts + 1, PL_FILTER);
3681 3676 if (res != IPQOS_CONF_SUCCESS) {
3682 3677 return (res);
3683 3678 }
3684 3679
3685 3680 PRINT_TABS(fp, tab_inserts);
3686 3681 (void) fprintf(fp, "}\n");
3687 3682
3688 3683 /*
3689 3684 * if not printall advance filter parameter to last instance of this
3690 3685 * filter.
3691 3686 */
3692 3687
3693 3688 if (!printall) {
3694 3689 for (;;) {
3695 3690 if ((*filter)->next == NULL ||
3696 3691 strcmp((*filter)->name, (*filter)->next->name) !=
3697 3692 0) {
3698 3693 break;
3699 3694 }
3700 3695 *filter = (*filter)->next;
3701 3696 }
3702 3697 }
3703 3698
3704 3699 return (IPQOS_CONF_SUCCESS);
3705 3700 }
3706 3701
3707 3702 /*
3708 3703 * Returns a pointer to str if no whitespace is present, else it returns
3709 3704 * a pointer to a string with the contents of str enclose in double quotes.
3710 3705 * This returned strings contents may change in subsequent calls so a copy
3711 3706 * should be made of it if the caller wishes to retain it.
3712 3707 */
3713 3708 static char *
3714 3709 quote_ws_string(const char *str)
3715 3710 {
3716 3711 static char *buf = NULL;
3717 3712 const char *cp; /* we don't modify the contents of str so const */
3718 3713
3719 3714 IPQOSCDBG0(L0, "In quote_ws_string\n");
3720 3715
3721 3716 /*
3722 3717 * Just return str if no whitespace.
3723 3718 */
3724 3719 for (cp = str; (*cp != '\0') && !isspace(*cp); cp++)
3725 3720 ;
3726 3721 if (*cp == '\0')
3727 3722 return ((char *)str);
3728 3723
3729 3724 if (buf == NULL) {
3730 3725 /*
3731 3726 * if first run just allocate buffer of
3732 3727 * strlen(str) + 2 quote characters + NULL terminator.
3733 3728 */
3734 3729 buf = malloc(strlen(str) + 3);
3735 3730 } else if ((strlen(str) + 2) > strlen(buf)) {
3736 3731 /*
3737 3732 * Not first run, so check if we have a big enough buffer
3738 3733 * and if not reallocate the buffer to a sufficient size.
3739 3734 */
3740 3735 buf = realloc(buf, strlen(str) + 3);
3741 3736 }
3742 3737 if (buf == NULL)
3743 3738 return ("");
3744 3739
3745 3740 /*
3746 3741 * copy string into buffer with quotes.
3747 3742 */
3748 3743 (void) strcpy(buf, "\"");
3749 3744 (void) strcat(buf, str);
3750 3745 (void) strcat(buf, "\"");
3751 3746
3752 3747 return (buf);
3753 3748 }
3754 3749
3755 3750 /*
3756 3751 * print an action clause for action to fp. If the printall flag is set
3757 3752 * then all filters and classes (regardless of their originator) and
3758 3753 * their originators are displayed.
3759 3754 * RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
3760 3755 */
3761 3756 static int
3762 3757 printaction(
3763 3758 FILE *fp,
3764 3759 ipqos_conf_action_t *action,
3765 3760 int printall,
3766 3761 int tab_inserts)
3767 3762 {
3768 3763
3769 3764 ipqos_conf_filter_t *flt;
3770 3765 ipqos_conf_class_t *cls;
3771 3766 int res;
3772 3767
3773 3768 /* print opening clause, module and name */
3774 3769
3775 3770 PRINT_TABS(fp, tab_inserts);
3776 3771 (void) fprintf(fp, IPQOS_CONF_ACTION_STR " {\n");
3777 3772 PRINT_TABS(fp, tab_inserts + 1);
3778 3773 (void) fprintf(fp, IPQOS_CONF_MODULE_STR " %s\n",
3779 3774 quote_ws_string(action->module));
3780 3775 PRINT_TABS(fp, tab_inserts + 1);
3781 3776 (void) fprintf(fp, "name %s\n", quote_ws_string(action->name));
3782 3777
3783 3778 /* print params clause */
3784 3779
3785 3780 (void) fprintf(fp, "\n");
3786 3781 res = printparams(fp, action->module, action->params, printall,
3787 3782 tab_inserts + 1);
3788 3783 if (res != IPQOS_CONF_SUCCESS) {
3789 3784 return (res);
3790 3785 }
3791 3786
3792 3787 /*
3793 3788 * print classes clause for each class if printall is set, else
3794 3789 * just ipqosconf created or permanent classes.
3795 3790 */
3796 3791 for (cls = action->classes; cls != NULL; cls = cls->next) {
3797 3792 if (printall ||
3798 3793 cls->originator == IPP_CONFIG_IPQOSCONF ||
3799 3794 cls->originator == IPP_CONFIG_PERMANENT) {
3800 3795 (void) fprintf(fp, "\n");
3801 3796 printclass(fp, cls, printall, tab_inserts + 1);
3802 3797 }
3803 3798 }
3804 3799
3805 3800 /*
3806 3801 * print filter clause for each filter if printall is set, else
3807 3802 * just ipqosconf created or permanent filters.
3808 3803 */
3809 3804 for (flt = action->filters; flt != NULL; flt = flt->next) {
3810 3805 if (printall ||
3811 3806 flt->originator == IPP_CONFIG_IPQOSCONF ||
3812 3807 flt->originator == IPP_CONFIG_PERMANENT) {
3813 3808 (void) fprintf(fp, "\n");
3814 3809 res = printfilter(fp, action->module, &flt, printall,
3815 3810 tab_inserts + 1);
3816 3811 if (res != IPQOS_CONF_SUCCESS) {
3817 3812 return (res);
3818 3813 }
3819 3814 }
3820 3815 }
3821 3816
3822 3817 PRINT_TABS(fp, tab_inserts);
3823 3818 (void) fprintf(fp, "}\n");
3824 3819
3825 3820 return (IPQOS_CONF_SUCCESS);
3826 3821 }
3827 3822
3828 3823
3829 3824
3830 3825 /* *************************************************************** */
3831 3826
3832 3827
3833 3828 static void
3834 3829 list_end(
3835 3830 ipqos_list_el_t **listp,
3836 3831 ipqos_list_el_t ***lendpp)
3837 3832 {
3838 3833 *lendpp = listp;
3839 3834 while (**lendpp != NULL) {
3840 3835 *lendpp = &(**lendpp)->next;
3841 3836 }
3842 3837 }
3843 3838
3844 3839 static void
3845 3840 add_to_list(
3846 3841 ipqos_list_el_t **listp,
3847 3842 ipqos_list_el_t *el)
3848 3843 {
3849 3844 el->next = *listp;
3850 3845 *listp = el;
3851 3846 }
3852 3847
3853 3848 /*
3854 3849 * given mask calculates the number of bits it spans. The mask must be
3855 3850 * continuous.
3856 3851 * RETURNS: number of bits spanned.
3857 3852 */
3858 3853 static int
3859 3854 masktocidr(
3860 3855 int af,
3861 3856 in6_addr_t *mask)
3862 3857 {
3863 3858 int zeros = 0;
3864 3859 int byte;
3865 3860 int cidr;
3866 3861
3867 3862 /*
3868 3863 * loop through from lowest byte to highest byte counting the
3869 3864 * number of zero bits till hitting a one bit.
3870 3865 */
3871 3866 for (byte = 15; byte >= 0; byte--) {
3872 3867 /*
3873 3868 * zero byte, so add 8 to zeros.
3874 3869 */
3875 3870 if (mask->s6_addr[byte] == 0) {
3876 3871 zeros += 8;
3877 3872 /*
3878 3873 * non-zero byte, add zero count to zeros.
3879 3874 */
3880 3875 } else {
3881 3876 zeros += (ffs((int)mask->s6_addr[byte]) - 1);
3882 3877 break;
3883 3878 }
3884 3879 }
3885 3880 /*
3886 3881 * translate zero bits to 32 or 128 bit mask based on af.
3887 3882 */
3888 3883 if (af == AF_INET) {
3889 3884 cidr = 32 - zeros;
3890 3885 } else {
3891 3886 cidr = 128 - zeros;
3892 3887 }
3893 3888
3894 3889 return (cidr);
3895 3890 }
3896 3891
3897 3892 /*
3898 3893 * Sets the first prefix_len bits in the v4 or v6 address (based upon af)
3899 3894 * contained in the v6 address referenced by addr to 1.
3900 3895 */
3901 3896 static void
3902 3897 setmask(int prefix_len, in6_addr_t *addr, int af)
3903 3898 {
3904 3899
3905 3900 int i;
3906 3901 int shift;
3907 3902 int maskstartbit = 128 - prefix_len;
3908 3903 int end_u32;
3909 3904
3910 3905 IPQOSCDBG2(L1, "In setmask, prefix_len: %u, af: %s\n", prefix_len,
3911 3906 af == AF_INET ? "AF_INET" : "AF_INET6");
3912 3907
3913 3908 /* zero addr */
3914 3909 bzero(addr, sizeof (in6_addr_t));
3915 3910
3916 3911
3917 3912 /* set which 32bits in *addr are relevant to this af */
3918 3913
3919 3914 if (af == AF_INET) {
3920 3915 end_u32 = 3;
3921 3916 maskstartbit = 32 - prefix_len;
3922 3917 /* AF_INET6 */
3923 3918 } else {
3924 3919 end_u32 = 0;
3925 3920 }
3926 3921 /*
3927 3922 * go through each of the 32bit quantities in 128 bit in6_addr_t
3928 3923 * and set appropriate bits according to prefix_len.
3929 3924 */
3930 3925 for (i = 3; i >= end_u32; i--) {
3931 3926
3932 3927 /* does the prefix apply to this 32bits? */
3933 3928
3934 3929 if (maskstartbit < ((4 - i) * 32)) {
3935 3930
3936 3931 /* is this 32bits fully masked? */
3937 3932
3938 3933 if (maskstartbit <= ((3 - i) * 32)) {
3939 3934 shift = 0;
3940 3935 } else {
3941 3936 shift = maskstartbit % 32;
3942 3937 }
3943 3938 addr->_S6_un._S6_u32[i] = (uint32_t)~0;
3944 3939 addr->_S6_un._S6_u32[i] =
3945 3940 addr->_S6_un._S6_u32[i] >> shift;
3946 3941 addr->_S6_un._S6_u32[i] =
3947 3942 addr->_S6_un._S6_u32[i] << shift;
3948 3943 }
3949 3944
3950 3945 /* translate to NBO */
3951 3946 addr->_S6_un._S6_u32[i] = htonl(addr->_S6_un._S6_u32[i]);
3952 3947 }
3953 3948 }
3954 3949
3955 3950 /*
3956 3951 * search nvlist for an element with the name specified and return a ptr
3957 3952 * to it if found.
3958 3953 * RETURNS: pointer to nvpair named name if found, else NULL.
3959 3954 */
3960 3955 static nvpair_t *
3961 3956 find_nvpair(nvlist_t *nvl, char *name)
3962 3957 {
3963 3958
3964 3959 nvpair_t *nvp;
3965 3960 nvpair_t *match = NULL;
3966 3961 char *nvp_name;
3967 3962
3968 3963 IPQOSCDBG0(L1, "In find_nvpair\n");
3969 3964
3970 3965 nvp = nvlist_next_nvpair(nvl, NULL);
3971 3966 while (nvp) {
3972 3967 nvp_name = nvpair_name(nvp);
3973 3968 if (strcmp(name, nvp_name) == 0) {
3974 3969 match = nvp;
3975 3970 }
3976 3971 nvp = nvlist_next_nvpair(nvl, nvp);
3977 3972 }
3978 3973
3979 3974 return (match);
3980 3975 }
3981 3976
3982 3977 /*
3983 3978 * returns a string containing module_name '.' name.
3984 3979 * RETURNS: IPQOS_CONF_ERR if error, else IPQOS_CONF_SUCCESS.
3985 3980 */
3986 3981 static char *
3987 3982 prepend_module_name(
3988 3983 char *name,
3989 3984 char *module)
3990 3985 {
3991 3986
3992 3987 char *ret;
3993 3988
3994 3989 IPQOSCDBG0(L2, "In prepend_module_name\n");
3995 3990
3996 3991 ret = malloc(strlen(module) + strlen(".") + strlen(name) + 1);
3997 3992 if (ret == NULL) {
3998 3993 ipqos_msg(MT_ENOSTR, "malloc");
3999 3994 return (NULL);
4000 3995 }
4001 3996
4002 3997 (void) strcpy(ret, module);
4003 3998 (void) strcat(ret, ".");
4004 3999 (void) strcat(ret, name);
4005 4000
4006 4001 return (ret);
4007 4002 }
4008 4003
4009 4004 #if 0
4010 4005
4011 4006 /*
4012 4007 * check if element with matching s1 and s2 string is in table table.
4013 4008 * RETURNS: 1 if found else 0.
4014 4009 */
4015 4010 static int
4016 4011 in_str_str_table(
4017 4012 str_str_t *table,
4018 4013 char *s1,
4019 4014 char *s2)
4020 4015 {
4021 4016
4022 4017 str_str_t *ss = table;
4023 4018
4024 4019 /* loop through table till matched or end */
4025 4020
4026 4021 while (ss->s1[0] != '\0' &&
4027 4022 (strcmp(ss->s1, s1) != 0 || strcmp(ss->s2, s2) != 0)) {
4028 4023 ss++;
4029 4024 }
4030 4025
4031 4026 if (ss->s1[0] != '\0') {
4032 4027 return (1);
4033 4028 }
4034 4029
4035 4030 return (0);
4036 4031 }
4037 4032 #endif /* 0 */
4038 4033
4039 4034 /*
4040 4035 * check whether name is a valid action/class/filter name.
4041 4036 * RETURNS: IPQOS_CONF_ERR if invalid name else IPQOS_CONF_SUCCESS.
4042 4037 */
4043 4038 static int
4044 4039 valid_name(char *name)
4045 4040 {
4046 4041
4047 4042 IPQOSCDBG1(L1, "In valid_name: name: %s\n", name);
4048 4043
4049 4044 /* first char can't be '!' */
4050 4045 if (name[0] == '!') {
4051 4046 ipqos_msg(MT_ERROR, gettext("Name not allowed to start with "
4052 4047 "'!', line %u.\n"), lineno);
4053 4048 return (IPQOS_CONF_ERR);
4054 4049 }
4055 4050
4056 4051 /* can't exceed IPQOS_CONF_NAME_LEN size */
4057 4052 if (strlen(name) >= IPQOS_CONF_NAME_LEN) {
4058 4053 ipqos_msg(MT_ERROR, gettext("Name exceeds maximum name length "
4059 4054 "line %u.\n"), lineno);
4060 4055 return (IPQOS_CONF_ERR);
4061 4056 }
4062 4057
4063 4058 return (IPQOS_CONF_SUCCESS);
4064 4059 }
4065 4060
4066 4061 /* ********************* string value manip fns ************************** */
4067 4062
4068 4063
4069 4064 /*
4070 4065 * searches through the str_val_nd_t list of string value pairs finding
4071 4066 * the minimum and maximum values for value and places them in the
4072 4067 * integers pointed at by min and max.
4073 4068 */
4074 4069 static void
4075 4070 get_str_val_value_range(
4076 4071 str_val_nd_t *svnp,
4077 4072 int *min,
4078 4073 int *max)
4079 4074 {
4080 4075 if (svnp != NULL) {
4081 4076 *min = *max = svnp->sv.value;
4082 4077 svnp = svnp->next;
4083 4078 }
4084 4079 while (svnp != NULL) {
4085 4080 if (svnp->sv.value > *max)
4086 4081 *max = svnp->sv.value;
4087 4082 if (svnp->sv.value < *min)
4088 4083 *min = svnp->sv.value;
4089 4084 svnp = svnp->next;
4090 4085 }
4091 4086 }
4092 4087
4093 4088 /*
4094 4089 * add an entry with string string and value val to sv_entrys.
4095 4090 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
4096 4091 */
4097 4092 static int
4098 4093 add_str_val_entry(
4099 4094 str_val_nd_t **sv_entrys,
4100 4095 char *string,
4101 4096 uint32_t val)
4102 4097 {
4103 4098
4104 4099 str_val_nd_t *sv_entry;
4105 4100
4106 4101 IPQOSCDBG2(L1, "In add_str_val_entry: string: %s, val: %u\n", string,
4107 4102 val);
4108 4103
4109 4104 /* alloc new node */
4110 4105
4111 4106 sv_entry = malloc(sizeof (str_val_nd_t));
4112 4107 if (sv_entry == NULL) {
4113 4108 return (IPQOS_CONF_ERR);
4114 4109 }
4115 4110
4116 4111 /* populate node */
4117 4112
4118 4113 sv_entry->sv.string = malloc(strlen(string) + 1);
4119 4114 if (sv_entry->sv.string == NULL) {
4120 4115 free(sv_entry);
4121 4116 ipqos_msg(MT_ENOSTR, "malloc");
4122 4117 return (IPQOS_CONF_ERR);
4123 4118 } else {
4124 4119 (void) strcpy(sv_entry->sv.string, string);
4125 4120 }
4126 4121 sv_entry->sv.value = val;
4127 4122
4128 4123 /* place at start of sv_entrys list */
4129 4124
4130 4125 sv_entry->next = *sv_entrys;
4131 4126 *sv_entrys = sv_entry;
4132 4127
4133 4128 return (IPQOS_CONF_SUCCESS);
4134 4129 }
4135 4130
4136 4131
4137 4132 /* frees all the elements of sv_entrys. */
4138 4133 static void
4139 4134 free_str_val_entrys(
4140 4135 str_val_nd_t *sv_entrys)
4141 4136 {
4142 4137
4143 4138 str_val_nd_t *sve = sv_entrys;
4144 4139 str_val_nd_t *tmp;
4145 4140
4146 4141 IPQOSCDBG0(L1, "In free_str_val_entrys\n");
4147 4142
4148 4143 while (sve) {
4149 4144 free(sve->sv.string);
4150 4145 tmp = sve->next;
4151 4146 free(sve);
4152 4147 sve = tmp;
4153 4148 }
4154 4149 }
4155 4150
4156 4151 /*
4157 4152 * finds the value associated with string and assigns it to value ref'd by
4158 4153 * val.
4159 4154 * RETURNS: IPQOS_CONF_ERR if string not found, else IPQOS_CONF_SUCCESS.
4160 4155 */
4161 4156 static int
4162 4157 str_val_list_lookup(
4163 4158 str_val_nd_t *svs,
4164 4159 char *string,
4165 4160 uint32_t *val)
4166 4161 {
4167 4162
4168 4163 str_val_nd_t *sv = svs;
4169 4164
4170 4165 IPQOSCDBG1(L1, "In str_val_list_lookup: %s\n", string);
4171 4166
4172 4167 /* loop through list and exit when found or list end */
4173 4168
4174 4169 while (sv != NULL) {
4175 4170 if (strcmp(sv->sv.string, string) == 0) {
4176 4171 break;
4177 4172 }
4178 4173 sv = sv->next;
4179 4174 }
4180 4175
4181 4176 /* ret error if not found */
4182 4177
4183 4178 if (sv == NULL) {
4184 4179 return (IPQOS_CONF_ERR);
4185 4180 }
4186 4181
4187 4182 *val = sv->sv.value;
4188 4183
4189 4184 IPQOSCDBG1(L1, "svll: Value returned is %u\n", *val);
4190 4185 return (IPQOS_CONF_SUCCESS);
4191 4186 }
4192 4187
4193 4188
4194 4189 /* ************************ conf file read fns ***************************** */
4195 4190
4196 4191 /*
4197 4192 * Reads a uid or username from string 'str' and assigns either the uid
4198 4193 * or associated uid respectively to storage pointed at by 'uid'. The
4199 4194 * function determines whether to read a uid by checking whether the first
4200 4195 * character of 'str' is numeric, in which case it reads a uid; otherwise it
4201 4196 * assumes a username.
4202 4197 * RETURNS: IPQOS_CONF_ERR if a NULL string pointer is passed, the read uid
4203 4198 * doesn't have an entry on the system, or the read username doesn't have an
4204 4199 * entry on the system.
4205 4200 */
4206 4201 static int
4207 4202 readuser(
4208 4203 char *str,
4209 4204 uid_t *uid)
4210 4205 {
4211 4206 struct passwd *pwd;
4212 4207 char *lo;
4213 4208
4214 4209 IPQOSCDBG1(L0, "In readuser, str: %s\n", str);
4215 4210
4216 4211 if (str == NULL)
4217 4212 return (IPQOS_CONF_ERR);
4218 4213 /*
4219 4214 * Check if this appears to be a uid, and if so check that a
4220 4215 * corresponding user exists.
4221 4216 */
4222 4217 if (isdigit((int)str[0])) {
4223 4218 /*
4224 4219 * Read a 32bit integer and check in doing so that
4225 4220 * we have consumed the whole string.
4226 4221 */
4227 4222 if (readint32(str, (int *)uid, &lo) != IPQOS_CONF_SUCCESS ||
4228 4223 *lo != '\0')
4229 4224 return (IPQOS_CONF_ERR);
4230 4225 if (getpwuid(*uid) == NULL)
4231 4226 return (IPQOS_CONF_ERR);
4232 4227
4233 4228 } else { /* This must be a username, so lookup the uid. */
4234 4229 pwd = getpwnam(str);
4235 4230 if (pwd == NULL) {
4236 4231 return (IPQOS_CONF_ERR);
4237 4232 } else {
4238 4233 *uid = pwd->pw_uid;
4239 4234 }
4240 4235 }
4241 4236 return (IPQOS_CONF_SUCCESS);
4242 4237 }
4243 4238
4244 4239 /*
4245 4240 * Reads a range from range_st, either of form 'a-b' or simply 'a'.
4246 4241 * In the former case lower and upper have their values set to a
4247 4242 * and b respectively; in the later lower and upper have both
4248 4243 * their values set to a.
4249 4244 * RETURNS: IPQOS_CONF_ERR if there's a parse error, else IPQOS_CONF_SUCCESS.
4250 4245 */
4251 4246 static int
4252 4247 readrange(
4253 4248 char *range_st,
4254 4249 int *lower,
4255 4250 int *upper)
4256 4251 {
4257 4252 char *cp;
4258 4253 char *end, *end2;
4259 4254
4260 4255 IPQOSCDBG1(L0, "In readrange: string: %s\n", range_st);
4261 4256
4262 4257 /*
4263 4258 * get range boundarys.
4264 4259 */
4265 4260 cp = strchr(range_st, '-');
4266 4261
4267 4262 if (cp != NULL) { /* we have a range */
4268 4263 *cp++ = '\0';
4269 4264 *lower = (int)strtol(range_st, &end, 10);
4270 4265 *upper = (int)strtol(cp, &end2, 10);
4271 4266 SKIPWS(end);
4272 4267 SKIPWS(end2);
4273 4268 if ((range_st == end) || (*end != NULL) ||
4274 4269 (cp == end) || (*end2 != NULL)) {
4275 4270 IPQOSCDBG0(L0, "Failed reading a-b\n");
4276 4271 return (IPQOS_CONF_ERR);
4277 4272 }
4278 4273
4279 4274 } else { /* single value */
4280 4275
4281 4276 *lower = *upper = (int)strtol(range_st, &end, 10);
4282 4277 SKIPWS(end);
4283 4278 if ((range_st == end) || (*end != NULL)) {
4284 4279 IPQOSCDBG0(L0, "Failed reading a\n");
4285 4280 return (IPQOS_CONF_ERR);
4286 4281 }
4287 4282 }
4288 4283
4289 4284 return (IPQOS_CONF_SUCCESS);
4290 4285 }
4291 4286
4292 4287 /*
4293 4288 * Reads the values of an integer array from fp whose format is:
4294 4289 * '{'RANGE[,RANGE[..]]:VALUE[;RANGE:VALUE[..]]'}', creates an array of size
4295 4290 * arr_size, applies the values to it and points arrp at this array.
4296 4291 * RANGE is one set of array indexes over which this value is to
4297 4292 * be applied, and VALUE either an integer within the range
4298 4293 * llimit - ulimit, or if enum_nvs isn't NULL, an enumeration value
4299 4294 * found in the list enum_nvs. Those values which aren't explicity set
4300 4295 * will be set to -1.
4301 4296 *
4302 4297 * RETURNS: IPQOS_CONF_ERR on resource or parse error, else IPQOS_CONF_SUCCESS.
4303 4298 */
4304 4299 static int
4305 4300 read_int_array(
4306 4301 FILE *fp,
4307 4302 char *first_token,
4308 4303 int **arrp,
4309 4304 uint32_t arr_size,
4310 4305 int llimit,
4311 4306 int ulimit,
4312 4307 str_val_nd_t *enum_nvs)
4313 4308 {
4314 4309
4315 4310 char buf[5 * IPQOS_CONF_LINEBUF_SZ];
4316 4311 char *token;
4317 4312 char *range;
4318 4313 char *ranges;
4319 4314 char *svalue;
4320 4315 int value;
4321 4316 int res;
4322 4317 char *entry;
4323 4318 char *tmp;
4324 4319 char *end;
4325 4320 int lower, upper;
4326 4321 int x;
4327 4322 uint32_t startln;
4328 4323
4329 4324 IPQOSCDBG4(L0, "In read_int_array: size: %u, lower: %u, upper: %u, "
4330 4325 "first_token: %s\n", arr_size, llimit, ulimit, first_token);
4331 4326
4332 4327 /*
4333 4328 * read beginning curl.
4334 4329 */
4335 4330 if (first_token[0] != CURL_BEGIN) {
4336 4331 ipqos_msg(MT_ERROR, gettext("\'{\' missing at line "
4337 4332 "%u.\n"), lineno);
4338 4333 return (IPQOS_CONF_ERR);
4339 4334 }
4340 4335
4341 4336 /*
4342 4337 * allocate and initialise array for holding read values.
4343 4338 */
4344 4339 *arrp = malloc(arr_size * sizeof (int));
4345 4340 if (*arrp == NULL) {
4346 4341 ipqos_msg(MT_ENOSTR, "malloc");
4347 4342 return (IPQOS_CONF_ERR);
4348 4343 }
4349 4344 (void) memset(*arrp, -1, arr_size * sizeof (int));
4350 4345
4351 4346 /*
4352 4347 * read whole array declaration string into buffer.
4353 4348 * this is because readtoken doesn't interpret our
4354 4349 * delimeter values specially and may return them
4355 4350 * within another string.
4356 4351 */
4357 4352 startln = lineno; /* store starting lineno for error reports */
4358 4353 buf[0] = '\0';
4359 4354 res = readtoken(fp, &token);
4360 4355 while ((res != IPQOS_CONF_CURL_END) && (res != IPQOS_CONF_ERR) &&
4361 4356 (res != IPQOS_CONF_EOF)) {
4362 4357 (void) strlcat(buf, token, sizeof (buf));
4363 4358 free(token);
4364 4359 res = readtoken(fp, &token);
4365 4360 }
4366 4361 if (res != IPQOS_CONF_CURL_END) {
4367 4362 goto array_err;
4368 4363 }
4369 4364 IPQOSCDBG1(L0, "array declaration buffer contains: %s\n", buf);
4370 4365
4371 4366 /*
4372 4367 * loop reading "ranges ':' value;" till end of buffer.
4373 4368 */
4374 4369 entry = strtok(buf, ";");
4375 4370 while (entry != NULL) {
4376 4371 svalue = strchr(entry, ':');
4377 4372 if (svalue == NULL) { /* missing value string */
4378 4373 IPQOSCDBG0(L0, "Missing value string\n");
4379 4374 goto array_err;
4380 4375 }
4381 4376 *svalue++ = '\0';
4382 4377 ranges = entry;
4383 4378
4384 4379 /*
4385 4380 * get value of number or enumerated symbol.
4386 4381 */
4387 4382 if (enum_nvs) {
4388 4383 /*
4389 4384 * get rid of surrounding whitespace so as not to
4390 4385 * confuse read_enum_value.
4391 4386 */
4392 4387 SKIPWS(svalue);
4393 4388 tmp = svalue;
4394 4389 while (*tmp != '\0') {
4395 4390 if (isspace(*tmp)) {
4396 4391 *tmp = '\0';
4397 4392 break;
4398 4393 } else {
4399 4394 tmp++;
4400 4395 }
4401 4396 }
4402 4397
4403 4398 /*
4404 4399 * read enumeration value.
4405 4400 */
4406 4401 res = read_enum_value(NULL, svalue, enum_nvs,
4407 4402 (uint32_t *)&value);
4408 4403 if (res != IPQOS_CONF_SUCCESS)
4409 4404 goto array_err;
4410 4405 } else {
4411 4406 value = (int)strtol(svalue, &end, 10);
4412 4407 SKIPWS(end);
4413 4408 if ((svalue == end) || (*end != NULL)) {
4414 4409 IPQOSCDBG0(L0, "Invalid value\n");
4415 4410 goto array_err;
4416 4411 }
4417 4412 IPQOSCDBG1(L0, "value: %u\n", value);
4418 4413
4419 4414 /*
4420 4415 * check value within valid range.
4421 4416 */
4422 4417 if ((value < llimit) || (value > ulimit)) {
4423 4418 IPQOSCDBG0(L0, "value out of range\n");
4424 4419 goto array_err;
4425 4420 }
4426 4421 }
4427 4422
4428 4423 /*
4429 4424 * loop reading ranges for this value.
4430 4425 */
4431 4426 range = strtok_r(ranges, ",", &tmp);
4432 4427 while (range != NULL) {
4433 4428 res = readrange(range, &lower, &upper);
4434 4429 if (res != IPQOS_CONF_SUCCESS)
4435 4430 goto array_err;
4436 4431 IPQOSCDBG2(L0, "range: %u - %u\n", lower, upper);
4437 4432
4438 4433
4439 4434 if (upper < lower) {
4440 4435 uint32_t u = lower;
4441 4436 lower = upper;
4442 4437 upper = u;
4443 4438 }
4444 4439
4445 4440 /*
4446 4441 * check range valid for array size.
4447 4442 */
4448 4443 if ((lower < 0) || (upper > arr_size)) {
4449 4444 IPQOSCDBG0(L0, "Range out of array "
4450 4445 "dimensions\n");
4451 4446 goto array_err;
4452 4447 }
4453 4448
4454 4449 /*
4455 4450 * add this value to array indexes within range.
4456 4451 */
4457 4452 for (x = lower; x <= upper; x++)
4458 4453 (*arrp)[x] = value;
4459 4454
4460 4455 /*
4461 4456 * get next range.
4462 4457 */
4463 4458 range = strtok_r(NULL, ",", &tmp);
4464 4459 }
4465 4460
4466 4461 entry = strtok(NULL, ";");
4467 4462 }
4468 4463
4469 4464 return (IPQOS_CONF_SUCCESS);
4470 4465
4471 4466 array_err:
4472 4467 ipqos_msg(MT_ERROR,
4473 4468 gettext("Array declaration line %u is invalid.\n"), startln);
4474 4469 free(*arrp);
4475 4470 return (IPQOS_CONF_ERR);
4476 4471 }
4477 4472
4478 4473 static int
4479 4474 readllong(char *str, long long *llp, char **lo)
4480 4475 {
4481 4476
4482 4477 *llp = strtoll(str, lo, 0);
4483 4478 if (*lo == str) {
4484 4479 return (IPQOS_CONF_ERR);
4485 4480 }
4486 4481 return (IPQOS_CONF_SUCCESS);
4487 4482 }
4488 4483
4489 4484 static int
4490 4485 readuint8(char *str, uint8_t *ui8, char **lo)
4491 4486 {
4492 4487
4493 4488 long long tmp;
4494 4489
4495 4490 if (readllong(str, &tmp, lo) != 0) {
4496 4491 return (IPQOS_CONF_ERR);
4497 4492 }
4498 4493 if (tmp > UCHAR_MAX || tmp < 0) {
4499 4494 return (IPQOS_CONF_ERR);
4500 4495 }
4501 4496 *ui8 = (uint8_t)tmp;
4502 4497 return (IPQOS_CONF_SUCCESS);
4503 4498 }
4504 4499
4505 4500 static int
4506 4501 readuint16(char *str, uint16_t *ui16, char **lo)
4507 4502 {
4508 4503 long long tmp;
4509 4504
4510 4505 if (readllong(str, &tmp, lo) != IPQOS_CONF_SUCCESS) {
4511 4506 return (IPQOS_CONF_ERR);
4512 4507 }
4513 4508 if (tmp > USHRT_MAX || tmp < 0) {
4514 4509 return (IPQOS_CONF_ERR);
4515 4510 }
4516 4511 *ui16 = (uint16_t)tmp;
4517 4512 return (IPQOS_CONF_SUCCESS);
4518 4513 }
4519 4514
4520 4515 static int
4521 4516 readint16(char *str, int16_t *i16, char **lo)
4522 4517 {
4523 4518 long long tmp;
4524 4519
4525 4520 if (readllong(str, &tmp, lo) != 0) {
4526 4521 return (IPQOS_CONF_ERR);
4527 4522 }
4528 4523 if (tmp > SHRT_MAX || tmp < SHRT_MIN) {
4529 4524 return (IPQOS_CONF_ERR);
4530 4525 }
4531 4526 *i16 = (int16_t)tmp;
4532 4527 return (IPQOS_CONF_SUCCESS);
4533 4528 }
4534 4529
4535 4530 static int
4536 4531 readint32(char *str, int *i32, char **lo)
4537 4532 {
4538 4533 long long tmp;
4539 4534
4540 4535 if (readllong(str, &tmp, lo) != IPQOS_CONF_SUCCESS) {
4541 4536 return (IPQOS_CONF_ERR);
4542 4537 }
4543 4538 if (tmp > INT_MAX || tmp < INT_MIN) {
4544 4539 return (IPQOS_CONF_ERR);
4545 4540 }
4546 4541 *i32 = tmp;
4547 4542 return (IPQOS_CONF_SUCCESS);
4548 4543 }
4549 4544
4550 4545 static int
4551 4546 readuint32(char *str, uint32_t *ui32, char **lo)
4552 4547 {
4553 4548 long long tmp;
4554 4549
4555 4550 if (readllong(str, &tmp, lo) != IPQOS_CONF_SUCCESS) {
4556 4551 return (IPQOS_CONF_ERR);
4557 4552 }
4558 4553 if (tmp > UINT_MAX || tmp < 0) {
4559 4554 return (IPQOS_CONF_ERR);
4560 4555 }
4561 4556 *ui32 = (uint32_t)tmp;
4562 4557 return (IPQOS_CONF_SUCCESS);
4563 4558 }
4564 4559
4565 4560 /*
4566 4561 * retrieves the index associated with the interface named ifname and assigns
4567 4562 * it to the int pointed to by ifindex.
4568 4563 * RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
4569 4564 */
4570 4565 static int
4571 4566 readifindex(
4572 4567 char *ifname,
4573 4568 int *ifindex)
4574 4569 {
4575 4570
4576 4571 int s;
4577 4572 struct lifreq lifrq;
4578 4573
4579 4574
4580 4575 /* open socket */
4581 4576
4582 4577 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
4583 4578 ipqos_msg(MT_ENOSTR, gettext("opening AF_INET socket"));
4584 4579 return (IPQOS_CONF_ERR);
4585 4580 }
4586 4581
4587 4582 /* copy ifname into lifreq */
4588 4583
4589 4584 (void) strlcpy(lifrq.lifr_name, ifname, LIFNAMSIZ);
4590 4585
4591 4586 /* do SIOGLIFINDEX ioctl */
4592 4587
4593 4588 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifrq) == -1) {
4594 4589 (void) close(s);
4595 4590 return (IPQOS_CONF_ERR);
4596 4591 }
4597 4592
4598 4593 /* Warn if a virtual interface is specified */
4599 4594 if ((ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrq) != -1) &&
4600 4595 (lifrq.lifr_flags & IFF_VIRTUAL)) {
4601 4596 ipqos_msg(MT_WARNING, gettext("Invalid interface"));
4602 4597 }
4603 4598 (void) close(s);
4604 4599 *ifindex = lifrq.lifr_index;
4605 4600 return (IPQOS_CONF_SUCCESS);
4606 4601 }
4607 4602
4608 4603 /*
4609 4604 * Case insensitively compares the string in str with IPQOS_CONF_TRUE_STR
4610 4605 * and IPQOS_CONF_FALSE_STR and sets boolean pointed to by bool accordingly.
4611 4606 * RETURNS: if failure to match either IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
4612 4607 */
4613 4608 static int
4614 4609 readbool(char *str, boolean_t *bool)
4615 4610 {
4616 4611
4617 4612 if (strcasecmp(str, IPQOS_CONF_TRUE_STR) == 0) {
4618 4613 *bool = B_TRUE;
4619 4614 } else if (strcasecmp(str, IPQOS_CONF_FALSE_STR) == 0) {
4620 4615 *bool = B_FALSE;
4621 4616 } else {
4622 4617 return (IPQOS_CONF_ERR);
4623 4618 }
4624 4619
4625 4620 return (IPQOS_CONF_SUCCESS);
4626 4621 }
4627 4622
4628 4623 /*
4629 4624 * reads a protocol name/number from proto_str and assigns the number
4630 4625 * to the uint8 ref'd by proto.
4631 4626 * RETURNS: If not a valid name or protocol number IPQOS_CONF_ERR, else
4632 4627 * IPQOS_CONF_SUCCESS.
4633 4628 */
4634 4629 static int
4635 4630 readproto(char *proto_str, uint8_t *proto)
4636 4631 {
4637 4632
4638 4633 struct protoent *pent;
4639 4634 char *lo;
4640 4635 int res;
4641 4636
4642 4637 IPQOSCDBG1(L1, "In readproto: string: %s\n", proto_str);
4643 4638
4644 4639 /* try name lookup */
4645 4640
4646 4641 pent = getprotobyname(proto_str);
4647 4642 if (pent) {
4648 4643 *proto = pent->p_proto;
4649 4644
4650 4645 /* check valid protocol number */
4651 4646 } else {
4652 4647 res = readuint8(proto_str, proto, &lo);
4653 4648 if (res != IPQOS_CONF_SUCCESS || proto == 0) {
4654 4649 return (IPQOS_CONF_ERR);
4655 4650 }
4656 4651 }
4657 4652
4658 4653 return (IPQOS_CONF_SUCCESS);
4659 4654 }
4660 4655
4661 4656 /*
4662 4657 * reads either a port service, or a port number from port_str and assigns
4663 4658 * the associated port number to short ref'd by port.
4664 4659 * RETURNS: If invalid name and number IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
4665 4660 */
4666 4661 static int
4667 4662 readport(char *port_str, uint16_t *port)
4668 4663 {
4669 4664
4670 4665 struct servent *sent;
4671 4666 char *tmp;
4672 4667
4673 4668 IPQOSCDBG1(L1, "In readport: string: %s\n", port_str);
4674 4669
4675 4670 /* try service name lookup */
4676 4671 sent = getservbyname(port_str, NULL);
4677 4672
4678 4673 /* failed name lookup so read port number */
4679 4674 if (sent == NULL) {
4680 4675 if (readuint16(port_str, port, &tmp) != IPQOS_CONF_SUCCESS ||
4681 4676 *port == 0) {
4682 4677 return (IPQOS_CONF_ERR);
4683 4678 }
4684 4679 *port = htons(*port);
4685 4680 } else {
4686 4681 *port = sent->s_port;
4687 4682 }
4688 4683
4689 4684 return (IPQOS_CONF_SUCCESS);
4690 4685 }
4691 4686
4692 4687
4693 4688 /*
4694 4689 * Reads a curly brace, a string enclosed in double quotes, or a whitespace/
4695 4690 * curly brace delimited string. If a double quote enclosed string the
4696 4691 * closing quotes need to be on the same line.
4697 4692 * RETURNS:
4698 4693 * on reading a CURL_BEGIN token it returns IPQOS_CONF_CURL_BEGIN,
4699 4694 * on reading a CURL_END token it returns IPQOS_CONF_CURL_END,
4700 4695 * on reading another valid token it returns IPQOS_CONF_SUCCESS.
4701 4696 * for each of these token is set to point at the read string.
4702 4697 * at EOF it returns IPQOS_CONF_EOF and if errors it returns IPQOS_CONF_ERR.
4703 4698 */
4704 4699 static int
4705 4700 readtoken(
4706 4701 FILE *fp,
4707 4702 char **token)
4708 4703 {
4709 4704
4710 4705 char *st, *tmp;
4711 4706 int len;
4712 4707 int quoted = 0;
4713 4708 char *cmnt;
4714 4709 char *bpos;
4715 4710 int rembuf;
4716 4711
4717 4712 static char *lo;
4718 4713 static char *buf = NULL;
4719 4714 static int bufsize;
4720 4715
4721 4716 /* if first call initialize line buf to default size */
4722 4717
4723 4718 if (buf == NULL) {
4724 4719 bufsize = IPQOS_CONF_LINEBUF_SZ;
4725 4720 buf = malloc(bufsize);
4726 4721 if (buf == NULL) {
4727 4722 ipqos_msg(MT_ENOSTR, "malloc");
4728 4723 return (IPQOS_CONF_ERR);
4729 4724 }
4730 4725 }
4731 4726
4732 4727 /* set buffer postition and size to use whole buffer */
4733 4728
4734 4729 bpos = buf;
4735 4730 rembuf = bufsize;
4736 4731
4737 4732
4738 4733 /*
4739 4734 * loop reading lines until we've read a line with a non-whitespace
4740 4735 * char.
4741 4736 */
4742 4737
4743 4738 do {
4744 4739 /* if no leftover from previous invocation */
4745 4740
4746 4741 if (lo == NULL) {
4747 4742
4748 4743 /*
4749 4744 * loop reading into buffer doubling if necessary until
4750 4745 * we have either read a complete line or reached the
4751 4746 * end of file.
4752 4747 */
4753 4748 for (;;) {
4754 4749 st = fgets(bpos, rembuf, fp);
4755 4750
4756 4751 if (st == NULL) {
4757 4752
4758 4753 /* if read error */
4759 4754 if (ferror(fp)) {
4760 4755 free(buf);
4761 4756 buf = NULL;
4762 4757 ipqos_msg(MT_ENOSTR,
4763 4758 "fgets");
4764 4759 return (IPQOS_CONF_ERR);
4765 4760
4766 4761 /* end of file */
4767 4762 } else {
4768 4763 free(buf);
4769 4764 buf = NULL;
4770 4765 *token = NULL;
4771 4766 return (IPQOS_CONF_EOF);
4772 4767 }
4773 4768 } else {
4774 4769 /* if read a newline */
4775 4770
4776 4771 if (buf[strlen(buf) - 1] == '\n') {
4777 4772 lineno++;
4778 4773 break;
4779 4774
4780 4775 /* if read the last line */
4781 4776
4782 4777 } else if (feof(fp)) {
4783 4778 break;
4784 4779
4785 4780 /*
4786 4781 * not read a full line so buffer size
4787 4782 * is too small, double it and retry.
4788 4783 */
4789 4784 } else {
4790 4785 bufsize *= 2;
4791 4786 tmp = realloc(buf, bufsize);
4792 4787 if (tmp == NULL) {
4793 4788 ipqos_msg(MT_ENOSTR,
4794 4789 "realloc");
4795 4790 free(buf);
4796 4791 return (IPQOS_CONF_ERR);
4797 4792 } else {
4798 4793 buf = tmp;
4799 4794 }
4800 4795
4801 4796 /*
4802 4797 * make parameters to fgets read
4803 4798 * into centre of doubled buffer
4804 4799 * so we retain what we've
4805 4800 * already read.
4806 4801 */
4807 4802 bpos = &buf[(bufsize / 2) - 1];
4808 4803 rembuf = (bufsize / 2) + 1;
4809 4804 }
4810 4805 }
4811 4806 }
4812 4807
4813 4808 st = buf;
4814 4809
4815 4810 /* previous leftover, assign to st */
4816 4811
4817 4812 } else {
4818 4813 st = lo;
4819 4814 lo = NULL;
4820 4815 }
4821 4816
4822 4817 /* truncate at comment */
4823 4818
4824 4819 cmnt = strchr(st, '#');
4825 4820 if (cmnt) {
4826 4821 *cmnt = '\0';
4827 4822 }
4828 4823
4829 4824 /* Skip any whitespace */
4830 4825
4831 4826 while (isspace(*st) && st != '\0') {
4832 4827 st++;
4833 4828 }
4834 4829
4835 4830 } while (*st == '\0');
4836 4831
4837 4832
4838 4833 /* find end of token */
4839 4834
4840 4835 tmp = st;
4841 4836
4842 4837 /* if curl advance 1 char */
4843 4838
4844 4839 if (*tmp == CURL_BEGIN || *tmp == CURL_END) {
4845 4840 tmp++;
4846 4841
4847 4842
4848 4843 /* if dbl quote read until matching quote */
4849 4844
4850 4845 } else if (*tmp == '"') {
4851 4846 quoted++;
4852 4847 tmp = ++st;
4853 4848
4854 4849 while (*tmp != '"' && *tmp != '\n' && *tmp != '\0') {
4855 4850 tmp++;
4856 4851 }
4857 4852 if (*tmp != '"') {
4858 4853 ipqos_msg(MT_ERROR, gettext("Quoted string exceeds "
4859 4854 "line, line %u.\n"), lineno);
4860 4855 free(buf);
4861 4856 return (IPQOS_CONF_ERR);
4862 4857 }
4863 4858
4864 4859 /* normal token */
4865 4860 } else {
4866 4861 /* find first whitespace, curl, newline or string end */
4867 4862
4868 4863 while (!isspace(*tmp) && *tmp != CURL_BEGIN &&
4869 4864 *tmp != CURL_END && *tmp != '\n' && *tmp != '\0') {
4870 4865 tmp++;
4871 4866 }
4872 4867 }
4873 4868
4874 4869 /* copy token to return */
4875 4870 len = tmp - st;
4876 4871 *token = malloc(len + 1);
4877 4872 if (!*token) {
4878 4873 free(buf);
4879 4874 ipqos_msg(MT_ENOSTR, "malloc");
4880 4875 return (IPQOS_CONF_ERR);
4881 4876 }
4882 4877 bcopy(st, *token, len);
4883 4878 (*token)[len] = '\0';
4884 4879
4885 4880 /* if just read quoted string remove quote from remaining string */
4886 4881
4887 4882 if (quoted) {
4888 4883 tmp++;
4889 4884 }
4890 4885
4891 4886 /* if not end of string, store rest for latter parsing */
4892 4887
4893 4888 if (*tmp != '\0' && *tmp != '\n') {
4894 4889 lo = tmp;
4895 4890 }
4896 4891
4897 4892 /* for curl_end and curl_begin return special ret codes */
4898 4893
4899 4894 if ((*token)[1] == '\0') {
4900 4895 if (**token == CURL_BEGIN) {
4901 4896 return (IPQOS_CONF_CURL_BEGIN);
4902 4897 } else if (**token == CURL_END) {
4903 4898 return (IPQOS_CONF_CURL_END);
4904 4899 }
4905 4900 }
4906 4901
4907 4902 return (IPQOS_CONF_SUCCESS);
4908 4903 }
4909 4904
4910 4905 /*
4911 4906 * Reads an enumeration bitmask definition from line. The format is:
4912 4907 * { NAME=VAL, NAME2=VAL2 }. The resulting names and values are returned.
4913 4908 * RETURNS: NULL on error, else ptr to name/values.
4914 4909 */
4915 4910 static str_val_nd_t *
4916 4911 read_enum_nvs(char *line, char *module_name)
4917 4912 {
4918 4913
4919 4914 str_val_nd_t *enum_vals = NULL;
4920 4915 char *cp;
4921 4916 char *start;
4922 4917 char *name = NULL;
4923 4918 int len;
4924 4919 uint32_t val;
4925 4920 int ret;
4926 4921 int readc;
4927 4922
4928 4923 IPQOSCDBG1(L1, "In read_enum_nvs, line: %s\n", line);
4929 4924
4930 4925 /* read opening brace */
4931 4926
4932 4927 cp = strchr(line, CURL_BEGIN);
4933 4928 if (cp == NULL) {
4934 4929 IPQOSCDBG0(L1, "missing curl begin\n");
4935 4930 goto fail;
4936 4931 } else {
4937 4932 start = cp + 1;
4938 4933 }
4939 4934
4940 4935 /*
4941 4936 * loop reading 'name = value' entrys seperated by comma until
4942 4937 * reach closing brace.
4943 4938 */
4944 4939
4945 4940 for (;;) {
4946 4941 SKIPWS(start);
4947 4942 if (*start == '\0') {
4948 4943 IPQOSCDBG0(L1, "missing closing bracket\n");
4949 4944 goto fail;
4950 4945 }
4951 4946
4952 4947 /*
4953 4948 * read name - read until whitespace, '=', closing curl,
4954 4949 * or string end.
4955 4950 */
4956 4951
4957 4952 for (cp = start;
4958 4953 !isspace(*cp) && *cp != '=' && *cp != CURL_END &&
4959 4954 *cp != '\0'; cp++) {}
4960 4955
4961 4956 if (*cp == '\0') {
4962 4957 IPQOSCDBG0(L1, "Unexpected line end in enum def'n\n");
4963 4958 goto fail;
4964 4959
4965 4960 /* finished definition, exit loop */
4966 4961 } else if (*cp == CURL_END) {
4967 4962 break;
4968 4963 }
4969 4964
4970 4965 /* store name */
4971 4966
4972 4967 len = cp - start;
4973 4968 name = malloc(len + 1);
4974 4969 if (name == NULL) {
4975 4970 ipqos_msg(MT_ENOSTR, "malloc");
4976 4971 goto fail;
4977 4972 }
4978 4973 bcopy(start, name, len);
4979 4974 name[len] = NULL;
4980 4975 IPQOSCDBG1(L0, "Stored name: %s\n", name);
4981 4976
4982 4977 /* read assignment */
4983 4978
4984 4979 start = strchr(cp, '=');
4985 4980 if (start == NULL) {
4986 4981 IPQOSCDBG0(L1, "Missing = in enum def'n\n");
4987 4982 goto fail;
4988 4983 }
4989 4984
4990 4985 /* read value */
4991 4986
4992 4987 ret = sscanf(++start, "%x%n", &val, &readc);
4993 4988 if (ret != 1) {
4994 4989 IPQOSCDBG1(L1, "sscanf of value failed, string: %s\n",
4995 4990 cp);
4996 4991 goto fail;
4997 4992 }
4998 4993
4999 4994 /* add name value to set */
5000 4995
5001 4996 ret = add_str_val_entry(&enum_vals, name, val);
5002 4997 if (ret != IPQOS_CONF_SUCCESS) {
5003 4998 IPQOSCDBG0(L1, "Failed to add str_val entry\n");
5004 4999 goto fail;
5005 5000 }
5006 5001 free(name);
5007 5002 name = NULL;
5008 5003
5009 5004 /* try reading comma */
5010 5005 cp = strchr(start, ',');
5011 5006
5012 5007 if (cp != NULL) {
5013 5008 start = cp + 1;
5014 5009
5015 5010 /* no comma, advance to char past value last read */
5016 5011 } else {
5017 5012 start += readc;
5018 5013 }
5019 5014 }
5020 5015
5021 5016 return (enum_vals);
5022 5017 fail:
5023 5018 free_str_val_entrys(enum_vals);
5024 5019 if (name != NULL)
5025 5020 free(name);
5026 5021
5027 5022 /* if a parse error */
5028 5023
5029 5024 if (errno == 0) {
5030 5025 ipqos_msg(MT_ERROR, gettext("Types file for module %s is "
5031 5026 "corrupt.\n"), module_name);
5032 5027 }
5033 5028
5034 5029 return (NULL);
5035 5030 }
5036 5031
5037 5032 /*
5038 5033 * Given mapped_list with is a comma seperated list of map names, and value,
5039 5034 * which is used to index into these maps, the function creates x new entries
5040 5035 * in nvpp, where x is the number of map names specified. Each of these
5041 5036 * entries has the value from the map in the position indexed by value and
5042 5037 * with name module.${MAP_NAME}. The maps are contained in the modules config
5043 5038 * file and have the form:
5044 5039 * map map1 uint32 1,23,32,45,3
5045 5040 * As you can see the map values are uint32, and along with uint8 are the
5046 5041 * only supported types at the moment.
5047 5042 *
5048 5043 * RETURNS: IPQOS_CONF_ERR if one of the maps specified in mapped_list
5049 5044 * doesn't exist, if value is not a valid map position for a map, or if
5050 5045 * there's a resource failure. otherwise IPQOS_CONF_SUCCESS is returned.
5051 5046 */
5052 5047 static int
5053 5048 read_mapped_values(
5054 5049 FILE *tfp,
5055 5050 nvlist_t **nvlp,
5056 5051 char *module,
5057 5052 char *mapped_list,
5058 5053 int value)
5059 5054 {
5060 5055 char *map_name, *lastparam, *tmpname;
5061 5056 int res;
5062 5057 ipqos_nvtype_t type;
5063 5058 char dfltst[IPQOS_VALST_MAXLEN+1] = "";
5064 5059 str_val_nd_t *enum_nvs;
5065 5060 place_t place;
5066 5061
5067 5062 IPQOSCDBG0(L1, "In read_mapped_values\n");
5068 5063
5069 5064 map_name = (char *)strtok_r(mapped_list, ",", &lastparam);
5070 5065 while (map_name != NULL) {
5071 5066 char *tokval, *lastval;
5072 5067 int index = 0;
5073 5068
5074 5069 /*
5075 5070 * get map info from types file.
5076 5071 */
5077 5072 place = PL_MAP;
5078 5073 res = readtype(tfp, module, map_name, &type, &enum_nvs,
5079 5074 dfltst, B_FALSE, &place);
5080 5075 if (res != IPQOS_CONF_SUCCESS) {
5081 5076 return (IPQOS_CONF_ERR);
5082 5077 }
5083 5078
5084 5079 /*
5085 5080 * Just keep browsing the list till we get to the element
5086 5081 * with the index from the value parameter or the end.
5087 5082 */
5088 5083 tokval = (char *)strtok_r(dfltst, ",", &lastval);
5089 5084 for (;;) {
5090 5085 if (tokval == NULL) {
5091 5086 ipqos_msg(MT_ERROR,
5092 5087 gettext("Invalid value, %u, line %u.\n"),
5093 5088 value, lineno);
5094 5089 return (IPQOS_CONF_ERR);
5095 5090 }
5096 5091 if (index++ == value) {
5097 5092 break;
5098 5093 }
5099 5094 tokval = (char *)strtok_r(NULL, ",", &lastval);
5100 5095 }
5101 5096
5102 5097
5103 5098 /*
5104 5099 * create fully qualified parameter name for map value.
5105 5100 */
5106 5101 tmpname = prepend_module_name(map_name, module);
5107 5102 if (tmpname == NULL) {
5108 5103 return (IPQOS_CONF_ERR);
5109 5104 }
5110 5105
5111 5106 /*
5112 5107 * add map value with fqn to parameter nvlist.
5113 5108 */
5114 5109 IPQOSCDBG2(L0, "Adding map %s, value %u to nvlist\n",
5115 5110 tmpname, atoi(tokval));
5116 5111 switch (type) {
5117 5112 case IPQOS_DATA_TYPE_UINT8: {
5118 5113 res = nvlist_add_byte(*nvlp, tmpname,
5119 5114 (uint8_t)atoi(tokval));
5120 5115 if (res != 0) {
5121 5116 free(tmpname);
5122 5117 ipqos_msg(MT_ENOSTR,
5123 5118 "nvlist_add_uint8");
5124 5119 return (IPQOS_CONF_ERR);
5125 5120 }
5126 5121 break;
5127 5122 }
5128 5123 case IPQOS_DATA_TYPE_UINT32: {
5129 5124 res = nvlist_add_uint32(*nvlp, tmpname,
5130 5125 (uint32_t)atoi(tokval));
5131 5126 if (res != 0) {
5132 5127 free(tmpname);
5133 5128 ipqos_msg(MT_ENOSTR,
5134 5129 "nvlist_add_uint32");
5135 5130 return (IPQOS_CONF_ERR);
5136 5131 }
5137 5132 break;
5138 5133 }
5139 5134 default: {
5140 5135 ipqos_msg(MT_ERROR,
5141 5136 gettext("Types file for module %s is "
5142 5137 "corrupt.\n"), module);
5143 5138 IPQOSCDBG1(L0, "Unsupported map type for "
5144 5139 "parameter %s given in types file.\n",
5145 5140 map_name);
5146 5141 return (IPQOS_CONF_ERR);
5147 5142 }
5148 5143 }
5149 5144 free(tmpname);
5150 5145
5151 5146 map_name = (char *)strtok_r(NULL, ",", &lastparam);
5152 5147 }
5153 5148
5154 5149 return (IPQOS_CONF_SUCCESS);
5155 5150 }
5156 5151
5157 5152 /*
5158 5153 * Parses the string info_str into it's components. Its format is:
5159 5154 * SIZE','[ENUM_DEF | RANGE], where SIZE is the size of the array,
5160 5155 * ENUM_DEF is the definition of the enumeration for this array,
5161 5156 * and RANGE is the set of values this array can accept. In
5162 5157 * the event this array has an enumeration definition enum_nvs is
5163 5158 * set to point at a str_val_nd_t structure which stores the names
5164 5159 * and values associated with this enumeration. Otherwise, if this
5165 5160 * is not an enumerated array, lower and upper are set to the lower
5166 5161 * and upper values of RANGE.
5167 5162 * RETURNS: IPQOS_CONF_ERR due to unexpected parse errors, else
5168 5163 * IPQOS_CONF_SUCCESS.
5169 5164 */
5170 5165 static int
5171 5166 read_int_array_info(
5172 5167 char *info_str,
5173 5168 str_val_nd_t **enum_nvs,
5174 5169 uint32_t *size,
5175 5170 int *lower,
5176 5171 int *upper,
5177 5172 char *module)
5178 5173 {
5179 5174 int res;
5180 5175 char *end;
5181 5176 char *token;
5182 5177 char *tmp;
5183 5178
5184 5179 IPQOSCDBG1(L0, "In read_array_info: info_str: %s\n",
5185 5180 (info_str != NULL) ? info_str : "NULL");
5186 5181
5187 5182 if (info_str == NULL) {
5188 5183 IPQOSCDBG0(L0, "Null info string\n");
5189 5184 goto fail;
5190 5185 }
5191 5186
5192 5187 /*
5193 5188 * read size.
5194 5189 */
5195 5190 token = strtok(info_str, ",");
5196 5191 *size = (uint32_t)strtol(token, &end, 10);
5197 5192 SKIPWS(end);
5198 5193 if ((end == token) || (*end != NULL)) {
5199 5194 IPQOSCDBG0(L0, "Invalid size\n");
5200 5195 goto fail;
5201 5196 }
5202 5197 IPQOSCDBG1(L0, "read size: %u\n", *size);
5203 5198
5204 5199 /*
5205 5200 * check we have another string.
5206 5201 */
5207 5202 token = strtok(NULL, "\n");
5208 5203 if (token == NULL) {
5209 5204 IPQOSCDBG0(L0, "Missing range/enum def\n");
5210 5205 goto fail;
5211 5206 }
5212 5207 IPQOSCDBG1(L0, "range/enum def: %s\n", token);
5213 5208
5214 5209 /*
5215 5210 * check if enumeration set or integer set and read enumeration
5216 5211 * definition or integer range respectively.
5217 5212 */
5218 5213 tmp = strchr(token, CURL_BEGIN);
5219 5214 if (tmp == NULL) { /* a numeric range */
5220 5215 res = readrange(token, lower, upper);
5221 5216 if (res != IPQOS_CONF_SUCCESS) {
5222 5217 IPQOSCDBG0(L0, "Failed reading range\n");
5223 5218 goto fail;
5224 5219 }
5225 5220 } else { /* an enumeration */
5226 5221 *enum_nvs = read_enum_nvs(token, module);
5227 5222 if (*enum_nvs == NULL) {
5228 5223 IPQOSCDBG0(L0, "Failed reading enum def\n");
5229 5224 goto fail;
5230 5225 }
5231 5226 }
5232 5227
5233 5228 return (IPQOS_CONF_SUCCESS);
5234 5229 fail:
5235 5230 ipqos_msg(MT_ERROR,
5236 5231 gettext("Types file for module %s is corrupt.\n"), module);
5237 5232 return (IPQOS_CONF_ERR);
5238 5233 }
5239 5234
5240 5235 /*
5241 5236 * reads the value of an enumeration parameter from first_token and fp.
5242 5237 * first_token is the first token of the value.
5243 5238 * The format expected is NAME | { NAME1 [, NAME2 ] [, NAME3 ] }.
5244 5239 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
5245 5240 */
5246 5241 static int
5247 5242 read_enum_value(
5248 5243 FILE *fp,
5249 5244 char *first_token,
5250 5245 str_val_nd_t *enum_vals,
5251 5246 uint32_t *val)
5252 5247 {
5253 5248
5254 5249 uint32_t u32;
5255 5250 int ret;
5256 5251 char *tk;
5257 5252 char *lo = NULL;
5258 5253 char *cm;
5259 5254 int name_expected = 0;
5260 5255
5261 5256 IPQOSCDBG0(L1, "In read_enum_value\n");
5262 5257
5263 5258 /* init param val */
5264 5259 *val = 0;
5265 5260
5266 5261 /* first token not curl_begin, so lookup its value */
5267 5262
5268 5263 if (*first_token != CURL_BEGIN) {
5269 5264 ret = str_val_list_lookup(enum_vals, first_token, val);
5270 5265 if (ret != IPQOS_CONF_SUCCESS) {
5271 5266 ipqos_msg(MT_ERROR,
5272 5267 gettext("Unrecognized value, %s, line %u.\n"),
5273 5268 first_token, lineno);
5274 5269 return (ret);
5275 5270 }
5276 5271
5277 5272 /* curl_begin, so read values till curl_end, dicing at ',' */
5278 5273 } else {
5279 5274
5280 5275 name_expected++;
5281 5276
5282 5277 for (;;) {
5283 5278
5284 5279 /*
5285 5280 * no leftover from pervious iteration so read new
5286 5281 * token. This leftover happens because readtoken
5287 5282 * doesn't interpret comma's as special characters
5288 5283 * and thus could return 'val1,val2' as one token.
5289 5284 * If this happens the val1 will be used in the
5290 5285 * current iteration and what follows saved in lo
5291 5286 * for processing by successive iterations.
5292 5287 */
5293 5288
5294 5289 if (lo == NULL) {
5295 5290 ret = readtoken(fp, &tk);
5296 5291 if (ret == IPQOS_CONF_ERR) {
5297 5292 return (ret);
5298 5293 } else if (ret == IPQOS_CONF_EOF) {
5299 5294 ipqos_msg(MT_ERROR,
5300 5295 gettext("Unexpected EOF.\n"));
5301 5296 return (IPQOS_CONF_ERR);
5302 5297
5303 5298 }
5304 5299 } else { /* previous leftover, so use it */
5305 5300
5306 5301 IPQOSCDBG1(L1, "Using leftover %s.\n", lo);
5307 5302 tk = lo;
5308 5303 lo = NULL;
5309 5304 }
5310 5305
5311 5306 if (name_expected) {
5312 5307 if (ret == IPQOS_CONF_CURL_END ||
5313 5308 tk[0] == ',') {
5314 5309 ipqos_msg(MT_ERROR,
5315 5310 gettext("Malformed value list "
5316 5311 "line %u.\n"), lineno);
5317 5312 free(tk);
5318 5313 return (IPQOS_CONF_ERR);
5319 5314 }
5320 5315
5321 5316 /*
5322 5317 * check if this token contains a ',' and
5323 5318 * if so store it and what follows for next
5324 5319 * iteration.
5325 5320 */
5326 5321 cm = strchr(tk, ',');
5327 5322 if (cm != NULL) {
5328 5323 lo = malloc(strlen(cm) + 1);
5329 5324 if (lo == NULL) {
5330 5325 ipqos_msg(MT_ENOSTR, "malloc");
5331 5326 free(tk);
5332 5327 return (IPQOS_CONF_ERR);
5333 5328 }
5334 5329
5335 5330 (void) strcpy(lo, cm);
5336 5331 *cm = '\0';
5337 5332 }
5338 5333
5339 5334
5340 5335 /* get name value and add to total val */
5341 5336
5342 5337 ret = str_val_list_lookup(enum_vals, tk, &u32);
5343 5338 if (ret != IPQOS_CONF_SUCCESS) {
5344 5339 ipqos_msg(MT_ERROR,
5345 5340 gettext("Unrecognized value, %s, "
5346 5341 "line %u.\n"), tk, lineno);
5347 5342 free(tk);
5348 5343 return (IPQOS_CONF_ERR);
5349 5344 }
5350 5345
5351 5346 *val = *val | u32;
5352 5347 name_expected--;
5353 5348
5354 5349 /* comma or curl end accepted */
5355 5350 } else {
5356 5351
5357 5352 /* we've reached curl_end so break */
5358 5353
5359 5354 if (ret == IPQOS_CONF_CURL_END) {
5360 5355 free(tk);
5361 5356 break;
5362 5357
5363 5358 /* not curl end and not comma */
5364 5359
5365 5360 } else if (tk[0] != ',') {
5366 5361 ipqos_msg(MT_ERROR,
5367 5362 gettext("Malformed value list "
5368 5363 "line %u.\n"), lineno);
5369 5364 free(tk);
5370 5365 return (IPQOS_CONF_ERR);
5371 5366 }
5372 5367
5373 5368 /*
5374 5369 * store anything after the comma for next
5375 5370 * iteration.
5376 5371 */
5377 5372 if (tk[1] != '\0') {
5378 5373 lo = malloc(strlen(&tk[1]) + 1);
5379 5374 if (lo == NULL) {
5380 5375 ipqos_msg(MT_ENOSTR, "malloc");
5381 5376 free(tk);
5382 5377 return (IPQOS_CONF_ERR);
5383 5378 }
5384 5379 (void) strcpy(lo, &tk[1]);
5385 5380 }
5386 5381
5387 5382 name_expected++;
5388 5383 }
5389 5384
5390 5385 free(tk);
5391 5386 }
5392 5387 }
5393 5388
5394 5389 IPQOSCDBG1(L1, "value returned is: %u\n", *val);
5395 5390
5396 5391 return (IPQOS_CONF_SUCCESS);
5397 5392 }
5398 5393
5399 5394 /*
5400 5395 * read the set of permanent classes/filter from the types file ref'd by tfp
5401 5396 * and store them in a string table pointed to by perm_items,
5402 5397 * with *nitems getting set to number of items read. perm_filters is set
5403 5398 * to 1 if we're searching for permanent filters, else 0 for classes.
5404 5399 * RETURNS: IPQOS_CONF_ERR if any errors, else IPQOS_CONF_SUCCESS.
5405 5400 */
5406 5401 static int
5407 5402 read_perm_items(
5408 5403 int perm_filters,
5409 5404 FILE *tfp,
5410 5405 char *module_name,
5411 5406 char ***perm_items,
5412 5407 int *nitems)
5413 5408 {
5414 5409
5415 5410 char lbuf[IPQOS_CONF_TYPE_LINE_LEN];
5416 5411 int cnt = 0;
5417 5412 char name[IPQOS_CONF_NAME_LEN+1];
5418 5413 char foo[IPQOS_CONF_NAME_LEN+1];
5419 5414 int res;
5420 5415 char **items = NULL;
5421 5416 char **tmp;
5422 5417 char *marker;
5423 5418
5424 5419 IPQOSCDBG0(L1, "In read_perm_items\n");
5425 5420
5426 5421
5427 5422 /* seek to start of types file */
5428 5423
5429 5424 if (fseek(tfp, 0, SEEK_SET) != 0) {
5430 5425 ipqos_msg(MT_ENOSTR, "fseek");
5431 5426 return (IPQOS_CONF_ERR);
5432 5427 }
5433 5428
5434 5429 /* select which marker were looking for */
5435 5430
5436 5431 if (perm_filters) {
5437 5432 marker = IPQOS_CONF_PERM_FILTER_MK;
5438 5433 } else {
5439 5434 marker = IPQOS_CONF_PERM_CLASS_MK;
5440 5435 }
5441 5436
5442 5437 /* scan file line by line till end */
5443 5438
5444 5439 while (fgets(lbuf, IPQOS_CONF_TYPE_LINE_LEN, tfp) != NULL) {
5445 5440
5446 5441 /*
5447 5442 * if the line is marked as containing a default item name
5448 5443 * read the name, extend the items string array
5449 5444 * and store the string off the array.
5450 5445 */
5451 5446 if (strncmp(lbuf, marker, strlen(marker)) == 0) {
5452 5447
5453 5448 res = sscanf(lbuf,
5454 5449 "%" VAL2STR(IPQOS_CONF_NAME_LEN) "s"
5455 5450 "%" VAL2STR(IPQOS_CONF_NAME_LEN) "s",
5456 5451 foo, name);
5457 5452 if (res < 2) {
5458 5453 ipqos_msg(MT_ERROR,
5459 5454 gettext("Types file for module %s is "
5460 5455 "corrupt.\n"), module_name);
5461 5456 IPQOSCDBG1(L0, "Missing name with a %s.\n",
5462 5457 marker);
5463 5458 goto fail;
5464 5459 }
5465 5460
5466 5461 /* extend items array to accomodate new item */
5467 5462
5468 5463 tmp = realloc(items, (cnt + 1) * sizeof (char *));
5469 5464 if (tmp == NULL) {
5470 5465 ipqos_msg(MT_ENOSTR, "realloc");
5471 5466 goto fail;
5472 5467 } else {
5473 5468 items = tmp;
5474 5469 }
5475 5470
5476 5471 /* copy and store item name */
5477 5472
5478 5473 items[cnt] = malloc(strlen(name) + 1);
5479 5474 if (items[cnt] == NULL) {
5480 5475 ipqos_msg(MT_ENOSTR, "malloc");
5481 5476 goto fail;
5482 5477 }
5483 5478
5484 5479 (void) strcpy(items[cnt], name);
5485 5480 cnt++;
5486 5481
5487 5482
5488 5483 IPQOSCDBG1(L1, "stored %s in perm items array\n",
5489 5484 name);
5490 5485 }
5491 5486 }
5492 5487
5493 5488 *perm_items = items;
5494 5489 *nitems = cnt;
5495 5490
5496 5491 return (IPQOS_CONF_SUCCESS);
5497 5492 fail:
5498 5493 for (cnt--; cnt >= 0; cnt--)
5499 5494 free(items[cnt]);
5500 5495 free(items);
5501 5496 return (IPQOS_CONF_ERR);
5502 5497 }
5503 5498
5504 5499 /*
5505 5500 * Searches types file ref'd by tfp for the parameter named name
5506 5501 * with the place corresponding with place parameter. The format
5507 5502 * of the lines in the file are:
5508 5503 * PLACE NAME TYPE [ ENUM_DEF ] [ DEFAULT_STR ]
5509 5504 * The ENUM_DEF is an enumeration definition and is only present
5510 5505 * for parameters of type enum. DEFAULT_STR is a default value for
5511 5506 * this parameter. If present type is set to the appropriate type
5512 5507 * enumeration and dfltst filled with DEFAULT_STR if one was set.
5513 5508 * Also if the type is enum enum_nvps is made to point at a
5514 5509 * set of name value pairs representing ENUM_DEF.
5515 5510 *
5516 5511 * RETURNS: If any resource errors occur, or a matching parameter
5517 5512 * isn't found IPQOS_CONF_ERR is returned, else IPQOS_CONF_SUCCESS.
5518 5513 */
5519 5514 static int
5520 5515 readtype(
5521 5516 FILE *tfp,
5522 5517 char *module_name,
5523 5518 char *name,
5524 5519 ipqos_nvtype_t *type,
5525 5520 str_val_nd_t **enum_nvps,
5526 5521 char *dfltst,
5527 5522 boolean_t allow_ipgpc_priv,
5528 5523 place_t *place)
5529 5524 {
5530 5525
5531 5526 int ac;
5532 5527 char lbuf[IPQOS_CONF_TYPE_LINE_LEN];
5533 5528 char param[IPQOS_CONF_PNAME_LEN+1];
5534 5529 char typest[IPQOS_CONF_TYPE_LEN+1];
5535 5530 char place_st[IPQOS_CONF_TYPE_LEN+1];
5536 5531 char *cp;
5537 5532 int x;
5538 5533 char *ipgpc_nm;
5539 5534 int found = 0;
5540 5535
5541 5536 IPQOSCDBG1(L1, "In readtype: param: %s\n", name);
5542 5537
5543 5538
5544 5539 /*
5545 5540 * if allow_ipgpc_priv is true then we allow ipgpc parameters that are
5546 5541 * private between ipqosconf and ipgpc. eg. address masks, port masks.
5547 5542 */
5548 5543 if (allow_ipgpc_priv && strcmp(module_name, IPGPC_NAME) == 0) {
5549 5544 ipgpc_nm = prepend_module_name(name, IPGPC_NAME);
5550 5545 if (ipgpc_nm == NULL) {
5551 5546 return (IPQOS_CONF_ERR);
5552 5547 }
5553 5548
5554 5549 if (strcmp(ipgpc_nm, IPGPC_SADDR_MASK) == 0 ||
5555 5550 strcmp(ipgpc_nm, IPGPC_DADDR_MASK) == 0) {
5556 5551 *type = IPQOS_DATA_TYPE_ADDRESS_MASK;
5557 5552 return (IPQOS_CONF_SUCCESS);
5558 5553 } else if (strcmp(ipgpc_nm, IPGPC_SPORT_MASK) == 0 ||
5559 5554 strcmp(ipgpc_nm, IPGPC_DPORT_MASK) == 0) {
5560 5555 *type = IPQOS_DATA_TYPE_UINT16;
5561 5556 return (IPQOS_CONF_SUCCESS);
5562 5557 } else if (strcmp(ipgpc_nm, IPGPC_FILTER_TYPE) == 0) {
5563 5558 *type = IPQOS_DATA_TYPE_UINT32;
5564 5559 return (IPQOS_CONF_SUCCESS);
5565 5560 } else if (strcmp(ipgpc_nm, IPGPC_IF_INDEX) == 0) {
5566 5561 *type = IPQOS_DATA_TYPE_IFINDEX;
5567 5562 return (IPQOS_CONF_SUCCESS);
5568 5563 }
5569 5564
5570 5565 free(ipgpc_nm);
5571 5566 }
5572 5567
5573 5568 /*
5574 5569 * read upto and including module version line.
5575 5570 */
5576 5571 if (read_tfile_ver(tfp, IPQOS_MOD_STR, module_name) == -1)
5577 5572 return (IPQOS_CONF_ERR);
5578 5573
5579 5574
5580 5575 /*
5581 5576 * loop reading lines of the types file until named parameter
5582 5577 * found or EOF.
5583 5578 */
5584 5579 while (fgets(lbuf, IPQOS_CONF_TYPE_LINE_LEN, tfp) != NULL) {
5585 5580
5586 5581 /*
5587 5582 * check whether blank or commented line; if so skip
5588 5583 */
5589 5584 for (cp = lbuf; isspace(*cp) && *cp != '\0'; cp++) {}
5590 5585 if (*cp == '\0' || *cp == '#') {
5591 5586 continue;
5592 5587 }
5593 5588
5594 5589 dfltst[0] = '\0';
5595 5590
5596 5591 /*
5597 5592 * read place, param, type and if present default str
5598 5593 * from line.
5599 5594 */
5600 5595 ac = sscanf(lbuf,
5601 5596 "%" VAL2STR(IPQOS_CONF_TYPE_LEN) "s "
5602 5597 "%" VAL2STR(IPQOS_CONF_PNAME_LEN) "s "
5603 5598 "%" VAL2STR(IPQOS_CONF_TYPE_LEN) "s "
5604 5599 "%" VAL2STR(IPQOS_VALST_MAXLEN) "s",
5605 5600 place_st, param, typest, dfltst);
5606 5601 if (ac < 3) {
5607 5602 ipqos_msg(MT_ERROR,
5608 5603 gettext("Types file for module %s is corrupt.\n"),
5609 5604 module_name);
5610 5605 IPQOSCDBG0(L0, "sscanf failed to read 3 strings.\n");
5611 5606 return (IPQOS_CONF_ERR);
5612 5607 }
5613 5608
5614 5609 /*
5615 5610 * if the place and name match no need to look any further.
5616 5611 */
5617 5612 if ((*place == PL_ANY) ||
5618 5613 ((*place == PL_PARAMS) &&
5619 5614 strcmp(place_st, IPQOS_PLACE_PRM_STR) == 0) ||
5620 5615 ((*place == PL_FILTER) &&
5621 5616 strcmp(place_st, IPQOS_PLACE_FILTER_STR) == 0) ||
5622 5617 ((*place == PL_MAP) &&
5623 5618 strcmp(place_st, IPQOS_PLACE_MAP_STR) == 0)) {
5624 5619 if (strcmp(param, name) == 0) {
5625 5620 found++;
5626 5621 break;
5627 5622 }
5628 5623 }
5629 5624 }
5630 5625 if (found == 0) {
5631 5626 ipqos_msg(MT_ERROR,
5632 5627 gettext("Invalid parameter, %s, line %u.\n"), name,
5633 5628 lineno);
5634 5629 return (IPQOS_CONF_ERR);
5635 5630 }
5636 5631
5637 5632 /*
5638 5633 * set the place parameter to the actual place when the PL_ANY flag
5639 5634 * was set.
5640 5635 */
5641 5636 if (*place == PL_ANY) {
5642 5637 if (strcmp(place_st, IPQOS_PLACE_PRM_STR) == 0) {
5643 5638 *place = PL_PARAMS;
5644 5639 } else if (strcmp(place_st, IPQOS_PLACE_FILTER_STR) == 0) {
5645 5640 *place = PL_FILTER;
5646 5641 } else if (strcmp(place_st, IPQOS_PLACE_MAP_STR) == 0) {
5647 5642 *place = PL_MAP;
5648 5643 }
5649 5644 }
5650 5645
5651 5646 /*
5652 5647 * get type enumeration
5653 5648 */
5654 5649 for (x = 0; nv_types[x].string[0]; x++) {
5655 5650 if (strcmp(nv_types[x].string, typest) == 0) {
5656 5651 break;
5657 5652 }
5658 5653 }
5659 5654 /*
5660 5655 * check that we have a type corresponding with the one the types
5661 5656 * file specifies.
5662 5657 */
5663 5658 if (nv_types[x].string[0] == '\0') {
5664 5659 ipqos_msg(MT_ERROR,
5665 5660 gettext("Types file for module %s is corrupt.\n"),
5666 5661 module_name);
5667 5662 return (IPQOS_CONF_ERR);
5668 5663 }
5669 5664 *type = nv_types[x].value;
5670 5665
5671 5666 /*
5672 5667 * if enumeration type get set of name/vals and any default value
5673 5668 */
5674 5669 if (*type == IPQOS_DATA_TYPE_ENUM) {
5675 5670 *enum_nvps = read_enum_nvs(lbuf, module_name);
5676 5671 if (*enum_nvps == NULL) {
5677 5672 return (IPQOS_CONF_ERR);
5678 5673 }
5679 5674
5680 5675 dfltst[0] = '\0';
5681 5676 cp = strchr(lbuf, CURL_END);
5682 5677 (void) sscanf(++cp,
5683 5678 "%" VAL2STR(IPQOS_VALST_MAXLEN) "s", dfltst);
5684 5679 }
5685 5680
5686 5681
5687 5682 IPQOSCDBG2(L1, "read type: %s default: %s\n", nv_types[x].string,
5688 5683 *dfltst ? dfltst : "None");
5689 5684 return (IPQOS_CONF_SUCCESS);
5690 5685 }
5691 5686
5692 5687
5693 5688 /*
5694 5689 * Reads a name and a value from file ref'd by cfp into list indirectly
5695 5690 * ref'd by nvlp; If this list is NULL it will be created to accomodate
5696 5691 * the name/value. The name must be either a special token for
5697 5692 * for the place, or be present in the module types file ref'd by tfp.
5698 5693 * *type is set to the enumeration of the type of the parameter and
5699 5694 * nvp to point at the element with the nvlp ref'd list.
5700 5695 * RETURNS: IPQOS_CONF_CURL_END if read CURL_END as name,
5701 5696 * IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
5702 5697 */
5703 5698 static int
5704 5699 readnvpair(
5705 5700 FILE *cfp,
5706 5701 FILE *tfp,
5707 5702 nvlist_t **nvlp,
5708 5703 nvpair_t **nvp,
5709 5704 ipqos_nvtype_t *type,
5710 5705 place_t place,
5711 5706 char *module_name)
5712 5707 {
5713 5708
5714 5709 char *name = NULL;
5715 5710 char *valst = NULL;
5716 5711 int res;
5717 5712 char *tmp;
5718 5713 str_val_nd_t *enum_nvs = NULL;
5719 5714 char dfltst[IPQOS_VALST_MAXLEN+1];
5720 5715
5721 5716 IPQOSCDBG0(L1, "in readnvpair\n");
5722 5717
5723 5718 /*
5724 5719 * read nvpair name
5725 5720 */
5726 5721 res = readtoken(cfp, &name);
5727 5722
5728 5723 /*
5729 5724 * if reached eof, curl end or error encountered return to caller
5730 5725 */
5731 5726 if (res == IPQOS_CONF_EOF) {
5732 5727 ipqos_msg(MT_ERROR, gettext("Unexpected EOF.\n"));
5733 5728 return (IPQOS_CONF_ERR);
5734 5729 } else if (res == IPQOS_CONF_ERR) {
5735 5730 return (res);
5736 5731 } else if (res == IPQOS_CONF_CURL_END) {
5737 5732 free(name);
5738 5733 return (res);
5739 5734 }
5740 5735
5741 5736 /*
5742 5737 * read nvpair value
5743 5738 */
5744 5739 res = readtoken(cfp, &valst);
5745 5740
5746 5741 /*
5747 5742 * check we've read a valid value
5748 5743 */
5749 5744 if (res != IPQOS_CONF_SUCCESS && res != IPQOS_CONF_CURL_BEGIN) {
5750 5745 if (res == IPQOS_CONF_EOF) {
5751 5746 ipqos_msg(MT_ERROR, gettext("Unexpected EOF.\n"));
5752 5747 } else if (res == IPQOS_CONF_CURL_END) {
5753 5748 ipqos_msg(MT_ERROR,
5754 5749 gettext("Missing parameter value line %u.\n"),
5755 5750 lineno);
5756 5751 free(valst);
5757 5752 } /* we do nothing special for IPQOS_CONF_ERR */
5758 5753 free(name);
5759 5754 return (IPQOS_CONF_ERR);
5760 5755 }
5761 5756
5762 5757 /*
5763 5758 * check for generic parameters.
5764 5759 */
5765 5760
5766 5761 if ((place == PL_CLASS) &&
5767 5762 strcmp(name, IPQOS_CONF_NEXT_ACTION_STR) == 0) {
5768 5763 *type = IPQOS_DATA_TYPE_ACTION;
5769 5764
5770 5765 } else if (place == PL_PARAMS &&
5771 5766 strcmp(name, IPQOS_CONF_GLOBAL_STATS_STR) == 0 ||
5772 5767 place == PL_CLASS &&
5773 5768 strcmp(name, IPQOS_CONF_STATS_ENABLE_STR) == 0) {
5774 5769 *type = IPQOS_DATA_TYPE_BOOLEAN;
5775 5770
5776 5771 } else if (tfp == NULL ||
5777 5772 ((place != PL_PARAMS) && strcmp(name, IPQOS_CONF_NAME_STR) == 0) ||
5778 5773 (place == PL_FILTER) && (strcmp(name, IPQOS_CONF_CLASS_STR) ==
5779 5774 0) ||
5780 5775 (place == PL_ACTION) && (strcmp(name, IPQOS_CONF_MODULE_STR) ==
5781 5776 0)) {
5782 5777 *type = IPQOS_DATA_TYPE_STRING;
5783 5778
5784 5779 } else { /* if not generic parameter */
5785 5780 /*
5786 5781 * get type from types file
5787 5782 */
5788 5783 if (readtype(tfp, module_name, name, type, &enum_nvs, dfltst,
5789 5784 B_FALSE, &place) != IPQOS_CONF_SUCCESS) {
5790 5785 free(name);
5791 5786 free(valst);
5792 5787 return (IPQOS_CONF_ERR);
5793 5788 }
5794 5789
5795 5790 /*
5796 5791 * get full module prefix parameter name
5797 5792 */
5798 5793 tmp = name;
5799 5794 if ((name = prepend_module_name(name, module_name)) == NULL) {
5800 5795 name = tmp;
5801 5796 goto fail;
5802 5797 }
5803 5798 free(tmp);
5804 5799 }
5805 5800
5806 5801 IPQOSCDBG3(L1, "NVP, name: %s, str_value: %s, type: %s\n", name,
5807 5802 valst, nv_types[*type].string);
5808 5803
5809 5804
5810 5805 /*
5811 5806 * create nvlist if not present already
5812 5807 */
5813 5808 if (*nvlp == NULL) {
5814 5809 res = nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0);
5815 5810 if (res != 0) {
5816 5811 ipqos_msg(MT_ENOSTR, "nvlist_alloc");
5817 5812 free(name);
5818 5813 free(valst);
5819 5814 return (IPQOS_CONF_ERR);
5820 5815 }
5821 5816 }
5822 5817
5823 5818 /*
5824 5819 * check we haven't already read this parameter
5825 5820 */
5826 5821 if (find_nvpair(*nvlp, name)) {
5827 5822 ipqos_msg(MT_ERROR, gettext("Duplicate parameter line %u.\n"),
5828 5823 lineno);
5829 5824 goto fail;
5830 5825 }
5831 5826
5832 5827 /*
5833 5828 * convert value string to appropriate type and add to nvlist
5834 5829 */
5835 5830
5836 5831 switch (*type) {
5837 5832 case IPQOS_DATA_TYPE_IFNAME: {
5838 5833 uint32_t ifidx;
5839 5834
5840 5835 res = readifindex(valst, (int *)&ifidx);
5841 5836 if (res == IPQOS_CONF_SUCCESS) {
5842 5837 res = nvlist_add_uint32(*nvlp, IPGPC_IF_INDEX,
5843 5838 ifidx);
5844 5839 if (res != 0) {
5845 5840 ipqos_msg(MT_ENOSTR,
5846 5841 "nvlist_add_uint32");
5847 5842 goto fail;
5848 5843 }
5849 5844 (void) nvlist_remove_all(*nvlp, name);
5850 5845 /*
5851 5846 * change name to point at the name of the
5852 5847 * new ifindex nvlist entry as name is used
5853 5848 * later in the function.
5854 5849 */
5855 5850 free(name);
5856 5851 name = malloc(strlen(IPGPC_IF_INDEX) + 1);
5857 5852 if (name == NULL) {
5858 5853 ipqos_msg(MT_ENOSTR, "malloc");
5859 5854 goto fail;
5860 5855 }
5861 5856 (void) strcpy(name, IPGPC_IF_INDEX);
5862 5857 }
5863 5858 break;
5864 5859 }
5865 5860 case IPQOS_DATA_TYPE_PROTO: {
5866 5861 uint8_t proto;
5867 5862
5868 5863 res = readproto(valst, &proto);
5869 5864 if (res == IPQOS_CONF_SUCCESS) {
5870 5865 res = nvlist_add_byte(*nvlp, name, proto);
5871 5866 if (res != 0) {
5872 5867 ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
5873 5868 goto fail;
5874 5869 }
5875 5870 }
5876 5871 break;
5877 5872 }
5878 5873 case IPQOS_DATA_TYPE_PORT: {
5879 5874 uint16_t port;
5880 5875
5881 5876 res = readport(valst, &port);
5882 5877 if (res == IPQOS_CONF_SUCCESS) {
5883 5878
5884 5879 /* add port */
5885 5880
5886 5881 res = nvlist_add_uint16(*nvlp, name, port);
5887 5882 if (res != 0) {
5888 5883 ipqos_msg(MT_ENOSTR,
5889 5884 "nvlist_add_uint16");
5890 5885 goto fail;
5891 5886 }
5892 5887
5893 5888 /* add appropriate all ones port mask */
5894 5889
5895 5890 if (strcmp(name, IPGPC_DPORT) == 0) {
5896 5891 res = nvlist_add_uint16(*nvlp,
5897 5892 IPGPC_DPORT_MASK, ~0);
5898 5893
5899 5894 } else if (strcmp(name, IPGPC_SPORT) == 0) {
5900 5895 res = nvlist_add_uint16(*nvlp,
5901 5896 IPGPC_SPORT_MASK, ~0);
5902 5897 }
5903 5898 if (res != 0) {
5904 5899 ipqos_msg(MT_ENOSTR,
5905 5900 "nvlist_add_uint16");
5906 5901 goto fail;
5907 5902 }
5908 5903 }
5909 5904 break;
5910 5905 }
5911 5906 case IPQOS_DATA_TYPE_ADDRESS:
5912 5907 case IPQOS_DATA_TYPE_ACTION:
5913 5908 case IPQOS_DATA_TYPE_STRING:
5914 5909 res = nvlist_add_string(*nvlp, name, valst);
5915 5910 if (res != 0) {
5916 5911 ipqos_msg(MT_ENOSTR, "nvlist_add_string");
5917 5912 goto fail;
5918 5913 }
5919 5914 break;
5920 5915 case IPQOS_DATA_TYPE_BOOLEAN: {
5921 5916 boolean_t b;
5922 5917
5923 5918 res = readbool(valst, &b);
5924 5919 if (res == IPQOS_CONF_SUCCESS) {
5925 5920 res = nvlist_add_uint32(*nvlp, name,
5926 5921 (uint32_t)b);
5927 5922 if (res != 0) {
5928 5923 ipqos_msg(MT_ENOSTR,
5929 5924 "nvlist_add_uint32");
5930 5925 goto fail;
5931 5926 }
5932 5927 }
5933 5928 break;
5934 5929 }
5935 5930 case IPQOS_DATA_TYPE_UINT8: {
5936 5931 uint8_t u8;
5937 5932
5938 5933 res = readuint8(valst, &u8, &tmp);
5939 5934 if (res == IPQOS_CONF_SUCCESS) {
5940 5935 res = nvlist_add_byte(*nvlp, name, u8);
5941 5936 if (res != 0) {
5942 5937 ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
5943 5938 goto fail;
5944 5939 }
5945 5940 }
5946 5941 break;
5947 5942 }
5948 5943 case IPQOS_DATA_TYPE_INT16: {
5949 5944 int16_t i16;
5950 5945
5951 5946 res = readint16(valst, &i16, &tmp);
5952 5947 if (res == IPQOS_CONF_SUCCESS) {
5953 5948 res = nvlist_add_int16(*nvlp, name, i16);
5954 5949 if (res != 0) {
5955 5950 ipqos_msg(MT_ENOSTR,
5956 5951 "nvlist_add_int16");
5957 5952 goto fail;
5958 5953 }
5959 5954 }
5960 5955 break;
5961 5956 }
5962 5957 case IPQOS_DATA_TYPE_UINT16: {
5963 5958 uint16_t u16;
5964 5959
5965 5960 res = readuint16(valst, &u16, &tmp);
5966 5961 if (res == IPQOS_CONF_SUCCESS) {
5967 5962 res = nvlist_add_uint16(*nvlp, name, u16);
5968 5963 if (res != 0) {
5969 5964 ipqos_msg(MT_ENOSTR,
5970 5965 "nvlist_add_int16");
5971 5966 goto fail;
5972 5967 }
5973 5968 }
5974 5969 break;
5975 5970 }
5976 5971 case IPQOS_DATA_TYPE_INT32: {
5977 5972 int i32;
5978 5973
5979 5974 res = readint32(valst, &i32, &tmp);
5980 5975 if (res == IPQOS_CONF_SUCCESS) {
5981 5976 res = nvlist_add_int32(*nvlp, name, i32);
5982 5977 if (res != 0) {
5983 5978 ipqos_msg(MT_ENOSTR,
5984 5979 "nvlist_add_int32");
5985 5980 goto fail;
5986 5981 }
5987 5982 }
5988 5983 break;
5989 5984 }
5990 5985 case IPQOS_DATA_TYPE_UINT32: {
5991 5986 uint32_t u32;
5992 5987
5993 5988 res = readuint32(valst, &u32, &tmp);
5994 5989 if (res == IPQOS_CONF_SUCCESS) {
5995 5990 res = nvlist_add_uint32(*nvlp, name, u32);
5996 5991 if (res != 0) {
5997 5992 ipqos_msg(MT_ENOSTR,
5998 5993 "nvlist_add_uint32");
5999 5994 goto fail;
6000 5995 }
6001 5996 }
6002 5997 break;
6003 5998 }
6004 5999 case IPQOS_DATA_TYPE_ENUM: {
6005 6000 uint32_t val;
6006 6001
6007 6002 res = read_enum_value(cfp, valst, enum_nvs, &val);
6008 6003 if (res == IPQOS_CONF_SUCCESS) {
6009 6004 res = nvlist_add_uint32(*nvlp, name, val);
6010 6005 if (res != 0) {
6011 6006 ipqos_msg(MT_ENOSTR,
6012 6007 "nvlist_add_uint32");
6013 6008 goto fail;
6014 6009 }
6015 6010 } else {
6016 6011 goto fail;
6017 6012 }
6018 6013 break;
6019 6014 }
6020 6015 /*
6021 6016 * For now the dfltst contains a comma separated list of the
6022 6017 * type we need this parameter to be mapped to.
6023 6018 * read_mapped_values will fill in all the mapped parameters
6024 6019 * and their values in the nvlist.
6025 6020 */
6026 6021 case IPQOS_DATA_TYPE_M_INDEX: {
6027 6022 uint8_t u8;
6028 6023
6029 6024 res = readuint8(valst, &u8, &tmp);
6030 6025 if (res == IPQOS_CONF_SUCCESS) {
6031 6026 res = nvlist_add_byte(*nvlp, name, u8);
6032 6027 if (res != 0) {
6033 6028 ipqos_msg(MT_ENOSTR,
6034 6029 "nvlist_add_uint8");
6035 6030 goto fail;
6036 6031 }
6037 6032 } else {
6038 6033 *type = IPQOS_DATA_TYPE_UINT8;
6039 6034 break;
6040 6035 }
6041 6036 res = read_mapped_values(tfp, nvlp, module_name,
6042 6037 dfltst, u8);
6043 6038 if (res != IPQOS_CONF_SUCCESS) {
6044 6039 goto fail;
6045 6040 }
6046 6041 break;
6047 6042 }
6048 6043 case IPQOS_DATA_TYPE_INT_ARRAY: {
6049 6044 str_val_nd_t *arr_enum_nvs = NULL;
6050 6045 uint32_t size;
6051 6046 int llimit = 0, ulimit = 0;
6052 6047 int *arr;
6053 6048
6054 6049 /*
6055 6050 * read array info from types file.
6056 6051 */
6057 6052 res = read_int_array_info(dfltst, &arr_enum_nvs, &size,
6058 6053 &llimit, &ulimit, module_name);
6059 6054 if (res != IPQOS_CONF_SUCCESS) {
6060 6055 goto fail;
6061 6056 }
6062 6057
6063 6058 /*
6064 6059 * read array contents from config file and construct
6065 6060 * array with them.
6066 6061 */
6067 6062 res = read_int_array(cfp, valst, &arr, size, llimit,
6068 6063 ulimit, arr_enum_nvs);
6069 6064 if (res != IPQOS_CONF_SUCCESS) {
6070 6065 goto fail;
6071 6066 }
6072 6067
6073 6068 /*
6074 6069 * add array to nvlist.
6075 6070 */
6076 6071 res = nvlist_add_int32_array(*nvlp, name, arr, size);
6077 6072 if (res != 0) {
6078 6073 ipqos_msg(MT_ENOSTR, "nvlist_add_int32");
6079 6074 goto fail;
6080 6075 }
6081 6076
6082 6077 /*
6083 6078 * free uneeded resources.
6084 6079 */
6085 6080 free(arr);
6086 6081 if (arr_enum_nvs)
6087 6082 free_str_val_entrys(arr_enum_nvs);
6088 6083
6089 6084 break;
6090 6085 }
6091 6086 case IPQOS_DATA_TYPE_USER: {
6092 6087 uid_t uid;
6093 6088
6094 6089 res = readuser(valst, &uid);
6095 6090 if (res == IPQOS_CONF_SUCCESS) {
6096 6091 res = nvlist_add_int32(*nvlp, name, (int)uid);
6097 6092 if (res != 0) {
6098 6093 ipqos_msg(MT_ENOSTR,
6099 6094 "nvlist_add_int32");
6100 6095 goto fail;
6101 6096 }
6102 6097 }
6103 6098 break;
6104 6099 }
6105 6100 #ifdef _IPQOS_CONF_DEBUG
6106 6101 default: {
6107 6102 /*
6108 6103 * we shouldn't have a type that doesn't have a switch
6109 6104 * entry.
6110 6105 */
6111 6106 assert(1);
6112 6107 }
6113 6108 #endif
6114 6109 }
6115 6110 if (res != 0) {
6116 6111 ipqos_msg(MT_ERROR, gettext("Invalid %s, line %u.\n"),
6117 6112 nv_types[*type].string, lineno);
6118 6113 goto fail;
6119 6114 }
6120 6115
6121 6116 /* set the nvp parameter to point at the newly added nvlist entry */
6122 6117
6123 6118 *nvp = find_nvpair(*nvlp, name);
6124 6119
6125 6120 free(name);
6126 6121 free(valst);
6127 6122 if (enum_nvs)
6128 6123 free_str_val_entrys(enum_nvs);
6129 6124 return (IPQOS_CONF_SUCCESS);
6130 6125 fail:
6131 6126 if (name != NULL)
6132 6127 free(name);
6133 6128 if (valst != NULL)
6134 6129 free(valst);
6135 6130 if (enum_nvs != NULL)
6136 6131 free_str_val_entrys(enum_nvs);
6137 6132 return (IPQOS_CONF_ERR);
6138 6133 }
6139 6134
6140 6135 /*
6141 6136 * read a parameter clause from cfp into *params.
6142 6137 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
6143 6138 */
6144 6139 static int
6145 6140 readparams(
6146 6141 FILE *cfp,
6147 6142 FILE *tfp,
6148 6143 char *module_name,
6149 6144 ipqos_conf_params_t *params)
6150 6145 {
6151 6146
6152 6147 int res;
6153 6148 nvpair_t *nvp;
6154 6149 ipqos_nvtype_t type;
6155 6150 boolean_t bl;
6156 6151 char *nm;
6157 6152 char *action;
6158 6153 char tmp[IPQOS_CONF_PNAME_LEN];
6159 6154 int read_stats = 0;
6160 6155
6161 6156 IPQOSCDBG0(L0, "in readparams\n");
6162 6157
6163 6158 /* read beginning curl */
6164 6159
6165 6160 res = read_curl_begin(cfp);
6166 6161 if (res != IPQOS_CONF_SUCCESS) {
6167 6162 return (res);
6168 6163 }
6169 6164
6170 6165 /*
6171 6166 * loop reading nvpairs, adding to params nvlist until encounter
6172 6167 * CURL_END.
6173 6168 */
6174 6169 for (;;) {
6175 6170 /* read nvpair */
6176 6171
6177 6172 res = readnvpair(cfp, tfp, ¶ms->nvlist,
6178 6173 &nvp, &type, PL_PARAMS, module_name);
6179 6174 if (res == IPQOS_CONF_ERR) {
6180 6175 goto fail;
6181 6176
6182 6177 /* we have finished reading params */
6183 6178
6184 6179 } else if (res == IPQOS_CONF_CURL_END) {
6185 6180 break;
6186 6181 }
6187 6182
6188 6183 /*
6189 6184 * read global stats - place into params struct and remove
6190 6185 * from nvlist.
6191 6186 */
6192 6187 if (strcmp(nvpair_name(nvp), IPQOS_CONF_GLOBAL_STATS_STR) ==
6193 6188 0) {
6194 6189 /* check we haven't read stats before */
6195 6190
6196 6191 if (read_stats) {
6197 6192 ipqos_msg(MT_ERROR,
6198 6193 gettext("Duplicate parameter line %u.\n"),
6199 6194 lineno);
6200 6195 goto fail;
6201 6196 }
6202 6197 read_stats++;
6203 6198
6204 6199 (void) nvpair_value_uint32(nvp, (uint32_t *)&bl);
6205 6200 params->stats_enable = bl;
6206 6201 (void) nvlist_remove_all(params->nvlist,
6207 6202 IPQOS_CONF_GLOBAL_STATS_STR);
6208 6203
6209 6204
6210 6205 /*
6211 6206 * read action type parameter - add it to list of action refs.
6212 6207 * also, if it's one of continue or drop virtual actions
6213 6208 * change the action name to their special ipp names in
6214 6209 * the action ref list and the nvlist.
6215 6210 */
6216 6211 } else if (type == IPQOS_DATA_TYPE_ACTION) {
6217 6212
6218 6213 /* get name and value from nvlist */
6219 6214
6220 6215 nm = nvpair_name(nvp);
6221 6216 (void) nvpair_value_string(nvp, &action);
6222 6217
6223 6218 /* if virtual action names change to ipp name */
6224 6219
6225 6220 if ((strcmp(action, IPQOS_CONF_CONT_STR) == 0) ||
6226 6221 strcmp(action, IPQOS_CONF_DROP_STR) == 0) {
6227 6222 /*
6228 6223 * we copy nm to a seperate buffer as nv_pair
6229 6224 * name above gave us a ptr to internal
6230 6225 * memory which causes strange behaviour
6231 6226 * when we re-value that nvlist element.
6232 6227 */
6233 6228 (void) strlcpy(tmp, nm, sizeof (tmp));
6234 6229 nm = tmp;
6235 6230
6236 6231
6237 6232 /* modify nvlist entry and change action */
6238 6233
6239 6234 if (strcmp(action, IPQOS_CONF_CONT_STR) == 0) {
6240 6235 action = IPP_ANAME_CONT;
6241 6236 res = nvlist_add_string(params->nvlist,
6242 6237 nm, action);
6243 6238 } else {
6244 6239 action = IPP_ANAME_DROP;
6245 6240 res = nvlist_add_string(params->nvlist,
6246 6241 nm, action);
6247 6242 }
6248 6243 if (res != 0) {
6249 6244 ipqos_msg(MT_ENOSTR,
6250 6245 "nvlist_add_string");
6251 6246 goto fail;
6252 6247 }
6253 6248 }
6254 6249
6255 6250 /* add action reference to params */
6256 6251
6257 6252 res = add_aref(¶ms->actions, nm, action);
6258 6253 }
6259 6254 }
6260 6255
6261 6256 return (IPQOS_CONF_SUCCESS);
6262 6257 fail:
6263 6258
6264 6259 if (params->nvlist) {
6265 6260 nvlist_free(params->nvlist);
6266 6261 params->nvlist = NULL;
6267 6262 }
6268 6263 if (params->actions) {
6269 6264 free_arefs(params->actions);
6270 6265 params->actions = NULL;
6271 6266 }
6272 6267 return (IPQOS_CONF_ERR);
6273 6268 }
6274 6269
6275 6270 /* ************************* class manip fns ****************************** */
6276 6271
6277 6272
6278 6273
6279 6274 /*
6280 6275 * make dst point at a dupicate class struct with duplicate elements to src.
6281 6276 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
6282 6277 */
6283 6278 static int
6284 6279 dup_class(
6285 6280 ipqos_conf_class_t *src,
6286 6281 ipqos_conf_class_t **dst)
6287 6282 {
6288 6283
6289 6284 ipqos_conf_class_t *cls;
6290 6285 int res;
6291 6286
6292 6287 IPQOSCDBG1(DIFF, "In dup_class: class: %s\n", src->name);
6293 6288 cls = alloc_class();
6294 6289 if (cls == NULL) {
6295 6290 return (IPQOS_CONF_ERR);
6296 6291 }
6297 6292
6298 6293 /* struct copy */
6299 6294 *cls = *src;
6300 6295
6301 6296 /* we're not interested in the nvlist for a class */
6302 6297 cls->nvlist = NULL;
6303 6298
6304 6299
6305 6300 /* copy first action reference */
6306 6301 cls->alist = NULL;
6307 6302 res = add_aref(&cls->alist, src->alist->field, src->alist->name);
6308 6303 if (res != IPQOS_CONF_SUCCESS) {
6309 6304 free(cls);
6310 6305 return (res);
6311 6306 }
6312 6307
6313 6308 *dst = cls;
6314 6309
6315 6310 return (IPQOS_CONF_SUCCESS);
6316 6311 }
6317 6312
6318 6313 /*
6319 6314 * create a zero'd class struct and return a ptr to it.
6320 6315 * RETURNS: ptr to struct on success, NULL otherwise.
6321 6316 */
6322 6317 static ipqos_conf_class_t *
6323 6318 alloc_class()
6324 6319 {
6325 6320
6326 6321 ipqos_conf_class_t *class;
6327 6322
6328 6323 class = malloc(sizeof (ipqos_conf_class_t));
6329 6324 if (class) {
6330 6325 bzero(class, sizeof (ipqos_conf_class_t));
6331 6326 } else {
6332 6327 ipqos_msg(MT_ENOSTR, "malloc");
6333 6328 }
6334 6329
6335 6330 return (class);
6336 6331 }
6337 6332
↓ open down ↓ |
5547 lines elided |
↑ open up ↑ |
6338 6333 /* frees up all memory occupied by a filter struct and its contents. */
6339 6334 static void
6340 6335 free_class(ipqos_conf_class_t *cls)
6341 6336 {
6342 6337
6343 6338 if (cls == NULL)
6344 6339 return;
6345 6340
6346 6341 /* free its nvlist if present */
6347 6342
6348 - if (cls->nvlist)
6349 - nvlist_free(cls->nvlist);
6343 + nvlist_free(cls->nvlist);
6350 6344
6351 6345 /* free its action refs if present */
6352 6346
6353 6347 if (cls->alist)
6354 6348 free_arefs(cls->alist);
6355 6349
6356 6350 /* finally free class itself */
6357 6351 free(cls);
6358 6352 }
6359 6353
6360 6354 /*
6361 6355 * Checks whether there is a class called class_nm in classes list.
6362 6356 * RETURNS: ptr to first matched class, else if not matched NULL.
6363 6357 */
6364 6358 static ipqos_conf_class_t *
6365 6359 classexist(
6366 6360 char *class_nm,
6367 6361 ipqos_conf_class_t *classes)
6368 6362 {
6369 6363
6370 6364 ipqos_conf_class_t *cls;
6371 6365
6372 6366 IPQOSCDBG1(L1, "In classexist: name: %s\n", class_nm);
6373 6367
6374 6368 for (cls = classes; cls; cls = cls->next) {
6375 6369 if (strcmp(class_nm, cls->name) == 0) {
6376 6370 break;
6377 6371 }
6378 6372 }
6379 6373
6380 6374 return (cls);
6381 6375 }
6382 6376
6383 6377
6384 6378
6385 6379 /* ************************** filter manip fns **************************** */
6386 6380
6387 6381
6388 6382
6389 6383 /*
6390 6384 * Checks whether there is a filter called filter_nm with instance number
6391 6385 * instance in filters list created by us or permanent. Instance value -1
6392 6386 * is a wildcard.
6393 6387 * RETURNS: ptr to first matched filter, else if not matched NULL.
6394 6388 */
6395 6389 static ipqos_conf_filter_t *
6396 6390 filterexist(
6397 6391 char *filter_nm,
6398 6392 int instance,
6399 6393 ipqos_conf_filter_t *filters)
6400 6394 {
6401 6395
6402 6396 IPQOSCDBG2(L1, "In filterexist: name :%s, inst: %d\n", filter_nm,
6403 6397 instance);
6404 6398
6405 6399 while (filters) {
6406 6400 if (strcmp(filters->name, filter_nm) == 0 &&
6407 6401 (instance == -1 || filters->instance == instance) &&
6408 6402 (filters->originator == IPP_CONFIG_IPQOSCONF ||
6409 6403 filters->originator == IPP_CONFIG_PERMANENT)) {
6410 6404 break;
6411 6405 }
6412 6406 filters = filters->next;
6413 6407 }
6414 6408 return (filters);
6415 6409 }
6416 6410
6417 6411 /*
6418 6412 * allocate and zero a filter structure.
6419 6413 * RETURNS: NULL on error, else ptr to filter struct.
6420 6414 */
6421 6415 static ipqos_conf_filter_t *
6422 6416 alloc_filter()
6423 6417 {
6424 6418
6425 6419 ipqos_conf_filter_t *flt;
6426 6420
6427 6421 flt = malloc(sizeof (ipqos_conf_filter_t));
6428 6422 if (flt) {
6429 6423 bzero(flt, sizeof (ipqos_conf_filter_t));
6430 6424 flt->instance = -1;
6431 6425 } else {
6432 6426 ipqos_msg(MT_ENOSTR, "malloc");
6433 6427 }
6434 6428
6435 6429 return (flt);
6436 6430 }
6437 6431
6438 6432 /* free flt and all it's contents. */
6439 6433
6440 6434 static void
6441 6435 free_filter(ipqos_conf_filter_t *flt)
6442 6436 {
6443 6437
6444 6438 IPQOSCDBG2(L1, "In free_filter: filter: %s, inst: %d\n", flt->name,
6445 6439 flt->instance);
6446 6440
6447 6441 if (flt == NULL)
6448 6442 return;
6449 6443
6450 6444 if (flt->src_nd_name)
6451 6445 free(flt->src_nd_name);
6452 6446 if (flt->dst_nd_name)
6453 6447 free(flt->dst_nd_name);
6454 6448 if (flt->nvlist) {
6455 6449 nvlist_free(flt->nvlist);
6456 6450 }
6457 6451 free(flt);
6458 6452 }
6459 6453
6460 6454 /*
6461 6455 * makes a copy of ofilter and its contents and points nfilter at it. It
6462 6456 * also adds an instance number to the filter and if either saddr or
6463 6457 * daddr are non-null that address to the filters nvlist along with
6464 6458 * an all 1s address mask and the af.
6465 6459 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
6466 6460 */
6467 6461 static int
6468 6462 dup_filter(
6469 6463 ipqos_conf_filter_t *ofilter,
6470 6464 ipqos_conf_filter_t **nfilter,
6471 6465 int af,
6472 6466 int inv6, /* if saddr or daddr set and v4 filter are they in v6 addr */
6473 6467 void *saddr,
6474 6468 void *daddr,
6475 6469 int inst)
6476 6470 {
6477 6471
6478 6472 ipqos_conf_filter_t *nf;
6479 6473 int res;
6480 6474 in6_addr_t v6addr;
6481 6475 in6_addr_t all_1s_v6;
6482 6476
6483 6477 IPQOSCDBG4(MHME, "In dup_filter: name: %s, af: %u, inv6: %u, ins: %d\n",
6484 6478 ofilter->name, af, inv6, inst);
6485 6479
6486 6480 /* show src address and dst address if present */
6487 6481 #ifdef _IPQOS_CONF_DEBUG
6488 6482 if (ipqosconf_dbg_flgs & MHME) {
6489 6483 char st[100];
6490 6484
6491 6485 if (saddr) {
6492 6486 (void) fprintf(stderr, "saddr: %s\n",
6493 6487 inet_ntop(inv6 ? AF_INET6 : AF_INET, saddr, st,
6494 6488 100));
6495 6489 }
6496 6490
6497 6491 if (daddr) {
6498 6492 (void) fprintf(stderr, "daddr: %s\n",
6499 6493 inet_ntop(inv6 ? AF_INET6 : AF_INET, daddr, st,
6500 6494 100));
6501 6495 }
6502 6496 }
6503 6497 #endif /* _IPQOS_CONF_DEBUG */
6504 6498
6505 6499 /* init local v6 address to 0 */
6506 6500 (void) bzero(&v6addr, sizeof (in6_addr_t));
6507 6501
6508 6502 /* create an all 1s address for use as mask */
6509 6503 (void) memset(&all_1s_v6, ~0, sizeof (in6_addr_t));
6510 6504
6511 6505 /* create a new filter */
6512 6506
6513 6507 nf = alloc_filter();
6514 6508 if (nf == NULL) {
6515 6509 return (IPQOS_CONF_ERR);
6516 6510 }
6517 6511
6518 6512 /* struct copy old filter to new */
6519 6513 *nf = *ofilter;
6520 6514
6521 6515 /* copy src filters nvlist if there is one to copy */
6522 6516
6523 6517 if (ofilter->nvlist) {
6524 6518 res = nvlist_dup(ofilter->nvlist, &nf->nvlist, 0);
6525 6519 if (res != 0) {
6526 6520 ipqos_msg(MT_ENOSTR, "nvlist_dup");
6527 6521 goto fail;
6528 6522 }
6529 6523 }
6530 6524
6531 6525 /* copy src and dst node names if present */
6532 6526
6533 6527 if (ofilter->src_nd_name) {
6534 6528 nf->src_nd_name = malloc(strlen(ofilter->src_nd_name) + 1);
6535 6529 if (nf->src_nd_name == NULL) {
6536 6530 ipqos_msg(MT_ENOSTR, "malloc");
6537 6531 goto fail;
6538 6532 }
6539 6533 (void) strcpy(nf->src_nd_name, ofilter->src_nd_name);
6540 6534 }
6541 6535 if (ofilter->dst_nd_name) {
6542 6536 nf->dst_nd_name = malloc(strlen(ofilter->dst_nd_name) + 1);
6543 6537 if (nf->dst_nd_name == NULL) {
6544 6538 ipqos_msg(MT_ENOSTR, "malloc");
6545 6539 goto fail;
6546 6540 }
6547 6541 (void) strcpy(nf->dst_nd_name, ofilter->dst_nd_name);
6548 6542 }
6549 6543
6550 6544 /* add filter addresses type */
6551 6545
6552 6546 res = nvlist_add_byte(nf->nvlist, IPGPC_FILTER_TYPE,
6553 6547 af == AF_INET ? IPGPC_V4_FLTR : IPGPC_V6_FLTR);
6554 6548 if (res != 0) {
6555 6549 ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
6556 6550 goto fail;
6557 6551 }
6558 6552 IPQOSCDBG1(MHME, "adding address type %s in dup filter\n",
6559 6553 af == AF_INET ? "AF_INET" : "AF_INET6");
6560 6554
6561 6555 /* add saddr if present */
6562 6556
6563 6557 if (saddr) {
6564 6558 if (af == AF_INET && !inv6) {
6565 6559 V4_PART_OF_V6(v6addr) = *(uint32_t *)saddr;
6566 6560 saddr = &v6addr;
6567 6561 }
6568 6562
6569 6563 /* add address and all 1's mask */
6570 6564
6571 6565 if (nvlist_add_uint32_array(nf->nvlist, IPGPC_SADDR,
6572 6566 (uint32_t *)saddr, 4) != 0 ||
6573 6567 nvlist_add_uint32_array(nf->nvlist, IPGPC_SADDR_MASK,
6574 6568 (uint32_t *)&all_1s_v6, 4) != 0) {
6575 6569 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32_array");
6576 6570 goto fail;
6577 6571 }
6578 6572
6579 6573 }
6580 6574
6581 6575 /* add daddr if present */
6582 6576
6583 6577 if (daddr) {
6584 6578 if (af == AF_INET && !inv6) {
6585 6579 V4_PART_OF_V6(v6addr) = *(uint32_t *)daddr;
6586 6580 daddr = &v6addr;
6587 6581 }
6588 6582
6589 6583 /* add address and all 1's mask */
6590 6584
6591 6585 if (nvlist_add_uint32_array(nf->nvlist, IPGPC_DADDR,
6592 6586 (uint32_t *)daddr, 4) != 0 ||
6593 6587 nvlist_add_uint32_array(nf->nvlist, IPGPC_DADDR_MASK,
6594 6588 (uint32_t *)&all_1s_v6, 4) != 0) {
6595 6589 ipqos_msg(MT_ENOSTR, "nvlist_add_uint32_array");
6596 6590 goto fail;
6597 6591 }
6598 6592 }
6599 6593
6600 6594 /* add filter instance */
6601 6595
6602 6596 nf->instance = inst;
6603 6597
6604 6598 *nfilter = nf;
6605 6599 return (IPQOS_CONF_SUCCESS);
6606 6600 fail:
6607 6601 free_filter(nf);
6608 6602 return (IPQOS_CONF_ERR);
6609 6603 }
6610 6604
6611 6605
6612 6606
6613 6607 /* ************************* action manip fns ********************** */
6614 6608
6615 6609
6616 6610
6617 6611 /*
6618 6612 * create and zero action structure and a params structure hung off of it.
6619 6613 * RETURNS: ptr to allocated action on success, else NULL.
6620 6614 */
6621 6615 static ipqos_conf_action_t *
6622 6616 alloc_action()
6623 6617 {
6624 6618
6625 6619 ipqos_conf_action_t *action;
6626 6620
6627 6621 action = (ipqos_conf_action_t *)malloc(sizeof (ipqos_conf_action_t));
6628 6622 if (action == NULL) {
6629 6623 ipqos_msg(MT_ENOSTR, "malloc");
6630 6624 return (action);
6631 6625 }
6632 6626 bzero(action, sizeof (ipqos_conf_action_t));
6633 6627
6634 6628 action->params = (ipqos_conf_params_t *)
6635 6629 malloc(sizeof (ipqos_conf_params_t));
6636 6630 if (action->params == NULL) {
6637 6631 free(action);
6638 6632 return (NULL);
6639 6633 }
6640 6634 bzero(action->params, sizeof (ipqos_conf_params_t));
6641 6635 action->params->stats_enable = B_FALSE;
6642 6636
6643 6637 return (action);
6644 6638 }
6645 6639
6646 6640 /*
6647 6641 * free all the memory used in all the actions in actions list.
6648 6642 */
6649 6643 static void
6650 6644 free_actions(
6651 6645 ipqos_conf_action_t *actions)
6652 6646 {
6653 6647
6654 6648 ipqos_conf_action_t *act = actions;
6655 6649 ipqos_conf_action_t *next;
6656 6650 ipqos_conf_filter_t *flt, *nf;
6657 6651 ipqos_conf_class_t *cls, *nc;
6658 6652
6659 6653 while (act != NULL) {
6660 6654 /* free parameters */
6661 6655
6662 6656 if (act->params != NULL) {
6663 6657 free_arefs(act->params->actions);
6664 6658 if (act->params->nvlist != NULL) {
6665 6659 nvlist_free(act->params->nvlist);
6666 6660 }
6667 6661 free(act->params);
6668 6662 }
6669 6663
6670 6664 /* free action nvlist */
6671 6665
6672 6666 if (act->nvlist != NULL)
6673 6667 free(act->nvlist);
6674 6668
6675 6669 /* free filters */
6676 6670
6677 6671 flt = act->filters;
6678 6672 while (flt != NULL) {
6679 6673 nf = flt->next;
6680 6674 free_filter(flt);
6681 6675 flt = nf;
6682 6676 }
6683 6677
6684 6678 /* free classes */
6685 6679
6686 6680 cls = act->classes;
6687 6681 while (cls != NULL) {
6688 6682 nc = cls->next;
6689 6683 free_class(cls);
6690 6684 cls = nc;
6691 6685 }
6692 6686
6693 6687 /* free permanent classes table */
6694 6688 cleanup_string_table(act->perm_classes, act->num_perm_classes);
6695 6689
6696 6690 /* free filters to retry */
6697 6691
6698 6692 flt = act->retry_filters;
6699 6693 while (flt != NULL) {
6700 6694 nf = flt->next;
6701 6695 free_filter(flt);
6702 6696 flt = nf;
6703 6697 }
6704 6698
6705 6699 /* free dependency pointers */
6706 6700 free_arefs(act->dependencies);
6707 6701
6708 6702 next = act->next;
6709 6703 free(act);
6710 6704 act = next;
6711 6705 }
6712 6706 }
6713 6707
6714 6708 /*
6715 6709 * Checks whether there is an action called action_name in actions list.
6716 6710 * RETURNS: ptr to first matched action, else if not matched NULL.
6717 6711 *
6718 6712 */
6719 6713 static ipqos_conf_action_t *
6720 6714 actionexist(
6721 6715 char *action_name,
6722 6716 ipqos_conf_action_t *actions)
6723 6717 {
6724 6718
6725 6719 IPQOSCDBG1(L1, "In actionexist: name: %s\n", action_name);
6726 6720
6727 6721 while (actions) {
6728 6722 if (strcmp(action_name, actions->name) == 0) {
6729 6723 break;
6730 6724 }
6731 6725 actions = actions->next;
6732 6726 }
6733 6727
6734 6728 return (actions);
6735 6729 }
6736 6730
6737 6731 /* **************************** act ref manip fns ******************** */
6738 6732
6739 6733
6740 6734 /*
6741 6735 * add an action reference element with parameter field and action
6742 6736 * action_name to arefs.
6743 6737 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
6744 6738 */
6745 6739 static int
6746 6740 add_aref(
6747 6741 ipqos_conf_act_ref_t **arefs,
6748 6742 char *field,
6749 6743 char *action_name)
6750 6744 {
6751 6745
6752 6746 ipqos_conf_act_ref_t *aref;
6753 6747
6754 6748 IPQOSCDBG1(L1, "add_aref: action: %s.\n", action_name);
6755 6749
6756 6750 /* allocate zero'd aref */
6757 6751
6758 6752 aref = malloc(sizeof (ipqos_conf_act_ref_t));
6759 6753 if (aref == NULL) {
6760 6754 ipqos_msg(MT_ENOSTR, "malloc");
6761 6755 return (IPQOS_CONF_ERR);
6762 6756 }
6763 6757 (void) bzero(aref, sizeof (ipqos_conf_act_ref_t));
6764 6758
6765 6759 /* copy parameter name if present */
6766 6760
6767 6761 if (field)
6768 6762 (void) strlcpy(aref->field, field, IPQOS_CONF_PNAME_LEN);
6769 6763
6770 6764 /* copy action name */
6771 6765 (void) strlcpy(aref->name, action_name, IPQOS_CONF_NAME_LEN);
6772 6766
6773 6767 /* place at head of list */
6774 6768
6775 6769 aref->next = *arefs;
6776 6770 *arefs = aref;
6777 6771
6778 6772 return (IPQOS_CONF_SUCCESS);
6779 6773 }
6780 6774
6781 6775 /*
6782 6776 * free all the memory used by the action references in arefs.
↓ open down ↓ |
423 lines elided |
↑ open up ↑ |
6783 6777 */
6784 6778 static void
6785 6779 free_arefs(
6786 6780 ipqos_conf_act_ref_t *arefs)
6787 6781 {
6788 6782
6789 6783 ipqos_conf_act_ref_t *aref = arefs;
6790 6784 ipqos_conf_act_ref_t *next;
6791 6785
6792 6786 while (aref) {
6793 - if (aref->nvlist)
6794 - nvlist_free(aref->nvlist);
6787 + nvlist_free(aref->nvlist);
6795 6788 next = aref->next;
6796 6789 free(aref);
6797 6790 aref = next;
6798 6791 }
6799 6792 }
6800 6793
6801 6794
6802 6795
6803 6796 /* *************************************************************** */
6804 6797
6805 6798
6806 6799
6807 6800 /*
6808 6801 * checks whether aname is a valid action name.
6809 6802 * RETURNS: IPQOS_CONF_ERR if invalid, else IPQOS_CONF_SUCCESS.
6810 6803 */
6811 6804 static int
6812 6805 valid_aname(char *aname)
6813 6806 {
6814 6807
6815 6808 /*
6816 6809 * dissallow the use of the name of a virtual action, either
6817 6810 * the ipqosconf name, or the longer ipp names.
6818 6811 */
6819 6812 if (strcmp(aname, IPQOS_CONF_CONT_STR) == 0 ||
6820 6813 strcmp(aname, IPQOS_CONF_DEFER_STR) == 0 ||
6821 6814 strcmp(aname, IPQOS_CONF_DROP_STR) == 0 ||
6822 6815 virtual_action(aname)) {
6823 6816 ipqos_msg(MT_ERROR, gettext("Invalid action name line %u.\n"),
6824 6817 lineno);
6825 6818 return (IPQOS_CONF_ERR);
6826 6819 }
6827 6820
6828 6821 return (IPQOS_CONF_SUCCESS);
6829 6822 }
6830 6823
6831 6824 /*
6832 6825 * Opens a stream to the types file for module module_name (assuming
6833 6826 * that the file path is TYPES_FILE_DIR/module_name.types). if
6834 6827 * a file open failure occurs, *openerr is set to 1.
6835 6828 * RETURNS: NULL on error, else stream ptr to module types file.
6836 6829 */
6837 6830 static FILE *
6838 6831 validmod(
6839 6832 char *module_name,
6840 6833 int *openerr)
6841 6834 {
6842 6835
6843 6836 FILE *fp;
6844 6837 char *path;
6845 6838
6846 6839 IPQOSCDBG1(L1, "In validmod: module_name: %s\n", module_name);
6847 6840
6848 6841 *openerr = 0;
6849 6842
6850 6843 /* create modules type file path */
6851 6844
6852 6845 path = malloc(strlen(TYPES_FILE_DIR) + strlen(module_name) +
6853 6846 strlen(".types") + 1);
6854 6847 if (path == NULL) {
6855 6848 ipqos_msg(MT_ENOSTR, "malloc");
6856 6849 return (NULL);
6857 6850 }
6858 6851 (void) strcpy(path, TYPES_FILE_DIR);
6859 6852 (void) strcat(path, module_name);
6860 6853 (void) strcat(path, ".types");
6861 6854
6862 6855
6863 6856 IPQOSCDBG1(L1, "opening file %s\n", path);
6864 6857
6865 6858 /* open stream to types file */
6866 6859
6867 6860 fp = fopen(path, "r");
6868 6861 if (fp == NULL) {
6869 6862 (*openerr)++;
6870 6863 }
6871 6864
6872 6865 free(path);
6873 6866 return (fp);
6874 6867 }
6875 6868
6876 6869
6877 6870 /*
6878 6871 * read a class clause from cfp into a class struct and point class at this.
6879 6872 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
6880 6873 */
6881 6874 static int
6882 6875 readclass(
6883 6876 FILE *cfp,
6884 6877 char *module_name,
6885 6878 ipqos_conf_class_t **class,
6886 6879 char **perm_classes,
6887 6880 int num_perm_classes)
6888 6881 {
6889 6882
6890 6883 int nm, act;
6891 6884 int res;
6892 6885 nvpair_t *nvp;
6893 6886 ipqos_nvtype_t type;
6894 6887 char *name;
6895 6888 char *action;
6896 6889 int stats;
6897 6890
6898 6891 IPQOSCDBG0(L0, "in readclass\n");
6899 6892
6900 6893 /* create and zero class struct */
6901 6894
6902 6895 *class = alloc_class();
6903 6896 if (!*class) {
6904 6897 return (IPQOS_CONF_ERR);
6905 6898 }
6906 6899 (*class)->originator = IPP_CONFIG_IPQOSCONF;
6907 6900
6908 6901 /* get starting line for error reporting */
6909 6902 (*class)->lineno = lineno;
6910 6903
6911 6904 /* read curl_begin */
6912 6905
6913 6906 res = read_curl_begin(cfp);
6914 6907 if (res != IPQOS_CONF_SUCCESS) {
6915 6908 goto fail;
6916 6909 }
6917 6910
6918 6911 /* loop reading parameters till read curl_end */
6919 6912
6920 6913 stats = nm = act = 0;
6921 6914 for (;;) {
6922 6915 /* read nvpair */
6923 6916 res = readnvpair(cfp, NULL, &(*class)->nvlist,
6924 6917 &nvp, &type, PL_CLASS, module_name);
6925 6918 if (res == IPQOS_CONF_ERR) {
6926 6919 goto fail;
6927 6920
6928 6921 /* reached end of class clause */
6929 6922 } else if (res == IPQOS_CONF_CURL_END) {
6930 6923 break;
6931 6924 }
6932 6925
6933 6926 /*
6934 6927 * catch name and action nv pairs and stats if present
6935 6928 * and place values in class structure.
6936 6929 */
6937 6930
6938 6931 /* name */
6939 6932
6940 6933 if (nm == 0 &&
6941 6934 strcmp(nvpair_name(nvp), IPQOS_CONF_NAME_STR) == 0) {
6942 6935
6943 6936 (void) nvpair_value_string(nvp, &name);
6944 6937
6945 6938 if (valid_name(name) != IPQOS_CONF_SUCCESS) {
6946 6939 goto fail;
6947 6940 }
6948 6941 (void) strcpy((*class)->name, name);
6949 6942 nm++;
6950 6943
6951 6944 /* next action */
6952 6945
6953 6946 } else if (act == 0 &&
6954 6947 strcmp(nvpair_name(nvp), IPQOS_CONF_NEXT_ACTION_STR) == 0) {
6955 6948
6956 6949 (void) nvpair_value_string(nvp, &action);
6957 6950
6958 6951 /*
6959 6952 * if next action string continue string set action to
6960 6953 * IPP_ANAME_CONT, else if drop string IPP_ANAME_DROP
6961 6954 */
6962 6955 if (strcmp(action, IPQOS_CONF_CONT_STR) == 0) {
6963 6956 action = IPP_ANAME_CONT;
6964 6957 } else if (strcmp(action, IPQOS_CONF_DROP_STR) == 0) {
6965 6958 action = IPP_ANAME_DROP;
6966 6959 }
6967 6960
6968 6961 /* add an action reference to action list */
6969 6962
6970 6963 res = add_aref(&(*class)->alist,
6971 6964 IPQOS_CONF_NEXT_ACTION_STR, action);
6972 6965 if (res != IPQOS_CONF_SUCCESS) {
6973 6966 goto fail;
6974 6967 }
6975 6968 act++;
6976 6969
6977 6970 /* class stats enable */
6978 6971
6979 6972 } else if (stats == 0 &&
6980 6973 strcmp(nvpair_name(nvp), IPQOS_CONF_STATS_ENABLE_STR) ==
6981 6974 0) {
6982 6975 boolean_t bl;
6983 6976
6984 6977 (void) nvpair_value_uint32(nvp, (uint32_t *)&bl);
6985 6978 (*class)->stats_enable = bl;
6986 6979
6987 6980 stats++;
6988 6981
6989 6982 /* no other / duplicate parameters allowed */
6990 6983
6991 6984 } else {
6992 6985 ipqos_msg(MT_ERROR,
6993 6986 gettext("Unexpected parameter line %u.\n"), lineno);
6994 6987 goto fail;
6995 6988 }
6996 6989 }
6997 6990 if (nm == 0 || act == 0) {
6998 6991 ipqos_msg(MT_ERROR,
6999 6992 gettext("Missing class name/next action before line %u.\n"),
7000 6993 lineno);
7001 6994 goto fail;
7002 6995 }
7003 6996
7004 6997 /* change class originator field to permanent if permanent class */
7005 6998
7006 6999 if (in_string_table(perm_classes, num_perm_classes, (*class)->name)) {
7007 7000 IPQOSCDBG1(L0, "Setting class %s as permanent.\n", (*class)->name);
7008 7001 (*class)->originator = IPP_CONFIG_PERMANENT;
7009 7002 }
7010 7003
7011 7004 return (IPQOS_CONF_SUCCESS);
7012 7005 fail:
7013 7006 if (*class)
7014 7007 free_class(*class);
7015 7008 return (IPQOS_CONF_ERR);
7016 7009 }
7017 7010
7018 7011 /*
7019 7012 * This function assumes either src_nd_name or dst_node_nm are set in filter.
7020 7013 *
7021 7014 * Creates one of more copies of filter according to the ip versions
7022 7015 * requested (or assumed) and the resolution of the src and dst address
7023 7016 * node names if spec'd. If both node names are spec'd then a filter is
7024 7017 * created for each pair of addresses (one from each node name) that is
7025 7018 * compatible with the chosen address family, otherwise a filter copy is
7026 7019 * created for just each address of the single node name that is
7027 7020 * compatible.
7028 7021 * If filter->ip_versions has been set that is used to determine the
7029 7022 * af's we will create filters for, else if a numeric address was
7030 7023 * added the family of that will be used, otherwise we fall back
7031 7024 * to both v4 and v6 addresses.
7032 7025 *
7033 7026 * Any name lookup failures that occur are checked to see whether the failure
7034 7027 * was a soft or hard failure and the nlerr field of filter set accordingly
7035 7028 * before the error is returned.
7036 7029 *
7037 7030 * RETURNS: IPQOS_CONF_ERR on any error, else IPQOS_CONF_SUCCESS.
7038 7031 */
7039 7032
7040 7033 static int
7041 7034 domultihome(
7042 7035 ipqos_conf_filter_t *filter,
7043 7036 ipqos_conf_filter_t **flist,
7044 7037 boolean_t last_retry)
7045 7038 {
7046 7039
7047 7040 uint32_t ftype;
7048 7041 int v4 = 1, v6 = 1; /* default lookup family is v4 and v6 */
7049 7042 int saf, daf;
7050 7043 struct hostent *shp = NULL;
7051 7044 struct hostent *dhp = NULL;
7052 7045 in6_addr_t daddr, saddr;
7053 7046 int idx = 0;
7054 7047 ipqos_conf_filter_t *nfilter;
7055 7048 int res;
7056 7049 int ernum;
7057 7050 int in32b = 0;
7058 7051 char **sp, **dp;
7059 7052
7060 7053 IPQOSCDBG3(MHME, "In domultihome: filter: %s, src_node: %s, "
7061 7054 "dst_node: %s\n", filter->name,
7062 7055 (filter->src_nd_name ? filter->src_nd_name : "NULL"),
7063 7056 (filter->dst_nd_name ? filter->dst_nd_name : "NULL"));
7064 7057
7065 7058 /* check if we've read an ip_version request to get the versions */
7066 7059
7067 7060 if (filter->ip_versions != 0) {
7068 7061 v4 = VERSION_IS_V4(filter);
7069 7062 v6 = VERSION_IS_V6(filter);
7070 7063
7071 7064 /* otherwise check if we've read a numeric address and get versions */
7072 7065
7073 7066 } else if (nvlist_lookup_uint32(filter->nvlist, IPGPC_FILTER_TYPE,
7074 7067 &ftype) == 0) {
7075 7068 if (ftype == IPGPC_V4_FLTR) {
7076 7069 v6--;
7077 7070 } else {
7078 7071 v4--;
7079 7072 }
7080 7073 }
7081 7074
7082 7075 /* read saddrs if src node name */
7083 7076
7084 7077 if (filter->src_nd_name) {
7085 7078
7086 7079 /* v4 only address */
7087 7080
7088 7081 if (v4 && !v6) {
7089 7082 in32b++;
7090 7083 shp = getipnodebyname(filter->src_nd_name, AF_INET,
7091 7084 AI_ADDRCONFIG, &ernum);
7092 7085
7093 7086 /* v6 only */
7094 7087
7095 7088 } else if (v6 && !v4) {
7096 7089 shp = getipnodebyname(filter->src_nd_name, AF_INET6,
7097 7090 AI_DEFAULT, &ernum);
7098 7091
7099 7092 /* v4 and v6 */
7100 7093
7101 7094 } else if (v6 && v4) {
7102 7095 shp = getipnodebyname(filter->src_nd_name, AF_INET6,
7103 7096 AI_DEFAULT|AI_ALL, &ernum);
7104 7097 }
7105 7098
7106 7099 #ifdef TESTING_RETRY
7107 7100 if (!last_retry) {
7108 7101 filter->nlerr = IPQOS_LOOKUP_RETRY;
7109 7102 goto fail;
7110 7103 }
7111 7104 #endif
7112 7105
7113 7106 /*
7114 7107 * if lookup error determine whether it was a soft or hard
7115 7108 * failure and mark as such in filter.
7116 7109 */
7117 7110 if (shp == NULL) {
7118 7111 if (ernum != TRY_AGAIN) {
7119 7112 ipqos_msg(MT_ERROR, gettext("Failed to "
7120 7113 "resolve src host name for filter at "
7121 7114 "line %u, ignoring filter.\n"),
7122 7115 filter->lineno);
7123 7116 filter->nlerr = IPQOS_LOOKUP_FAIL;
7124 7117 } else {
7125 7118 if (last_retry) {
7126 7119 ipqos_msg(MT_ERROR, gettext("Failed "
7127 7120 "to resolve src host name for "
7128 7121 "filter at line %u, ignoring "
7129 7122 "filter.\n"), filter->lineno);
7130 7123 }
7131 7124 filter->nlerr = IPQOS_LOOKUP_RETRY;
7132 7125 }
7133 7126 goto fail;
7134 7127 }
7135 7128 }
7136 7129
7137 7130 /* read daddrs if dst node name */
7138 7131 if (filter->dst_nd_name) {
7139 7132
7140 7133 /* v4 only address */
7141 7134
7142 7135 if (v4 && !v6) {
7143 7136 in32b++;
7144 7137 dhp = getipnodebyname(filter->dst_nd_name, AF_INET,
7145 7138 AI_ADDRCONFIG, &ernum);
7146 7139
7147 7140 /* v6 only */
7148 7141
7149 7142 } else if (v6 && !v4) {
7150 7143 dhp = getipnodebyname(filter->dst_nd_name, AF_INET6,
7151 7144 AI_DEFAULT, &ernum);
7152 7145
7153 7146 /* v6 and v4 addresses */
7154 7147
7155 7148 } else {
7156 7149 dhp = getipnodebyname(filter->dst_nd_name, AF_INET6,
7157 7150 AI_DEFAULT|AI_ALL, &ernum);
7158 7151 }
7159 7152
7160 7153 if (dhp == NULL) {
7161 7154 if (ernum != TRY_AGAIN) {
7162 7155 ipqos_msg(MT_ERROR, gettext("Failed to "
7163 7156 "resolve dst host name for filter at "
7164 7157 "line %u, ignoring filter.\n"),
7165 7158 filter->lineno);
7166 7159 filter->nlerr = IPQOS_LOOKUP_FAIL;
7167 7160 } else {
7168 7161 if (last_retry) {
7169 7162 ipqos_msg(MT_ERROR, gettext("Failed "
7170 7163 "to resolve dst host name for "
7171 7164 "filter at line %u, ignoring "
7172 7165 "filter.\n"), filter->lineno);
7173 7166 }
7174 7167 filter->nlerr = IPQOS_LOOKUP_RETRY;
7175 7168 }
7176 7169 goto fail;
7177 7170 }
7178 7171 }
7179 7172
7180 7173 /*
7181 7174 * if src and dst node name, create set of filters; one for each
7182 7175 * src and dst address of matching types.
7183 7176 */
7184 7177 if (filter->src_nd_name && filter->dst_nd_name) {
7185 7178
7186 7179 for (sp = shp->h_addr_list; *sp != NULL; sp++) {
7187 7180 (void) bcopy(*sp, &saddr, shp->h_length);
7188 7181
7189 7182 /* get saddr family */
7190 7183
7191 7184 if (in32b || IN6_IS_ADDR_V4MAPPED(&saddr)) {
7192 7185 saf = AF_INET;
7193 7186 } else {
7194 7187 saf = AF_INET6;
7195 7188 }
7196 7189
7197 7190 for (dp = dhp->h_addr_list; *dp != NULL; dp++) {
7198 7191 (void) bcopy(*dp, &daddr, dhp->h_length);
7199 7192
7200 7193 /* get daddr family */
7201 7194
7202 7195 if (in32b || IN6_IS_ADDR_V4MAPPED(&daddr)) {
7203 7196 daf = AF_INET;
7204 7197 } else {
7205 7198 daf = AF_INET6;
7206 7199 }
7207 7200
7208 7201 /*
7209 7202 * if saddr and daddr same af duplicate
7210 7203 * filter adding addresses and new instance
7211 7204 * number and add to flist filter list.
7212 7205 */
7213 7206
7214 7207 if (daf == saf) {
7215 7208
7216 7209 res = dup_filter(filter, &nfilter, saf,
7217 7210 !in32b, &saddr, &daddr, ++idx);
7218 7211 if (res != IPQOS_CONF_SUCCESS) {
7219 7212 goto fail;
7220 7213 }
7221 7214 ADD_TO_LIST(flist, nfilter);
7222 7215 }
7223 7216 }
7224 7217 }
7225 7218
7226 7219 /* if src name only create set of filters, one for each node address */
7227 7220
7228 7221 } else if (filter->src_nd_name) {
7229 7222
7230 7223 for (sp = shp->h_addr_list; *sp != NULL; sp++) {
7231 7224 (void) bcopy(*sp, &saddr, shp->h_length);
7232 7225
7233 7226 /* get af */
7234 7227
7235 7228 if (in32b || IN6_IS_ADDR_V4MAPPED(&saddr)) {
7236 7229 saf = AF_INET;
7237 7230 } else {
7238 7231 saf = AF_INET6;
7239 7232 }
7240 7233
7241 7234
7242 7235 /*
7243 7236 * dup filter adding saddr and new instance num and
7244 7237 * add to flist filter list.
7245 7238 */
7246 7239 res = dup_filter(filter, &nfilter, saf, !in32b, &saddr,
7247 7240 NULL, ++idx);
7248 7241 if (res != IPQOS_CONF_SUCCESS) {
7249 7242 goto fail;
7250 7243 }
7251 7244
7252 7245 ADD_TO_LIST(flist, nfilter);
7253 7246
7254 7247 }
7255 7248
7256 7249 /* if dname only create set of filters, one for each node address */
7257 7250
7258 7251 } else {
7259 7252 for (dp = dhp->h_addr_list; *dp != NULL; dp++) {
7260 7253 (void) bcopy(*dp, &daddr, dhp->h_length);
7261 7254
7262 7255 /* get af */
7263 7256
7264 7257 if (in32b || IN6_IS_ADDR_V4MAPPED(&daddr)) {
7265 7258 daf = AF_INET;
7266 7259 } else {
7267 7260 daf = AF_INET6;
7268 7261 }
7269 7262
7270 7263 /*
7271 7264 * dup filter adding daddr and new instance num and
7272 7265 * add to flist filter list.
7273 7266 */
7274 7267 res = dup_filter(filter, &nfilter, daf, !in32b, NULL,
7275 7268 &daddr, ++idx);
7276 7269 if (res != IPQOS_CONF_SUCCESS) {
7277 7270 goto fail;
7278 7271 }
7279 7272
7280 7273 ADD_TO_LIST(flist, nfilter);
7281 7274 }
7282 7275 }
7283 7276
7284 7277 if (shp)
7285 7278 freehostent(shp);
7286 7279 if (dhp)
7287 7280 freehostent(dhp);
7288 7281 return (IPQOS_CONF_SUCCESS);
7289 7282 fail:
7290 7283 /*
7291 7284 * should really clean up any filters that we have created,
7292 7285 * however, free_actions called from readaction will cleam them up.
7293 7286 */
7294 7287 if (shp)
7295 7288 freehostent(shp);
7296 7289 if (dhp)
7297 7290 freehostent(dhp);
7298 7291 return (IPQOS_CONF_ERR);
7299 7292 }
7300 7293
7301 7294
7302 7295 /*
7303 7296 * read a filter clause from cfp into a filter struct and point filter
7304 7297 * at this.
7305 7298 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
7306 7299 */
7307 7300 static int
7308 7301 readfilter(
7309 7302 FILE *cfp,
7310 7303 FILE *tfp,
7311 7304 char *module_name,
7312 7305 ipqos_conf_filter_t **filter,
7313 7306 char **perm_filters,
7314 7307 int num_perm_filters)
7315 7308 {
7316 7309
7317 7310 int res;
7318 7311 int nm, cls, ipv;
7319 7312 in6_addr_t mask;
7320 7313 char *addr_str;
7321 7314 char *sl = NULL;
7322 7315 in6_addr_t addr;
7323 7316 int sa;
7324 7317 struct hostent *hp;
7325 7318 int err_num;
7326 7319 int v4 = 0, v6 = 0;
7327 7320 uchar_t mlen;
7328 7321 char *tmp;
7329 7322 nvpair_t *nvp;
7330 7323 ipqos_nvtype_t type;
7331 7324 char *name;
7332 7325 char *class;
7333 7326 uchar_t b;
7334 7327 in6_addr_t v6addr;
7335 7328
7336 7329 IPQOSCDBG0(L0, "in readfilter\n");
7337 7330
7338 7331
7339 7332 /* create and zero filter struct */
7340 7333
7341 7334 *filter = alloc_filter();
7342 7335 if (*filter == NULL) {
7343 7336 return (IPQOS_CONF_ERR);
7344 7337 }
7345 7338 (*filter)->originator = IPP_CONFIG_IPQOSCONF;
7346 7339
7347 7340 /* get starting line for error reporting */
7348 7341 (*filter)->lineno = lineno;
7349 7342
7350 7343 /* read beginning curl */
7351 7344
7352 7345 res = read_curl_begin(cfp);
7353 7346 if (res != IPQOS_CONF_SUCCESS) {
7354 7347 goto fail;
7355 7348 }
7356 7349
7357 7350
7358 7351 /*
7359 7352 * loop reading nvpairs onto nvlist until encounter CURL_END
7360 7353 */
7361 7354 ipv = nm = cls = 0;
7362 7355 for (;;) {
7363 7356 /* read nvpair */
7364 7357
7365 7358 res = readnvpair(cfp, tfp, &(*filter)->nvlist,
7366 7359 &nvp, &type, PL_FILTER, module_name);
7367 7360 if (res == IPQOS_CONF_ERR) {
7368 7361 goto fail;
7369 7362
7370 7363 /* reached the end of filter definition */
7371 7364
7372 7365 } else if (res == IPQOS_CONF_CURL_END) {
7373 7366 break;
7374 7367 }
7375 7368
7376 7369 /*
7377 7370 * catch name and class and place value into filter
7378 7371 * structure.
7379 7372 */
7380 7373
7381 7374 /* read filter name */
7382 7375
7383 7376 if (strcmp(nvpair_name(nvp), IPQOS_CONF_NAME_STR) == 0) {
7384 7377 if (nm != 0) {
7385 7378 ipqos_msg(MT_ERROR,
7386 7379 gettext("Duplicate parameter line %u.\n"),
7387 7380 lineno);
7388 7381 goto fail;
7389 7382 }
7390 7383
7391 7384 (void) nvpair_value_string(nvp, &name);
7392 7385 if (valid_name(name) != IPQOS_CONF_SUCCESS) {
7393 7386 goto fail;
7394 7387 }
7395 7388
7396 7389 (void) strcpy((*filter)->name, name);
7397 7390 (void) nvlist_remove_all((*filter)->nvlist,
7398 7391 IPQOS_CONF_NAME_STR);
7399 7392 nm++;
7400 7393
7401 7394 /* read class name */
7402 7395
7403 7396 } else if (strcmp(nvpair_name(nvp), IPQOS_CONF_CLASS_STR) ==
7404 7397 0) {
7405 7398 if (cls != 0) {
7406 7399 ipqos_msg(MT_ERROR,
7407 7400 gettext("Duplicate parameter line %u.\n"),
7408 7401 lineno);
7409 7402 goto fail;
7410 7403 }
7411 7404
7412 7405 if (nvpair_value_string(nvp, &class) != 0) {
7413 7406 ipqos_msg(MT_ENOSTR, "nvpair_value_string");
7414 7407 break;
7415 7408 }
7416 7409 if (valid_name(class) != IPQOS_CONF_SUCCESS) {
7417 7410 goto fail;
7418 7411 }
7419 7412 (void) strcpy((*filter)->class_name, class);
7420 7413 (void) nvlist_remove_all((*filter)->nvlist,
7421 7414 IPQOS_CONF_CLASS_STR);
7422 7415 cls++;
7423 7416
7424 7417 /*
7425 7418 * if a src or dst ip node name/address. For those that
7426 7419 * are determined to be addresses we convert them from
7427 7420 * strings here and add to the filter nvlist; for node names
7428 7421 * we add the name to the filter struct for readaction to
7429 7422 * process.
7430 7423 */
7431 7424 } else if (strcmp(nvpair_name(nvp), IPGPC_SADDR) == 0 ||
7432 7425 strcmp(nvpair_name(nvp), IPGPC_DADDR) == 0) {
7433 7426
7434 7427 sa = 0;
7435 7428
7436 7429 if (strcmp(nvpair_name(nvp), IPGPC_SADDR) == 0) {
7437 7430 sa++;
7438 7431 }
7439 7432
7440 7433 (void) nvpair_value_string(nvp, &addr_str);
7441 7434
7442 7435 /*
7443 7436 * get the address mask if present.
7444 7437 * make a copy so that the nvlist element that
7445 7438 * it is part of doesn't dissapear and causes probs.
7446 7439 */
7447 7440 sl = strchr(addr_str, '/');
7448 7441 if (sl) {
7449 7442 *sl = '\0';
7450 7443 tmp = malloc(strlen(++sl) + 1);
7451 7444 if (tmp == NULL) {
7452 7445 ipqos_msg(MT_ENOSTR, "malloc");
7453 7446 goto fail;
7454 7447 }
7455 7448 (void) strcpy(tmp, sl);
7456 7449 sl = tmp;
7457 7450 }
7458 7451
7459 7452
7460 7453 /* if a numeric address */
7461 7454
7462 7455 if (inet_pton(AF_INET, addr_str, &addr) == 1 ||
7463 7456 inet_pton(AF_INET6, addr_str, &addr) == 1) {
7464 7457
7465 7458 /* get address */
7466 7459
7467 7460 hp = getipnodebyname(addr_str, AF_INET6,
7468 7461 AI_DEFAULT, &err_num);
7469 7462 if (hp == NULL) {
7470 7463 ipqos_msg(MT_ENOSTR,
7471 7464 "getipnodebyname");
7472 7465 goto fail;
7473 7466 }
7474 7467
7475 7468 (void) bcopy(hp->h_addr_list[0], &v6addr,
7476 7469 hp->h_length);
7477 7470 freehostent(hp);
7478 7471
7479 7472 /* determine address type */
7480 7473
7481 7474 v4 = IN6_IS_ADDR_V4MAPPED(&v6addr);
7482 7475 if (!v4) {
7483 7476 v6++;
7484 7477 }
7485 7478
7486 7479 /*
7487 7480 * check any previous addresses have same
7488 7481 * version.
7489 7482 */
7490 7483 if (nvlist_lookup_byte((*filter)->nvlist,
7491 7484 IPGPC_FILTER_TYPE, &b) == 0) {
7492 7485 if (v4 && b != IPGPC_V4_FLTR ||
7493 7486 v6 && b != IPGPC_V6_FLTR) {
7494 7487 ipqos_msg(MT_ERROR,
7495 7488 gettext("Incompatible "
7496 7489 "address version line "
7497 7490 "%u.\n"), lineno);
7498 7491 goto fail;
7499 7492 }
7500 7493 }
7501 7494
7502 7495 /*
7503 7496 * check that if ip_version spec'd it
7504 7497 * corresponds.
7505 7498 */
7506 7499 if ((*filter)->ip_versions != 0) {
7507 7500 if (v4 && !VERSION_IS_V4(*filter) ||
7508 7501 v6 && !VERSION_IS_V6(*filter)) {
7509 7502 ipqos_msg(MT_ERROR,
7510 7503 gettext("Incompatible "
7511 7504 "address version line %u"
7512 7505 ".\n"), lineno);
7513 7506 goto fail;
7514 7507 }
7515 7508 }
7516 7509
7517 7510 /* add the address type */
7518 7511
7519 7512 res = nvlist_add_byte(
7520 7513 (*filter)->nvlist, IPGPC_FILTER_TYPE,
7521 7514 v4 ? IPGPC_V4_FLTR : IPGPC_V6_FLTR);
7522 7515 if (res != 0) {
7523 7516 ipqos_msg(MT_ENOSTR,
7524 7517 "nvlist_add_byte");
7525 7518 goto fail;
7526 7519 }
7527 7520
7528 7521 /* add address to list */
7529 7522
7530 7523 res = nvlist_add_uint32_array((*filter)->nvlist,
7531 7524 sa ? IPGPC_SADDR : IPGPC_DADDR,
7532 7525 (uint32_t *)&v6addr, 4);
7533 7526 if (res != 0) {
7534 7527 ipqos_msg(MT_ENOSTR,
7535 7528 "nvlist_add_uint32_array");
7536 7529 goto fail;
7537 7530 }
7538 7531
7539 7532
7540 7533 /*
7541 7534 * add mask entry in list.
7542 7535 */
7543 7536
7544 7537 if (sl) { /* have CIDR mask */
7545 7538 char *lo;
7546 7539 res = readuint8(sl, &mlen, &lo);
7547 7540 if (res != IPQOS_CONF_SUCCESS ||
7548 7541 v4 && mlen > 32 ||
7549 7542 !v4 && mlen > 128 ||
7550 7543 mlen == 0) {
7551 7544 ipqos_msg(MT_ERROR,
7552 7545 gettext("Invalid CIDR "
7553 7546 "mask line %u.\n"), lineno);
7554 7547 goto fail;
7555 7548 }
7556 7549 setmask(mlen, &mask,
7557 7550 v4 ? AF_INET : AF_INET6);
7558 7551 free(sl);
7559 7552 } else {
7560 7553 /* no CIDR mask spec'd - use all 1s */
7561 7554
7562 7555 (void) memset(&mask, ~0,
7563 7556 sizeof (in6_addr_t));
7564 7557 }
7565 7558 res = nvlist_add_uint32_array((*filter)->nvlist,
7566 7559 sa ? IPGPC_SADDR_MASK : IPGPC_DADDR_MASK,
7567 7560 (uint32_t *)&mask, 4);
7568 7561 if (res != 0) {
7569 7562 ipqos_msg(MT_ENOSTR,
7570 7563 "nvlist_add_uint32_arr");
7571 7564 goto fail;
7572 7565 }
7573 7566
7574 7567 /* inet_pton returns fail - we assume a node name */
7575 7568
7576 7569 } else {
7577 7570 /*
7578 7571 * doesn't make sense to have a mask
7579 7572 * with a node name.
7580 7573 */
7581 7574 if (sl) {
7582 7575 ipqos_msg(MT_ERROR,
7583 7576 gettext("Address masks aren't "
7584 7577 "allowed for host names line "
7585 7578 "%u.\n"), lineno);
7586 7579 goto fail;
7587 7580 }
7588 7581
7589 7582 /*
7590 7583 * store node name in filter struct for
7591 7584 * later resolution.
7592 7585 */
7593 7586 if (sa) {
7594 7587 (*filter)->src_nd_name =
7595 7588 malloc(strlen(addr_str) + 1);
7596 7589 (void) strcpy((*filter)->src_nd_name,
7597 7590 addr_str);
7598 7591 } else {
7599 7592 (*filter)->dst_nd_name =
7600 7593 malloc(strlen(addr_str) + 1);
7601 7594 (void) strcpy((*filter)->dst_nd_name,
7602 7595 addr_str);
7603 7596 }
7604 7597 }
7605 7598
7606 7599 /* ip_version enumeration */
7607 7600
7608 7601 } else if (strcmp(nvpair_name(nvp), IPQOS_CONF_IP_VERSION) ==
7609 7602 0) {
7610 7603 /* check we haven't read ip_version before */
7611 7604 if (ipv) {
7612 7605 ipqos_msg(MT_ERROR,
7613 7606 gettext("Duplicate parameter line %u.\n"),
7614 7607 lineno);
7615 7608 goto fail;
7616 7609 }
7617 7610 ipv++;
7618 7611
7619 7612 /* get bitmask value */
7620 7613
7621 7614 (void) nvpair_value_uint32(nvp,
7622 7615 &(*filter)->ip_versions);
7623 7616
7624 7617 /*
7625 7618 * check that if either ip address is spec'd it
7626 7619 * corresponds.
7627 7620 */
7628 7621 if (v4 && !VERSION_IS_V4(*filter) ||
7629 7622 v6 && !VERSION_IS_V6(*filter)) {
7630 7623 ipqos_msg(MT_ERROR, gettext("Incompatible "
7631 7624 "address version line %u.\n"), lineno);
7632 7625 goto fail;
7633 7626 }
7634 7627
7635 7628 /* remove ip_version from nvlist */
7636 7629
7637 7630 (void) nvlist_remove_all((*filter)->nvlist,
7638 7631 IPQOS_CONF_IP_VERSION);
7639 7632 }
7640 7633 }
7641 7634 if (nm == 0 || cls == 0) {
7642 7635 ipqos_msg(MT_ERROR, gettext("Missing filter/class name "
7643 7636 "before line %u.\n"), lineno);
7644 7637 goto fail;
7645 7638 }
7646 7639
7647 7640 if (in_string_table(perm_filters, num_perm_filters, (*filter)->name)) {
7648 7641 IPQOSCDBG1(L0, "Setting filter %s as permanent.\n",
7649 7642 (*filter)->name);
7650 7643
7651 7644 (*filter)->originator = IPP_CONFIG_PERMANENT;
7652 7645 }
7653 7646
7654 7647 return (IPQOS_CONF_SUCCESS);
7655 7648 fail:
7656 7649 if (*filter)
7657 7650 free_filter(*filter);
7658 7651 if (hp)
7659 7652 freehostent(hp);
7660 7653 if (sl)
7661 7654 free(sl);
7662 7655
7663 7656 return (IPQOS_CONF_ERR);
7664 7657 }
7665 7658
7666 7659 /*
7667 7660 * reads the curl begin token from cfp stream.
7668 7661 * RETURNS: IPQOS_CONF_ERR if not read successfully, else IPQOS_CONF_SUCCES.
7669 7662 */
7670 7663 static int
7671 7664 read_curl_begin(FILE *cfp)
7672 7665 {
7673 7666
7674 7667 int res;
7675 7668 char *st;
7676 7669
7677 7670 res = readtoken(cfp, &st);
7678 7671
7679 7672 if (res != IPQOS_CONF_CURL_BEGIN) {
7680 7673 if (res == IPQOS_CONF_EOF) {
7681 7674 ipqos_msg(MT_ERROR, gettext("Unexpected EOF.\n"));
7682 7675
7683 7676 /* if CURL_END or something else */
7684 7677 } else if (res != IPQOS_CONF_ERR) {
7685 7678 free(st);
7686 7679 ipqos_msg(MT_ERROR, gettext("\'{\' missing at line "
7687 7680 "%u.\n"), lineno);
7688 7681 }
7689 7682 return (IPQOS_CONF_ERR);
7690 7683 }
7691 7684
7692 7685 free(st);
7693 7686 return (IPQOS_CONF_SUCCESS);
7694 7687 }
7695 7688
7696 7689 /*
7697 7690 * This function parses the parameter string version into a version of the
7698 7691 * form "%u.%u" (as a sscanf format string). It then encodes this into an
7699 7692 * int and returns this encoding.
7700 7693 * RETURNS: -1 if an invalid string, else the integer encoding.
7701 7694 */
7702 7695 static int
7703 7696 ver_str_to_int(
7704 7697 char *version)
7705 7698 {
7706 7699 uint32_t major, minor;
7707 7700 int ver;
7708 7701
7709 7702 if (sscanf(version, "%u.%u", &major, &minor) != 2) {
7710 7703 IPQOSCDBG0(L0, "Failed to process version number string\n");
7711 7704 return (-1);
7712 7705 }
7713 7706
7714 7707 ver = (int)((major * 10000) + minor);
7715 7708 return (ver);
7716 7709 }
7717 7710
7718 7711 /*
7719 7712 * This function scans through the stream fp line by line looking for
7720 7713 * a line beginning with version_tag and returns a integer encoding of
7721 7714 * the version following it.
7722 7715 *
7723 7716 * RETURNS: If the version definition isn't found or the version is not
7724 7717 * a valid version (%u.%u) then -1 is returned, else an integer encoding
7725 7718 * of the read version.
7726 7719 */
7727 7720 static int
7728 7721 read_tfile_ver(
7729 7722 FILE *fp,
7730 7723 char *version_tag,
7731 7724 char *module_name)
7732 7725 {
7733 7726 char lbuf[IPQOS_CONF_LINEBUF_SZ];
7734 7727 char buf[IPQOS_CONF_LINEBUF_SZ+1];
7735 7728 char buf2[IPQOS_CONF_LINEBUF_SZ+1];
7736 7729 int found = 0;
7737 7730 int version;
7738 7731
7739 7732 /*
7740 7733 * reset to file start
7741 7734 */
7742 7735 if (fseek(fp, 0, SEEK_SET) != 0) {
7743 7736 ipqos_msg(MT_ENOSTR, "fseek");
7744 7737 return (-1);
7745 7738 }
7746 7739
7747 7740 /*
7748 7741 * loop reading lines till found the one beginning with version_tag.
7749 7742 */
7750 7743 while (fgets(lbuf, IPQOS_CONF_LINEBUF_SZ, fp) != NULL) {
7751 7744 if ((sscanf(lbuf,
7752 7745 "%" VAL2STR(IPQOS_CONF_LINEBUF_SZ) "s"
7753 7746 "%" VAL2STR(IPQOS_CONF_LINEBUF_SZ) "s",
7754 7747 buf, buf2) == 2) &&
7755 7748 (strcmp(buf, version_tag) == 0)) {
7756 7749 found++;
7757 7750 break;
7758 7751 }
7759 7752 }
7760 7753 if (found == 0) {
7761 7754 ipqos_msg(MT_ERROR, gettext("Types file for module %s is "
7762 7755 "corrupt.\n"), module_name);
7763 7756 IPQOSCDBG1(L1, "Couldn't find %s in types file\n",
7764 7757 version_tag);
7765 7758 return (-1);
7766 7759 }
7767 7760
7768 7761 /*
7769 7762 * convert version string into int.
7770 7763 */
7771 7764 if ((version = ver_str_to_int(buf2)) == -1) {
7772 7765 ipqos_msg(MT_ERROR, gettext("Types file for module %s is "
7773 7766 "corrupt.\n"), module_name);
7774 7767 return (-1);
7775 7768 }
7776 7769
7777 7770 return (version);
7778 7771 }
7779 7772
7780 7773 /*
7781 7774 * read action clause and params/classes/filters clauses within and
7782 7775 * store in and hang off an action structure, and point action at it.
7783 7776 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
7784 7777 */
7785 7778 static int
7786 7779 readaction(
7787 7780 FILE *cfp,
7788 7781 ipqos_conf_action_t **action)
7789 7782 {
7790 7783
7791 7784 char *st;
7792 7785 FILE *tfp = NULL;
7793 7786 int nm, md;
7794 7787 int readprms = 0;
7795 7788 int res;
7796 7789 char *strval;
7797 7790 char *name;
7798 7791 nvpair_t *nvp;
7799 7792 ipqos_nvtype_t type;
7800 7793 ipqos_conf_filter_t *filter;
7801 7794 ipqos_conf_class_t *class;
7802 7795 int oe;
7803 7796 char **perm_filters;
7804 7797 int num_perm_filters;
7805 7798 int tf_fmt_ver;
7806 7799
7807 7800 IPQOSCDBG0(L0, "in readaction\n");
7808 7801
7809 7802 res = readtoken(cfp, &st);
7810 7803 if (res == IPQOS_CONF_ERR || res == IPQOS_CONF_EOF) {
7811 7804 return (res);
7812 7805 } else if (strcmp(st, IPQOS_CONF_ACTION_STR) != 0) {
7813 7806 ipqos_msg(MT_ERROR, gettext("Missing %s token line "
7814 7807 "%u.\n"), IPQOS_CONF_ACTION_STR, lineno);
7815 7808 free(st);
7816 7809 return (IPQOS_CONF_ERR);
7817 7810 }
7818 7811 free(st);
7819 7812
7820 7813 /* create action structure */
7821 7814
7822 7815 *action = alloc_action();
7823 7816 if (*action == NULL) {
7824 7817 return (IPQOS_CONF_ERR);
7825 7818 }
7826 7819 (*action)->params->originator = IPP_CONFIG_IPQOSCONF;
7827 7820
7828 7821
7829 7822 /* get starting line for error reporting */
7830 7823 (*action)->lineno = lineno;
7831 7824
7832 7825 /* read beginning curl */
7833 7826
7834 7827 res = read_curl_begin(cfp);
7835 7828 if (res != IPQOS_CONF_SUCCESS) {
7836 7829 goto fail;
7837 7830 }
7838 7831
7839 7832 /* loop till read both action name and module */
7840 7833
7841 7834 nm = md = 0;
7842 7835 do {
7843 7836 /* read nvpair */
7844 7837
7845 7838 res = readnvpair(cfp, NULL, &(*action)->nvlist, &nvp, &type,
7846 7839 PL_ACTION, NULL);
7847 7840 if (res == IPQOS_CONF_ERR) {
7848 7841 goto fail;
7849 7842
7850 7843 /* read curl_end */
7851 7844
7852 7845 } else if (res == IPQOS_CONF_CURL_END) {
7853 7846 if (nm == 0 || md == 0) {
7854 7847 ipqos_msg(MT_ERROR,
7855 7848 gettext("Missing action name/ module "
7856 7849 "before line %u.\n"), lineno);
7857 7850 goto fail;
7858 7851 }
7859 7852 }
7860 7853
7861 7854
7862 7855 /* store name and module in action structure */
7863 7856
7864 7857 name = nvpair_name(nvp);
7865 7858
7866 7859 /* read action name */
7867 7860
7868 7861 if (nm == 0 && strcmp(name, IPQOS_CONF_NAME_STR) == 0) {
7869 7862
7870 7863 (void) nvpair_value_string(nvp, &strval);
7871 7864
7872 7865 /* check name is valid */
7873 7866
7874 7867 if (valid_name(strval) != IPQOS_CONF_SUCCESS ||
7875 7868 valid_aname(strval) != IPQOS_CONF_SUCCESS) {
7876 7869 goto fail;
7877 7870 }
7878 7871
7879 7872 /* store and remove from list */
7880 7873
7881 7874 (void) strcpy((*action)->name, strval);
7882 7875 /* remove name from nvlist */
7883 7876 (void) nvlist_remove_all((*action)->nvlist,
7884 7877 IPQOS_CONF_NAME_STR);
7885 7878
7886 7879 nm++;
7887 7880
7888 7881 /* read module name */
7889 7882
7890 7883 } else if (md == 0 &&
7891 7884 strcmp(name, IPQOS_CONF_MODULE_STR) == 0) {
7892 7885 /*
7893 7886 * check that module has a type file and get
7894 7887 * open stream to it.
7895 7888 */
7896 7889 (void) nvpair_value_string(nvp, &strval);
7897 7890 if ((tfp = validmod(strval, &oe)) == NULL) {
7898 7891 if (oe) {
7899 7892 if (errno == ENOENT) {
7900 7893 ipqos_msg(MT_ERROR,
7901 7894 gettext("Invalid "
7902 7895 "module name line %u.\n"),
7903 7896 lineno);
7904 7897 } else {
7905 7898 ipqos_msg(MT_ENOSTR, "fopen");
7906 7899 }
7907 7900 }
7908 7901 goto fail;
7909 7902 }
7910 7903
7911 7904 /*
7912 7905 * move module name to action struct
7913 7906 */
7914 7907 (void) strlcpy((*action)->module, strval,
7915 7908 IPQOS_CONF_NAME_LEN);
7916 7909 (void) nvlist_remove_all((*action)->nvlist,
7917 7910 IPQOS_CONF_MODULE_STR);
7918 7911 md++;
7919 7912
7920 7913 /* duplicate/other parameter */
7921 7914
7922 7915 } else {
7923 7916 ipqos_msg(MT_ERROR,
7924 7917 gettext("Unexpected parameter line %u.\n"),
7925 7918 lineno);
7926 7919 goto fail;
7927 7920 }
7928 7921
7929 7922 } while (nm == 0 || md == 0);
7930 7923
7931 7924 /*
7932 7925 * check that if the ipgpc action it is named correctly
7933 7926 */
7934 7927 if ((strcmp((*action)->module, IPGPC_NAME) == 0) &&
7935 7928 (strcmp((*action)->name, IPGPC_CLASSIFY) != 0)) {
7936 7929 ipqos_msg(MT_ERROR,
7937 7930 gettext("%s action has incorrect name line %u.\n"),
7938 7931 IPGPC_NAME, (*action)->lineno);
7939 7932 goto fail;
7940 7933 }
7941 7934
7942 7935 /* get list of permanent classes */
7943 7936
7944 7937 res = read_perm_items(0, tfp, (*action)->module,
7945 7938 &(*action)->perm_classes, &(*action)->num_perm_classes);
7946 7939 if (res != IPQOS_CONF_SUCCESS) {
7947 7940 goto fail;
7948 7941 }
7949 7942
7950 7943 /* get list of permanent filters */
7951 7944
7952 7945 res = read_perm_items(1, tfp, (*action)->module,
7953 7946 &perm_filters, &num_perm_filters);
7954 7947 if (res != IPQOS_CONF_SUCCESS) {
7955 7948 goto fail;
7956 7949 }
7957 7950
7958 7951 /*
7959 7952 * get types file format version and check its supported.
7960 7953 */
7961 7954 if ((tf_fmt_ver = read_tfile_ver(tfp, IPQOS_FMT_STR,
7962 7955 (*action)->module)) == -1)
7963 7956 goto fail;
7964 7957 if (IPP_MAJOR_MODULE_VER(tf_fmt_ver) > 1 ||
7965 7958 IPP_MINOR_MODULE_VER(tf_fmt_ver) > 0) {
7966 7959 ipqos_msg(MT_ERROR, gettext("Types file for module %s is "
7967 7960 "incompatible.\n"), (*action)->module);
7968 7961 IPQOSCDBG0(L1, "Unsupported fmt major/minor version\n");
7969 7962 goto fail;
7970 7963 }
7971 7964
7972 7965 /*
7973 7966 * get module version
7974 7967 */
7975 7968 if (((*action)->module_version = read_tfile_ver(tfp, IPQOS_MOD_STR,
7976 7969 (*action)->module)) == -1)
7977 7970 goto fail;
7978 7971
7979 7972 /* read filter/class/params blocks until CURL_END */
7980 7973
7981 7974 for (;;) {
7982 7975 /* read token */
7983 7976 res = readtoken(cfp, &st);
7984 7977
7985 7978 if (res == IPQOS_CONF_ERR) {
7986 7979 goto fail;
7987 7980 } else if (res == IPQOS_CONF_EOF) {
7988 7981 ipqos_msg(MT_ERROR, gettext("Unexpected EOF.\n"));
7989 7982 goto fail;
7990 7983
7991 7984 /* read CURL_END - end of action definition */
7992 7985
7993 7986 } else if (res == IPQOS_CONF_CURL_END) {
7994 7987 free(st);
7995 7988 break;
7996 7989 }
7997 7990
7998 7991
7999 7992 /*
8000 7993 * read in either a filter/class or parameter block.
8001 7994 */
8002 7995
8003 7996 /* read filter */
8004 7997
8005 7998 if (strcmp(st, IPQOS_CONF_FILTER_STR) == 0) {
8006 7999 free(st);
8007 8000
8008 8001 res = readfilter(cfp, tfp, (*action)->module, &filter,
8009 8002 perm_filters, num_perm_filters);
8010 8003 if (res != IPQOS_CONF_SUCCESS) {
8011 8004 goto fail;
8012 8005 }
8013 8006
8014 8007 /*
8015 8008 * if we read a host name for either src or dst addr
8016 8009 * resolve the hostnames and create the appropriate
8017 8010 * number of filters.
8018 8011 */
8019 8012
8020 8013 if (filter->src_nd_name || filter->dst_nd_name) {
8021 8014
8022 8015 res = domultihome(filter, &(*action)->filters,
8023 8016 B_FALSE);
8024 8017 /*
8025 8018 * if a lookup fails and the filters
8026 8019 * marked as retry we add it to a list
8027 8020 * for another attempt later, otherwise
8028 8021 * it is thrown away.
8029 8022 */
8030 8023 if (res != IPQOS_CONF_SUCCESS) {
8031 8024
8032 8025 /* if not name lookup problem */
8033 8026
8034 8027 if (filter->nlerr == 0) {
8035 8028 free_filter(filter);
8036 8029 goto fail;
8037 8030
8038 8031 /* name lookup problem */
8039 8032
8040 8033 /*
8041 8034 * if intermitent lookup failure
8042 8035 * add to list of filters to
8043 8036 * retry later.
8044 8037 */
8045 8038 } else if (filter->nlerr ==
8046 8039 IPQOS_LOOKUP_RETRY) {
8047 8040 filter->nlerr = 0;
8048 8041 ADD_TO_LIST(
8049 8042 &(*action)->retry_filters,
8050 8043 filter);
8051 8044 /*
8052 8045 * for non-existing names
8053 8046 * ignore the filter.
8054 8047 */
8055 8048 } else {
8056 8049 free_filter(filter);
8057 8050 }
8058 8051
8059 8052 /* creation of new filters successful */
8060 8053
8061 8054 } else {
8062 8055 free_filter(filter);
8063 8056 }
8064 8057
8065 8058 /* non-node name filter */
8066 8059
8067 8060 } else {
8068 8061 ADD_TO_LIST(&(*action)->filters, filter);
8069 8062 }
8070 8063
8071 8064 /* read class */
8072 8065
8073 8066 } else if (strcmp(st, IPQOS_CONF_CLASS_STR) == 0) {
8074 8067 free(st);
8075 8068 res = readclass(cfp, (*action)->module, &class,
8076 8069 (*action)->perm_classes,
8077 8070 (*action)->num_perm_classes);
8078 8071 if (res != IPQOS_CONF_SUCCESS) {
8079 8072 goto fail;
8080 8073 }
8081 8074
8082 8075 ADD_TO_LIST(&(*action)->classes, class);
8083 8076
8084 8077 /* read params */
8085 8078
8086 8079 } else if (strcmp(st, IPQOS_CONF_PARAMS_STR) == 0) {
8087 8080 free(st);
8088 8081 if (readprms) {
8089 8082 ipqos_msg(MT_ERROR,
8090 8083 gettext("Second parameter clause not "
8091 8084 "supported line %u.\n"), lineno);
8092 8085 goto fail;
8093 8086 }
8094 8087 res = readparams(cfp, tfp, (*action)->module,
8095 8088 (*action)->params);
8096 8089 if (res != IPQOS_CONF_SUCCESS) {
8097 8090 goto fail;
8098 8091 }
8099 8092 readprms++;
8100 8093
8101 8094 /* something unexpected */
8102 8095 } else {
8103 8096 free(st);
8104 8097 ipqos_msg(MT_ERROR,
8105 8098 gettext("Params/filter/class clause expected "
8106 8099 "line %u.\n"), lineno);
8107 8100 goto fail;
8108 8101 }
8109 8102 }
8110 8103
8111 8104 (void) fclose(tfp);
8112 8105 return (IPQOS_CONF_SUCCESS);
8113 8106
8114 8107 fail:
8115 8108 if (tfp)
8116 8109 (void) fclose(tfp);
8117 8110 if (*action) {
8118 8111 free_actions(*action);
8119 8112 *action = NULL;
8120 8113 }
8121 8114 return (IPQOS_CONF_ERR);
8122 8115 }
8123 8116
8124 8117 /*
8125 8118 * check that each of the actions in actions is uniquely named. If one isn't
8126 8119 * set *name to point at the name of the duplicate action.
8127 8120 * RETURNS: IPQOS_CONF_ERR if a non-unique action, else IPQOS_CONF_SUCCESS.
8128 8121 */
8129 8122 static int
8130 8123 actions_unique(ipqos_conf_action_t *actions, char **name)
8131 8124 {
8132 8125
8133 8126 IPQOSCDBG0(L1, "In actions_unique.\n");
8134 8127
8135 8128 while (actions) {
8136 8129 if (actionexist(actions->name, actions->next)) {
8137 8130 *name = actions->name;
8138 8131 return (IPQOS_CONF_ERR);
8139 8132 }
8140 8133 actions = actions->next;
8141 8134 }
8142 8135
8143 8136 return (IPQOS_CONF_SUCCESS);
8144 8137 }
8145 8138
8146 8139 /*
8147 8140 * checks whether the action parameter is involved in an action cycle.
8148 8141 * RETURNS: 1 if involved in a cycle, 0 otherwise.
8149 8142 */
8150 8143 static int
8151 8144 in_cycle(
8152 8145 ipqos_conf_action_t *action)
8153 8146 {
8154 8147
8155 8148 ipqos_conf_act_ref_t *aref;
8156 8149 ipqos_conf_class_t *c;
8157 8150
8158 8151 IPQOSCDBG1(L0, "in_cycle: visiting action %s\n", action->name);
8159 8152
8160 8153
8161 8154 /* have we visited this action before? */
8162 8155
8163 8156 if (action->visited == INCYCLE_VISITED) {
8164 8157 action->visited = 0;
8165 8158 return (1);
8166 8159 }
8167 8160 action->visited = INCYCLE_VISITED;
8168 8161
8169 8162 /*
8170 8163 * recurse down the child actions of this action through the
8171 8164 * classes next action and parameter actions.
8172 8165 */
8173 8166
8174 8167 for (aref = action->params->actions; aref != NULL; aref = aref->next) {
8175 8168
8176 8169 /* skip virtual actions - they can't be in a cycle */
8177 8170
8178 8171 if (virtual_action(aref->name)) {
8179 8172 continue;
8180 8173 }
8181 8174
8182 8175 if (in_cycle(aref->action)) {
8183 8176 action->visited = 0;
8184 8177 return (1);
8185 8178 }
8186 8179 }
8187 8180
8188 8181 for (c = action->classes; c != NULL; c = c->next) {
8189 8182 aref = c->alist;
8190 8183
8191 8184 if (virtual_action(aref->name)) {
8192 8185 continue;
8193 8186 }
8194 8187
8195 8188 if (in_cycle(aref->action)) {
8196 8189 action->visited = 0;
8197 8190 return (1);
8198 8191 }
8199 8192 }
8200 8193
8201 8194 IPQOSCDBG0(L0, "in_cycle: return\n");
8202 8195 action->visited = 0;
8203 8196 return (0);
8204 8197 }
8205 8198
8206 8199 /*
8207 8200 * checks that the configuration in actions is a valid whole, that
8208 8201 * all actions are unique, all filters and classes are unique within
8209 8202 * their action, that classes referenced by filters exist and actions
8210 8203 * referenced by classes and params exist. Also checks that there are no root
8211 8204 * actions but ipgpc and that no actions are involved in cycles. As
8212 8205 * a consequence of checking that the actions exist two way pointers
8213 8206 * are created between the dependee and dependant actions.
8214 8207 *
8215 8208 * In the case the the userconf flag is zero only this link creation is
8216 8209 * set as we trust the kernel to return a valid configuration.
8217 8210 *
8218 8211 * RETURNS: IPQOS_CONF_ERR if config isn't valid, else IPQOS_CONF_SUCCESS.
8219 8212 *
8220 8213 */
8221 8214
8222 8215 static int
8223 8216 validconf(
8224 8217 ipqos_conf_action_t *actions,
8225 8218 int userconf) /* are we checking a conf file ? */
8226 8219 {
8227 8220 char *name;
8228 8221 ipqos_conf_action_t *act;
8229 8222 int res;
8230 8223 ipqos_conf_action_t *dact;
8231 8224 ipqos_conf_filter_t *flt;
8232 8225 ipqos_conf_class_t *cls;
8233 8226 ipqos_conf_params_t *params;
8234 8227 ipqos_conf_act_ref_t *aref;
8235 8228
8236 8229 IPQOSCDBG0(L0, "In validconf\n");
8237 8230
8238 8231 /* check actions are unique */
8239 8232
8240 8233 if (userconf && actions_unique(actions, &name) != IPQOS_CONF_SUCCESS) {
8241 8234 ipqos_msg(MT_ERROR, gettext("Duplicate named action %s.\n"),
8242 8235 name);
8243 8236 return (IPQOS_CONF_ERR);
8244 8237 }
8245 8238
8246 8239 for (act = actions; act; act = act->next) {
8247 8240
8248 8241 /*
8249 8242 * check filters (for user land configs only).
8250 8243 * check they are unique in this action and their class exists.
8251 8244 */
8252 8245 if (userconf) {
8253 8246 for (flt = act->filters; flt; flt = flt->next) {
8254 8247
8255 8248 /* check unique name */
8256 8249
8257 8250 if (filterexist(flt->name, flt->instance,
8258 8251 flt->next)) {
8259 8252 ipqos_msg(MT_ERROR,
8260 8253 gettext("Duplicate named filter "
8261 8254 "%s in action %s.\n"), flt->name,
8262 8255 act->name);
8263 8256 return (IPQOS_CONF_ERR);
8264 8257 }
8265 8258
8266 8259 /*
8267 8260 * check existence of class and error if
8268 8261 * class doesn't exist and not a perm class
8269 8262 */
8270 8263
8271 8264 if (!classexist(flt->class_name,
8272 8265 act->classes)) {
8273 8266 if (!in_string_table(act->perm_classes,
8274 8267 act->num_perm_classes,
8275 8268 flt->class_name)) {
8276 8269 ipqos_msg(MT_ERROR,
8277 8270 gettext("Undefined "
8278 8271 "class in filter %s, "
8279 8272 "action %s.\n"), flt->name,
8280 8273 act->name);
8281 8274 return (IPQOS_CONF_ERR);
8282 8275 }
8283 8276 }
8284 8277 }
8285 8278 }
8286 8279
8287 8280 /* check classes */
8288 8281
8289 8282 for (cls = act->classes; cls; cls = cls->next) {
8290 8283
8291 8284 /* check if class name unique (userland only) */
8292 8285
8293 8286 if (userconf && classexist(cls->name, cls->next)) {
8294 8287 ipqos_msg(MT_ERROR,
8295 8288 gettext("Duplicate named class %s in "
8296 8289 "action %s.\n"), cls->name, act->name);
8297 8290 return (IPQOS_CONF_ERR);
8298 8291 }
8299 8292
8300 8293 /*
8301 8294 * virtual actions always exist so don't check for next
8302 8295 * action.
8303 8296 */
8304 8297 if (virtual_action(cls->alist->name)) {
8305 8298 continue;
8306 8299 }
8307 8300
8308 8301 /*
8309 8302 * check existance of next action and create link to
8310 8303 * it.
8311 8304 */
8312 8305 if ((cls->alist->action =
8313 8306 actionexist(cls->alist->name, actions)) == NULL) {
8314 8307 ipqos_msg(MT_ERROR,
8315 8308 gettext("Undefined action in class %s, "
8316 8309 "action %s.\n"), cls->name, act->name);
8317 8310 return (IPQOS_CONF_ERR);
8318 8311 }
8319 8312
8320 8313 /* create backwards link - used for deletions */
8321 8314
8322 8315 dact = cls->alist->action;
8323 8316 res = add_aref(&dact->dependencies, NULL, act->name);
8324 8317 if (res != IPQOS_CONF_SUCCESS) {
8325 8318 return (IPQOS_CONF_ERR);
8326 8319 }
8327 8320 dact->dependencies->action = act;
8328 8321 }
8329 8322
8330 8323
8331 8324 /* check actions exist for action type parameters */
8332 8325
8333 8326 params = act->params;
8334 8327 for (aref = params->actions; aref; aref = aref->next) {
8335 8328
8336 8329 /* skip virtuals */
8337 8330
8338 8331 if (virtual_action(aref->name)) {
8339 8332 continue;
8340 8333 }
8341 8334
8342 8335 /*
8343 8336 * check existance of action in this ref
8344 8337 * and if present create a ptr to it.
8345 8338 */
8346 8339 aref->action = actionexist(aref->name, actions);
8347 8340 if (aref->action == NULL) {
8348 8341 ipqos_msg(MT_ERROR,
8349 8342 gettext("Undefined action in parameter "
8350 8343 "%s, action %s.\n"),
8351 8344 SHORT_NAME(aref->field), act->name);
8352 8345 return (IPQOS_CONF_ERR);
8353 8346 }
8354 8347
8355 8348 /* create backwards link */
8356 8349
8357 8350 dact = aref->action;
8358 8351 res = add_aref(&dact->dependencies, NULL,
8359 8352 act->name);
8360 8353 if (res != IPQOS_CONF_SUCCESS) {
8361 8354 return (IPQOS_CONF_ERR);
8362 8355 }
8363 8356 dact->dependencies->action = act;
8364 8357 }
8365 8358 }
8366 8359
8367 8360 /* for kernel retrieved configs we don't do the following checks. */
8368 8361 if (!userconf) {
8369 8362 return (IPQOS_CONF_SUCCESS);
8370 8363 }
8371 8364
8372 8365 /* check for cycles in config and orphaned actions other than ipgpc */
8373 8366
8374 8367 for (act = actions; act; act = act->next) {
8375 8368
8376 8369 /* check if involved in cycle */
8377 8370
8378 8371 if (in_cycle(act)) {
8379 8372 ipqos_msg(MT_ERROR,
8380 8373 gettext("Action %s involved in cycle.\n"),
8381 8374 act->name);
8382 8375 return (IPQOS_CONF_ERR);
8383 8376 }
8384 8377
8385 8378 /* check that this action has a parent (except ipgpc) */
8386 8379
8387 8380 if (act->dependencies == NULL &&
8388 8381 strcmp(act->name, IPGPC_CLASSIFY) != 0) {
8389 8382 ipqos_msg(MT_ERROR, gettext("Action %s isn't "
8390 8383 "referenced by any other actions.\n"), act->name);
8391 8384 return (IPQOS_CONF_ERR);
8392 8385 }
8393 8386 }
8394 8387
8395 8388 return (IPQOS_CONF_SUCCESS);
8396 8389 }
8397 8390
8398 8391 /*
8399 8392 * Read the version from the config file with stream cfp with
8400 8393 * the tag version_tag. The tag-value pair should be the first tokens
8401 8394 * encountered.
8402 8395 *
8403 8396 * RETURNS: -1 if a missing or invalid version or a read error,
8404 8397 * else an integer encoding of the version.
8405 8398 */
8406 8399 static int
8407 8400 read_cfile_ver(
8408 8401 FILE *cfp,
8409 8402 char *version_tag)
8410 8403 {
8411 8404 char *sp = NULL;
8412 8405 int res;
8413 8406 int version;
8414 8407
8415 8408 IPQOSCDBG0(L1, "In read_cfile_ver:\n");
8416 8409
8417 8410 /*
8418 8411 * read version tag string.
8419 8412 */
8420 8413 res = readtoken(cfp, &sp);
8421 8414 if (res != IPQOS_CONF_SUCCESS) {
8422 8415 goto fail;
8423 8416 } else if (strcasecmp(sp, version_tag) != 0) {
8424 8417 goto fail;
8425 8418 }
8426 8419 free(sp);
8427 8420 sp = NULL;
8428 8421
8429 8422 /*
8430 8423 * read version number string.
8431 8424 */
8432 8425 res = readtoken(cfp, &sp);
8433 8426 if (res != IPQOS_CONF_SUCCESS) {
8434 8427 goto fail;
8435 8428 }
8436 8429
8437 8430 /*
8438 8431 * encode version into int.
8439 8432 */
8440 8433 if ((version = ver_str_to_int(sp)) == -1) {
8441 8434 goto fail;
8442 8435 }
8443 8436 free(sp);
8444 8437
8445 8438 return (version);
8446 8439 fail:
8447 8440 ipqos_msg(MT_ERROR,
8448 8441 gettext("Missing/Invalid config file %s.\n"), version_tag);
8449 8442 if (sp != NULL)
8450 8443 free(sp);
8451 8444 return (-1);
8452 8445 }
8453 8446
8454 8447 /*
8455 8448 * read the set of actions definitions from the stream cfp and store
8456 8449 * them in a list pointed to by conf.
8457 8450 * RETURNS: IPQOS_CONF_ERR if any errors, else IPQOS_CONF_SUCCESS.
8458 8451 */
8459 8452 static int
8460 8453 readconf(
8461 8454 FILE *cfp,
8462 8455 ipqos_conf_action_t **conf)
8463 8456 {
8464 8457
8465 8458 int res;
8466 8459 ipqos_conf_action_t *action;
8467 8460 boolean_t ipgpc_action = B_FALSE;
8468 8461 int fmt_ver;
8469 8462
8470 8463 IPQOSCDBG0(L0, "In readconf\n");
8471 8464
8472 8465 *conf = NULL;
8473 8466
8474 8467 /*
8475 8468 * get config file format version.
8476 8469 */
8477 8470 fmt_ver = read_cfile_ver(cfp, IPQOS_FMT_VERSION_STR);
8478 8471 if (fmt_ver == -1) {
8479 8472 return (IPQOS_CONF_ERR);
8480 8473 } else {
8481 8474 /*
8482 8475 * check version is valid
8483 8476 */
8484 8477 if ((IPP_MAJOR_MODULE_VER(fmt_ver) > 1) ||
8485 8478 (IPP_MINOR_MODULE_VER(fmt_ver) > 0)) {
8486 8479 ipqos_msg(MT_ERROR, gettext("Unsupported config file "
8487 8480 "format version.\n"));
8488 8481 return (IPQOS_CONF_ERR);
8489 8482 }
8490 8483 }
8491 8484
8492 8485 /* loop reading actions adding to conf till EOF */
8493 8486
8494 8487 for (;;) {
8495 8488 action = NULL;
8496 8489
8497 8490 /* readaction */
8498 8491
8499 8492 res = readaction(cfp, &action);
8500 8493 if (res == IPQOS_CONF_ERR) {
8501 8494 goto fail;
8502 8495 }
8503 8496
8504 8497 /* reached eof, finish */
8505 8498
8506 8499 if (res == IPQOS_CONF_EOF) {
8507 8500 break;
8508 8501 }
8509 8502
8510 8503 ADD_TO_LIST(conf, action);
8511 8504
8512 8505 /* check if we just read an ipgpc action */
8513 8506
8514 8507 if (strcmp(action->name, IPGPC_CLASSIFY) == 0)
8515 8508 ipgpc_action = B_TRUE;
8516 8509 }
8517 8510
8518 8511 /* check that there is one or more actions and that one is ipgpc */
8519 8512
8520 8513 if (ipgpc_action == B_FALSE) {
8521 8514 ipqos_msg(MT_ERROR, gettext("No %s action defined.\n"),
8522 8515 IPGPC_NAME);
8523 8516 goto fail;
8524 8517 }
8525 8518
8526 8519 return (IPQOS_CONF_SUCCESS);
8527 8520 fail:
8528 8521 free_actions(*conf);
8529 8522 *conf = NULL;
8530 8523 return (IPQOS_CONF_ERR);
8531 8524 }
8532 8525
8533 8526 /* ************************ kernel config retrieval ************************ */
8534 8527
8535 8528
8536 8529 /*
8537 8530 * read the current configuration from the kernel and make *conf a ptr to it.
8538 8531 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
8539 8532 */
8540 8533 static int
8541 8534 readkconf(ipqos_conf_action_t **conf)
8542 8535 {
8543 8536
8544 8537 int res;
8545 8538 char **modnames = NULL;
8546 8539 int nmods;
8547 8540 char **actnames = NULL;
8548 8541 int nacts;
8549 8542 int x, y;
8550 8543 FILE *tfp;
8551 8544 int openerr;
8552 8545 ipqos_actinfo_prm_t ai_prm;
8553 8546
8554 8547
8555 8548 IPQOSCDBG0(L0, "In readkconf\n");
8556 8549
8557 8550 /* initialise conf to NULL */
8558 8551 *conf = NULL;
8559 8552
8560 8553 /* get list of modules currently loaded */
8561 8554
8562 8555 res = ipp_list_mods(&modnames, &nmods);
8563 8556 if (res != 0) {
8564 8557 ipqos_msg(MT_ENOSTR, "ipp_list_mods");
8565 8558 return (IPQOS_CONF_ERR);
8566 8559 }
8567 8560
8568 8561 /*
8569 8562 * iterate through all loaded modules retrieving their list of actions
8570 8563 * and then retrieving the configuration of each of these
8571 8564 * and attatching it to conf.
8572 8565 */
8573 8566 for (x = 0; x < nmods; x++) {
8574 8567
8575 8568 /* skip actions of modules that we can't open types file of */
8576 8569
8577 8570 if ((tfp = validmod(modnames[x], &openerr)) == NULL) {
8578 8571
8579 8572 /* mem error */
8580 8573
8581 8574 if (!openerr) {
8582 8575 goto fail;
8583 8576
8584 8577 /*
8585 8578 * fopen fail - if we failed because the file didn't
8586 8579 * exist we assume this is an unknown module and
8587 8580 * ignore this module, otherwise error.
8588 8581 */
8589 8582 } else {
8590 8583 if (errno == ENOENT) {
8591 8584 continue;
8592 8585 } else {
8593 8586 ipqos_msg(MT_ENOSTR, "fopen");
8594 8587 goto fail;
8595 8588 }
8596 8589 }
8597 8590 }
8598 8591 (void) fclose(tfp);
8599 8592
8600 8593 /* get action list for this module */
8601 8594
8602 8595 res = ipp_mod_list_actions(modnames[x], &actnames, &nacts);
8603 8596 if (res != 0) {
8604 8597 ipqos_msg(MT_ENOSTR, "ipp_mod_list_actions");
8605 8598 goto fail;
8606 8599 }
8607 8600
8608 8601 /* read config of each action of this module */
8609 8602
8610 8603 for (y = 0; y < nacts; y++) {
8611 8604 ai_prm.action = alloc_action();
8612 8605 if (ai_prm.action == NULL) {
8613 8606 goto fail;
8614 8607 }
8615 8608
8616 8609 /* copy action name into action struct */
8617 8610
8618 8611 (void) strlcpy(ai_prm.action->name, actnames[y],
8619 8612 IPQOS_CONF_NAME_LEN);
8620 8613
8621 8614 /* copy module name into action struct */
8622 8615
8623 8616 (void) strlcpy(ai_prm.action->module, modnames[x],
8624 8617 IPQOS_CONF_NAME_LEN);
8625 8618
8626 8619 /* get action info */
8627 8620
8628 8621 res = ipp_action_info(actnames[y],
8629 8622 (int (*)(nvlist_t *, void *))parse_kaction,
8630 8623 (void *)&ai_prm, 0);
8631 8624 if (res != 0) {
8632 8625 /* was this an ipp error */
8633 8626 if (ai_prm.intl_ret == IPQOS_CONF_SUCCESS) {
8634 8627 ipqos_msg(MT_ENOSTR,
8635 8628 "ipp_action_info");
8636 8629 }
8637 8630 goto fail;
8638 8631 }
8639 8632
8640 8633 ADD_TO_LIST(conf, ai_prm.action);
8641 8634 }
8642 8635
8643 8636 cleanup_string_table(actnames, nacts);
8644 8637 }
8645 8638
8646 8639 cleanup_string_table(modnames, nmods);
8647 8640 return (IPQOS_CONF_SUCCESS);
8648 8641 fail:
8649 8642 free_actions(*conf);
8650 8643 *conf = NULL;
8651 8644 cleanup_string_table(modnames, nmods);
8652 8645 cleanup_string_table(actnames, nacts);
8653 8646 return (IPQOS_CONF_ERR);
8654 8647 }
8655 8648
8656 8649 /*
8657 8650 * This is passed as a parameter to ipp_action_info() in readkaction and
8658 8651 * is called back one for each configuration element within the action
8659 8652 * specified. This results in filters and classes being created and chained
8660 8653 * off of action, and action having its params set.
8661 8654 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
8662 8655 */
8663 8656 static int
8664 8657 parse_kaction(
8665 8658 nvlist_t *nvl,
8666 8659 ipqos_actinfo_prm_t *ai_prm)
8667 8660 {
8668 8661
8669 8662 int ret;
8670 8663 uint8_t cfgtype;
8671 8664 ipqos_conf_filter_t *filter = NULL;
8672 8665 ipqos_conf_class_t *class = NULL;
8673 8666 ipqos_conf_action_t *action = ai_prm->action;
8674 8667
8675 8668
8676 8669 IPQOSCDBG1(KRET, "In parse_kaction: action_name: %s\n", action->name);
8677 8670
8678 8671 /* get config type */
8679 8672
8680 8673 (void) nvlist_lookup_byte(nvl, IPP_CONFIG_TYPE, &cfgtype);
8681 8674 (void) nvlist_remove_all(nvl, IPP_CONFIG_TYPE);
8682 8675
8683 8676 switch (cfgtype) {
8684 8677 case CLASSIFIER_ADD_FILTER: {
8685 8678 /*
8686 8679 * parse the passed filter nvlist
8687 8680 * and add result to action's filter list.
8688 8681 */
8689 8682 filter = alloc_filter();
8690 8683 if (filter == NULL) {
8691 8684 ai_prm->intl_ret = IPQOS_CONF_ERR;
8692 8685 return (IPQOS_CONF_ERR);
8693 8686 }
8694 8687
8695 8688 ret = parse_kfilter(filter, nvl);
8696 8689 if (ret != IPQOS_CONF_SUCCESS) {
8697 8690 free_filter(filter);
8698 8691 ai_prm->intl_ret = IPQOS_CONF_ERR;
8699 8692 return (ret);
8700 8693 }
8701 8694
8702 8695 ADD_TO_LIST(&action->filters, filter);
8703 8696 break;
8704 8697 }
8705 8698 case CLASSIFIER_ADD_CLASS:
8706 8699 case CLASSIFIER_MODIFY_CLASS: {
8707 8700 /*
8708 8701 * parse the passed class nvlist
8709 8702 * and add result to action's class list.
8710 8703 */
8711 8704 class = alloc_class();
8712 8705 if (class == NULL) {
8713 8706 ai_prm->intl_ret = IPQOS_CONF_ERR;
8714 8707 return (IPQOS_CONF_ERR);
8715 8708 }
8716 8709
8717 8710 ret = parse_kclass(class, nvl);
8718 8711 if (ret != IPQOS_CONF_SUCCESS) {
8719 8712 free_class(class);
8720 8713 ai_prm->intl_ret = IPQOS_CONF_ERR;
8721 8714 return (ret);
8722 8715 }
8723 8716
8724 8717 ADD_TO_LIST(&action->classes, class);
8725 8718 break;
8726 8719 }
8727 8720 case IPP_SET: {
8728 8721 /*
8729 8722 * we don't alloc a params struct as it is created
8730 8723 * as part of an action.
8731 8724 */
8732 8725
8733 8726 /* parse the passed params nvlist */
8734 8727
8735 8728 ret = parse_kparams(action->module, action->params,
8736 8729 nvl);
8737 8730 if (ret != IPQOS_CONF_SUCCESS) {
8738 8731 ai_prm->intl_ret = IPQOS_CONF_ERR;
8739 8732 return (ret);
8740 8733 }
8741 8734 }
8742 8735 }
8743 8736
8744 8737 ai_prm->intl_ret = IPQOS_CONF_SUCCESS;
8745 8738 return (IPQOS_CONF_SUCCESS);
8746 8739 }
8747 8740
8748 8741 /*
8749 8742 * parses a params nvlist returned from the kernel.
8750 8743 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
8751 8744 */
8752 8745 int
8753 8746 parse_kparams(
8754 8747 char *module,
8755 8748 ipqos_conf_params_t *params,
8756 8749 nvlist_t *nvl) {
8757 8750
8758 8751 int ret;
8759 8752 ipqos_nvtype_t type;
8760 8753 str_val_nd_t *tmp;
8761 8754 char *act;
8762 8755 uint32_t u32;
8763 8756 nvpair_t *nvp;
8764 8757 FILE *tfp;
8765 8758 char dfltst[IPQOS_VALST_MAXLEN];
8766 8759 char *param;
8767 8760 nvlist_t *nvlcp;
8768 8761 int openerr;
8769 8762 place_t place;
8770 8763
8771 8764 IPQOSCDBG0(KRET, "In parse_kparams:\n");
8772 8765
8773 8766 /* get stream to module types file */
8774 8767
8775 8768 tfp = validmod(module, &openerr);
8776 8769 if (tfp == NULL) {
8777 8770 if (openerr) {
8778 8771 ipqos_msg(MT_ENOSTR, "fopen");
8779 8772 }
8780 8773 return (IPQOS_CONF_ERR);
8781 8774 }
8782 8775
8783 8776 /* make copy of passed in nvlist as it is freed by the caller */
8784 8777
8785 8778 ret = nvlist_dup(nvl, &nvlcp, 0);
8786 8779 if (ret != 0) {
8787 8780 return (IPQOS_CONF_ERR);
8788 8781 }
8789 8782
8790 8783 /*
8791 8784 * get config originator and remove from nvlist. If no owner we
8792 8785 * assume ownership.
8793 8786 */
8794 8787 ret = nvlist_lookup_uint32(nvlcp, IPP_CONFIG_ORIGINATOR, &u32);
8795 8788 if (ret == 0) {
8796 8789 params->originator = u32;
8797 8790 (void) nvlist_remove_all(nvlcp, IPP_CONFIG_ORIGINATOR);
8798 8791 } else {
8799 8792 params->originator = IPP_CONFIG_IPQOSCONF;
8800 8793 }
8801 8794
8802 8795 /* get action stats and remove from nvlist */
8803 8796
8804 8797 ret = nvlist_lookup_uint32(nvlcp, IPP_ACTION_STATS_ENABLE, &u32);
8805 8798 if (ret == 0) {
8806 8799 params->stats_enable = *(boolean_t *)&u32;
8807 8800 (void) nvlist_remove_all(nvlcp, IPP_ACTION_STATS_ENABLE);
8808 8801 }
8809 8802
8810 8803 /*
8811 8804 * loop throught nvlist elements and for those that are actions create
8812 8805 * action ref entrys for them.
8813 8806 */
8814 8807 nvp = nvlist_next_nvpair(nvlcp, NULL);
8815 8808 while (nvp != NULL) {
8816 8809 param = SHORT_NAME(nvpair_name(nvp));
8817 8810 place = PL_ANY;
8818 8811 ret = readtype(tfp, module, param, &type, &tmp, dfltst,
8819 8812 B_FALSE, &place);
8820 8813 if (ret != IPQOS_CONF_SUCCESS) {
8821 8814 goto fail;
8822 8815 }
8823 8816
8824 8817 if ((place == PL_PARAMS) && /* avoid map entries */
8825 8818 (type == IPQOS_DATA_TYPE_ACTION)) {
8826 8819 (void) nvpair_value_string(nvp, &act);
8827 8820 ret = add_aref(¶ms->actions, nvpair_name(nvp), act);
8828 8821 if (ret != IPQOS_CONF_SUCCESS) {
8829 8822 goto fail;
8830 8823 }
8831 8824 }
8832 8825
8833 8826 nvp = nvlist_next_nvpair(nvlcp, nvp);
8834 8827 }
8835 8828
8836 8829 /* assign copied nvlist to params struct */
8837 8830
8838 8831 params->nvlist = nvlcp;
8839 8832
8840 8833 (void) fclose(tfp);
8841 8834 return (IPQOS_CONF_SUCCESS);
8842 8835 fail:
8843 8836 (void) fclose(tfp);
8844 8837 free_arefs(params->actions);
8845 8838 params->actions = NULL;
8846 8839 nvlist_free(nvlcp);
8847 8840 return (IPQOS_CONF_ERR);
8848 8841 }
8849 8842
8850 8843 /*
8851 8844 * parses a classes nvlist returned from the kernel.
8852 8845 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
8853 8846 */
8854 8847 static int
8855 8848 parse_kclass(
8856 8849 ipqos_conf_class_t *class,
8857 8850 nvlist_t *nvl)
8858 8851 {
8859 8852
8860 8853 int ret;
8861 8854 uint32_t u32;
8862 8855 char *str;
8863 8856
8864 8857 IPQOSCDBG0(KRET, "In parse_kclass:\n");
8865 8858
8866 8859 /* lookup object originator */
8867 8860
8868 8861 ret = nvlist_lookup_uint32(nvl, IPP_CONFIG_ORIGINATOR, &u32);
8869 8862 if (ret == 0) {
8870 8863 class->originator = u32;
8871 8864 } else {
8872 8865 class->originator = IPP_CONFIG_IPQOSCONF;
8873 8866 }
8874 8867
8875 8868 /* lookup name */
8876 8869
8877 8870 (void) nvlist_lookup_string(nvl, CLASSIFIER_CLASS_NAME, &str);
8878 8871 (void) strlcpy(class->name, str, IPQOS_CONF_NAME_LEN);
8879 8872 IPQOSCDBG1(KRET, "reading class %s\n", class->name);
8880 8873
8881 8874 /* lookup next action */
8882 8875
8883 8876 (void) nvlist_lookup_string(nvl, CLASSIFIER_NEXT_ACTION, &str);
8884 8877 ret = add_aref(&class->alist, NULL, str);
8885 8878 if (ret != IPQOS_CONF_SUCCESS) {
8886 8879 return (IPQOS_CONF_ERR);
8887 8880 }
8888 8881
8889 8882 /* lookup stats enable */
8890 8883
8891 8884 ret = nvlist_lookup_uint32(nvl, CLASSIFIER_CLASS_STATS_ENABLE, &u32);
8892 8885 if (ret == 0) {
8893 8886 class->stats_enable = *(boolean_t *)&u32;
8894 8887 }
8895 8888
8896 8889 return (IPQOS_CONF_SUCCESS);
8897 8890 }
8898 8891
8899 8892 /*
8900 8893 * parses a filters nvlist returned from the kernel.
8901 8894 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
8902 8895 */
8903 8896 static int
8904 8897 parse_kfilter(
8905 8898 ipqos_conf_filter_t *filter,
8906 8899 nvlist_t *nvl)
8907 8900 {
8908 8901
8909 8902 int ret;
8910 8903 char *str;
8911 8904 uint32_t u32;
8912 8905 nvlist_t *nvlcp;
8913 8906 char *end;
8914 8907
8915 8908 IPQOSCDBG0(KRET, "In parse_kfilter:\n");
8916 8909
8917 8910 /* make copy of passed in nvlist as it is freed by the caller */
8918 8911
8919 8912 ret = nvlist_dup(nvl, &nvlcp, 0);
8920 8913 if (ret != 0) {
8921 8914 return (IPQOS_CONF_ERR);
8922 8915 }
8923 8916
8924 8917 /* lookup originator */
8925 8918
8926 8919 ret = nvlist_lookup_uint32(nvlcp, IPP_CONFIG_ORIGINATOR, &u32);
8927 8920 if (ret == 0) {
8928 8921 filter->originator = u32;
8929 8922 (void) nvlist_remove_all(nvlcp, IPP_CONFIG_ORIGINATOR);
8930 8923 } else {
8931 8924 filter->originator = IPP_CONFIG_IPQOSCONF;
8932 8925 }
8933 8926
8934 8927 /* lookup filter name */
8935 8928
8936 8929 (void) nvlist_lookup_string(nvlcp, CLASSIFIER_FILTER_NAME, &str);
8937 8930 (void) strlcpy(filter->name, str, IPQOS_CONF_NAME_LEN);
8938 8931 (void) nvlist_remove_all(nvlcp, CLASSIFIER_FILTER_NAME);
8939 8932
8940 8933 /* lookup class name */
8941 8934
8942 8935 (void) nvlist_lookup_string(nvlcp, CLASSIFIER_CLASS_NAME, &str);
8943 8936 (void) strlcpy(filter->class_name, str, IPQOS_CONF_NAME_LEN);
8944 8937 (void) nvlist_remove_all(nvlcp, CLASSIFIER_CLASS_NAME);
8945 8938
8946 8939 /* lookup src and dst host names if present */
8947 8940
8948 8941 if (nvlist_lookup_string(nvlcp, IPGPC_SADDR_HOSTNAME, &str) == 0) {
8949 8942 filter->src_nd_name = malloc(strlen(str) + 1);
8950 8943 if (filter->src_nd_name) {
8951 8944 (void) strcpy(filter->src_nd_name, str);
8952 8945 (void) nvlist_remove_all(nvlcp, IPGPC_SADDR_HOSTNAME);
8953 8946 } else {
8954 8947 ipqos_msg(MT_ENOSTR, "malloc");
8955 8948 nvlist_free(nvlcp);
8956 8949 return (IPQOS_CONF_ERR);
8957 8950 }
8958 8951 }
8959 8952 if (nvlist_lookup_string(nvlcp, IPGPC_DADDR_HOSTNAME, &str) == 0) {
8960 8953 filter->dst_nd_name = malloc(strlen(str) + 1);
8961 8954 if (filter->dst_nd_name) {
8962 8955 (void) strcpy(filter->dst_nd_name, str);
8963 8956 (void) nvlist_remove_all(nvlcp, IPGPC_DADDR_HOSTNAME);
8964 8957 } else {
8965 8958 ipqos_msg(MT_ENOSTR, "malloc");
8966 8959 nvlist_free(nvlcp);
8967 8960 return (IPQOS_CONF_ERR);
8968 8961 }
8969 8962 }
8970 8963
8971 8964 /* lookup ip_version if present */
8972 8965
8973 8966 if (nvlist_lookup_string(nvlcp, IPGPC_FILTER_PRIVATE, &str) == 0) {
8974 8967 filter->ip_versions = (uint32_t)strtol(str, &end, 0);
8975 8968 if (end != str) {
8976 8969 (void) nvlist_remove_all(nvlcp, IPGPC_FILTER_PRIVATE);
8977 8970 } else {
8978 8971 ipqos_msg(MT_ERROR,
8979 8972 gettext("Corrupted ip_version returned from "
8980 8973 "kernel.\n"));
8981 8974 nvlist_free(nvlcp);
8982 8975 return (IPQOS_CONF_ERR);
8983 8976 }
8984 8977 }
8985 8978
8986 8979 /* lookup filter instance if present */
8987 8980
8988 8981 ret = nvlist_lookup_int32(nvlcp, IPGPC_FILTER_INSTANCE,
8989 8982 &filter->instance);
8990 8983 if (ret != 0) {
8991 8984 filter->instance = -1;
8992 8985 } else {
8993 8986 (void) nvlist_remove_all(nvlcp, IPGPC_FILTER_INSTANCE);
8994 8987 }
8995 8988
8996 8989 /* attach new trimmed nvlist to filter */
8997 8990 filter->nvlist = nvlcp;
8998 8991
8999 8992 return (IPQOS_CONF_SUCCESS);
9000 8993 }
9001 8994
9002 8995
9003 8996 /*
9004 8997 * determines whether action_name is a virtual action name.
9005 8998 * RETURNS: if virtual action 1, else 0.
9006 8999 */
9007 9000 static int
9008 9001 virtual_action(char *action_name)
9009 9002 {
9010 9003
9011 9004 if (strcmp(action_name, IPP_ANAME_CONT) == 0 ||
9012 9005 strcmp(action_name, IPP_ANAME_DEFER) == 0 ||
9013 9006 strcmp(action_name, IPP_ANAME_DROP) == 0) {
9014 9007 return (1);
9015 9008 }
9016 9009
9017 9010 return (0);
9018 9011 }
9019 9012
9020 9013 /*
9021 9014 * remove all the actions within the kernel. If there is a failure
9022 9015 * modified is set to represent whether the attempt to flush modified
9023 9016 * the configuration in any way.
9024 9017 * RETURNS: IPQOS_CONF_ERR if the ipp_* functions return any errors,
9025 9018 * else IPQOS_CONF_SUCCESS.
9026 9019 */
9027 9020 static int
9028 9021 flush(
9029 9022 boolean_t *modified)
9030 9023 {
9031 9024
9032 9025 int res;
9033 9026 char **modnames = NULL;
9034 9027 int nmods;
9035 9028 char **actnames = NULL;
9036 9029 int nacts;
9037 9030 int x, y;
9038 9031
9039 9032 IPQOSCDBG0(L0, "In flush\n");
9040 9033
9041 9034 *modified = B_FALSE;
9042 9035
9043 9036 /*
9044 9037 * get list of modules currently loaded.
9045 9038 */
9046 9039 res = ipp_list_mods(&modnames, &nmods);
9047 9040 if (res != 0) {
9048 9041 ipqos_msg(MT_ENOSTR, "ipp_list_mods");
9049 9042 return (IPQOS_CONF_ERR);
9050 9043 }
9051 9044
9052 9045 /*
9053 9046 * iterate through all the modules listing their actions and
9054 9047 * deleting all of them.
9055 9048 */
9056 9049 for (x = 0; x < nmods; x++) {
9057 9050 IPQOSCDBG1(APPLY, "Getting actions of module %s.\n",
9058 9051 modnames[x]);
9059 9052 res = ipp_mod_list_actions(modnames[x], &actnames, &nacts);
9060 9053 if (res != 0) {
9061 9054 ipqos_msg(MT_ENOSTR, "ipp_mod_list_actions");
9062 9055 cleanup_string_table(modnames, nmods);
9063 9056 return (IPQOS_CONF_ERR);
9064 9057 }
9065 9058
9066 9059 for (y = 0; y < nacts; y++) {
9067 9060 IPQOSCDBG1(APPLY, "deleting action %s\n", actnames[y]);
9068 9061 res = ipp_action_destroy(actnames[y], IPP_DESTROY_REF);
9069 9062 /*
9070 9063 * if fails for reason other than action doesn't
9071 9064 * exist or action has dependency.
9072 9065 */
9073 9066 if (res != 0 && errno != ENOENT && errno != EBUSY) {
9074 9067 ipqos_msg(MT_ENOSTR, "ipp_action_destroy");
9075 9068 cleanup_string_table(modnames, nmods);
9076 9069 cleanup_string_table(actnames, nacts);
9077 9070 return (IPQOS_CONF_ERR);
9078 9071 }
9079 9072
9080 9073 if (res == 0)
9081 9074 *modified = B_TRUE;
9082 9075 }
9083 9076 cleanup_string_table(actnames, nacts);
9084 9077 }
9085 9078 cleanup_string_table(modnames, nmods);
9086 9079
9087 9080 return (IPQOS_CONF_SUCCESS);
9088 9081 }
9089 9082
9090 9083 /*
9091 9084 * Trys to flush the configuration. If it fails and nothing has been modified
9092 9085 * and force_flush is false just return an error, otherwise persist trying to
9093 9086 * completion.
9094 9087 * RETURNS: IPQOS_CONF_ERR if flush attempt failed without modifying anything
9095 9088 * and force_flush was set to false, otherwise IPQOS_CONF_SUCCESS.
9096 9089 */
9097 9090 static int
9098 9091 atomic_flush(
9099 9092 boolean_t force_flush)
9100 9093 {
9101 9094 int x = 0;
9102 9095 int res;
9103 9096 boolean_t modified = B_FALSE;
9104 9097
9105 9098 /*
9106 9099 * attempt first flush of config.
9107 9100 */
9108 9101 res = flush(&modified);
9109 9102 if ((force_flush == B_FALSE) && (res != IPQOS_CONF_SUCCESS) &&
9110 9103 (modified == B_FALSE)) {
9111 9104 return (IPQOS_CONF_ERR);
9112 9105 } else if (res == IPQOS_CONF_SUCCESS) {
9113 9106 return (IPQOS_CONF_SUCCESS);
9114 9107 }
9115 9108
9116 9109 /*
9117 9110 * failed flush that modified config, or force flush set; loop till
9118 9111 * successful flush.
9119 9112 */
9120 9113 while (res != IPQOS_CONF_SUCCESS) {
9121 9114 if (x == 5) { /* 10 secs since start/last message. */
9122 9115 ipqos_msg(MT_ERROR,
9123 9116 gettext("Retrying configuration flush.\n"));
9124 9117 x = 0;
9125 9118 }
9126 9119 (void) sleep(2);
9127 9120 x++;
9128 9121 res = flush(&modified);
9129 9122 }
9130 9123
9131 9124 return (IPQOS_CONF_SUCCESS);
9132 9125 }
9133 9126
9134 9127 /*
9135 9128 * Performs a flush of the configuration within a signal blocking region
9136 9129 * so that there's minimal chance of it being killed and the flush only
9137 9130 * partially completing.
9138 9131 * RETURNS: IPQOS_CONF_SUCCESS (for symmetry with the other main functions).
9139 9132 */
9140 9133 static int
9141 9134 flushconf()
9142 9135 {
9143 9136 int res;
9144 9137
9145 9138 /*
9146 9139 * make sure that flush is as atomic as possible.
9147 9140 */
9148 9141 if ((res = block_all_signals()) == -1)
9149 9142 return (IPQOS_CONF_ERR);
9150 9143
9151 9144 res = atomic_flush(B_FALSE);
9152 9145
9153 9146 /*
9154 9147 * restore signals.
9155 9148 */
9156 9149 (void) restore_all_signals();
9157 9150
9158 9151 if (res == IPQOS_CONF_SUCCESS) {
9159 9152 ipqos_msg(MT_LOG, gettext("Configuration flushed.\n"));
9160 9153 } else {
9161 9154 ipqos_msg(MT_ENOSTR, "atomic_flush");
9162 9155 }
9163 9156
9164 9157 return (res);
9165 9158 }
9166 9159
9167 9160 static int
9168 9161 in_string_table(char *stable[], int size, char *string)
9169 9162 {
9170 9163
9171 9164 IPQOSCDBG1(L1, "In in_string_table: search string %s\n", string);
9172 9165
9173 9166 for (--size; size >= 0; size--) {
9174 9167 if (strcmp(stable[size], string) == 0) {
9175 9168 IPQOSCDBG1(L1, "Found %s in string table\n", string);
9176 9169 return (1);
9177 9170 }
9178 9171 }
9179 9172
9180 9173 return (0);
9181 9174 }
9182 9175
9183 9176 /* free the memory occupied by the string table ctable and its contents. */
9184 9177 static void
9185 9178 cleanup_string_table(char *ctable[], int size)
9186 9179 {
9187 9180
9188 9181 int x;
9189 9182
9190 9183 if (ctable) {
9191 9184 for (x = 0; x < size; x++) {
9192 9185 free(ctable[x]);
9193 9186 }
9194 9187 free(ctable);
9195 9188 }
9196 9189 }
9197 9190
9198 9191 #if 0
9199 9192
9200 9193 /*
9201 9194 * makes a copy of a string table and returns a ptr to it.
9202 9195 * RETURNS: NULL on error or if size was 0, else ptr to copied table.
9203 9196 */
9204 9197 static char **
9205 9198 copy_string_table(char *stable1[], int size)
9206 9199 {
9207 9200
9208 9201 char **st = NULL;
9209 9202 int pos;
9210 9203
9211 9204 /* create char ptr array */
9212 9205
9213 9206 st = malloc(size * sizeof (char *));
9214 9207 if (st == NULL) {
9215 9208 ipqos_msg(MT_ENOSTR, "malloc");
9216 9209 return (st);
9217 9210 }
9218 9211
9219 9212 /* create copy of each string from stable1 in array */
9220 9213
9221 9214 for (pos = size - 1; pos >= 0; pos--) {
9222 9215 st[pos] = malloc(strlen(stable1[pos] + 1));
9223 9216 if (st[pos] == NULL) {
9224 9217 for (pos++; pos < size; pos++)
9225 9218 free(st[pos]);
9226 9219 free(st);
9227 9220 ipqos_msg(MT_ENOSTR, "malloc");
9228 9221 return (NULL);
9229 9222 }
9230 9223
9231 9224 (void) strcpy(st[pos], stable1[pos]);
9232 9225 }
9233 9226
9234 9227 return (st);
9235 9228 }
9236 9229 #endif /* 0 */
9237 9230
9238 9231 /*
9239 9232 * retry lookups on filters that soft failed a previous lookup and
9240 9233 * were put on the retry list.
9241 9234 * RETURNS: IPQOS_CONF_ERR on any errors, else IPQOS_CONF_SUCCESS.
9242 9235 */
9243 9236 static int
9244 9237 retry_name_lookups(
9245 9238 ipqos_conf_action_t *actions)
9246 9239 {
9247 9240
9248 9241 ipqos_conf_action_t *act;
9249 9242 ipqos_conf_filter_t **new_filters;
9250 9243 ipqos_conf_filter_t *flt;
9251 9244
9252 9245 IPQOSCDBG0(APPLY, "In retry_name_lookups:\n");
9253 9246
9254 9247 for (act = actions; act != NULL; act = act->next) {
9255 9248
9256 9249 /* store start of new resolved filters */
9257 9250 LIST_END(&act->filters, &new_filters);
9258 9251
9259 9252 /*
9260 9253 * do name resolution on retry list adding resolved filters
9261 9254 * to end of actions filters.
9262 9255 */
9263 9256 for (flt = act->retry_filters; flt != NULL; flt = flt->next) {
9264 9257
9265 9258 if (domultihome(flt, new_filters, B_TRUE) !=
9266 9259 IPQOS_CONF_SUCCESS) {
9267 9260
9268 9261 /* if resource failure */
9269 9262
9270 9263 if (flt->nlerr == 0) {
9271 9264 return (IPQOS_CONF_ERR);
9272 9265 }
9273 9266 }
9274 9267 }
9275 9268
9276 9269 /* add the newly resolved filters to the kernel action */
9277 9270
9278 9271 for (flt = *new_filters; flt != NULL; flt = flt->next) {
9279 9272 if (add_filter(act->name, flt, act->module_version) !=
9280 9273 IPQOS_CONF_SUCCESS) {
9281 9274 return (IPQOS_CONF_ERR);
9282 9275 }
9283 9276 }
9284 9277 }
9285 9278
9286 9279 return (IPQOS_CONF_SUCCESS);
9287 9280 }
9288 9281
9289 9282 /*
9290 9283 * write the configuration in conf to the file given in dstpath. This
9291 9284 * is done by writing first to a temporary file and then renaming that
9292 9285 * file to dstpath. This assures an atomic write.
9293 9286 * RETURNS: IPQOS_CONF_ERR on any errors, else IPQOS_CONF_SUCCESS.
9294 9287 */
9295 9288 static int
9296 9289 writeconf(
9297 9290 ipqos_conf_action_t *conf,
9298 9291 char *dstpath)
9299 9292 {
9300 9293
9301 9294 FILE *tmpfp;
9302 9295 char *tmppath;
9303 9296 char *pathend;
9304 9297 ipqos_conf_action_t *act;
9305 9298 int res;
9306 9299
9307 9300 IPQOSCDBG0(L0, "in writeconf\n");
9308 9301
9309 9302 /* construct tmp file path so we can use rename() */
9310 9303
9311 9304 pathend = strrchr(dstpath, '/');
9312 9305
9313 9306 /* dstpath in current dir */
9314 9307
9315 9308 if (pathend == NULL) {
9316 9309 tmppath = malloc(strlen("ipqosconf.tmp") + 1);
9317 9310 if (tmppath == NULL) {
9318 9311 ipqos_msg(MT_ENOSTR, "malloc");
9319 9312 return (IPQOS_CONF_ERR);
9320 9313 }
9321 9314 (void) strcpy(tmppath, "ipqosconf.tmp");
9322 9315
9323 9316 /* dstpath in root dir */
9324 9317
9325 9318 } else if (pathend == dstpath) {
9326 9319 tmppath = malloc(strlen("/ipqosconf.tmp") + 1);
9327 9320 if (tmppath == NULL) {
9328 9321 ipqos_msg(MT_ENOSTR, "malloc");
9329 9322 return (IPQOS_CONF_ERR);
9330 9323 }
9331 9324 (void) strcpy(tmppath, "/ipqosconf.tmp");
9332 9325
9333 9326 /* not pwd or root */
9334 9327
9335 9328 } else {
9336 9329 *pathend = NULL;
9337 9330 tmppath = malloc(strlen(dstpath) + strlen("/ipqosconf.tmp") +
9338 9331 1);
9339 9332 if (tmppath == NULL) {
9340 9333 ipqos_msg(MT_ENOSTR, "malloc");
9341 9334 return (IPQOS_CONF_ERR);
9342 9335 }
9343 9336 (void) strcpy(tmppath, dstpath);
9344 9337 (void) strcat(tmppath, "/ipqosconf.tmp");
9345 9338 *pathend = '/';
9346 9339 }
9347 9340
9348 9341
9349 9342 /* open tmp file */
9350 9343
9351 9344 tmpfp = fopen(tmppath, "w");
9352 9345 if (tmpfp == NULL) {
9353 9346 ipqos_msg(MT_ENOSTR, "fopen");
9354 9347 free(tmppath);
9355 9348 return (IPQOS_CONF_ERR);
9356 9349 }
9357 9350
9358 9351 /* write out format version */
9359 9352
9360 9353 (void) fprintf(tmpfp, "%s %d.%d\n\n", IPQOS_FMT_VERSION_STR,
9361 9354 IPQOS_CUR_FMT_MAJOR_VER, IPQOS_CUR_FMT_MINOR_VER);
9362 9355
9363 9356 /*
9364 9357 * loop through actions in list writing ipqosconf originated
9365 9358 * ones out to the tmp file.
9366 9359 */
9367 9360 for (act = conf; act != NULL; act = act->next) {
9368 9361 if (act->params->originator == IPP_CONFIG_IPQOSCONF) {
9369 9362 res = printaction(tmpfp, act, 0, 0);
9370 9363 if (res != IPQOS_CONF_SUCCESS) {
9371 9364 free(tmppath);
9372 9365 (void) fclose(tmpfp);
9373 9366 return (res);
9374 9367 }
9375 9368 }
9376 9369 }
9377 9370 (void) fclose(tmpfp);
9378 9371
9379 9372 /* rename tmp file to dst file */
9380 9373
9381 9374 if (rename(tmppath, dstpath) != 0) {
9382 9375 ipqos_msg(MT_ENOSTR, "rename");
9383 9376 free(tmppath);
9384 9377 return (IPQOS_CONF_ERR);
9385 9378 }
9386 9379 free(tmppath);
9387 9380
9388 9381 return (IPQOS_CONF_SUCCESS);
9389 9382 }
9390 9383
9391 9384 /*
9392 9385 * read the configuration back from the kernel and then write each of the
9393 9386 * actions read to IPQOS_CONF_INIT_PATH.
9394 9387 * RETURNS: IPQOS_CONF_ERR if error, else IPQOS_CONF_SUCCESS.
9395 9388 */
9396 9389 static int
9397 9390 commitconf()
9398 9391 {
9399 9392
9400 9393 int ret;
9401 9394 ipqos_conf_action_t *conf;
9402 9395
9403 9396 IPQOSCDBG0(L0, "In commitconf\n");
9404 9397
9405 9398 /* read the configuration from the kernel */
9406 9399
9407 9400 ret = readkconf(&conf);
9408 9401 if (ret != IPQOS_CONF_SUCCESS) {
9409 9402 return (IPQOS_CONF_ERR);
9410 9403 }
9411 9404
9412 9405 /* dissallow a null config to be stored (we can't read one in) */
9413 9406
9414 9407 if (conf == NULL) {
9415 9408 ipqos_msg(MT_ERROR,
9416 9409 gettext("Can't commit a null configuration.\n"));
9417 9410 return (IPQOS_CONF_ERR);
9418 9411 }
9419 9412
9420 9413 /* make sure if we create file that perms are 644 */
9421 9414
9422 9415 (void) umask(S_IXUSR | S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH);
9423 9416
9424 9417 /* write the configuration to the init file */
9425 9418
9426 9419 ret = writeconf(conf, IPQOS_CONF_INIT_PATH);
9427 9420 if (ret != IPQOS_CONF_SUCCESS) {
9428 9421 return (IPQOS_CONF_ERR);
9429 9422 }
9430 9423
9431 9424 ipqos_msg(MT_LOG,
9432 9425 gettext("Current configuration saved to init file.\n"));
9433 9426
9434 9427 return (IPQOS_CONF_SUCCESS);
9435 9428 }
9436 9429
9437 9430 /*
9438 9431 * Called in the event of a failed rollback. It first flushes the
9439 9432 * current configuration, then attempts to apply the oconf (the old
9440 9433 * one), and if that fails flushes again.
9441 9434 *
9442 9435 * RETURNS: IPQOS_CONF_ERR if the application of old config fails,
9443 9436 * else IPQOS_CONF_SUCCESS.
9444 9437 */
9445 9438 static int
9446 9439 rollback_recover(
9447 9440 ipqos_conf_action_t *oconf)
9448 9441 {
9449 9442 int res;
9450 9443
9451 9444 IPQOSCDBG0(RBK, "In rollback_recover\n");
9452 9445
9453 9446 /*
9454 9447 * flush configuration.
9455 9448 */
9456 9449 (void) atomic_flush(B_TRUE);
9457 9450
9458 9451 /*
9459 9452 * mark all elements of old config for application.
9460 9453 */
9461 9454 mark_config_new(oconf);
9462 9455
9463 9456 /*
9464 9457 * attempt to apply old config.
9465 9458 */
9466 9459 res = applydiff(oconf, NULL);
9467 9460 /*
9468 9461 * if failed force flush of config.
9469 9462 */
9470 9463 if (res != IPQOS_CONF_SUCCESS) {
9471 9464 (void) atomic_flush(B_TRUE);
9472 9465 return (IPQOS_CONF_ERR);
9473 9466 }
9474 9467
9475 9468 return (IPQOS_CONF_SUCCESS);
9476 9469 }
9477 9470
9478 9471 /*
9479 9472 * read and apply the configuration contained if file ifile to the kernel.
9480 9473 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
9481 9474 */
9482 9475 static int
9483 9476 applyconf(char *ifile)
9484 9477 {
9485 9478
9486 9479 FILE *ifp;
9487 9480 ipqos_conf_action_t *conf = NULL;
9488 9481 ipqos_conf_action_t *oconf = NULL;
9489 9482 ipqos_conf_action_t *act, *oact;
9490 9483 int res;
9491 9484
9492 9485 IPQOSCDBG0(L0, "In applyconf:\n");
9493 9486
9494 9487
9495 9488 /* if filename '-' read from stdin */
9496 9489
9497 9490 if (strcmp(ifile, "-") == 0) {
9498 9491 ifp = stdin;
9499 9492 } else {
9500 9493 ifp = fopen(ifile, "r");
9501 9494 if (ifp == NULL) {
9502 9495 ipqos_msg(MT_ERROR,
9503 9496 gettext("Opening file %s for read: %s.\n"),
9504 9497 ifile, strerror(errno));
9505 9498 return (IPQOS_CONF_ERR);
9506 9499 }
9507 9500 }
9508 9501
9509 9502 /* read in new configuration */
9510 9503
9511 9504 res = readconf(ifp, &conf);
9512 9505 if (res != IPQOS_CONF_SUCCESS) {
9513 9506 goto fail;
9514 9507 }
9515 9508
9516 9509 /* check configuration is valid */
9517 9510
9518 9511 res = validconf(conf, 1);
9519 9512 if (res != IPQOS_CONF_SUCCESS) {
9520 9513 goto fail;
9521 9514 }
9522 9515
9523 9516 /* read in kernel configuration */
9524 9517
9525 9518 res = readkconf(&oconf);
9526 9519 if (res != IPQOS_CONF_SUCCESS) {
9527 9520 goto fail;
9528 9521 }
9529 9522
9530 9523 /*
9531 9524 * check there are no same named actions in both config file and the
9532 9525 * the kernel that are for a different module. The application
9533 9526 * system can't handle these as we would try to add the new
9534 9527 * action before we deleted the old one and because actions
9535 9528 * in the kernel are indexed solely on their name (their module
9536 9529 * isn't included) the kernel would return an error. We want
9537 9530 * to avoid this error and the resulting rollback.
9538 9531 */
9539 9532 for (act = conf; act != NULL; act = act->next) {
9540 9533 for (oact = oconf; oact != NULL; oact = oact->next) {
9541 9534 /* found action */
9542 9535 if (strcmp(act->name, oact->name) == 0) {
9543 9536 /* different module */
9544 9537 if (strcmp(act->module, oact->module) != 0) {
9545 9538 ipqos_msg(MT_ERROR,
9546 9539 gettext("Action at line %u has "
9547 9540 "same name as currently "
9548 9541 "installed action, but is for a "
9549 9542 "different module.\n"),
9550 9543 act->lineno);
9551 9544 goto fail;
9552 9545 /* same module - stop search */
9553 9546 } else {
9554 9547 break;
9555 9548 }
9556 9549 }
9557 9550 }
9558 9551 }
9559 9552
9560 9553
9561 9554 /* create links between actions for use with deletions etc.. */
9562 9555
9563 9556 res = validconf(oconf, 0);
9564 9557 if (res != IPQOS_CONF_SUCCESS) {
9565 9558 goto fail;
9566 9559 }
9567 9560
9568 9561 /* diff conf file against kernel */
9569 9562
9570 9563 res = diffconf(oconf, conf);
9571 9564 if (res != IPQOS_CONF_SUCCESS) {
9572 9565 goto fail;
9573 9566 }
9574 9567
9575 9568 /* make kernel mods as atomic as possible */
9576 9569
9577 9570 if ((res = block_all_signals()) == -1) {
9578 9571 res = IPQOS_CONF_ERR;
9579 9572 goto fail;
9580 9573 }
9581 9574
9582 9575 /* apply difference to kernel */
9583 9576
9584 9577 res = applydiff(conf, oconf);
9585 9578 #ifdef _IPQOS_CONF_DEBUG
9586 9579 if (force_rback || res != IPQOS_CONF_SUCCESS) {
9587 9580 #else
9588 9581 if (res != IPQOS_CONF_SUCCESS) {
9589 9582 #endif /* _IPQOS_CONF_DEBUG */
9590 9583
9591 9584 res = rollback(conf, oconf);
9592 9585 if (res != IPQOS_CONF_SUCCESS) {
9593 9586 res = rollback_recover(oconf);
9594 9587 if (res != IPQOS_CONF_SUCCESS) {
9595 9588 /* system left flushed */
9596 9589 ipqos_msg(MT_ERROR,
9597 9590 gettext("Failed to rollback from failed "
9598 9591 "configuration, configuration flushed.\n"));
9599 9592 res = IPQOS_CONF_RECOVER_ERR;
9600 9593 } else { /* old config re-applied */
9601 9594 ipqos_msg(MT_ERROR,
9602 9595 gettext("Configuration failed, system "
9603 9596 "state unchanged.\n"));
9604 9597 res = IPQOS_CONF_ERR;
9605 9598 }
9606 9599 } else {
9607 9600 ipqos_msg(MT_ERROR,
9608 9601 gettext("Configuration failed, system "
9609 9602 "state unchanged.\n"));
9610 9603 res = IPQOS_CONF_ERR;
9611 9604 }
9612 9605 goto fail;
9613 9606 }
9614 9607
9615 9608 /* retry any soft name lookup failures */
9616 9609
9617 9610 res = retry_name_lookups(conf);
9618 9611 if (res != IPQOS_CONF_SUCCESS) {
9619 9612 res = rollback(conf, oconf);
9620 9613 if (res != IPQOS_CONF_SUCCESS) {
9621 9614 res = rollback_recover(oconf);
9622 9615 if (res != IPQOS_CONF_SUCCESS) {
9623 9616 /* system left flushed */
9624 9617 ipqos_msg(MT_ERROR,
9625 9618 gettext("Failed to rollback from failed "
9626 9619 "configuration, configuration flushed.\n"));
9627 9620 res = IPQOS_CONF_RECOVER_ERR;
9628 9621 } else { /* old config re-applied */
9629 9622 ipqos_msg(MT_ERROR,
9630 9623 gettext("Configuration failed, system "
9631 9624 "state unchanged.\n"));
9632 9625 res = IPQOS_CONF_ERR;
9633 9626 }
9634 9627 } else {
9635 9628 ipqos_msg(MT_ERROR,
9636 9629 gettext("Configuration failed, system "
9637 9630 "state unchanged.\n"));
9638 9631 res = IPQOS_CONF_ERR;
9639 9632 }
9640 9633 goto fail;
9641 9634
9642 9635 }
9643 9636
9644 9637 ipqos_msg(MT_LOG, gettext("IPQoS configuration applied.\n"));
9645 9638
9646 9639 /* re-enable signals */
9647 9640 (void) restore_all_signals();
9648 9641
9649 9642 (void) fclose(ifp);
9650 9643 free_actions(conf);
9651 9644 free_actions(oconf);
9652 9645 return (IPQOS_CONF_SUCCESS);
9653 9646 fail:
9654 9647 (void) fclose(ifp);
9655 9648 (void) restore_all_signals();
9656 9649 if (conf)
9657 9650 free_actions(conf);
9658 9651 if (oconf)
9659 9652 free_actions(oconf);
9660 9653 if (res == IPQOS_CONF_RECOVER_ERR)
9661 9654 ipqos_msg(MT_LOG, gettext("Configuration flushed.\n"));
9662 9655 return (res);
9663 9656 }
9664 9657
9665 9658 static sigset_t set, oset;
9666 9659
9667 9660 static int
9668 9661 block_all_signals()
9669 9662 {
9670 9663 if (sigfillset(&set) == -1) {
9671 9664 ipqos_msg(MT_ENOSTR, "sigfillset");
9672 9665 return (-1);
9673 9666 }
9674 9667 if (sigprocmask(SIG_SETMASK, &set, &oset) == -1) {
9675 9668 ipqos_msg(MT_ENOSTR, "sigprocmask");
9676 9669 return (-1);
9677 9670 }
9678 9671 return (0);
9679 9672 }
9680 9673
9681 9674 static int
9682 9675 restore_all_signals()
9683 9676 {
9684 9677 if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
9685 9678 ipqos_msg(MT_ENOSTR, "sigprocmask");
9686 9679 return (-1);
9687 9680 }
9688 9681 return (0);
9689 9682 }
9690 9683
9691 9684 static int
9692 9685 unlock(int fd)
9693 9686 {
9694 9687 if (lockf(fd, F_ULOCK, 0) == -1) {
9695 9688 ipqos_msg(MT_ENOSTR, "lockf");
9696 9689 return (-1);
9697 9690 }
9698 9691 return (0);
9699 9692 }
9700 9693
9701 9694 static int
9702 9695 lock()
9703 9696 {
9704 9697 int fd;
9705 9698 struct stat sbuf1;
9706 9699 struct stat sbuf2;
9707 9700
9708 9701 /*
9709 9702 * Open the file with O_CREAT|O_EXCL. If it exists already, it
9710 9703 * will fail. If it already exists, check whether it looks like
9711 9704 * the one we created.
9712 9705 */
9713 9706 (void) umask(0077);
9714 9707 if ((fd = open(IPQOS_CONF_LOCK_FILE, O_EXCL|O_CREAT|O_RDWR,
9715 9708 S_IRUSR|S_IWUSR)) == -1) {
9716 9709 if (errno != EEXIST) {
9717 9710 /* Some other problem. */
9718 9711 ipqos_msg(MT_ENOSTR,
9719 9712 gettext("Cannot open lock file %s"),
9720 9713 IPQOS_CONF_LOCK_FILE);
9721 9714 return (-1);
9722 9715 }
9723 9716
9724 9717 /*
9725 9718 * open() returned an EEXIST error. We don't fail yet
9726 9719 * as it could be a residual from a previous
9727 9720 * execution. However, we need to clear errno here.
9728 9721 * If we don't and print_cmd_buf() is later invoked
9729 9722 * as the result of a parsing error, it
9730 9723 * will assume that the current error is EEXIST and
9731 9724 * that a corresponding error message has already been
9732 9725 * printed, which results in an incomplete error
9733 9726 * message. If errno is zero, print_cmd_buf() will
9734 9727 * assume that it is called as a result of a
9735 9728 * parsing error and will print the appropriate
9736 9729 * error message.
9737 9730 */
9738 9731 errno = 0;
9739 9732
9740 9733 /*
9741 9734 * File exists. make sure it is OK. We need to lstat()
9742 9735 * as fstat() stats the file pointed to by the symbolic
9743 9736 * link.
9744 9737 */
9745 9738 if (lstat(IPQOS_CONF_LOCK_FILE, &sbuf1) == -1) {
9746 9739 ipqos_msg(MT_ENOSTR,
9747 9740 gettext("Cannot lstat lock file %s\n"),
9748 9741 IPQOS_CONF_LOCK_FILE);
9749 9742 return (-1);
9750 9743 }
9751 9744 /*
9752 9745 * Check whether it is a regular file and not a symbolic
9753 9746 * link. Its link count should be 1. The owner should be
9754 9747 * root and the file should be empty.
9755 9748 */
9756 9749 if (!S_ISREG(sbuf1.st_mode) ||
9757 9750 sbuf1.st_nlink != 1 ||
9758 9751 sbuf1.st_uid != 0 ||
9759 9752 sbuf1.st_size != 0) {
9760 9753 ipqos_msg(MT_ERROR, gettext("Bad lock file %s.\n"),
9761 9754 IPQOS_CONF_LOCK_FILE);
9762 9755 return (-1);
9763 9756 }
9764 9757 if ((fd = open(IPQOS_CONF_LOCK_FILE, O_CREAT|O_RDWR,
9765 9758 S_IRUSR|S_IWUSR)) == -1) {
9766 9759 ipqos_msg(MT_ENOSTR,
9767 9760 gettext("Cannot open lock file %s"),
9768 9761 IPQOS_CONF_LOCK_FILE);
9769 9762 return (-1);
9770 9763 }
9771 9764
9772 9765 /* Check whether we opened the file that we lstat()ed. */
9773 9766 if (fstat(fd, &sbuf2) == -1) {
9774 9767 ipqos_msg(MT_ENOSTR,
9775 9768 gettext("Cannot fstat lock file %s\n"),
9776 9769 IPQOS_CONF_LOCK_FILE);
9777 9770 return (-1);
9778 9771 }
9779 9772 if (sbuf1.st_dev != sbuf2.st_dev ||
9780 9773 sbuf1.st_ino != sbuf2.st_ino) {
9781 9774 /* File changed after we did the lstat() above */
9782 9775 ipqos_msg(MT_ERROR, gettext("Bad lock file %s.\n"),
9783 9776 IPQOS_CONF_LOCK_FILE);
9784 9777 return (-1);
9785 9778 }
9786 9779 }
9787 9780 if (lockf(fd, F_LOCK, 0) == -1) {
9788 9781 ipqos_msg(MT_ENOSTR, "lockf");
9789 9782 return (-1);
9790 9783 }
9791 9784 return (fd);
9792 9785 }
9793 9786
9794 9787 /*
9795 9788 * print the current kernel configuration out to stdout. If viewall
9796 9789 * is set this causes more verbose configuration listing including
9797 9790 * showing objects we didn't create, each instance of a mhome filter,
9798 9791 * etc.. see printaction().
9799 9792 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
9800 9793 */
9801 9794
9802 9795 static int
9803 9796 viewconf(int viewall)
9804 9797 {
9805 9798
9806 9799 ipqos_conf_action_t *conf = NULL;
9807 9800 ipqos_conf_action_t *act;
9808 9801 int ret;
9809 9802
9810 9803 IPQOSCDBG0(L0, "In viewconf\n");
9811 9804
9812 9805 /* get kernel configuration */
9813 9806
9814 9807 ret = readkconf(&conf);
9815 9808 if (ret != IPQOS_CONF_SUCCESS) {
9816 9809 return (IPQOS_CONF_ERR);
9817 9810 }
9818 9811
9819 9812 /* write out format version */
9820 9813
9821 9814 if (conf != NULL) {
9822 9815 (void) fprintf(stdout, "%s %d.%d\n\n", IPQOS_FMT_VERSION_STR,
9823 9816 IPQOS_CUR_FMT_MAJOR_VER, IPQOS_CUR_FMT_MINOR_VER);
9824 9817 }
9825 9818
9826 9819 /* print each of the actions in the kernel config to stdout */
9827 9820
9828 9821 for (act = conf; act != NULL; act = act->next) {
9829 9822 ret = printaction(stdout, act, viewall, 0);
9830 9823 if (ret != IPQOS_CONF_SUCCESS) {
9831 9824 free_actions(conf);
9832 9825 return (ret);
9833 9826 }
9834 9827 (void) fprintf(stdout, "\n");
9835 9828 }
9836 9829
9837 9830 free_actions(conf);
9838 9831
9839 9832 return (IPQOS_CONF_SUCCESS);
9840 9833 }
9841 9834
9842 9835
9843 9836 /*
9844 9837 * debug function that reads the config file and prints it out after
9845 9838 * interpreting to stdout.
9846 9839 */
9847 9840 #ifdef _IPQOS_CONF_DEBUG
9848 9841 static int
9849 9842 viewcfile(char *cfile)
9850 9843 {
9851 9844
9852 9845 ipqos_conf_action_t *conf;
9853 9846 ipqos_conf_action_t *act;
9854 9847 int res;
9855 9848 FILE *ifp;
9856 9849 int viewall = 1;
9857 9850
9858 9851 IPQOSCDBG0(L0, "In viewcfile\n");
9859 9852 ifp = fopen(cfile, "r");
9860 9853 if (ifp == NULL) {
9861 9854 ipqos_msg(MT_ERROR, gettext("Opening file %s for read: %s.\n"),
9862 9855 cfile, strerror(errno));
9863 9856 return (IPQOS_CONF_ERR);
9864 9857 }
9865 9858
9866 9859 res = readconf(ifp, &conf);
9867 9860 if (res != IPQOS_CONF_SUCCESS) {
9868 9861 free(ifp);
9869 9862 return (IPQOS_CONF_ERR);
9870 9863 }
9871 9864
9872 9865 /* print each of the actions in the kernel config to stdout */
9873 9866 for (act = conf; act != NULL; act = act->next) {
9874 9867 res = printaction(stdout, act, viewall, 0);
9875 9868 if (res != IPQOS_CONF_SUCCESS) {
9876 9869 free(ifp);
9877 9870 return (res);
9878 9871 }
9879 9872
9880 9873 (void) fprintf(stdout, "\n");
9881 9874 }
9882 9875
9883 9876 (void) fprintf(stdout, "\n");
9884 9877
9885 9878
9886 9879 return (IPQOS_CONF_SUCCESS);
9887 9880 }
9888 9881 #endif /* _IPQOS_CONF_DEBUG */
9889 9882
9890 9883 static void
9891 9884 usage(void)
9892 9885 {
9893 9886 (void) fprintf(stderr, gettext("usage:\n"
9894 9887 "\tipqosconf [-sv] -a file|-\n"
9895 9888 "\tipqosconf -c\n"
9896 9889 "\tipqosconf -l\n"
9897 9890 "\tipqosconf -L\n"
9898 9891 "\tipqosconf -f\n"));
9899 9892 }
9900 9893
9901 9894 int
9902 9895 main(int argc, char *argv[])
9903 9896 {
9904 9897
9905 9898 int c;
9906 9899 char *ifile = NULL;
9907 9900 int args;
9908 9901 int ret;
9909 9902 int cmd;
9910 9903 int viewall = 0;
9911 9904 int lfp;
9912 9905
9913 9906 /* init global flags */
9914 9907 use_syslog = verbose = 0;
9915 9908
9916 9909 /* init current line number */
9917 9910 lineno = 0;
9918 9911
9919 9912 /* setup internationalisation */
9920 9913
9921 9914 (void) setlocale(LC_ALL, "");
9922 9915 #if !defined(TEXT_DOMAIN)
9923 9916 #define TEXT_DOMAIN "SYS_TEST"
9924 9917 #endif
9925 9918 (void) textdomain(TEXT_DOMAIN);
9926 9919
9927 9920 /* setup syslog parameters */
9928 9921 openlog("ipqosconf", 0, LOG_USER);
9929 9922
9930 9923 args = 0;
9931 9924
9932 9925 /* enable debug options */
9933 9926
9934 9927 #ifdef _IPQOS_CONF_DEBUG
9935 9928 #define DBGOPTS "rz:"
9936 9929 #else
9937 9930 #define DBGOPTS
9938 9931 #endif /* _IPQOS_CONF_DEBUG */
9939 9932
9940 9933 while ((c = getopt(argc, argv, "sca:vflL" DBGOPTS)) != EOF) {
9941 9934 switch (c) {
9942 9935 #ifdef _IPQOS_CONF_DEBUG
9943 9936 case 'z':
9944 9937 cmd = -1;
9945 9938 ifile = optarg;
9946 9939 if (*ifile == '\0') {
9947 9940 usage();
9948 9941 exit(1);
9949 9942 }
9950 9943 args++;
9951 9944 break;
9952 9945 case 'r':
9953 9946 force_rback++;
9954 9947 break;
9955 9948 #endif /* _IPQOS_CONF_DEBUG */
9956 9949 case 'c':
9957 9950 cmd = IPQOS_CONF_COMMIT;
9958 9951 args++;
9959 9952 break;
9960 9953 case 'a':
9961 9954 cmd = IPQOS_CONF_APPLY;
9962 9955 ifile = optarg;
9963 9956 if (*ifile == '\0') {
9964 9957 usage();
9965 9958 exit(1);
9966 9959 }
9967 9960 args++;
9968 9961 break;
9969 9962 case 'f':
9970 9963 cmd = IPQOS_CONF_FLUSH;
9971 9964 args++;
9972 9965 break;
9973 9966 case 'l':
9974 9967 cmd = IPQOS_CONF_VIEW;
9975 9968 args++;
9976 9969 break;
9977 9970 case 'L':
9978 9971 cmd = IPQOS_CONF_VIEW;
9979 9972 viewall++;
9980 9973 args++;
9981 9974 break;
9982 9975 case 'v':
9983 9976 verbose++;
9984 9977 break;
9985 9978 case 's':
9986 9979 use_syslog++;
9987 9980 break;
9988 9981 case '?':
9989 9982 usage();
9990 9983 return (1);
9991 9984 }
9992 9985 }
9993 9986
9994 9987 /*
9995 9988 * dissallow non-option args, > 1 cmd args and syslog/verbose flags set
9996 9989 * for anything but apply.
9997 9990 */
9998 9991 if (optind != argc || args > 1 ||
9999 9992 use_syslog && cmd != IPQOS_CONF_APPLY ||
10000 9993 verbose && cmd != IPQOS_CONF_APPLY) {
10001 9994 usage();
10002 9995 exit(1);
10003 9996 }
10004 9997
10005 9998 /* if no cmd option then show config */
10006 9999
10007 10000 if (args == 0) {
10008 10001 cmd = IPQOS_CONF_VIEW;
10009 10002 }
10010 10003
10011 10004 /* stop concurrent ipqosconf invocations */
10012 10005 lfp = lock();
10013 10006 if (lfp == -1) {
10014 10007 exit(1);
10015 10008 }
10016 10009
10017 10010 switch (cmd) {
10018 10011 #ifdef _IPQOS_CONF_DEBUG
10019 10012 case -1:
10020 10013 ret = viewcfile(ifile);
10021 10014 break;
10022 10015 #endif /* _IPQOS_CONF_DEBUG */
10023 10016 case IPQOS_CONF_APPLY:
10024 10017 ret = applyconf(ifile);
10025 10018 break;
10026 10019 case IPQOS_CONF_COMMIT:
10027 10020 ret = commitconf();
10028 10021 break;
10029 10022 case IPQOS_CONF_VIEW:
10030 10023 ret = viewconf(viewall);
10031 10024 break;
10032 10025 case IPQOS_CONF_FLUSH:
10033 10026 ret = flushconf();
10034 10027 break;
10035 10028 }
10036 10029
10037 10030 (void) unlock(lfp);
10038 10031
10039 10032 return (ret);
10040 10033
10041 10034 }
↓ open down ↓ |
3237 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX