4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* enable debug output and some debug asserts */
28 #undef _IPQOS_CONF_DEBUG
35 #include <sys/nvpair.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
40 #include <sys/socket.h>
44 #include <sys/types.h>
48 #include <ipp/ipp_config.h>
49 #include <ipp/ipgpc/ipgpc.h>
51 #ifdef _IPQOS_CONF_DEBUG
54 #include <sys/sockio.h>
60 #include "ipqosconf.h"
62 #if defined(_IPQOS_CONF_DEBUG)
65 static int ipqosconf_dbg_flgs
=
80 #define IPQOSCDBG0(lvl, x)\
81 if (lvl & ipqosconf_dbg_flgs)\
82 (void) fprintf(stderr, x)
84 #define IPQOSCDBG1(lvl, x, y)\
85 if (lvl & ipqosconf_dbg_flgs)\
86 (void) fprintf(stderr, x, y)
88 #define IPQOSCDBG2(lvl, x, y, z)\
89 if (lvl & ipqosconf_dbg_flgs)\
90 (void) fprintf(stderr, x, y, z)
92 #define IPQOSCDBG3(lvl, x, y, z, a)\
93 if (lvl & ipqosconf_dbg_flgs)\
94 (void) fprintf(stderr, x, y, z, a)
96 #define IPQOSCDBG4(lvl, x, y, z, a, b)\
97 if (lvl & ipqosconf_dbg_flgs)\
98 (void) fprintf(stderr, x, y, z, a, b)
100 #define IPQOSCDBG5(lvl, x, y, z, a, b, c)\
101 if (lvl & ipqosconf_dbg_flgs)\
102 (void) fprintf(stderr, x, y, z, a, b, c)
104 #else /* defined(_IPQOS_CONF_DEBUG) && !defined(lint) */
106 #define IPQOSCDBG0(lvl, x)
107 #define IPQOSCDBG1(lvl, x, y)
108 #define IPQOSCDBG2(lvl, x, y, z)
109 #define IPQOSCDBG3(lvl, x, y, z, a)
110 #define IPQOSCDBG4(lvl, x, y, z, a, b)
111 #define IPQOSCDBG5(lvl, x, y, z, a, b, c)
113 #endif /* defined(_IPQOS_CONF_DEBUG) */
117 /* function prototypes */
119 static int modify_params(char *, nvlist_t
**, int, boolean_t
);
120 static int add_class(char *, char *, int, boolean_t
, char *);
121 static int modify_class(char *, char *, int, boolean_t
, char *,
123 static int remove_class(char *, char *, int, enum ipp_flags
);
124 static int add_filter(char *, ipqos_conf_filter_t
*, int);
125 static int modify_filter(char *, ipqos_conf_filter_t
*, int);
126 static int remove_filter(char *, char *, int, int);
127 static boolean_t
arrays_equal(int *, int *, uint32_t);
128 static int diffclass(ipqos_conf_class_t
*, ipqos_conf_class_t
*);
129 static int diffparams(ipqos_conf_params_t
*, ipqos_conf_params_t
*, char *);
130 static int difffilter(ipqos_conf_filter_t
*, ipqos_conf_filter_t
*, char *);
131 static int add_filters(ipqos_conf_filter_t
*, char *, int, boolean_t
);
132 static int add_classes(ipqos_conf_class_t
*, char *, int, boolean_t
);
133 static int modify_items(ipqos_conf_action_t
*);
134 static int add_items(ipqos_conf_action_t
*, boolean_t
);
135 static int add_item(ipqos_conf_action_t
*, boolean_t
);
136 static int remove_items(ipqos_conf_action_t
*, boolean_t
);
137 static int remove_item(ipqos_conf_action_t
*, boolean_t
);
138 static int undo_modifys(ipqos_conf_action_t
*, ipqos_conf_action_t
*);
139 static int applydiff(ipqos_conf_action_t
*, ipqos_conf_action_t
*);
140 static int rollback(ipqos_conf_action_t
*, ipqos_conf_action_t
*);
141 static int rollback_recover(ipqos_conf_action_t
*);
142 static ipqos_conf_class_t
*classexist(char *, ipqos_conf_class_t
*);
143 static ipqos_conf_filter_t
*filterexist(char *, int, ipqos_conf_filter_t
*);
144 static ipqos_conf_action_t
*actionexist(char *, ipqos_conf_action_t
*);
145 static int diffnvlists(nvlist_t
*, nvlist_t
*, char *, int *, place_t
);
146 static int diffaction(ipqos_conf_action_t
*, ipqos_conf_action_t
*);
147 static int diffconf(ipqos_conf_action_t
*, ipqos_conf_action_t
*);
148 static int readllong(char *, long long *, char **);
149 static int readuint8(char *, uint8_t *, char **);
150 static int readuint16(char *, uint16_t *, char **);
151 static int readint16(char *, int16_t *, char **);
152 static int readint32(char *, int *, char **);
153 static int readuint32(char *, uint32_t *, char **);
154 static int readbool(char *, boolean_t
*);
155 static void setmask(int, in6_addr_t
*, int);
156 static int readtoken(FILE *, char **);
157 static nvpair_t
*find_nvpair(nvlist_t
*, char *);
158 static char *prepend_module_name(char *, char *);
159 static int readnvpair(FILE *, FILE *, nvlist_t
**, nvpair_t
**,
160 ipqos_nvtype_t
*, place_t
, char *);
161 static int add_aref(ipqos_conf_act_ref_t
**, char *, char *);
162 static int readparams(FILE *, FILE *, char *, ipqos_conf_params_t
*);
163 static int readclass(FILE *, char *, ipqos_conf_class_t
**, char **, int);
164 static int readfilter(FILE *, FILE *, char *, ipqos_conf_filter_t
**, char **,
166 static FILE *validmod(char *, int *);
167 static int readaction(FILE *, ipqos_conf_action_t
**);
168 static int actions_unique(ipqos_conf_action_t
*, char **);
169 static int validconf(ipqos_conf_action_t
*, int);
170 static int readconf(FILE *, ipqos_conf_action_t
**);
171 static int flush(boolean_t
*);
172 static int atomic_flush(boolean_t
);
173 static int flushconf();
174 static int writeconf(ipqos_conf_action_t
*, char *);
175 static int commitconf();
176 static int applyconf(char *ifile
);
177 static int block_all_signals();
178 static int restore_all_signals();
179 static int unlock(int fd
);
181 static int viewconf(int);
183 static int valid_name(char *);
184 static int in_cycle(ipqos_conf_action_t
*);
185 static int readtype(FILE *, char *, char *, ipqos_nvtype_t
*, str_val_nd_t
**,
186 char *, boolean_t
, place_t
*);
187 static int read_int_array_info(char *, str_val_nd_t
**, uint32_t *, int *,
189 static str_val_nd_t
*read_enum_nvs(char *, char *);
190 static int add_str_val_entry(str_val_nd_t
**, char *, uint32_t);
191 static void free_str_val_entrys(str_val_nd_t
*);
192 static void get_str_val_value_range(str_val_nd_t
*, int *, int *);
193 static int read_enum_value(FILE *, char *, str_val_nd_t
*, uint32_t *);
194 static int read_mapped_values(FILE *, nvlist_t
**, char *, char *,
196 static int read_int_array(FILE *, char *, int **, uint32_t, int, int,
198 static int str_val_list_lookup(str_val_nd_t
*, char *, uint32_t *);
199 static int parse_kparams(char *, ipqos_conf_params_t
*, nvlist_t
*);
200 static int parse_kclass(ipqos_conf_class_t
*, nvlist_t
*);
201 static int parse_kfilter(ipqos_conf_filter_t
*, nvlist_t
*);
202 static int parse_kaction(nvlist_t
*, ipqos_actinfo_prm_t
*);
203 static int readkconf(ipqos_conf_action_t
**);
204 static void print_int_array(FILE *, int *, uint32_t, int, int, str_val_nd_t
*,
206 static void printrange(FILE *fp
, uint32_t, uint32_t);
207 static void printenum(FILE *, uint32_t, str_val_nd_t
*);
208 static void printproto(FILE *, uint8_t);
209 static void printport(FILE *, uint16_t);
210 static int printnvlist(FILE *, char *, nvlist_t
*, int, ipqos_conf_filter_t
*,
212 static int virtual_action(char *);
213 static void free_arefs(ipqos_conf_act_ref_t
*);
214 static void print_action_nm(FILE *, char *);
215 static int add_orig_ipqosconf(nvlist_t
*);
216 static char *get_originator_nm(uint32_t);
217 static void mark_classes_filters_new(ipqos_conf_action_t
*);
218 static void mark_classes_filters_del(ipqos_conf_action_t
*);
219 static void mark_config_new(ipqos_conf_action_t
*);
220 static int printifname(FILE *, int);
221 static int readifindex(char *, int *);
222 static void cleanup_string_table(char **, int);
223 static int domultihome(ipqos_conf_filter_t
*, ipqos_conf_filter_t
**,
225 static int dup_filter(ipqos_conf_filter_t
*, ipqos_conf_filter_t
**, int, int,
226 void *, void *, int);
227 static void free_actions(ipqos_conf_action_t
*);
228 static ipqos_conf_filter_t
*alloc_filter();
229 static void free_filter(ipqos_conf_filter_t
*);
230 static int read_curl_begin(FILE *);
231 static ipqos_conf_class_t
*alloc_class(void);
232 static int diffclasses(ipqos_conf_action_t
*old
, ipqos_conf_action_t
*new);
233 static int difffilters(ipqos_conf_action_t
*old
, ipqos_conf_action_t
*new);
234 static int dup_class(ipqos_conf_class_t
*src
, ipqos_conf_class_t
**dst
);
235 static int add_action(ipqos_conf_action_t
*act
);
236 static int masktocidr(int af
, in6_addr_t
*mask
);
237 static int read_perm_items(int, FILE *, char *, char ***, int *);
238 static int in_string_table(char *stable
[], int size
, char *string
);
239 static void list_end(ipqos_list_el_t
**listp
, ipqos_list_el_t
***lendpp
);
240 static void add_to_list(ipqos_list_el_t
**listp
, ipqos_list_el_t
*el
);
241 static int read_cfile_ver(FILE *, char *);
242 static char *quote_ws_string(const char *);
243 static int read_tfile_ver(FILE *, char *, char *);
244 static int ver_str_to_int(char *);
245 static void printuser(FILE *fp
, uid_t uid
);
246 static int readuser(char *str
, uid_t
*uid
);
249 * macros to call list functions with the more complex list element type
250 * cast to the skeletal type iqpos_list_el_t.
252 #define GET_LIST_END(list, end)\
253 list_end((ipqos_list_el_t **)list, (ipqos_list_el_t ***)end)
254 #define ADD_TO_LIST(list, el)\
255 add_to_list((ipqos_list_el_t **)list, (ipqos_list_el_t *)el)
258 * Macros to produce a quoted string containing the value of a
259 * preprocessor macro. For example, if SIZE is defined to be 256,
260 * VAL2STR(SIZE) is "256". This is used to construct format
261 * strings for scanf-family functions below.
264 #define VAL2STR(x) QUOTE(x)
269 /* table of supported parameter types and enum value */
270 static str_val_t nv_types
[] = {
271 {"uint8", IPQOS_DATA_TYPE_UINT8
},
272 {"int16", IPQOS_DATA_TYPE_INT16
},
273 {"uint16", IPQOS_DATA_TYPE_UINT16
},
274 {"int32", IPQOS_DATA_TYPE_INT32
},
275 {"uint32", IPQOS_DATA_TYPE_UINT32
},
276 {"boolean", IPQOS_DATA_TYPE_BOOLEAN
},
277 {"string", IPQOS_DATA_TYPE_STRING
},
278 {"action", IPQOS_DATA_TYPE_ACTION
},
279 {"address", IPQOS_DATA_TYPE_ADDRESS
},
280 {"port", IPQOS_DATA_TYPE_PORT
},
281 {"protocol", IPQOS_DATA_TYPE_PROTO
},
282 {"enum", IPQOS_DATA_TYPE_ENUM
},
283 {"ifname", IPQOS_DATA_TYPE_IFNAME
},
284 {"mindex", IPQOS_DATA_TYPE_M_INDEX
},
285 {"int_array", IPQOS_DATA_TYPE_INT_ARRAY
},
286 {"user", IPQOS_DATA_TYPE_USER
},
290 /* table of name to id mappings for originator field */
292 static str_val_t originators
[] = {
293 {IPP_CONFIG_NAME_PERMANENT
, IPP_CONFIG_PERMANENT
},
294 {IPP_CONFIG_NAME_IPQOSCONF
, IPP_CONFIG_IPQOSCONF
},
295 {IPP_CONFIG_NAME_FTPCL
, IPP_CONFIG_FTPCL
},
299 /* current parse line */
302 /* verbose output flag */
305 /* use syslog for msg reporting flag */
306 static int use_syslog
;
308 #ifdef _IPQOS_CONF_DEBUG
310 * flag used to indicate that a rollback should be carried out regardless.
311 * Only settable during debug.
313 static int force_rback
= 0;
314 #endif /* _IPQOS_CONF_DEBUG */
317 * delivers messages to either syslog or stderr, dependant upon the
318 * the state of the flags use_syslog and verbose. The type
319 * of the msg as given in msg_type is indicated in the output msg.
321 * valid message types are:
322 * o MT_ERROR (standard error message)
323 * o MT_ENOSTR (error message with system error string appended)
324 * o MT_WARNING (warning message)
325 * o MT_LOG (logging message)
327 * Log messages only go to syslog. Warning messages only go to stderr
328 * and only when the verbose flag is set. All other messages go by default
329 * to the console; to syslog if syslog flag set, and to both if both
330 * syslog and verbose are set.
335 ipqos_msg(enum msg_type msgt
, char *format
, ...)
338 char str_buf
[IPQOS_MSG_BUF_SZ
];
339 char fmt_buf
[IPQOS_MSG_BUF_SZ
];
342 IPQOSCDBG0(L1
, "In ipqos_msg:\n");
344 va_start(ap
, format
);
347 * send msgs to syslog if use_syslog set (except warning msgs),
350 if ((use_syslog
&& (msgt
!= MT_WARNING
)) || msgt
== MT_LOG
) {
352 /* fill in format string */
353 (void) vsnprintf(str_buf
, IPQOS_MSG_BUF_SZ
, format
, ap
);
356 * print message to syslog with appropriate severity
358 if (msgt
== MT_ERROR
) {
359 syslog(LOG_ERR
, str_buf
);
360 } else if (msgt
== MT_LOG
) {
361 syslog(LOG_INFO
, str_buf
);
363 * for errno message type suffix with %m for syslog to
366 } else if (msgt
== MT_ENOSTR
) {
368 * remove any newline in message parameter.
369 * syslog will reapply a newline for us later.
371 if ((cp
= strchr(str_buf
, '\n')) != NULL
)
373 (void) strlcat(str_buf
, ": %m", IPQOS_MSG_BUF_SZ
);
374 syslog(LOG_ERR
, str_buf
);
379 * send msgs to stderr if use_syslog not set (except log msgs), or
382 if ((!use_syslog
&& (msgt
!= MT_LOG
)) || (verbose
)) {
385 * prefix message with appropriate severity string
387 if (msgt
== MT_ERROR
) {
388 (void) strlcpy(fmt_buf
, gettext("Error: "),
390 } else if (msgt
== MT_WARNING
) {
391 if (!verbose
) { /* don't show warn msg if !verbose */
395 (void) strlcpy(fmt_buf
, gettext("Warning: "),
397 } else if (msgt
== MT_ENOSTR
) {
398 (void) strlcpy(fmt_buf
, gettext("Error: "),
400 } else if (msgt
== MT_LOG
) {
401 (void) strlcpy(fmt_buf
, gettext("Notice: "),
404 (void) strlcat(fmt_buf
, format
, IPQOS_MSG_BUF_SZ
);
407 * for errno message type suffix message with errno string
409 if (msgt
== MT_ENOSTR
) {
411 * get rid of any newline in passed message.
412 * we'll apply another later.
414 if ((cp
= strchr(fmt_buf
, '\n')) != NULL
)
416 (void) strlcat(fmt_buf
, ": ", IPQOS_MSG_BUF_SZ
);
417 (void) strlcat(fmt_buf
, strerror(errno
),
422 * append a newline to message if not one already.
424 if ((cp
= strchr(fmt_buf
, '\n')) == NULL
)
425 (void) strlcat(fmt_buf
, "\n", IPQOS_MSG_BUF_SZ
);
427 (void) vfprintf(stderr
, fmt_buf
, ap
);
433 /* **************** kernel filter/class/params manipulation fns *********** */
437 * modify the kernel parameters of the action action_nm using the nvlist
438 * parameter nvl and setting the stats according to stats_enable.
439 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
447 boolean_t stats_enable
)
453 IPQOSCDBG1(APPLY
, "In modify_params: action: %s\n", action_name
);
455 /* create nvlist if NULL */
458 res
= nvlist_alloc(nvl
, NV_UNIQUE_NAME
, 0);
460 ipqos_msg(MT_ENOSTR
, "nvlist_alloc");
461 return (IPQOS_CONF_ERR
);
465 /* add params modify config type */
466 res
= nvlist_add_byte(*nvl
, IPP_CONFIG_TYPE
, IPP_SET
);
468 ipqos_msg(MT_ENOSTR
, "nvlist_add_byte");
475 if (nvlist_add_uint32(*nvl
, IPP_MODULE_VERSION
,
476 (uint32_t)module_version
) != 0) {
477 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
481 /* add stats_enable */
482 res
= nvlist_add_uint32(*nvl
, IPP_ACTION_STATS_ENABLE
,
483 (uint32_t)stats_enable
);
485 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
489 /* add ipqosconf as originator */
490 res
= add_orig_ipqosconf(*nvl
);
491 if (res
!= IPQOS_CONF_SUCCESS
) {
495 /* call lib to do modify */
496 res
= ipp_action_modify(action_name
, nvl
, 0);
499 /* invalid parameters */
501 if (errno
== EINVAL
) {
503 gettext("Invalid parameters for action %s.\n"),
507 } else if (errno
== ENOENT
) {
509 gettext("Mandatory parameter missing for "
510 "action %s.\n"), action_name
);
513 } else { /* unexpected error */
514 ipqos_msg(MT_ERROR
, gettext("Failed to modify action "
515 "%s parameters: %s.\n"), action_name
,
522 return (IPQOS_CONF_SUCCESS
);
524 if (created
&& *nvl
!= NULL
) {
528 return (IPQOS_CONF_ERR
);
532 * add a class to the kernel action action_name called class_name with
533 * stats set according to stats_enable and the first action set to
535 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
542 boolean_t stats_enable
,
548 IPQOSCDBG4(APPLY
, "add_class: action: %s, class: %s, "
549 "first_action: %s, stats: %s\n", action_name
, class_name
,
550 first_action
, (stats_enable
== B_TRUE
? "true" : "false"));
554 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
555 ipqos_msg(MT_ENOSTR
, "nvlist_alloc");
556 return (IPQOS_CONF_ERR
);
559 /* add 'add class' config type */
560 if (nvlist_add_byte(nvl
, IPP_CONFIG_TYPE
, CLASSIFIER_ADD_CLASS
) != 0) {
561 ipqos_msg(MT_ENOSTR
, "nvlist_add_byte");
568 if (nvlist_add_uint32(nvl
, IPP_MODULE_VERSION
,
569 (uint32_t)module_version
) != 0) {
570 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
575 if (nvlist_add_string(nvl
, CLASSIFIER_CLASS_NAME
, class_name
) != 0) {
576 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
580 /* add next action */
581 if (nvlist_add_string(nvl
, CLASSIFIER_NEXT_ACTION
, first_action
) != 0) {
582 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
586 /* add stats_enable */
587 if (nvlist_add_uint32(nvl
, CLASSIFIER_CLASS_STATS_ENABLE
,
588 (uint32_t)stats_enable
) != 0) {
589 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
593 /* add ipqosconf as originator */
594 if (add_orig_ipqosconf(nvl
) != IPQOS_CONF_SUCCESS
) {
598 /* call lib to do modify */
599 if (ipp_action_modify(action_name
, &nvl
, 0) != 0) {
601 /* ipgpc max classes */
603 if (errno
== ENOSPC
&&
604 strcmp(action_name
, IPGPC_CLASSIFY
) == 0) {
606 gettext("Max number of classes reached in %s.\n"),
613 gettext("Failed to create class %s in action "
614 "%s: %s.\n"), class_name
, action_name
,
621 return (IPQOS_CONF_SUCCESS
);
624 return (IPQOS_CONF_ERR
);
629 * modify the class in the kernel action action_name called class_name with
630 * stats set according to stats_enable and the first action set to
632 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
639 boolean_t stats_enable
,
641 enum ipp_flags flags
)
646 IPQOSCDBG5(APPLY
, "modify_class: action: %s, class: %s, first: %s, "
647 "stats: %s, flags: %x\n", action_name
, class_name
, first_action
,
648 stats_enable
== B_TRUE
? "true" : "false", flags
);
652 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
653 ipqos_msg(MT_ENOSTR
, "nvlist_alloc");
654 return (IPQOS_CONF_ERR
);
657 /* add 'modify class' config type */
658 if (nvlist_add_byte(nvl
, IPP_CONFIG_TYPE
, CLASSIFIER_MODIFY_CLASS
) !=
660 ipqos_msg(MT_ENOSTR
, "nvlist_add_byte");
667 if (nvlist_add_uint32(nvl
, IPP_MODULE_VERSION
,
668 (uint32_t)module_version
) != 0) {
669 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
674 if (nvlist_add_string(nvl
, CLASSIFIER_CLASS_NAME
, class_name
) != 0) {
675 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
679 /* add next action */
680 if (nvlist_add_string(nvl
, CLASSIFIER_NEXT_ACTION
, first_action
) != 0) {
681 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
685 /* add stats enable */
686 if (nvlist_add_uint32(nvl
, CLASSIFIER_CLASS_STATS_ENABLE
,
687 (uint32_t)stats_enable
) != 0) {
688 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
692 /* add originator ipqosconf */
693 if (add_orig_ipqosconf(nvl
) != IPQOS_CONF_SUCCESS
) {
697 /* call lib to do modify */
698 if (ipp_action_modify(action_name
, &nvl
, flags
) != 0) {
700 /* generic error message */
703 gettext("Modifying class %s in action %s failed: %s.\n"),
704 class_name
, action_name
, strerror(errno
));
709 return (IPQOS_CONF_SUCCESS
);
712 return (IPQOS_CONF_ERR
);
716 * removes the class class_name from the kernel action action_name. The
717 * flags argument can currently be set to IPP_ACTION_DESTROY which will
718 * result in the action this class references being destroyed.
719 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
726 enum ipp_flags flags
)
731 IPQOSCDBG3(APPLY
, "remove_class: action: %s, class: %s, "
732 "flags: %x\n", action_name
, class_name
, flags
);
734 /* allocate nvlist */
735 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
736 ipqos_msg(MT_ENOSTR
, "nvlist_alloc");
737 return (IPQOS_CONF_ERR
);
740 /* add 'remove class' config type */
741 if (nvlist_add_byte(nvl
, IPP_CONFIG_TYPE
, CLASSIFIER_REMOVE_CLASS
) !=
743 ipqos_msg(MT_ENOSTR
, "nvlist_add_byte");
750 if (nvlist_add_uint32(nvl
, IPP_MODULE_VERSION
,
751 (uint32_t)module_version
) != 0) {
752 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
757 if (nvlist_add_string(nvl
, CLASSIFIER_CLASS_NAME
, class_name
) != 0) {
758 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
762 if (ipp_action_modify(action_name
, &nvl
, flags
) != 0) {
764 /* generic error message */
767 gettext("Removing class %s in action %s failed: %s.\n"),
768 class_name
, action_name
, strerror(errno
));
773 return (IPQOS_CONF_SUCCESS
);
776 return (IPQOS_CONF_ERR
);
780 * add the filter flt to the kernel action named action_name.
781 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
786 ipqos_conf_filter_t
*flt
,
790 nvlist_t
*nvl
= flt
->nvlist
;
791 char ipvsbuf
[IPQOS_INT_STR_LEN
];
793 IPQOSCDBG4(APPLY
, "add_filter: action: %s, filter: %s, "
794 "instance: %d, class: %s\n", action_name
, flt
->name
,
795 flt
->instance
, flt
->class_name
);
798 /* add 'add filter' config type to filter nvlist */
799 if (nvlist_add_byte(nvl
, IPP_CONFIG_TYPE
, CLASSIFIER_ADD_FILTER
) != 0) {
800 ipqos_msg(MT_ENOSTR
, "nvlist_add_byte");
801 return (IPQOS_CONF_ERR
);
807 if (nvlist_add_uint32(nvl
, IPP_MODULE_VERSION
,
808 (uint32_t)module_version
) != 0) {
809 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
810 return (IPQOS_CONF_ERR
);
813 /* add filter name to nvlist */
814 if (nvlist_add_string(nvl
, CLASSIFIER_FILTER_NAME
, flt
->name
) != 0) {
815 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
816 return (IPQOS_CONF_ERR
);
819 /* add class name to nvlist */
820 if (nvlist_add_string(nvl
, CLASSIFIER_CLASS_NAME
, flt
->class_name
) !=
822 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
823 return (IPQOS_CONF_ERR
);
826 /* add ipqosconf as originator to nvlist */
827 if (add_orig_ipqosconf(nvl
) != IPQOS_CONF_SUCCESS
) {
828 return (IPQOS_CONF_ERR
);
831 /* add ipgpc specific nv entrys */
832 if (strcmp(action_name
, IPGPC_CLASSIFY
) == 0) {
834 /* add src and dst nodes to nvlist if present */
836 if (flt
->src_nd_name
!= NULL
&&
837 nvlist_add_string(nvl
, IPGPC_SADDR_HOSTNAME
,
838 flt
->src_nd_name
) != 0) {
839 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
840 return (IPQOS_CONF_ERR
);
842 if (flt
->dst_nd_name
!= NULL
&&
843 nvlist_add_string(nvl
, IPGPC_DADDR_HOSTNAME
,
844 flt
->dst_nd_name
) != 0) {
845 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
846 return (IPQOS_CONF_ERR
);
850 * add ip_version to private list element if present.
851 * NOTE: this value is of only real use to ipqosconf so
852 * it is placed in this opaque private field.
854 if (flt
->ip_versions
!= 0) {
855 (void) sprintf(ipvsbuf
, "%d", flt
->ip_versions
);
856 if (nvlist_add_string(nvl
, IPGPC_FILTER_PRIVATE
,
858 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
859 return (IPQOS_CONF_ERR
);
863 /* add filter instance if present */
865 if (nvlist_add_int32(nvl
, IPGPC_FILTER_INSTANCE
,
866 flt
->instance
) != 0) {
867 ipqos_msg(MT_ENOSTR
, "nvlist_add_int32");
868 return (IPQOS_CONF_ERR
);
872 if (ipp_action_modify(action_name
, &flt
->nvlist
, 0) != 0) {
874 /* invalid parameters */
876 if (errno
== EINVAL
) {
878 gettext("Invalid/missing parameters for filter "
879 "%s in action %s.\n"), flt
->name
, action_name
);
881 /* max ipgpc filters/classes */
883 } else if (errno
== ENOSPC
&&
884 strcmp(action_name
, IPGPC_CLASSIFY
) == 0) {
885 ipqos_msg(MT_ERROR
, gettext("Max number of filters "
886 "reached in action %s.\n"), IPGPC_NAME
);
888 /* anything other errnos */
891 gettext("Failed to create filter %s in action "
892 "%s: %s.\n"), flt
->name
, action_name
,
896 return (IPQOS_CONF_ERR
);
899 return (IPQOS_CONF_SUCCESS
);
904 * modify the filter flt in the kernel action named action_name.
905 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
910 ipqos_conf_filter_t
*flt
,
914 nvlist_t
*nvl
= flt
->nvlist
;
915 char ipvsbuf
[IPQOS_INT_STR_LEN
];
917 IPQOSCDBG4(APPLY
, "modify_filter: action: %s, filter: %s, "
918 "instance: %d, class: %s\n", action_name
, flt
->name
,
919 flt
->instance
, flt
->class_name
);
921 /* show src address and dst address if present */
922 #ifdef _IPQOS_CONF_DEBUG
923 if (ipqosconf_dbg_flgs
& APPLY
) {
928 if (nvlist_lookup_uint32_array(nvl
, IPGPC_SADDR
,
929 (uint32_t **)&add
, &tmp
) == 0) {
930 (void) fprintf(stderr
, "saddr: %s\n",
931 inet_ntop(AF_INET6
, add
, st
, 100));
934 if (nvlist_lookup_uint32_array(nvl
, IPGPC_DADDR
,
935 (uint32_t **)&add
, &tmp
) == 0) {
936 (void) fprintf(stderr
, "daddr: %s\n",
937 inet_ntop(AF_INET6
, add
, st
, 100));
940 #endif /* _IPQOS_CONF_DEBUG */
942 /* add 'modify filter' config type to filters nvlist */
943 if (nvlist_add_byte(nvl
, IPP_CONFIG_TYPE
,
944 CLASSIFIER_MODIFY_FILTER
) != 0) {
945 ipqos_msg(MT_ENOSTR
, "nvlist_add_byte");
946 return (IPQOS_CONF_ERR
);
952 if (nvlist_add_uint32(nvl
, IPP_MODULE_VERSION
,
953 (uint32_t)module_version
) != 0) {
954 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
955 return (IPQOS_CONF_ERR
);
958 /* add filter name to nvlist */
959 if (nvlist_add_string(nvl
, CLASSIFIER_FILTER_NAME
, flt
->name
) != 0) {
960 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
961 return (IPQOS_CONF_ERR
);
964 /* add class name to nvlist */
965 if (nvlist_add_string(nvl
, CLASSIFIER_CLASS_NAME
, flt
->class_name
) !=
967 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
968 return (IPQOS_CONF_ERR
);
971 /* add originator ipqosconf to nvlist */
972 if (add_orig_ipqosconf(nvl
) != IPQOS_CONF_SUCCESS
) {
973 return (IPQOS_CONF_ERR
);
976 /* add ipgpc specific nvpairs */
977 if (strcmp(action_name
, IPGPC_CLASSIFY
) == 0) {
979 /* add src and dst nodes to nvlist if present */
981 if (flt
->src_nd_name
&&
982 nvlist_add_string(nvl
, IPGPC_SADDR_HOSTNAME
,
983 flt
->src_nd_name
) != 0) {
984 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
985 return (IPQOS_CONF_ERR
);
987 if (flt
->dst_nd_name
&&
988 nvlist_add_string(nvl
, IPGPC_DADDR_HOSTNAME
,
989 flt
->dst_nd_name
) != 0) {
990 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
991 return (IPQOS_CONF_ERR
);
995 * add ip_version to private list element if present.
996 * NOTE: this value is of only real use to ipqosconf so
997 * it is placed in this opaque private field.
999 if (flt
->ip_versions
!= 0) {
1000 (void) sprintf(ipvsbuf
, "%d", flt
->ip_versions
);
1001 if (nvlist_add_string(nvl
, IPGPC_FILTER_PRIVATE
,
1003 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
1004 return (IPQOS_CONF_ERR
);
1008 /* add filter instance if present */
1010 if (nvlist_add_int32(nvl
, IPGPC_FILTER_INSTANCE
,
1011 flt
->instance
) != 0) {
1012 ipqos_msg(MT_ENOSTR
, "nvlist_add_int32");
1013 return (IPQOS_CONF_ERR
);
1017 if (ipp_action_modify(action_name
, &flt
->nvlist
, 0) != 0) {
1019 /* invalid parameters */
1021 if (errno
== EINVAL
) {
1022 ipqos_msg(MT_ERROR
, gettext("Missing/Invalid "
1023 "parameter for filter %s in action %s.\n"),
1024 flt
->name
, action_name
);
1026 /* any other errnos */
1030 gettext("Failed to modify filter %s in action %s: "
1031 "%s.\n"), flt
->name
, action_name
, strerror(errno
));
1034 return (IPQOS_CONF_ERR
);
1037 return (IPQOS_CONF_SUCCESS
);
1041 * remove the filter named filter_name instance number instance from the
1042 * kernel action action_name.
1043 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
1055 IPQOSCDBG2(APPLY
, "remove_filter: action: %s, filter: %s\n",
1056 action_name
, filter_name
);
1059 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
1060 ipqos_msg(MT_ENOSTR
, "nvlist_alloc");
1061 return (IPQOS_CONF_ERR
);
1064 /* add 'remove filter' config type to list */
1065 if (nvlist_add_byte(nvl
, IPP_CONFIG_TYPE
, CLASSIFIER_REMOVE_FILTER
)
1067 ipqos_msg(MT_ENOSTR
, "nvlist_add_byte");
1068 return (IPQOS_CONF_ERR
);
1072 * add module version
1074 if (nvlist_add_uint32(nvl
, IPP_MODULE_VERSION
,
1075 (uint32_t)module_version
) != 0) {
1076 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
1077 return (IPQOS_CONF_ERR
);
1080 /* add filter name to list */
1081 if (nvlist_add_string(nvl
, CLASSIFIER_FILTER_NAME
, filter_name
) != 0) {
1082 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
1083 return (IPQOS_CONF_ERR
);
1086 /* add instance number if part of multi-instance filter */
1087 if (instance
!= -1 && nvlist_add_int32(nvl
, IPGPC_FILTER_INSTANCE
,
1089 ipqos_msg(MT_ENOSTR
, "nvlist_add_int32");
1090 return (IPQOS_CONF_ERR
);
1093 /* call into lib to remove */
1094 if (ipp_action_modify(action_name
, &nvl
, 0) != 0) {
1096 /* generic error message */
1099 gettext("Removing filter %s in action %s failed: %s.\n"),
1100 filter_name
, action_name
, strerror(errno
));
1102 return (IPQOS_CONF_ERR
);
1105 return (IPQOS_CONF_SUCCESS
);
1108 /* ******************************************************************* */
1112 * add originator nvpair set to ipqosconf to nvl.
1113 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
1116 add_orig_ipqosconf(nvlist_t
*nvl
)
1119 if (nvlist_add_uint32(nvl
, IPP_CONFIG_ORIGINATOR
,
1120 IPP_CONFIG_IPQOSCONF
) != 0) {
1121 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32: originator:");
1122 return (IPQOS_CONF_ERR
);
1125 return (IPQOS_CONF_SUCCESS
);
1128 /* ************************* differencing functions ************************ */
1132 * compares the contents of arrays array1 and array2, both of size size, and
1133 * returns B_TRUE or B_FALSE if they're equal or not respectively.
1134 * RETURNS: B_TRUE if equal, else B_FALSE.
1144 for (x
= 0; x
< size
; x
++) {
1145 if (array1
[x
] != array2
[x
])
1152 * difference class old against class new. It marks the new class as
1153 * modified if it is different.
1154 * RETURNS: IPQOS_CONF_SUCCESS.
1158 ipqos_conf_class_t
*old
,
1159 ipqos_conf_class_t
*new)
1162 IPQOSCDBG0(L0
, "In diffclass:\n");
1164 /* two different spec'd actions */
1165 if (strcmp(old
->alist
->name
, new->alist
->name
) != 0) {
1166 IPQOSCDBG1(DIFF
, "marking class %s as modified\n", new->name
);
1168 new->modified
= B_TRUE
;
1169 return (IPQOS_CONF_SUCCESS
);
1172 /* different stats values */
1173 if (old
->stats_enable
!= new->stats_enable
) {
1174 IPQOSCDBG1(DIFF
, "marking class %s as modified\n", new->name
);
1176 new->modified
= B_TRUE
;
1177 return (IPQOS_CONF_SUCCESS
);
1180 return (IPQOS_CONF_SUCCESS
);
1184 * difference params set old against params set new of module module_name. It
1185 * marks the new params as modified if different.
1186 * RETURNS: if error IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
1190 ipqos_conf_params_t
*old
,
1191 ipqos_conf_params_t
*new,
1198 IPQOSCDBG0(L0
, "In diffparams\n");
1201 if (old
->stats_enable
!= new->stats_enable
) {
1203 new->modified
= B_TRUE
;
1204 return (IPQOS_CONF_SUCCESS
);
1207 /* diff module specific params */
1208 res
= diffnvlists(old
->nvlist
, new->nvlist
, module_name
, &diff
,
1210 if (res
!= IPQOS_CONF_SUCCESS
) {
1215 new->modified
= B_TRUE
;
1218 return (IPQOS_CONF_SUCCESS
);
1222 * differences filter old against filter new of module module_name. It marks
1223 * filter new as different if so.
1224 * RETURNS: if error IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
1228 ipqos_conf_filter_t
*old
,
1229 ipqos_conf_filter_t
*new,
1236 IPQOSCDBG0(L0
, "In difffilter\n");
1238 /* compare class name */
1240 if (strcmp(old
->class_name
, new->class_name
) != 0) {
1241 IPQOSCDBG1(DIFF
, "Marking filter %s as modified\n", new->name
);
1243 new->modified
= B_TRUE
;
1244 return (IPQOS_CONF_SUCCESS
);
1247 /* compare module specific params */
1249 res
= diffnvlists(old
->nvlist
, new->nvlist
, module_name
, &diff
,
1251 if (res
!= IPQOS_CONF_SUCCESS
) {
1256 IPQOSCDBG1(DIFF
, "Marking filter %s as modified\n", new->name
);
1257 new->modified
= B_TRUE
;
1260 return (IPQOS_CONF_SUCCESS
);
1265 * mark all the filters and classes in parameter action either
1266 * for deletion (if they are ipqosconf originated) or for modification.
1269 mark_classes_filters_del(ipqos_conf_action_t
*action
)
1272 ipqos_conf_filter_t
*flt
;
1273 ipqos_conf_class_t
*cls
;
1275 IPQOSCDBG1(L1
, "In mark_classes_filters_del: action: %s\n",
1278 /* mark all non-permanent filters for del and permanent to modify */
1279 for (flt
= action
->filters
; flt
; flt
= flt
->next
) {
1280 if (flt
->originator
== IPP_CONFIG_PERMANENT
) {
1281 IPQOSCDBG1(DIFF
, "Marking prm filter %s as modified.\n",
1284 flt
->modified
= B_TRUE
;
1286 IPQOSCDBG1(DIFF
, "Marking filter %s as del.\n",
1289 flt
->todel
= B_TRUE
;
1293 /* mark all non-permanent classes for del and permanent to modify */
1294 for (cls
= action
->classes
; cls
; cls
= cls
->next
) {
1295 if (cls
->originator
== IPP_CONFIG_PERMANENT
) {
1296 IPQOSCDBG1(DIFF
, "Marking prm class %s as modified.\n",
1299 cls
->modified
= B_TRUE
;
1301 IPQOSCDBG1(DIFF
, "Marking class %s as del.\n",
1304 cls
->todel
= B_TRUE
;
1310 * mark all classes and filters either new (non-permanent) or modified.
1313 mark_classes_filters_new(ipqos_conf_action_t
*action
)
1316 ipqos_conf_filter_t
*flt
;
1317 ipqos_conf_class_t
*cls
;
1319 IPQOSCDBG1(L1
, "In mark_classes_filters_new: action: %s\n",
1322 /* mark all permanent filters as modified and all others new */
1324 for (flt
= action
->filters
; flt
; flt
= flt
->next
) {
1325 if (flt
->originator
== IPP_CONFIG_PERMANENT
) {
1326 IPQOSCDBG1(DIFF
, "Marking prm filter %s as modified.\n",
1329 flt
->modified
= B_TRUE
;
1330 action
->modified
= B_TRUE
;
1332 IPQOSCDBG1(DIFF
, "Marking filter %s as new.\n",
1339 /* mark all permanent classes as modified and all others new */
1340 for (cls
= action
->classes
; cls
; cls
= cls
->next
) {
1341 if (cls
->originator
== IPP_CONFIG_PERMANENT
) {
1342 IPQOSCDBG1(DIFF
, "Marking prm class %s as modified.\n",
1345 cls
->modified
= B_TRUE
;
1346 action
->modified
= B_TRUE
;
1348 IPQOSCDBG1(DIFF
, "Marking class %s as new.\n",
1357 * Marks all the actions and their constituent elements in conf
1362 ipqos_conf_action_t
*conf
)
1364 while (conf
!= NULL
) {
1365 IPQOSCDBG1(DIFF
, "Marking action %s as new\n", conf
->name
);
1366 mark_classes_filters_new(conf
);
1374 * differences the configuration in new against old marking the actions
1375 * and their contents appropriately.
1376 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
1380 ipqos_conf_action_t
*old
,
1381 ipqos_conf_action_t
*new)
1385 ipqos_conf_action_t
*act
;
1386 ipqos_conf_action_t
*tmp
;
1388 IPQOSCDBG0((L0
| DIFF
), "In diffconf\n");
1390 /* check the new actions against the old */
1392 for (act
= new; act
; act
= act
->next
) {
1394 /* if action not in old mark it and it's contents as new */
1396 if ((tmp
= actionexist(act
->name
, old
)) == NULL
) {
1397 IPQOSCDBG1(DIFF
, "marking act %s as new\n", act
->name
);
1400 mark_classes_filters_new(act
);
1404 /* if action in old diff old against new */
1406 res
= diffaction(tmp
, act
);
1407 if (res
!= IPQOS_CONF_SUCCESS
) {
1413 * mark actions, and their contents, in old but not new that were
1414 * created by us for del.
1417 for (act
= old
; act
; act
= act
->next
) {
1418 if (act
->params
->originator
== IPP_CONFIG_IPQOSCONF
&&
1419 actionexist(act
->name
, new) == NULL
) {
1420 IPQOSCDBG1(DIFF
, "marking act %s for del\n", act
->name
);
1422 act
->todel
= B_TRUE
;
1423 mark_classes_filters_del(act
);
1427 return (IPQOS_CONF_SUCCESS
);
1431 * differences action old against action new, comparing its classes, filters
1432 * and parameters. If it is different the new action is marked as modified
1433 * and it's different sub-objects are also marked approriately.
1434 * RETURNS: IPQOS_CONF_ERR if error, else IPQOS_CONF_SUCCESS.
1438 ipqos_conf_action_t
*old
,
1439 ipqos_conf_action_t
*new)
1444 IPQOSCDBG0(L0
, "In diffaction\n");
1446 /* compare and mark classes */
1447 res
= diffclasses(old
, new);
1448 if (res
!= IPQOS_CONF_SUCCESS
) {
1452 /* compare and mark filters */
1453 res
= difffilters(old
, new);
1454 if (res
!= IPQOS_CONF_SUCCESS
) {
1458 /* compare and mark parameters */
1459 res
= diffparams(old
->params
, new->params
, old
->module
);
1460 if (res
!= IPQOS_CONF_SUCCESS
) {
1464 /* mark action as modified if params are */
1465 if (new->params
->modified
== B_TRUE
) {
1466 IPQOSCDBG1(DIFF
, "Marking params for action %s modified\n",
1469 new->modified
= B_TRUE
;
1472 return (IPQOS_CONF_SUCCESS
);
1476 * differences the set of classes in new against those in old, marking any
1477 * that are new/modified, approriately in the new class, and any removed
1478 * in the old class appropriately. Also marks the action which has had an
1479 * object within marked, as modified.
1480 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
1485 ipqos_conf_action_t
*old
,
1486 ipqos_conf_action_t
*new)
1490 ipqos_conf_class_t
*cls
;
1491 ipqos_conf_class_t
*tmpc
;
1492 ipqos_conf_class_t
*ncls
;
1496 /* loop through old classes checking for classes not present in new */
1498 for (cls
= old
->classes
; cls
; cls
= cls
->next
) {
1500 if (classexist(cls
->name
, new->classes
) == NULL
) {
1502 /* if we created original class mark for deletion */
1504 if (cls
->originator
== IPP_CONFIG_IPQOSCONF
) {
1505 IPQOSCDBG1(DIFF
, "marking class %s for del\n",
1508 cls
->todel
= B_TRUE
;
1510 /* mark old action */
1511 old
->modified
= B_TRUE
;
1514 * if permanent class and next action created by us
1515 * copy it, set it's next action to continue and
1516 * add it to new action. This will cause the class
1517 * to be marked as and modified. This returns the class
1518 * to an assumed default state and prevents the
1519 * case where the class is pointing at an action
1520 * we want to remove and therefore couldn't without
1521 * this forced modify.
1523 } else if (cls
->originator
== IPP_CONFIG_PERMANENT
&&
1524 cls
->alist
->action
&& /* not virtual action */
1525 cls
->alist
->action
->params
->originator
==
1526 IPP_CONFIG_IPQOSCONF
) {
1530 res
= dup_class(cls
, &ncls
);
1531 if (res
!= IPQOS_CONF_SUCCESS
) {
1532 return (IPQOS_CONF_ERR
);
1535 /* set next action to continue */
1537 (void) strcpy(ncls
->alist
->name
,
1540 /* add to news classes to be diffed below */
1541 ADD_TO_LIST(&new->classes
, ncls
);
1546 /* loop through new classes checking for new / modified classes */
1548 for (cls
= new->classes
; cls
; cls
= cls
->next
) {
1550 /* new ipqosconf class */
1552 if ((tmpc
= classexist(cls
->name
, old
->classes
)) == NULL
||
1553 (tmpc
->originator
!= IPP_CONFIG_IPQOSCONF
&&
1554 tmpc
->originator
!= IPP_CONFIG_PERMANENT
)) {
1555 IPQOSCDBG1(DIFF
, "marking class %s new\n",
1560 new->modified
= B_TRUE
; /* mark new action */
1563 /* existing ipqosconf/perm class */
1565 res
= diffclass(tmpc
, cls
);
1566 if (res
!= IPQOS_CONF_SUCCESS
) {
1570 if (cls
->modified
== B_TRUE
) {
1571 new->modified
= B_TRUE
;
1576 return (IPQOS_CONF_SUCCESS
);
1580 * differences the set of filters in new against those in old, marking any
1581 * that are new/modified, approriately in the new filter/s, and any removed
1582 * in the old filter appropriately. Also marks the action which has had an
1583 * object within marked, as modified.
1584 * RETURNS: IPQOS_CONF_SUCCESS (we return an int for symmetry with diffclasses
1589 ipqos_conf_action_t
*old
,
1590 ipqos_conf_action_t
*new)
1593 ipqos_conf_filter_t
*flt
;
1594 ipqos_conf_filter_t
*tmpf
;
1599 /* check for new/modified filters */
1601 for (flt
= new->filters
; flt
; flt
= flt
->next
) {
1603 /* new ipqosconf filter */
1605 if ((tmpf
= filterexist(flt
->name
, -1, old
->filters
)) == NULL
) {
1607 /* mark all instances of this filter as new */
1609 IPQOSCDBG1(DIFF
, "Marking filter %s as "
1610 "new\n", flt
->name
);
1615 if (flt
->next
== NULL
||
1616 strcmp(flt
->next
->name
, flt
->name
) != 0) {
1621 new->modified
= B_TRUE
; /* mark new action */
1623 /* ipqosconf/permanent filter existed */
1626 * if ip node name force filter refresh - ie. mark
1627 * all old filter instances as todel and all new new.
1629 if (tmpf
->src_nd_name
|| tmpf
->dst_nd_name
||
1630 flt
->src_nd_name
|| flt
->dst_nd_name
) {
1632 /* init max previous filter instance */
1633 maxi
= tmpf
->instance
;
1635 /* mark old instances for deletion */
1637 IPQOSCDBG2(DIFF
, "Marking filter "
1638 "%s, instance %d for del\n",
1639 tmpf
->name
, tmpf
->instance
);
1641 tmpf
->todel
= B_TRUE
;
1644 * check and update previous instance
1647 if (tmpf
->instance
> maxi
) {
1648 maxi
= tmpf
->instance
;
1652 } while (tmpf
!= NULL
&&
1653 strcmp(tmpf
->name
, flt
->name
) == 0);
1656 * use the max previous instance + 1 for
1657 * the start of the new instance numbers.
1659 newi
= (uint32_t)++maxi
% INT_MAX
;
1662 * mark new instances for addition and
1663 * give new instance number.
1666 IPQOSCDBG2(DIFF
, "Marking filter "
1667 "%s, instance %d as new\n",
1671 flt
->instance
= newi
++;
1672 if (flt
->next
== NULL
||
1673 strcmp(flt
->next
->name
,
1679 new->modified
= B_TRUE
; /* mark new action */
1681 /* mark old action */
1682 old
->modified
= B_TRUE
;
1684 /* non-node name filter */
1686 /* compare and mark as modified if diff */
1688 res
= difffilter(tmpf
, flt
, new->module
);
1689 if (res
!= IPQOS_CONF_SUCCESS
) {
1692 if (flt
->modified
== B_TRUE
) {
1693 /* mark action if diff */
1694 new->modified
= B_TRUE
;
1701 * Check for deleted ipqosconf created filters and mark
1702 * any found for deletion.
1703 * For non-ipqosconf generated filters, including permanent
1704 * ones (none of these exist at the moment) we just leave
1705 * the filter unmarked.
1707 for (flt
= old
->filters
; flt
; flt
= flt
->next
) {
1709 if (flt
->originator
== IPP_CONFIG_IPQOSCONF
&&
1710 filterexist(flt
->name
, -1, new->filters
) == NULL
) {
1712 /* mark all old instances for deletions */
1714 IPQOSCDBG2(DIFF
, "marking flt %s, inst %d "
1715 "for del\n", flt
->name
, flt
->instance
);
1717 flt
->todel
= B_TRUE
;
1718 old
->modified
= B_TRUE
; /* mark old action */
1720 if (flt
->next
== NULL
||
1721 strcmp(flt
->next
->name
, flt
->name
) != 0) {
1729 return (IPQOS_CONF_SUCCESS
);
1734 * differences the elements of nvlists old and new using the types file
1735 * for module name to interpret the element types. It sets pdiff to either
1736 * 0 or 1 if they are the same or different respectively.
1737 * RETURNS: IPQOS_CONF_ERR if any errors, else IPQOS_CONF_SUCCESS.
1753 str_val_nd_t
*enum_nvs
;
1754 char dfltst
[IPQOS_VALST_MAXLEN
+1] = "";
1756 ipqos_nvtype_t type
;
1762 IPQOSCDBG0(L0
, "In diffnvlists\n");
1764 /* open stream to types file */
1766 tfp
= validmod(module_name
, &openerr
);
1769 ipqos_msg(MT_ENOSTR
, "fopen");
1771 return (IPQOS_CONF_ERR
);
1775 * loop through each of the elements of the new list comparing
1776 * it with the old one if present. If the old one isn't present
1777 * then it is compared with the default value for that type (if
1778 * set). Any time the values are determined to be different
1779 * or the default value is to be used but isn't present the diff
1780 * param is set to 1 and we return.
1782 * If the loop runs its course then the new and old nvlists are
1783 * reversed and the loop is entered for a second time.
1785 nvp
= nvlist_next_nvpair(new, NULL
);
1786 while (nvp
!= NULL
) {
1789 nme
= nvpair_name(nvp
);
1795 res
= readtype(tfp
, module_name
, SHORT_NAME(nme
), &type
,
1796 &enum_nvs
, dfltst
, B_TRUE
, &place
);
1797 if (res
!= IPQOS_CONF_SUCCESS
) {
1801 /* init diff to 1 */
1806 /* interface name */
1807 case IPQOS_DATA_TYPE_IFINDEX
: {
1812 (void) nvpair_value_uint32(nvp
, &ifidx
);
1814 /* compare against old if present */
1816 res
= nvlist_lookup_uint32(old
, nme
, &oifidx
);
1819 diff
= (ifidx
!= oifidx
);
1821 /* not in old so see if new value is default */
1824 diff
= (ifidx
!= 0);
1829 case IPQOS_DATA_TYPE_PROTO
: {
1833 (void) nvpair_value_byte(nvp
, &proto
);
1835 res
= nvlist_lookup_byte(old
, nme
, &oproto
);
1837 diff
= (proto
!= oproto
);
1839 diff
= (proto
!= 0);
1844 case IPQOS_DATA_TYPE_PORT
: {
1848 (void) nvpair_value_uint16(nvp
, &port
);
1849 res
= nvlist_lookup_uint16(old
, nme
, &oport
);
1851 diff
= (port
!= oport
);
1857 /* action name / string */
1858 case IPQOS_DATA_TYPE_ACTION
:
1859 case IPQOS_DATA_TYPE_STRING
: {
1863 (void) nvpair_value_string(nvp
, &str
);
1864 res
= nvlist_lookup_string(old
, nme
, &ostr
);
1866 diff
= strcmp(str
, ostr
);
1867 } else if (*dfltst
) {
1868 diff
= strcmp(str
, dfltst
);
1872 /* address mask / address */
1873 case IPQOS_DATA_TYPE_ADDRESS_MASK
:
1874 case IPQOS_DATA_TYPE_ADDRESS
: {
1880 * all addresses are stored as v6 addresses, so
1881 * a uint32_t[4] array is used.
1884 /* lookup new value */
1886 (void) nvpair_value_uint32_array(nvp
,
1887 (uint32_t **)&in6
, &x
);
1889 /* see if there's an old value and diff it */
1891 res
= nvlist_lookup_uint32_array(old
, nme
,
1892 (uint32_t **)&oin6
, &x
);
1894 /* diff each of the 16 v6 address bytes */
1896 for (x
= 0; x
< 16; x
++) {
1897 if (in6
->s6_addr
[x
] !=
1907 case IPQOS_DATA_TYPE_BOOLEAN
: {
1911 (void) nvpair_value_uint32(nvp
, (uint32_t *)&bl
);
1913 /* see if there's an old value and diff it */
1914 res
= nvlist_lookup_uint32(old
, nme
, (uint32_t *)&obl
);
1918 /* compare against default if present */
1919 } else if (*dfltst
) {
1920 res
= readbool(dfltst
, &obl
);
1921 if (res
== IPQOS_CONF_SUCCESS
) {
1928 case IPQOS_DATA_TYPE_UINT8
: {
1932 (void) nvpair_value_byte(nvp
, (uchar_t
*)&u8
);
1933 res
= nvlist_lookup_byte(old
, nme
, (uchar_t
*)&ou8
);
1936 } else if (*dfltst
) {
1937 res
= readuint8(dfltst
, &ou8
, &lo
);
1938 if (res
== IPQOS_CONF_SUCCESS
) {
1945 case IPQOS_DATA_TYPE_INT16
: {
1949 (void) nvpair_value_int16(nvp
, &i16
);
1950 res
= nvlist_lookup_int16(old
, nme
, &oi16
);
1952 diff
= (i16
!= oi16
);
1953 } else if (*dfltst
) {
1954 res
= readint16(dfltst
, &oi16
, &lo
);
1955 if (res
== IPQOS_CONF_SUCCESS
) {
1956 diff
= (i16
!= oi16
);
1962 case IPQOS_DATA_TYPE_UINT16
: {
1966 (void) nvpair_value_uint16(nvp
, &ui16
);
1967 res
= nvlist_lookup_uint16(old
, nme
, &oui16
);
1969 diff
= (ui16
!= oui16
);
1970 } else if (*dfltst
) {
1971 res
= readuint16(dfltst
, &oui16
, &lo
);
1972 if (res
== IPQOS_CONF_SUCCESS
) {
1973 diff
= (ui16
!= oui16
);
1980 * Since user uids are stored in an int32 nvpair we can use
1981 * the same comparison code.
1983 case IPQOS_DATA_TYPE_USER
:
1984 case IPQOS_DATA_TYPE_INT32
: {
1988 (void) nvpair_value_int32(nvp
, &i32
);
1989 res
= nvlist_lookup_int32(old
, nme
, &oi32
);
1991 diff
= (i32
!= oi32
);
1992 } else if (*dfltst
) {
1993 res
= readint32(dfltst
, &oi32
, &lo
);
1994 if (res
== IPQOS_CONF_SUCCESS
) {
1995 diff
= (i32
!= oi32
);
2001 case IPQOS_DATA_TYPE_UINT32
: {
2005 (void) nvpair_value_uint32(nvp
, &ui32
);
2006 res
= nvlist_lookup_uint32(old
, nme
, &oui32
);
2008 diff
= (ui32
!= oui32
);
2009 } else if (*dfltst
) {
2010 res
= readuint32(dfltst
, &oui32
, &lo
);
2011 if (res
== IPQOS_CONF_SUCCESS
) {
2012 diff
= (ui32
!= oui32
);
2018 case IPQOS_DATA_TYPE_ENUM
: {
2022 (void) nvpair_value_uint32(nvp
, &eval
);
2023 res
= nvlist_lookup_uint32(old
, nme
, &oeval
);
2025 diff
= (eval
!= oeval
);
2026 } else if (*dfltst
) {
2027 res
= readuint32(dfltst
, &oeval
, &lo
);
2028 if (res
== IPQOS_CONF_SUCCESS
) {
2029 diff
= (eval
!= oeval
);
2034 case IPQOS_DATA_TYPE_M_INDEX
: {
2037 (void) nvpair_value_byte(nvp
, &idx
);
2038 res
= nvlist_lookup_byte(old
, nme
, &oidx
);
2040 diff
= (idx
!= oidx
);
2043 case IPQOS_DATA_TYPE_INT_ARRAY
: {
2045 uint32_t osize
, size
;
2047 (void) nvpair_value_int32_array(nvp
, &arr
, &size
);
2048 res
= nvlist_lookup_int32_array(old
, nme
, &oarr
,
2051 diff
= (arrays_equal(arr
, oarr
, size
) ==
2055 #ifdef _IPQOS_CONF_DEBUG
2057 /* shouldn't get here as all types should be covered */
2063 IPQOSCDBG1(DIFF
, "parameter %s different\n", nme
);
2066 return (IPQOS_CONF_SUCCESS
);
2070 nvp
= nvlist_next_nvpair(new, nvp
);
2074 /* now compare all the stuff in the second list with the first */
2086 return (IPQOS_CONF_SUCCESS
);
2091 /* ************************** difference application *********************** */
2096 * causes all items marked as requiring change in actions and old_actions
2097 * to have the change applied.
2098 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
2102 ipqos_conf_action_t
*actions
,
2103 ipqos_conf_action_t
*old_actions
)
2108 IPQOSCDBG0(L1
, "In applydiff:\n");
2111 /* add each item marked as new */
2113 res
= add_items(actions
, B_FALSE
);
2114 if (res
!= IPQOS_CONF_SUCCESS
) {
2118 /* modify items marked for modification */
2120 res
= modify_items(actions
);
2121 if (res
!= IPQOS_CONF_SUCCESS
) {
2125 /* delete items marked for deletion */
2127 res
= remove_items(old_actions
, B_FALSE
);
2128 if (res
!= IPQOS_CONF_SUCCESS
) {
2132 return (IPQOS_CONF_SUCCESS
);
2137 ipqos_conf_action_t
*actions
,
2142 ipqos_conf_action_t
*act
;
2144 IPQOSCDBG1(L1
, "In add_items, rem_undo: %u\n", rem_undo
);
2147 * we need to create ipgpc action before any others as some actions
2148 * such as ftpcl which make calls to it depend on it being there on
2151 act
= actionexist(IPGPC_CLASSIFY
, actions
);
2153 (rem_undo
== B_FALSE
&& act
->new == B_TRUE
||
2154 rem_undo
== B_TRUE
&& act
->deleted
== B_TRUE
)) {
2156 res
= add_action(act
);
2157 if (res
!= IPQOS_CONF_SUCCESS
) {
2163 * loop though action list and add any actions marked as
2164 * new/modified action and apply any additions there, then return.
2167 for (act
= actions
; act
; act
= act
->next
) {
2168 res
= add_item(act
, rem_undo
);
2169 if (res
!= IPQOS_CONF_SUCCESS
) {
2170 return (IPQOS_CONF_ERR
);
2174 return (IPQOS_CONF_SUCCESS
);
2180 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
2184 ipqos_conf_action_t
*actions
,
2188 ipqos_conf_action_t
*act
= actions
;
2190 ipqos_conf_class_t
*cls
;
2191 ipqos_conf_act_ref_t
*pact
;
2193 IPQOSCDBG2(L1
, "In add_item: action: %s, rem_undo: %u\n",
2194 actions
->name
, rem_undo
);
2196 /* if already visited return immediately */
2198 if (act
->visited
== ADD_VISITED
) {
2199 IPQOSCDBG0(L1
, "Early exit due to visited\n");
2200 return (IPQOS_CONF_SUCCESS
);
2202 act
->visited
= ADD_VISITED
;
2205 /* recurse to last action in tree */
2207 for (cls
= act
->classes
; cls
; cls
= cls
->next
) {
2209 /* if not virtual action */
2211 if (cls
->alist
->action
) {
2212 res
= add_item(cls
->alist
->action
, rem_undo
);
2213 if (res
!= IPQOS_CONF_SUCCESS
) {
2219 for (pact
= act
->params
->actions
; pact
; pact
= pact
->next
) {
2221 /* if not virtual */
2224 res
= add_item(pact
->action
, rem_undo
);
2225 if (res
!= IPQOS_CONF_SUCCESS
) {
2232 /* if action marked as new and not ipgpc, create */
2234 if (((rem_undo
== B_FALSE
&& act
->new == B_TRUE
) ||
2235 (rem_undo
== B_TRUE
&& act
->deleted
== B_TRUE
)) &&
2236 strcmp(act
->name
, IPGPC_CLASSIFY
) != 0) {
2237 res
= add_action(act
);
2238 if (res
!= IPQOS_CONF_SUCCESS
) {
2243 /* add any classes and filters marked as new */
2245 if (add_classes(act
->classes
, act
->name
, act
->module_version
,
2246 rem_undo
) != IPQOS_CONF_SUCCESS
||
2247 add_filters(act
->filters
, act
->name
, act
->module_version
,
2248 rem_undo
) != IPQOS_CONF_SUCCESS
) {
2249 return (IPQOS_CONF_ERR
);
2252 return (IPQOS_CONF_SUCCESS
);
2257 * Uses the contents of acts params nvlist and adds an originator
2258 * element set to ipqosconf and the stats parameter. This list
2259 * is then used as the parameter to a call to ipp_action_create to create
2260 * this action in the kernel.
2261 * RETURNS: IPQOS_CONF_ERR on err, else IPQOS_CONF_SUCCESS.
2264 add_action(ipqos_conf_action_t
*act
)
2270 IPQOSCDBG2(APPLY
, "add_action: action: %s, module: %s\n", act
->name
,
2273 nvl
= &act
->params
->nvlist
;
2275 /* alloc params nvlist if not already one */
2278 res
= nvlist_alloc(nvl
, NV_UNIQUE_NAME
, 0);
2280 ipqos_msg(MT_ENOSTR
, "nvlist_alloc");
2281 return (IPQOS_CONF_ERR
);
2286 * add module version
2288 if (nvlist_add_uint32(*nvl
, IPP_MODULE_VERSION
,
2289 (uint32_t)act
->module_version
) != 0) {
2290 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32");
2291 return (IPQOS_CONF_ERR
);
2294 /* add action stats */
2296 if (nvlist_add_uint32(*nvl
, IPP_ACTION_STATS_ENABLE
,
2297 (uint32_t)act
->params
->stats_enable
) != 0) {
2298 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32: action stats");
2299 return (IPQOS_CONF_ERR
);
2302 /* add ipqosconf originator id */
2304 if (add_orig_ipqosconf(*nvl
) != IPQOS_CONF_SUCCESS
) {
2305 return (IPQOS_CONF_ERR
);
2308 /* call into lib to create action */
2310 res
= ipp_action_create(act
->module
, act
->name
, nvl
, 0);
2312 IPQOSCDBG2(APPLY
, "Create action %s, module %s failed\n",
2313 act
->name
, act
->module
);
2315 /* invalid params */
2317 if (errno
== EINVAL
) {
2319 gettext("Invalid Parameters for action %s.\n"),
2322 } else if (errno
== ENOENT
) {
2324 gettext("Missing required parameter for action "
2325 "%s.\n"), act
->name
);
2327 } else { /* unexpected error */
2328 ipqos_msg(MT_ERROR
, gettext("Failed to create action "
2329 "%s: %s.\n"), act
->name
, strerror(errno
));
2332 return (IPQOS_CONF_ERR
);
2335 /* mark action as created */
2336 act
->cr_mod
= B_TRUE
;
2338 return (IPQOS_CONF_SUCCESS
);
2342 * for each of the filters in parameter filters if rem_undo is false and
2343 * the filter is marked as new or if rem_undo is true and the filter is
2344 * marked as deleted then add the filter to the kernel action named by action
2345 * and if successful mark as created.
2346 * RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
2350 ipqos_conf_filter_t
*filters
,
2356 ipqos_conf_filter_t
*flt
;
2358 IPQOSCDBG0(L1
, "In add_filters\n");
2360 /* loop through filters in filters param */
2361 for (flt
= filters
; flt
; flt
= flt
->next
) {
2363 * skip filter if in normal mode and not new filter or
2364 * if doing rollback and filter wasn't previously deleted.
2366 if ((rem_undo
== B_FALSE
&& flt
->new == B_FALSE
) ||
2367 (rem_undo
== B_TRUE
&& flt
->deleted
== B_FALSE
)) {
2371 /* add filter to action */
2372 if (add_filter(action
, flt
, module_version
) !=
2373 IPQOS_CONF_SUCCESS
) {
2374 return (IPQOS_CONF_ERR
);
2377 /* mark as created */
2378 flt
->cr_mod
= B_TRUE
;
2381 return (IPQOS_CONF_SUCCESS
);
2385 * for each of the classes in parameter classes if rem_undo is false and
2386 * the class is marked as new or if rem_undo is true and the class is
2387 * marked as deleted then add the class to the kernel action named by action
2388 * and if successful mark as created.
2389 * RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
2393 ipqos_conf_class_t
*classes
,
2396 boolean_t rem_undo
) {
2399 ipqos_conf_class_t
*cls
;
2401 IPQOSCDBG0(L1
, "In add_classes\n");
2403 /* for each class */
2404 for (cls
= classes
; cls
; cls
= cls
->next
) {
2406 * skip class if in normal mode and not new class or
2407 * if doing rollback and class wasn't deleted.
2409 if ((rem_undo
== B_FALSE
&& cls
->new == B_FALSE
) ||
2410 (rem_undo
== B_TRUE
&& cls
->deleted
== B_FALSE
)) {
2414 /* add class to action */
2415 res
= add_class(action
, cls
->name
, module_version
,
2416 cls
->stats_enable
, cls
->alist
->name
);
2417 if (res
!= IPQOS_CONF_SUCCESS
) {
2418 return (IPQOS_CONF_ERR
);
2421 /* mark class as created */
2422 cls
->cr_mod
= B_TRUE
;
2425 return (IPQOS_CONF_SUCCESS
);
2429 * For each of the actions in actions remove the action if marked as
2430 * such or remove any objects within marked as such.
2431 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
2435 ipqos_conf_action_t
*actions
,
2440 ipqos_conf_action_t
*act
;
2442 IPQOSCDBG1(L0
, "In remove_items, add_undo: %u\n", add_undo
);
2445 * loop through actions removing any actions, or action contents
2446 * that are marked as such.
2448 for (act
= actions
; act
; act
= act
->next
) {
2449 res
= remove_item(act
, add_undo
);
2450 if (res
!= IPQOS_CONF_SUCCESS
) {
2455 return (IPQOS_CONF_SUCCESS
);
2459 * Deletes this action if marked for deletion or any of it's contents marked
2460 * for deletion. If the action is marked for deletion any actions referencing
2461 * this action are destroyed first if marked or have their contents destroyed
2462 * if marked. This is recursive.
2463 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
2467 ipqos_conf_action_t
*act
,
2471 ipqos_conf_class_t
*cls
;
2472 ipqos_conf_filter_t
*flt
;
2473 ipqos_conf_act_ref_t
*dep
;
2476 IPQOSCDBG3(L1
, "In remove_item: action: %s, add_undo: %u, mod: %u\n",
2477 act
->name
, add_undo
, act
->modified
);
2480 /* return immmediately if previously visited in remove phase */
2482 if (act
->visited
== REM_VISITED
) {
2483 IPQOSCDBG0(L1
, "Exit due to REM_VISITED set\n");
2484 return (IPQOS_CONF_SUCCESS
);
2486 act
->visited
= REM_VISITED
;
2489 /* if this action is to be deleted */
2491 if (add_undo
== B_FALSE
&& act
->todel
== B_TRUE
||
2492 add_undo
== B_TRUE
&& act
->new == B_TRUE
&&
2493 act
->cr_mod
== B_TRUE
) {
2495 /* modify parent actions first */
2497 for (dep
= act
->dependencies
; dep
; dep
= dep
->next
) {
2498 res
= remove_item(dep
->action
, add_undo
);
2499 if (res
!= IPQOS_CONF_SUCCESS
) {
2504 /* delete this action */
2506 IPQOSCDBG1(APPLY
, "deleting action %s\n", act
->name
);
2507 res
= ipp_action_destroy(act
->name
, 0);
2509 IPQOSCDBG1(APPLY
, "failed to destroy action %s\n",
2511 return (IPQOS_CONF_ERR
);
2514 /* flag as deleted */
2516 act
->deleted
= B_TRUE
;
2518 /* if modified action */
2520 } else if (act
->modified
== B_TRUE
) {
2522 /* loop through removing any filters marked for del */
2524 for (flt
= act
->filters
; flt
; flt
= flt
->next
) {
2525 if ((add_undo
== B_FALSE
&& flt
->todel
== B_TRUE
) ||
2526 (add_undo
== B_TRUE
&& flt
->new == B_TRUE
&&
2527 flt
->cr_mod
== B_TRUE
)) {
2531 res
= remove_filter(act
->name
, flt
->name
,
2532 flt
->instance
, act
->module_version
);
2533 if (res
!= IPQOS_CONF_SUCCESS
) {
2534 IPQOSCDBG2(APPLY
, "failed to destroy "
2535 "filter %s, inst: %d\n", flt
->name
,
2538 return (IPQOS_CONF_ERR
);
2543 flt
->deleted
= B_TRUE
;
2547 /* remove any classes marked for del */
2549 for (cls
= act
->classes
; cls
; cls
= cls
->next
) {
2550 if ((add_undo
== B_FALSE
&& cls
->todel
== B_TRUE
) ||
2551 (add_undo
== B_TRUE
&& cls
->new == B_TRUE
&&
2552 cls
->cr_mod
== B_TRUE
)) {
2556 res
= remove_class(act
->name
, cls
->name
,
2557 act
->module_version
, 0);
2558 if (res
!= IPQOS_CONF_SUCCESS
) {
2559 IPQOSCDBG1(APPLY
, "failed to destroy "
2560 "class %s\n", cls
->name
);
2562 return (IPQOS_CONF_ERR
);
2567 cls
->deleted
= B_TRUE
;
2571 /* mark action as having been modified */
2573 act
->cr_mod
= B_TRUE
;
2576 return (IPQOS_CONF_SUCCESS
);
2580 * for each of the actions in parameter actions apply any objects marked as
2581 * modified as a modification to the kernel action represented.
2582 * RETURNS: IPQOS_CONF_ERR on err, else IPQOS_CONF_SUCCESS.
2585 modify_items(ipqos_conf_action_t
*actions
)
2588 ipqos_conf_action_t
*act
;
2590 ipqos_conf_filter_t
*flt
;
2591 ipqos_conf_class_t
*cls
;
2594 IPQOSCDBG0(L1
, "In modify_items\n");
2596 /* loop through actions in parameter actions */
2598 for (act
= actions
; act
; act
= act
->next
) {
2600 /* skip unchanged actions */
2602 if (act
->modified
== B_FALSE
) {
2606 /* apply any parameter mods */
2608 if (act
->params
->modified
) {
2609 res
= modify_params(act
->name
,
2610 &act
->params
->nvlist
,
2611 act
->module_version
, act
->params
->stats_enable
);
2612 if (res
!= IPQOS_CONF_SUCCESS
) {
2613 return (IPQOS_CONF_ERR
);
2616 act
->params
->cr_mod
= B_TRUE
;
2619 /* apply any class mods */
2621 for (cls
= act
->classes
; cls
; cls
= cls
->next
) {
2622 if (cls
->modified
) {
2623 res
= modify_class(act
->name
, cls
->name
,
2624 act
->module_version
, cls
->stats_enable
,
2625 cls
->alist
->name
, 0);
2626 if (res
!= IPQOS_CONF_SUCCESS
) {
2627 return (IPQOS_CONF_ERR
);
2630 /* mark modification done */
2631 cls
->cr_mod
= B_TRUE
;
2635 /* apply any filter mods */
2637 for (flt
= act
->filters
; flt
; flt
= flt
->next
) {
2638 if (flt
->modified
) {
2639 res
= modify_filter(act
->name
, flt
,
2640 act
->module_version
);
2642 return (IPQOS_CONF_ERR
);
2645 /* mark modification done */
2646 flt
->cr_mod
= B_TRUE
;
2650 /* mark action modified */
2652 act
->cr_mod
= B_TRUE
;
2655 return (IPQOS_CONF_SUCCESS
);
2659 * For each of the objects of each of the actions in nactions that are
2660 * marked as having been modified the object modification is done in
2661 * reverse using the same named object from oactions.
2662 * RETURNS: IPQOS_CONF_ERR on error, IPQOS_CONF_SUCCESS otherwise.
2666 ipqos_conf_action_t
*oactions
,
2667 ipqos_conf_action_t
*nactions
)
2670 ipqos_conf_filter_t
*flt
;
2671 ipqos_conf_class_t
*cls
;
2672 ipqos_conf_action_t
*act
;
2673 ipqos_conf_action_t
*oldact
;
2674 ipqos_conf_filter_t
*oldflt
;
2675 ipqos_conf_class_t
*oldcls
;
2678 IPQOSCDBG0(L1
, "In undo_modifys:\n");
2680 /* loop throught new actions */
2682 for (act
= nactions
; act
; act
= act
->next
) {
2683 oldact
= actionexist(act
->name
, oactions
);
2686 * if the action was new then it will be removed and
2687 * any permamanent items that were marked for modify
2688 * will dissappear, so ignore action.
2690 if (oldact
== NULL
) {
2694 /* if parameters were modified switch them back */
2696 if (act
->params
->modified
== B_TRUE
&&
2697 act
->params
->cr_mod
== B_TRUE
) {
2698 res
= modify_params(act
->name
,
2699 &oldact
->params
->nvlist
,
2700 act
->module_version
, act
->params
->stats_enable
);
2701 if (res
!= IPQOS_CONF_SUCCESS
) {
2706 /* for each filter in action if filter modified switch back */
2708 for (flt
= act
->filters
; flt
; flt
= flt
->next
) {
2709 if (flt
->modified
== B_TRUE
&&
2710 flt
->cr_mod
== B_TRUE
) {
2711 oldflt
= filterexist(flt
->name
, -1,
2713 res
= modify_filter(act
->name
, oldflt
,
2714 act
->module_version
);
2715 if (res
!= IPQOS_CONF_SUCCESS
) {
2721 /* for each class in action if class modified switch back */
2723 for (cls
= act
->classes
; cls
; cls
= cls
->next
) {
2724 if (cls
->modified
== B_TRUE
&&
2725 cls
->cr_mod
== B_TRUE
) {
2726 oldcls
= classexist(cls
->name
, oldact
->classes
);
2727 if (oldcls
->alist
) {
2728 res
= modify_class(act
->name
,
2729 cls
->name
, act
->module_version
,
2730 oldcls
->stats_enable
,
2731 oldcls
->alist
->name
, 0);
2733 if (res
!= IPQOS_CONF_SUCCESS
) {
2741 * Go through the old actions modifying perm filters and classes
2742 * whose action was deleted.
2745 for (act
= oactions
; act
!= NULL
; act
= act
->next
) {
2747 if (act
->deleted
== B_FALSE
) {
2751 for (flt
= act
->filters
; flt
!= NULL
; flt
= flt
->next
) {
2752 if (flt
->originator
== IPP_CONFIG_PERMANENT
) {
2753 res
= modify_filter(act
->name
, flt
,
2754 act
->module_version
);
2755 if (res
!= IPQOS_CONF_SUCCESS
) {
2761 for (cls
= act
->classes
; cls
!= NULL
; cls
= cls
->next
) {
2762 if (cls
->originator
== IPP_CONFIG_PERMANENT
) {
2763 res
= modify_class(act
->name
, cls
->name
,
2764 act
->module_version
, cls
->stats_enable
,
2765 cls
->alist
->name
, 0);
2766 if (res
!= IPQOS_CONF_SUCCESS
) {
2774 return (IPQOS_CONF_SUCCESS
);
2779 * causes all changes marked as being done in actions and old_actions
2781 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
2785 ipqos_conf_action_t
*actions
,
2786 ipqos_conf_action_t
*old_actions
)
2791 IPQOSCDBG0(RBK
, "In rollback:\n");
2793 /* re-add items that were deleted */
2795 res
= add_items(old_actions
, B_TRUE
);
2796 if (res
!= IPQOS_CONF_SUCCESS
) {
2800 /* change modified items back how they were */
2802 res
= undo_modifys(old_actions
, actions
);
2803 if (res
!= IPQOS_CONF_SUCCESS
) {
2807 /* remove new items that were added */
2809 res
= remove_items(actions
, B_TRUE
);
2810 if (res
!= IPQOS_CONF_SUCCESS
) {
2814 return (IPQOS_CONF_SUCCESS
);
2817 /* ******************************* print config **************************** */
2820 * Prints the username of the user with uid 'uid' to 'fp' if the uid belongs
2821 * to a known user on the system, otherwise just print 'uid'.
2830 IPQOSCDBG0(L0
, "In printuser\n");
2832 pwd
= getpwuid(uid
);
2834 (void) fprintf(fp
, "%s\n", pwd
->pw_name
);
2836 (void) fprintf(fp
, "%u\n", (int)uid
);
2841 * print either a single value of start to fp (if start equals end), else
2842 * print start'-'end if start is the smaller of the two values, otherwise
2843 * print end'-'start.
2859 (void) fprintf(fp
, "%u", start
);
2861 (void) fprintf(fp
, "-%u", end
);
2865 * print the contents of the array arr to fp in the form:
2866 * {0-6:1;7-12:2;13:3.....} or {0-6:GREEN;7-12:YELLOW:...}
2867 * dependant upon whether this is an integer or enumerated array resectively
2868 * (if enum_nvs isn't set to NULL this is assumed to be an enumerated array);
2869 * where 0-6 is the range of indexes with value 1 (or GREEN), 7-12 the range
2870 * with value 2 (or YELLOW), and so forth. size is the array size and llimit
2871 * and ulimit are the lower and upper limits of the array values printed
2872 * respectively. For enumerated arrays enum_nvs carries the list of name
2873 * and value pairs and ulimit and llimit parameters are ignored and instead
2874 * determined from the enum_nvs list.
2883 str_val_nd_t
*enum_nvs
,
2887 uint32_t first
, last
;
2888 boolean_t first_entry
; /* first 'ranges:value' to be printed ? */
2889 boolean_t first_range
; /* first range for a value to be printed ? */
2890 boolean_t found_range
; /* did we find a range for this value ? */
2892 IPQOSCDBG4(L0
, "In print_int_array: size: %u, llimit: %u, ulimit: %u, "
2893 "enum_nvs: %x \n", size
, llimit
, ulimit
, enum_nvs
);
2896 * if an enumeration retrieve value range.
2898 if (enum_nvs
!= NULL
)
2899 get_str_val_value_range(enum_nvs
, &llimit
, &ulimit
);
2902 * print opening curl.
2904 (void) fprintf(fp
, "%c\n", CURL_BEGIN
);
2905 PRINT_TABS(fp
, tab_inserts
+ 1);
2907 first_entry
= B_TRUE
;
2909 * for each value in range.
2911 for (x
= llimit
; x
<= ulimit
; x
++) {
2912 found_range
= B_FALSE
;
2913 first_range
= B_TRUE
;
2916 * scan array and print ranges of indexes with value x.
2920 * get first occurence of value for this range.
2922 while ((arr
[y
] != x
) && (y
< size
))
2927 found_range
= B_TRUE
;
2932 * get last occurence of value for this range.
2934 while ((arr
[y
] == x
) && (y
< size
))
2939 * print entry delimiter (semi-colon)? It must be
2940 * the first range for this value and this mustn't
2941 * be the first 'ranges:value' entry.
2943 if (!first_entry
&& first_range
) {
2944 (void) fprintf(fp
, ";\n");
2945 PRINT_TABS(fp
, tab_inserts
+ 1);
2947 first_entry
= B_FALSE
;
2951 * print comma (range delimeter) only if there was
2952 * a previous range for this value.
2955 (void) fprintf(fp
, ",");
2957 first_range
= B_FALSE
;
2963 printrange(fp
, first
, last
);
2966 * only print a colon and value if we found a range with
2970 (void) fprintf(fp
, ":");
2973 * print numeric/symbolic value.
2976 printenum(fp
, x
, enum_nvs
);
2978 (void) fprintf(fp
, "%d", x
);
2984 * print closing curl.
2986 (void) fprintf(fp
, "\n");
2987 PRINT_TABS(fp
, tab_inserts
);
2988 (void) fprintf(fp
, "%c\n", CURL_END
);
2991 /* print the protocol name for proto, or if unknown protocol number proto. */
2998 struct protoent
*pent
;
3000 pent
= getprotobynumber(proto
);
3002 (void) fprintf(fp
, "%s\n", pent
->p_name
);
3004 (void) fprintf(fp
, "%u\n", proto
);
3009 * prints the name associated with interface with index ifindex to fp.
3010 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
3031 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
3032 ipqos_msg(MT_ENOSTR
, gettext("opening AF_INET socket"));
3033 return (IPQOS_CONF_ERR
);
3036 /* get number of lifreq structs that need to be alloc'd for */
3038 ln
.lifn_family
= AF_UNSPEC
;
3040 ret
= ioctl(s
, SIOCGLIFNUM
, &ln
);
3042 ipqos_msg(MT_ENOSTR
, "SIOCLIFNUM ioctl");
3044 return (IPQOS_CONF_ERR
);
3047 /* allocate buffer for SIOGLIFCONF ioctl */
3049 len
= ln
.lifn_count
* sizeof (struct lifreq
);
3052 ipqos_msg(MT_ENOSTR
, "malloc");
3054 return (IPQOS_CONF_ERR
);
3057 /* setup lifconf params for ioctl */
3059 lc
.lifc_family
= AF_UNSPEC
;
3064 /* do SIOCGLIFCONF ioctl */
3066 ret
= ioctl(s
, SIOCGLIFCONF
, &lc
);
3068 ipqos_msg(MT_ENOSTR
, "SIGLIFCONF");
3071 return (IPQOS_CONF_ERR
);
3076 * for each interface name given in the returned lifreq list get
3077 * it's index and compare with ifindex param. Break if equal.
3079 for (x
= ln
.lifn_count
, lr
= lc
.lifc_req
; x
> 0; x
--, lr
++) {
3080 ret
= readifindex(lr
->lifr_name
, &idx
);
3081 if (ret
!= IPQOS_CONF_SUCCESS
) {
3083 return (IPQOS_CONF_ERR
);
3085 if (idx
== ifindex
) {
3092 IPQOSCDBG1(L1
, "Failed to find if index %u in returned "
3093 "if list.\n", ifindex
);
3094 return (IPQOS_CONF_ERR
);
3096 /* truncate any logical suffix */
3098 if ((cp
= strchr(lr
->lifr_name
, '@')) != NULL
) {
3102 /* print interface name */
3103 (void) fprintf(fp
, "%s\n", lr
->lifr_name
);
3105 return (IPQOS_CONF_SUCCESS
);
3109 * print to fp the enumeration clause evaluating to the value val using the
3110 * names/values given in enum_nvs.
3116 str_val_nd_t
*enum_nvs
)
3119 boolean_t isfirstval
= B_TRUE
;
3120 str_val_nd_t
*name_val
= enum_nvs
;
3122 /* for each value in enum_nvs if same bit set in val print name */
3125 if ((name_val
->sv
.value
& val
) == name_val
->sv
.value
) {
3126 if (isfirstval
== B_TRUE
) {
3127 (void) fprintf(fp
, "%s", name_val
->sv
.string
);
3128 isfirstval
= B_FALSE
;
3130 (void) fprintf(fp
, ", %s", name_val
->sv
.string
);
3133 name_val
= name_val
->next
;
3138 /* prints the service name of port, or if unknown the number to fp. */
3145 struct servent
*sent
;
3147 sent
= getservbyport(port
, NULL
);
3149 (void) fprintf(fp
, "%s\n", sent
->s_name
);
3151 (void) fprintf(fp
, "%u\n", ntohs(port
));
3156 * prints tp fp the name and value of all user specifiable parameters in the
3158 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
3165 int printall
, /* are we want ip addresses printing if node name */
3166 ipqos_conf_filter_t
*flt
, /* used to determine if node name set */
3173 ipqos_nvtype_t type
;
3174 str_val_nd_t
*enum_nvs
;
3176 char dfltst
[IPQOS_VALST_MAXLEN
+1];
3181 IPQOSCDBG0(L1
, "In printnvlist\n");
3184 /* open stream to types file */
3186 tfp
= validmod(module
, &openerr
);
3189 ipqos_msg(MT_ENOSTR
, "fopen");
3191 return (IPQOS_CONF_ERR
);
3195 /* go through list getting param name and type and printing it */
3197 nvp
= nvlist_next_nvpair(nvl
, NULL
);
3200 /* get nvpair name */
3201 name
= nvpair_name(nvp
);
3202 IPQOSCDBG1(L0
, "processing element %s.\n", name
);
3204 /* skip ipgpc params that are not explicitly user settable */
3206 if (strcmp(name
, IPGPC_FILTER_TYPE
) == 0 ||
3207 strcmp(name
, IPGPC_SADDR_MASK
) == 0 ||
3208 strcmp(name
, IPGPC_DADDR_MASK
) == 0 ||
3209 strcmp(name
, IPGPC_SPORT_MASK
) == 0 ||
3210 strcmp(name
, IPGPC_DPORT_MASK
) == 0) {
3211 nvp
= nvlist_next_nvpair(nvl
, nvp
);
3215 param
= SHORT_NAME(name
);
3218 * get parameter type from types file.
3221 ret
= readtype(tfp
, module
, param
, &type
, &enum_nvs
, dfltst
,
3223 if (ret
!= IPQOS_CONF_SUCCESS
) {
3228 * for map entries we don't print the map value, only
3229 * the index value it was derived from.
3231 if (place
== PL_MAP
) {
3232 nvp
= nvlist_next_nvpair(nvl
, nvp
);
3237 * the ifindex is converted to the name and printed out
3238 * so print the parameter name as ifname.
3240 if (strcmp(name
, IPGPC_IF_INDEX
) == 0) {
3241 PRINT_TABS(fp
, tab_inserts
);
3242 (void) fprintf(fp
, "%s ", IPQOS_IFNAME_STR
);
3244 * we may not print the address due to us instead printing
3245 * the node name in printfilter, therefore we leave the
3246 * printing of the parameter in the addresses switch case code.
3248 } else if ((strcmp(name
, IPGPC_SADDR
) != 0 &&
3249 strcmp(name
, IPGPC_DADDR
) != 0)) {
3250 PRINT_TABS(fp
, tab_inserts
);
3251 (void) fprintf(fp
, "%s ", param
);
3255 case IPQOS_DATA_TYPE_IFINDEX
: {
3258 (void) nvpair_value_uint32(nvp
, &ifidx
);
3259 (void) printifname(fp
, ifidx
);
3262 case IPQOS_DATA_TYPE_BOOLEAN
: {
3265 (void) nvpair_value_uint32(nvp
,
3267 (void) fprintf(fp
, "%s\n",
3268 bl
== B_TRUE
? "true" : "false");
3271 case IPQOS_DATA_TYPE_ACTION
: {
3274 (void) nvpair_value_string(nvp
, &strval
);
3275 print_action_nm(fp
, strval
);
3278 case IPQOS_DATA_TYPE_STRING
: {
3281 (void) nvpair_value_string(nvp
, &strval
);
3282 (void) fprintf(fp
, "%s\n",
3283 quote_ws_string(strval
));
3286 case IPQOS_DATA_TYPE_ADDRESS
: {
3289 char addrstr
[INET6_ADDRSTRLEN
];
3295 * skip addresses that have node names for
3296 * non printall listings.
3298 if (printall
== 0 &&
3299 (strcmp(nvpair_name(nvp
), IPGPC_SADDR
) ==
3300 0 && flt
->src_nd_name
||
3301 strcmp(nvpair_name(nvp
), IPGPC_DADDR
) ==
3302 0 && flt
->dst_nd_name
)) {
3306 /* we skipped this above */
3308 PRINT_TABS(fp
, tab_inserts
);
3309 (void) fprintf(fp
, "%s ", param
);
3311 (void) nvpair_value_uint32_array(nvp
,
3312 (uint32_t **)&addr
, &tmp
);
3314 /* get filter type */
3316 (void) nvlist_lookup_byte(nvl
,
3317 IPGPC_FILTER_TYPE
, &ftype
);
3318 if (ftype
== IPGPC_V4_FLTR
) {
3320 addr
= (in6_addr_t
*)
3321 &V4_PART_OF_V6((*addr
));
3327 if (strcmp(nvpair_name(nvp
), IPGPC_SADDR
) ==
3329 ret
= nvlist_lookup_uint32_array(nvl
,
3331 (uint32_t **)&mask
, &tmp
);
3333 ret
= nvlist_lookup_uint32_array(nvl
,
3335 (uint32_t **)&mask
, &tmp
);
3338 /* print address/mask to fp */
3340 (void) fprintf(fp
, "%s/%u\n",
3341 inet_ntop(af
, addr
, addrstr
,
3342 INET6_ADDRSTRLEN
), masktocidr(af
, mask
));
3345 case IPQOS_DATA_TYPE_ENUM
: {
3348 (void) nvpair_value_uint32(nvp
, &val
);
3351 * print list of tokens resulting in val
3353 (void) fprintf(fp
, "{ ");
3354 printenum(fp
, val
, enum_nvs
);
3355 (void) fprintf(fp
, " }\n");
3358 case IPQOS_DATA_TYPE_PORT
: {
3361 (void) nvpair_value_uint16(nvp
, &port
);
3362 printport(fp
, port
);
3365 case IPQOS_DATA_TYPE_PROTO
: {
3368 (void) nvpair_value_byte(nvp
, &proto
);
3369 printproto(fp
, proto
);
3372 case IPQOS_DATA_TYPE_M_INDEX
:
3373 case IPQOS_DATA_TYPE_UINT8
: {
3376 (void) nvpair_value_byte(nvp
, &u8
);
3377 (void) fprintf(fp
, "%u\n", u8
);
3380 case IPQOS_DATA_TYPE_UINT16
: {
3383 (void) nvpair_value_uint16(nvp
, &u16
);
3384 (void) fprintf(fp
, "%u\n", u16
);
3387 case IPQOS_DATA_TYPE_INT16
: {
3390 (void) nvpair_value_int16(nvp
, &i16
);
3391 (void) fprintf(fp
, "%d\n", i16
);
3394 case IPQOS_DATA_TYPE_UINT32
: {
3397 (void) nvpair_value_uint32(nvp
, &u32
);
3398 (void) fprintf(fp
, "%u\n", u32
);
3401 case IPQOS_DATA_TYPE_INT32
: {
3404 (void) nvpair_value_int32(nvp
, &i32
);
3405 (void) fprintf(fp
, "%d\n", i32
);
3408 case IPQOS_DATA_TYPE_INT_ARRAY
: {
3409 str_val_nd_t
*arr_enum_nvs
= NULL
;
3414 (void) nvpair_value_int32_array(nvp
, &arr
,
3418 * read array info from types file.
3420 res
= read_int_array_info(dfltst
,
3421 &arr_enum_nvs
, &size
, &llimit
, &ulimit
,
3425 * print array with numbers, or symbols
3428 if (res
== IPQOS_CONF_SUCCESS
) {
3429 print_int_array(fp
, arr
, size
,
3430 llimit
, ulimit
, arr_enum_nvs
,
3432 if (arr_enum_nvs
!= NULL
) {
3433 free_str_val_entrys(
3439 case IPQOS_DATA_TYPE_USER
: {
3442 (void) nvpair_value_int32(nvp
, (int *)&uid
);
3446 #ifdef _IPQOS_CONF_DEBUG
3449 * we should have catered for all used data
3450 * types that readtype returns.
3457 nvp
= nvlist_next_nvpair(nvl
, nvp
);
3461 return (IPQOS_CONF_SUCCESS
);
3465 * print a parameter clause for the parmeters given in params to fp.
3466 * If printall is set, then the originator of the parameter object is printed.
3467 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
3473 ipqos_conf_params_t
*params
,
3480 /* print opening clause */
3482 PRINT_TABS(fp
, tab_inserts
);
3483 (void) fprintf(fp
, IPQOS_CONF_PARAMS_STR
" {\n");
3485 /* print originator name if printall flag set */
3488 PRINT_TABS(fp
, tab_inserts
+ 1);
3489 (void) fprintf(stdout
, "Originator %s\n",
3490 quote_ws_string(get_originator_nm(params
->originator
)));
3493 /* print global stats */
3495 PRINT_TABS(fp
, tab_inserts
+ 1);
3496 (void) fprintf(fp
, IPQOS_CONF_GLOBAL_STATS_STR
" %s\n",
3497 params
->stats_enable
== B_TRUE
? "true" : "false");
3499 /* print module specific parameters */
3500 res
= printnvlist(fp
, module
, params
->nvlist
, printall
, NULL
,
3501 tab_inserts
+ 1, PL_PARAMS
);
3502 if (res
!= IPQOS_CONF_SUCCESS
) {
3506 PRINT_TABS(fp
, tab_inserts
);
3507 (void) fprintf(fp
, "}\n");
3509 return (IPQOS_CONF_SUCCESS
);
3513 * print the interpreted name of the action_nm parameter if it is a special
3514 * action, else action_nm verbatim to fp parameter.
3517 print_action_nm(FILE *fp
, char *action_nm
)
3520 if (strcmp(action_nm
, IPP_ANAME_CONT
) == 0) {
3521 (void) fprintf(fp
, IPQOS_CONF_CONT_STR
"\n");
3522 } else if (strcmp(action_nm
, IPP_ANAME_DEFER
) == 0) {
3523 (void) fprintf(fp
, IPQOS_CONF_DEFER_STR
"\n");
3524 } else if (strcmp(action_nm
, IPP_ANAME_DROP
) == 0) {
3525 (void) fprintf(fp
, IPQOS_CONF_DROP_STR
"\n");
3527 (void) fprintf(fp
, "%s\n", quote_ws_string(action_nm
));
3532 * print a class clause for class to fp. If printall is set the originator
3538 ipqos_conf_class_t
*class,
3543 /* print opening clause */
3545 PRINT_TABS(fp
, tab_inserts
);
3546 (void) fprintf(fp
, IPQOS_CONF_CLASS_STR
" {\n");
3549 /* if printall flag print originator name */
3552 PRINT_TABS(fp
, tab_inserts
+ 1);
3553 (void) fprintf(stdout
, "Originator %s\n",
3554 get_originator_nm(class->originator
));
3557 /* print name, next action and stats enable */
3559 PRINT_TABS(fp
, tab_inserts
+ 1);
3560 (void) fprintf(fp
, IPQOS_CONF_NAME_STR
" %s\n",
3561 quote_ws_string(class->name
));
3562 PRINT_TABS(fp
, tab_inserts
+ 1);
3563 (void) fprintf(fp
, IPQOS_CONF_NEXT_ACTION_STR
" ");
3564 print_action_nm(fp
, class->alist
->name
);
3565 PRINT_TABS(fp
, tab_inserts
+ 1);
3566 (void) fprintf(fp
, IPQOS_CONF_STATS_ENABLE_STR
" %s\n",
3567 class->stats_enable
== B_TRUE
? "true" : "false");
3569 PRINT_TABS(fp
, tab_inserts
);
3570 (void) fprintf(fp
, "}\n");
3574 * Returns a ptr to the originator name associated with origid. If unknown
3575 * id returns ptr to "unknown".
3576 * RETURNS: ptr to originator name, or if id not known "unknown".
3579 get_originator_nm(uint32_t origid
)
3584 /* scan originators table for origid */
3586 for (x
= 0; originators
[x
].value
!= -1 &&
3587 originators
[x
].value
!= origid
; x
++) {}
3589 /* if we've reached end of array due to unknown type return "unknown" */
3591 if (originators
[x
].value
== -1) {
3595 return (originators
[x
].string
);
3599 * print a filter clause for filter pointed to by filter out to fp. If printall
3600 * is set then the originator is printed, for filters with node names instance
3601 * numbers are printed, and the filter pointer isn't advanced to point at the
3602 * last instance of the printed filter.
3603 * RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
3609 ipqos_conf_filter_t
**filter
,
3616 /* print opening clause */
3618 PRINT_TABS(fp
, tab_inserts
);
3619 (void) fprintf(fp
, IPQOS_CONF_FILTER_STR
" {\n");
3621 /* print originator if printall flag set */
3624 PRINT_TABS(fp
, tab_inserts
+ 1);
3625 (void) fprintf(stdout
, "Originator %s\n",
3626 quote_ws_string(get_originator_nm((*filter
)->originator
)));
3629 /* print name and class */
3631 PRINT_TABS(fp
, tab_inserts
+ 1);
3632 (void) fprintf(fp
, IPQOS_CONF_NAME_STR
" %s\n",
3633 quote_ws_string((*filter
)->name
));
3634 PRINT_TABS(fp
, tab_inserts
+ 1);
3635 (void) fprintf(fp
, IPQOS_CONF_CLASS_STR
" %s\n",
3636 quote_ws_string((*filter
)->class_name
));
3638 /* print the instance if printall and potential mhomed addresses */
3640 if (printall
&& ((*filter
)->src_nd_name
|| (*filter
)->dst_nd_name
)) {
3641 PRINT_TABS(fp
, tab_inserts
+ 1);
3642 (void) fprintf(fp
, "Instance %u\n", (*filter
)->instance
);
3645 /* print node names if any */
3647 if ((*filter
)->src_nd_name
) {
3648 PRINT_TABS(fp
, tab_inserts
+ 1);
3649 (void) fprintf(fp
, "%s %s\n", strchr(IPGPC_SADDR
, '.') + 1,
3650 (*filter
)->src_nd_name
);
3652 if ((*filter
)->dst_nd_name
) {
3653 PRINT_TABS(fp
, tab_inserts
+ 1);
3654 (void) fprintf(fp
, "%s %s\n", strchr(IPGPC_DADDR
, '.') + 1,
3655 (*filter
)->dst_nd_name
);
3658 /* print ip_version enumeration if set */
3660 if ((*filter
)->ip_versions
!= 0) {
3661 PRINT_TABS(fp
, tab_inserts
+ 1);
3662 (void) fprintf(fp
, IPQOS_CONF_IP_VERSION_STR
" {");
3663 if (VERSION_IS_V4(*filter
)) {
3664 (void) fprintf(fp
, " V4");
3666 if (VERSION_IS_V6(*filter
)) {
3667 (void) fprintf(fp
, " V6");
3669 (void) fprintf(fp
, " }\n");
3672 /* print other module specific parameters parameters */
3674 res
= printnvlist(fp
, module
, (*filter
)->nvlist
, printall
, *filter
,
3675 tab_inserts
+ 1, PL_FILTER
);
3676 if (res
!= IPQOS_CONF_SUCCESS
) {
3680 PRINT_TABS(fp
, tab_inserts
);
3681 (void) fprintf(fp
, "}\n");
3684 * if not printall advance filter parameter to last instance of this
3690 if ((*filter
)->next
== NULL
||
3691 strcmp((*filter
)->name
, (*filter
)->next
->name
) !=
3695 *filter
= (*filter
)->next
;
3699 return (IPQOS_CONF_SUCCESS
);
3703 * Returns a pointer to str if no whitespace is present, else it returns
3704 * a pointer to a string with the contents of str enclose in double quotes.
3705 * This returned strings contents may change in subsequent calls so a copy
3706 * should be made of it if the caller wishes to retain it.
3709 quote_ws_string(const char *str
)
3711 static char *buf
= NULL
;
3712 const char *cp
; /* we don't modify the contents of str so const */
3714 IPQOSCDBG0(L0
, "In quote_ws_string\n");
3717 * Just return str if no whitespace.
3719 for (cp
= str
; (*cp
!= '\0') && !isspace(*cp
); cp
++)
3722 return ((char *)str
);
3726 * if first run just allocate buffer of
3727 * strlen(str) + 2 quote characters + NULL terminator.
3729 buf
= malloc(strlen(str
) + 3);
3730 } else if ((strlen(str
) + 2) > strlen(buf
)) {
3732 * Not first run, so check if we have a big enough buffer
3733 * and if not reallocate the buffer to a sufficient size.
3735 buf
= realloc(buf
, strlen(str
) + 3);
3741 * copy string into buffer with quotes.
3743 (void) strcpy(buf
, "\"");
3744 (void) strcat(buf
, str
);
3745 (void) strcat(buf
, "\"");
3751 * print an action clause for action to fp. If the printall flag is set
3752 * then all filters and classes (regardless of their originator) and
3753 * their originators are displayed.
3754 * RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
3759 ipqos_conf_action_t
*action
,
3764 ipqos_conf_filter_t
*flt
;
3765 ipqos_conf_class_t
*cls
;
3768 /* print opening clause, module and name */
3770 PRINT_TABS(fp
, tab_inserts
);
3771 (void) fprintf(fp
, IPQOS_CONF_ACTION_STR
" {\n");
3772 PRINT_TABS(fp
, tab_inserts
+ 1);
3773 (void) fprintf(fp
, IPQOS_CONF_MODULE_STR
" %s\n",
3774 quote_ws_string(action
->module
));
3775 PRINT_TABS(fp
, tab_inserts
+ 1);
3776 (void) fprintf(fp
, "name %s\n", quote_ws_string(action
->name
));
3778 /* print params clause */
3780 (void) fprintf(fp
, "\n");
3781 res
= printparams(fp
, action
->module
, action
->params
, printall
,
3783 if (res
!= IPQOS_CONF_SUCCESS
) {
3788 * print classes clause for each class if printall is set, else
3789 * just ipqosconf created or permanent classes.
3791 for (cls
= action
->classes
; cls
!= NULL
; cls
= cls
->next
) {
3793 cls
->originator
== IPP_CONFIG_IPQOSCONF
||
3794 cls
->originator
== IPP_CONFIG_PERMANENT
) {
3795 (void) fprintf(fp
, "\n");
3796 printclass(fp
, cls
, printall
, tab_inserts
+ 1);
3801 * print filter clause for each filter if printall is set, else
3802 * just ipqosconf created or permanent filters.
3804 for (flt
= action
->filters
; flt
!= NULL
; flt
= flt
->next
) {
3806 flt
->originator
== IPP_CONFIG_IPQOSCONF
||
3807 flt
->originator
== IPP_CONFIG_PERMANENT
) {
3808 (void) fprintf(fp
, "\n");
3809 res
= printfilter(fp
, action
->module
, &flt
, printall
,
3811 if (res
!= IPQOS_CONF_SUCCESS
) {
3817 PRINT_TABS(fp
, tab_inserts
);
3818 (void) fprintf(fp
, "}\n");
3820 return (IPQOS_CONF_SUCCESS
);
3825 /* *************************************************************** */
3830 ipqos_list_el_t
**listp
,
3831 ipqos_list_el_t
***lendpp
)
3834 while (**lendpp
!= NULL
) {
3835 *lendpp
= &(**lendpp
)->next
;
3841 ipqos_list_el_t
**listp
,
3842 ipqos_list_el_t
*el
)
3849 * given mask calculates the number of bits it spans. The mask must be
3851 * RETURNS: number of bits spanned.
3863 * loop through from lowest byte to highest byte counting the
3864 * number of zero bits till hitting a one bit.
3866 for (byte
= 15; byte
>= 0; byte
--) {
3868 * zero byte, so add 8 to zeros.
3870 if (mask
->s6_addr
[byte
] == 0) {
3873 * non-zero byte, add zero count to zeros.
3876 zeros
+= (ffs((int)mask
->s6_addr
[byte
]) - 1);
3881 * translate zero bits to 32 or 128 bit mask based on af.
3883 if (af
== AF_INET
) {
3893 * Sets the first prefix_len bits in the v4 or v6 address (based upon af)
3894 * contained in the v6 address referenced by addr to 1.
3897 setmask(int prefix_len
, in6_addr_t
*addr
, int af
)
3902 int maskstartbit
= 128 - prefix_len
;
3905 IPQOSCDBG2(L1
, "In setmask, prefix_len: %u, af: %s\n", prefix_len
,
3906 af
== AF_INET
? "AF_INET" : "AF_INET6");
3909 bzero(addr
, sizeof (in6_addr_t
));
3912 /* set which 32bits in *addr are relevant to this af */
3914 if (af
== AF_INET
) {
3916 maskstartbit
= 32 - prefix_len
;
3922 * go through each of the 32bit quantities in 128 bit in6_addr_t
3923 * and set appropriate bits according to prefix_len.
3925 for (i
= 3; i
>= end_u32
; i
--) {
3927 /* does the prefix apply to this 32bits? */
3929 if (maskstartbit
< ((4 - i
) * 32)) {
3931 /* is this 32bits fully masked? */
3933 if (maskstartbit
<= ((3 - i
) * 32)) {
3936 shift
= maskstartbit
% 32;
3938 addr
->_S6_un
._S6_u32
[i
] = (uint32_t)~0;
3939 addr
->_S6_un
._S6_u32
[i
] =
3940 addr
->_S6_un
._S6_u32
[i
] >> shift
;
3941 addr
->_S6_un
._S6_u32
[i
] =
3942 addr
->_S6_un
._S6_u32
[i
] << shift
;
3945 /* translate to NBO */
3946 addr
->_S6_un
._S6_u32
[i
] = htonl(addr
->_S6_un
._S6_u32
[i
]);
3951 * search nvlist for an element with the name specified and return a ptr
3953 * RETURNS: pointer to nvpair named name if found, else NULL.
3956 find_nvpair(nvlist_t
*nvl
, char *name
)
3960 nvpair_t
*match
= NULL
;
3963 IPQOSCDBG0(L1
, "In find_nvpair\n");
3965 nvp
= nvlist_next_nvpair(nvl
, NULL
);
3967 nvp_name
= nvpair_name(nvp
);
3968 if (strcmp(name
, nvp_name
) == 0) {
3971 nvp
= nvlist_next_nvpair(nvl
, nvp
);
3978 * returns a string containing module_name '.' name.
3979 * RETURNS: IPQOS_CONF_ERR if error, else IPQOS_CONF_SUCCESS.
3982 prepend_module_name(
3989 IPQOSCDBG0(L2
, "In prepend_module_name\n");
3991 ret
= malloc(strlen(module
) + strlen(".") + strlen(name
) + 1);
3993 ipqos_msg(MT_ENOSTR
, "malloc");
3997 (void) strcpy(ret
, module
);
3998 (void) strcat(ret
, ".");
3999 (void) strcat(ret
, name
);
4007 * check if element with matching s1 and s2 string is in table table.
4008 * RETURNS: 1 if found else 0.
4017 str_str_t
*ss
= table
;
4019 /* loop through table till matched or end */
4021 while (ss
->s1
[0] != '\0' &&
4022 (strcmp(ss
->s1
, s1
) != 0 || strcmp(ss
->s2
, s2
) != 0)) {
4026 if (ss
->s1
[0] != '\0') {
4035 * check whether name is a valid action/class/filter name.
4036 * RETURNS: IPQOS_CONF_ERR if invalid name else IPQOS_CONF_SUCCESS.
4039 valid_name(char *name
)
4042 IPQOSCDBG1(L1
, "In valid_name: name: %s\n", name
);
4044 /* first char can't be '!' */
4045 if (name
[0] == '!') {
4046 ipqos_msg(MT_ERROR
, gettext("Name not allowed to start with "
4047 "'!', line %u.\n"), lineno
);
4048 return (IPQOS_CONF_ERR
);
4051 /* can't exceed IPQOS_CONF_NAME_LEN size */
4052 if (strlen(name
) >= IPQOS_CONF_NAME_LEN
) {
4053 ipqos_msg(MT_ERROR
, gettext("Name exceeds maximum name length "
4054 "line %u.\n"), lineno
);
4055 return (IPQOS_CONF_ERR
);
4058 return (IPQOS_CONF_SUCCESS
);
4061 /* ********************* string value manip fns ************************** */
4065 * searches through the str_val_nd_t list of string value pairs finding
4066 * the minimum and maximum values for value and places them in the
4067 * integers pointed at by min and max.
4070 get_str_val_value_range(
4076 *min
= *max
= svnp
->sv
.value
;
4079 while (svnp
!= NULL
) {
4080 if (svnp
->sv
.value
> *max
)
4081 *max
= svnp
->sv
.value
;
4082 if (svnp
->sv
.value
< *min
)
4083 *min
= svnp
->sv
.value
;
4089 * add an entry with string string and value val to sv_entrys.
4090 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
4094 str_val_nd_t
**sv_entrys
,
4099 str_val_nd_t
*sv_entry
;
4101 IPQOSCDBG2(L1
, "In add_str_val_entry: string: %s, val: %u\n", string
,
4104 /* alloc new node */
4106 sv_entry
= malloc(sizeof (str_val_nd_t
));
4107 if (sv_entry
== NULL
) {
4108 return (IPQOS_CONF_ERR
);
4113 sv_entry
->sv
.string
= malloc(strlen(string
) + 1);
4114 if (sv_entry
->sv
.string
== NULL
) {
4116 ipqos_msg(MT_ENOSTR
, "malloc");
4117 return (IPQOS_CONF_ERR
);
4119 (void) strcpy(sv_entry
->sv
.string
, string
);
4121 sv_entry
->sv
.value
= val
;
4123 /* place at start of sv_entrys list */
4125 sv_entry
->next
= *sv_entrys
;
4126 *sv_entrys
= sv_entry
;
4128 return (IPQOS_CONF_SUCCESS
);
4132 /* frees all the elements of sv_entrys. */
4134 free_str_val_entrys(
4135 str_val_nd_t
*sv_entrys
)
4138 str_val_nd_t
*sve
= sv_entrys
;
4141 IPQOSCDBG0(L1
, "In free_str_val_entrys\n");
4144 free(sve
->sv
.string
);
4152 * finds the value associated with string and assigns it to value ref'd by
4154 * RETURNS: IPQOS_CONF_ERR if string not found, else IPQOS_CONF_SUCCESS.
4157 str_val_list_lookup(
4163 str_val_nd_t
*sv
= svs
;
4165 IPQOSCDBG1(L1
, "In str_val_list_lookup: %s\n", string
);
4167 /* loop through list and exit when found or list end */
4169 while (sv
!= NULL
) {
4170 if (strcmp(sv
->sv
.string
, string
) == 0) {
4176 /* ret error if not found */
4179 return (IPQOS_CONF_ERR
);
4182 *val
= sv
->sv
.value
;
4184 IPQOSCDBG1(L1
, "svll: Value returned is %u\n", *val
);
4185 return (IPQOS_CONF_SUCCESS
);
4189 /* ************************ conf file read fns ***************************** */
4192 * Reads a uid or username from string 'str' and assigns either the uid
4193 * or associated uid respectively to storage pointed at by 'uid'. The
4194 * function determines whether to read a uid by checking whether the first
4195 * character of 'str' is numeric, in which case it reads a uid; otherwise it
4196 * assumes a username.
4197 * RETURNS: IPQOS_CONF_ERR if a NULL string pointer is passed, the read uid
4198 * doesn't have an entry on the system, or the read username doesn't have an
4199 * entry on the system.
4209 IPQOSCDBG1(L0
, "In readuser, str: %s\n", str
);
4212 return (IPQOS_CONF_ERR
);
4214 * Check if this appears to be a uid, and if so check that a
4215 * corresponding user exists.
4217 if (isdigit((int)str
[0])) {
4219 * Read a 32bit integer and check in doing so that
4220 * we have consumed the whole string.
4222 if (readint32(str
, (int *)uid
, &lo
) != IPQOS_CONF_SUCCESS
||
4224 return (IPQOS_CONF_ERR
);
4225 if (getpwuid(*uid
) == NULL
)
4226 return (IPQOS_CONF_ERR
);
4228 } else { /* This must be a username, so lookup the uid. */
4229 pwd
= getpwnam(str
);
4231 return (IPQOS_CONF_ERR
);
4236 return (IPQOS_CONF_SUCCESS
);
4240 * Reads a range from range_st, either of form 'a-b' or simply 'a'.
4241 * In the former case lower and upper have their values set to a
4242 * and b respectively; in the later lower and upper have both
4243 * their values set to a.
4244 * RETURNS: IPQOS_CONF_ERR if there's a parse error, else IPQOS_CONF_SUCCESS.
4255 IPQOSCDBG1(L0
, "In readrange: string: %s\n", range_st
);
4258 * get range boundarys.
4260 cp
= strchr(range_st
, '-');
4262 if (cp
!= NULL
) { /* we have a range */
4264 *lower
= (int)strtol(range_st
, &end
, 10);
4265 *upper
= (int)strtol(cp
, &end2
, 10);
4268 if ((range_st
== end
) || (*end
!= '\0') ||
4269 (cp
== end
) || (*end2
!= '\0')) {
4270 IPQOSCDBG0(L0
, "Failed reading a-b\n");
4271 return (IPQOS_CONF_ERR
);
4274 } else { /* single value */
4276 *lower
= *upper
= (int)strtol(range_st
, &end
, 10);
4278 if ((range_st
== end
) || (*end
!= '\0')) {
4279 IPQOSCDBG0(L0
, "Failed reading a\n");
4280 return (IPQOS_CONF_ERR
);
4284 return (IPQOS_CONF_SUCCESS
);
4288 * Reads the values of an integer array from fp whose format is:
4289 * '{'RANGE[,RANGE[..]]:VALUE[;RANGE:VALUE[..]]'}', creates an array of size
4290 * arr_size, applies the values to it and points arrp at this array.
4291 * RANGE is one set of array indexes over which this value is to
4292 * be applied, and VALUE either an integer within the range
4293 * llimit - ulimit, or if enum_nvs isn't NULL, an enumeration value
4294 * found in the list enum_nvs. Those values which aren't explicity set
4295 * will be set to -1.
4297 * RETURNS: IPQOS_CONF_ERR on resource or parse error, else IPQOS_CONF_SUCCESS.
4307 str_val_nd_t
*enum_nvs
)
4310 char buf
[5 * IPQOS_CONF_LINEBUF_SZ
];
4324 IPQOSCDBG4(L0
, "In read_int_array: size: %u, lower: %u, upper: %u, "
4325 "first_token: %s\n", arr_size
, llimit
, ulimit
, first_token
);
4328 * read beginning curl.
4330 if (first_token
[0] != CURL_BEGIN
) {
4331 ipqos_msg(MT_ERROR
, gettext("\'{\' missing at line "
4333 return (IPQOS_CONF_ERR
);
4337 * allocate and initialise array for holding read values.
4339 *arrp
= malloc(arr_size
* sizeof (int));
4340 if (*arrp
== NULL
) {
4341 ipqos_msg(MT_ENOSTR
, "malloc");
4342 return (IPQOS_CONF_ERR
);
4344 (void) memset(*arrp
, -1, arr_size
* sizeof (int));
4347 * read whole array declaration string into buffer.
4348 * this is because readtoken doesn't interpret our
4349 * delimeter values specially and may return them
4350 * within another string.
4352 startln
= lineno
; /* store starting lineno for error reports */
4354 res
= readtoken(fp
, &token
);
4355 while ((res
!= IPQOS_CONF_CURL_END
) && (res
!= IPQOS_CONF_ERR
) &&
4356 (res
!= IPQOS_CONF_EOF
)) {
4357 (void) strlcat(buf
, token
, sizeof (buf
));
4359 res
= readtoken(fp
, &token
);
4361 if (res
!= IPQOS_CONF_CURL_END
) {
4364 IPQOSCDBG1(L0
, "array declaration buffer contains: %s\n", buf
);
4367 * loop reading "ranges ':' value;" till end of buffer.
4369 entry
= strtok(buf
, ";");
4370 while (entry
!= NULL
) {
4371 svalue
= strchr(entry
, ':');
4372 if (svalue
== NULL
) { /* missing value string */
4373 IPQOSCDBG0(L0
, "Missing value string\n");
4380 * get value of number or enumerated symbol.
4384 * get rid of surrounding whitespace so as not to
4385 * confuse read_enum_value.
4389 while (*tmp
!= '\0') {
4390 if (isspace(*tmp
)) {
4399 * read enumeration value.
4401 res
= read_enum_value(NULL
, svalue
, enum_nvs
,
4402 (uint32_t *)&value
);
4403 if (res
!= IPQOS_CONF_SUCCESS
)
4406 value
= (int)strtol(svalue
, &end
, 10);
4408 if ((svalue
== end
) || (*end
!= '\0')) {
4409 IPQOSCDBG0(L0
, "Invalid value\n");
4412 IPQOSCDBG1(L0
, "value: %u\n", value
);
4415 * check value within valid range.
4417 if ((value
< llimit
) || (value
> ulimit
)) {
4418 IPQOSCDBG0(L0
, "value out of range\n");
4424 * loop reading ranges for this value.
4426 range
= strtok_r(ranges
, ",", &tmp
);
4427 while (range
!= NULL
) {
4428 res
= readrange(range
, &lower
, &upper
);
4429 if (res
!= IPQOS_CONF_SUCCESS
)
4431 IPQOSCDBG2(L0
, "range: %u - %u\n", lower
, upper
);
4434 if (upper
< lower
) {
4441 * check range valid for array size.
4443 if ((lower
< 0) || (upper
> arr_size
)) {
4444 IPQOSCDBG0(L0
, "Range out of array "
4450 * add this value to array indexes within range.
4452 for (x
= lower
; x
<= upper
; x
++)
4458 range
= strtok_r(NULL
, ",", &tmp
);
4461 entry
= strtok(NULL
, ";");
4464 return (IPQOS_CONF_SUCCESS
);
4468 gettext("Array declaration line %u is invalid.\n"), startln
);
4470 return (IPQOS_CONF_ERR
);
4474 readllong(char *str
, long long *llp
, char **lo
)
4477 *llp
= strtoll(str
, lo
, 0);
4479 return (IPQOS_CONF_ERR
);
4481 return (IPQOS_CONF_SUCCESS
);
4485 readuint8(char *str
, uint8_t *ui8
, char **lo
)
4490 if (readllong(str
, &tmp
, lo
) != 0) {
4491 return (IPQOS_CONF_ERR
);
4493 if (tmp
> UCHAR_MAX
|| tmp
< 0) {
4494 return (IPQOS_CONF_ERR
);
4496 *ui8
= (uint8_t)tmp
;
4497 return (IPQOS_CONF_SUCCESS
);
4501 readuint16(char *str
, uint16_t *ui16
, char **lo
)
4505 if (readllong(str
, &tmp
, lo
) != IPQOS_CONF_SUCCESS
) {
4506 return (IPQOS_CONF_ERR
);
4508 if (tmp
> USHRT_MAX
|| tmp
< 0) {
4509 return (IPQOS_CONF_ERR
);
4511 *ui16
= (uint16_t)tmp
;
4512 return (IPQOS_CONF_SUCCESS
);
4516 readint16(char *str
, int16_t *i16
, char **lo
)
4520 if (readllong(str
, &tmp
, lo
) != 0) {
4521 return (IPQOS_CONF_ERR
);
4523 if (tmp
> SHRT_MAX
|| tmp
< SHRT_MIN
) {
4524 return (IPQOS_CONF_ERR
);
4526 *i16
= (int16_t)tmp
;
4527 return (IPQOS_CONF_SUCCESS
);
4531 readint32(char *str
, int *i32
, char **lo
)
4535 if (readllong(str
, &tmp
, lo
) != IPQOS_CONF_SUCCESS
) {
4536 return (IPQOS_CONF_ERR
);
4538 if (tmp
> INT_MAX
|| tmp
< INT_MIN
) {
4539 return (IPQOS_CONF_ERR
);
4542 return (IPQOS_CONF_SUCCESS
);
4546 readuint32(char *str
, uint32_t *ui32
, char **lo
)
4550 if (readllong(str
, &tmp
, lo
) != IPQOS_CONF_SUCCESS
) {
4551 return (IPQOS_CONF_ERR
);
4553 if (tmp
> UINT_MAX
|| tmp
< 0) {
4554 return (IPQOS_CONF_ERR
);
4556 *ui32
= (uint32_t)tmp
;
4557 return (IPQOS_CONF_SUCCESS
);
4561 * retrieves the index associated with the interface named ifname and assigns
4562 * it to the int pointed to by ifindex.
4563 * RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
4572 struct lifreq lifrq
;
4577 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
4578 ipqos_msg(MT_ENOSTR
, gettext("opening AF_INET socket"));
4579 return (IPQOS_CONF_ERR
);
4582 /* copy ifname into lifreq */
4584 (void) strlcpy(lifrq
.lifr_name
, ifname
, LIFNAMSIZ
);
4586 /* do SIOGLIFINDEX ioctl */
4588 if (ioctl(s
, SIOCGLIFINDEX
, (caddr_t
)&lifrq
) == -1) {
4590 return (IPQOS_CONF_ERR
);
4593 /* Warn if a virtual interface is specified */
4594 if ((ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifrq
) != -1) &&
4595 (lifrq
.lifr_flags
& IFF_VIRTUAL
)) {
4596 ipqos_msg(MT_WARNING
, gettext("Invalid interface"));
4599 *ifindex
= lifrq
.lifr_index
;
4600 return (IPQOS_CONF_SUCCESS
);
4604 * Case insensitively compares the string in str with IPQOS_CONF_TRUE_STR
4605 * and IPQOS_CONF_FALSE_STR and sets boolean pointed to by bool accordingly.
4606 * RETURNS: if failure to match either IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
4609 readbool(char *str
, boolean_t
*bool)
4612 if (strcasecmp(str
, IPQOS_CONF_TRUE_STR
) == 0) {
4614 } else if (strcasecmp(str
, IPQOS_CONF_FALSE_STR
) == 0) {
4617 return (IPQOS_CONF_ERR
);
4620 return (IPQOS_CONF_SUCCESS
);
4624 * reads a protocol name/number from proto_str and assigns the number
4625 * to the uint8 ref'd by proto.
4626 * RETURNS: If not a valid name or protocol number IPQOS_CONF_ERR, else
4627 * IPQOS_CONF_SUCCESS.
4630 readproto(char *proto_str
, uint8_t *proto
)
4633 struct protoent
*pent
;
4637 IPQOSCDBG1(L1
, "In readproto: string: %s\n", proto_str
);
4639 /* try name lookup */
4641 pent
= getprotobyname(proto_str
);
4643 *proto
= pent
->p_proto
;
4645 /* check valid protocol number */
4647 res
= readuint8(proto_str
, proto
, &lo
);
4648 if (res
!= IPQOS_CONF_SUCCESS
|| proto
== 0) {
4649 return (IPQOS_CONF_ERR
);
4653 return (IPQOS_CONF_SUCCESS
);
4657 * reads either a port service, or a port number from port_str and assigns
4658 * the associated port number to short ref'd by port.
4659 * RETURNS: If invalid name and number IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
4662 readport(char *port_str
, uint16_t *port
)
4665 struct servent
*sent
;
4668 IPQOSCDBG1(L1
, "In readport: string: %s\n", port_str
);
4670 /* try service name lookup */
4671 sent
= getservbyname(port_str
, NULL
);
4673 /* failed name lookup so read port number */
4675 if (readuint16(port_str
, port
, &tmp
) != IPQOS_CONF_SUCCESS
||
4677 return (IPQOS_CONF_ERR
);
4679 *port
= htons(*port
);
4681 *port
= sent
->s_port
;
4684 return (IPQOS_CONF_SUCCESS
);
4689 * Reads a curly brace, a string enclosed in double quotes, or a whitespace/
4690 * curly brace delimited string. If a double quote enclosed string the
4691 * closing quotes need to be on the same line.
4693 * on reading a CURL_BEGIN token it returns IPQOS_CONF_CURL_BEGIN,
4694 * on reading a CURL_END token it returns IPQOS_CONF_CURL_END,
4695 * on reading another valid token it returns IPQOS_CONF_SUCCESS.
4696 * for each of these token is set to point at the read string.
4697 * at EOF it returns IPQOS_CONF_EOF and if errors it returns IPQOS_CONF_ERR.
4713 static char *buf
= NULL
;
4716 /* if first call initialize line buf to default size */
4719 bufsize
= IPQOS_CONF_LINEBUF_SZ
;
4720 buf
= malloc(bufsize
);
4722 ipqos_msg(MT_ENOSTR
, "malloc");
4723 return (IPQOS_CONF_ERR
);
4727 /* set buffer postition and size to use whole buffer */
4734 * loop reading lines until we've read a line with a non-whitespace
4739 /* if no leftover from previous invocation */
4744 * loop reading into buffer doubling if necessary until
4745 * we have either read a complete line or reached the
4749 st
= fgets(bpos
, rembuf
, fp
);
4757 ipqos_msg(MT_ENOSTR
,
4759 return (IPQOS_CONF_ERR
);
4766 return (IPQOS_CONF_EOF
);
4769 /* if read a newline */
4771 if (buf
[strlen(buf
) - 1] == '\n') {
4775 /* if read the last line */
4777 } else if (feof(fp
)) {
4781 * not read a full line so buffer size
4782 * is too small, double it and retry.
4786 tmp
= realloc(buf
, bufsize
);
4788 ipqos_msg(MT_ENOSTR
,
4791 return (IPQOS_CONF_ERR
);
4797 * make parameters to fgets read
4798 * into centre of doubled buffer
4799 * so we retain what we've
4802 bpos
= &buf
[(bufsize
/ 2) - 1];
4803 rembuf
= (bufsize
/ 2) + 1;
4810 /* previous leftover, assign to st */
4817 /* truncate at comment */
4819 cmnt
= strchr(st
, '#');
4824 /* Skip any whitespace */
4826 while (isspace(*st
) && *st
!= '\0') {
4830 } while (*st
== '\0');
4833 /* find end of token */
4837 /* if curl advance 1 char */
4839 if (*tmp
== CURL_BEGIN
|| *tmp
== CURL_END
) {
4843 /* if dbl quote read until matching quote */
4845 } else if (*tmp
== '"') {
4849 while (*tmp
!= '"' && *tmp
!= '\n' && *tmp
!= '\0') {
4853 ipqos_msg(MT_ERROR
, gettext("Quoted string exceeds "
4854 "line, line %u.\n"), lineno
);
4856 return (IPQOS_CONF_ERR
);
4861 /* find first whitespace, curl, newline or string end */
4863 while (!isspace(*tmp
) && *tmp
!= CURL_BEGIN
&&
4864 *tmp
!= CURL_END
&& *tmp
!= '\n' && *tmp
!= '\0') {
4869 /* copy token to return */
4871 *token
= malloc(len
+ 1);
4874 ipqos_msg(MT_ENOSTR
, "malloc");
4875 return (IPQOS_CONF_ERR
);
4877 bcopy(st
, *token
, len
);
4878 (*token
)[len
] = '\0';
4880 /* if just read quoted string remove quote from remaining string */
4886 /* if not end of string, store rest for latter parsing */
4888 if (*tmp
!= '\0' && *tmp
!= '\n') {
4892 /* for curl_end and curl_begin return special ret codes */
4894 if ((*token
)[1] == '\0') {
4895 if (**token
== CURL_BEGIN
) {
4896 return (IPQOS_CONF_CURL_BEGIN
);
4897 } else if (**token
== CURL_END
) {
4898 return (IPQOS_CONF_CURL_END
);
4902 return (IPQOS_CONF_SUCCESS
);
4906 * Reads an enumeration bitmask definition from line. The format is:
4907 * { NAME=VAL, NAME2=VAL2 }. The resulting names and values are returned.
4908 * RETURNS: NULL on error, else ptr to name/values.
4910 static str_val_nd_t
*
4911 read_enum_nvs(char *line
, char *module_name
)
4914 str_val_nd_t
*enum_vals
= NULL
;
4923 IPQOSCDBG1(L1
, "In read_enum_nvs, line: %s\n", line
);
4925 /* read opening brace */
4927 cp
= strchr(line
, CURL_BEGIN
);
4929 IPQOSCDBG0(L1
, "missing curl begin\n");
4936 * loop reading 'name = value' entrys seperated by comma until
4937 * reach closing brace.
4942 if (*start
== '\0') {
4943 IPQOSCDBG0(L1
, "missing closing bracket\n");
4948 * read name - read until whitespace, '=', closing curl,
4953 !isspace(*cp
) && *cp
!= '=' && *cp
!= CURL_END
&&
4954 *cp
!= '\0'; cp
++) {}
4957 IPQOSCDBG0(L1
, "Unexpected line end in enum def'n\n");
4960 /* finished definition, exit loop */
4961 } else if (*cp
== CURL_END
) {
4968 name
= malloc(len
+ 1);
4970 ipqos_msg(MT_ENOSTR
, "malloc");
4973 bcopy(start
, name
, len
);
4975 IPQOSCDBG1(L0
, "Stored name: %s\n", name
);
4977 /* read assignment */
4979 start
= strchr(cp
, '=');
4980 if (start
== NULL
) {
4981 IPQOSCDBG0(L1
, "Missing = in enum def'n\n");
4987 ret
= sscanf(++start
, "%x%n", &val
, &readc
);
4989 IPQOSCDBG1(L1
, "sscanf of value failed, string: %s\n",
4994 /* add name value to set */
4996 ret
= add_str_val_entry(&enum_vals
, name
, val
);
4997 if (ret
!= IPQOS_CONF_SUCCESS
) {
4998 IPQOSCDBG0(L1
, "Failed to add str_val entry\n");
5004 /* try reading comma */
5005 cp
= strchr(start
, ',');
5010 /* no comma, advance to char past value last read */
5018 free_str_val_entrys(enum_vals
);
5021 /* if a parse error */
5024 ipqos_msg(MT_ERROR
, gettext("Types file for module %s is "
5025 "corrupt.\n"), module_name
);
5032 * Given mapped_list with is a comma seperated list of map names, and value,
5033 * which is used to index into these maps, the function creates x new entries
5034 * in nvpp, where x is the number of map names specified. Each of these
5035 * entries has the value from the map in the position indexed by value and
5036 * with name module.${MAP_NAME}. The maps are contained in the modules config
5037 * file and have the form:
5038 * map map1 uint32 1,23,32,45,3
5039 * As you can see the map values are uint32, and along with uint8 are the
5040 * only supported types at the moment.
5042 * RETURNS: IPQOS_CONF_ERR if one of the maps specified in mapped_list
5043 * doesn't exist, if value is not a valid map position for a map, or if
5044 * there's a resource failure. otherwise IPQOS_CONF_SUCCESS is returned.
5054 char *map_name
, *lastparam
, *tmpname
;
5056 ipqos_nvtype_t type
;
5057 char dfltst
[IPQOS_VALST_MAXLEN
+1] = "";
5058 str_val_nd_t
*enum_nvs
;
5061 IPQOSCDBG0(L1
, "In read_mapped_values\n");
5063 map_name
= (char *)strtok_r(mapped_list
, ",", &lastparam
);
5064 while (map_name
!= NULL
) {
5065 char *tokval
, *lastval
;
5069 * get map info from types file.
5072 res
= readtype(tfp
, module
, map_name
, &type
, &enum_nvs
,
5073 dfltst
, B_FALSE
, &place
);
5074 if (res
!= IPQOS_CONF_SUCCESS
) {
5075 return (IPQOS_CONF_ERR
);
5079 * Just keep browsing the list till we get to the element
5080 * with the index from the value parameter or the end.
5082 tokval
= (char *)strtok_r(dfltst
, ",", &lastval
);
5084 if (tokval
== NULL
) {
5086 gettext("Invalid value, %u, line %u.\n"),
5088 return (IPQOS_CONF_ERR
);
5090 if (index
++ == value
) {
5093 tokval
= (char *)strtok_r(NULL
, ",", &lastval
);
5098 * create fully qualified parameter name for map value.
5100 tmpname
= prepend_module_name(map_name
, module
);
5101 if (tmpname
== NULL
) {
5102 return (IPQOS_CONF_ERR
);
5106 * add map value with fqn to parameter nvlist.
5108 IPQOSCDBG2(L0
, "Adding map %s, value %u to nvlist\n",
5109 tmpname
, atoi(tokval
));
5111 case IPQOS_DATA_TYPE_UINT8
: {
5112 res
= nvlist_add_byte(*nvlp
, tmpname
,
5113 (uint8_t)atoi(tokval
));
5116 ipqos_msg(MT_ENOSTR
,
5117 "nvlist_add_uint8");
5118 return (IPQOS_CONF_ERR
);
5122 case IPQOS_DATA_TYPE_UINT32
: {
5123 res
= nvlist_add_uint32(*nvlp
, tmpname
,
5124 (uint32_t)atoi(tokval
));
5127 ipqos_msg(MT_ENOSTR
,
5128 "nvlist_add_uint32");
5129 return (IPQOS_CONF_ERR
);
5135 gettext("Types file for module %s is "
5136 "corrupt.\n"), module
);
5137 IPQOSCDBG1(L0
, "Unsupported map type for "
5138 "parameter %s given in types file.\n",
5140 return (IPQOS_CONF_ERR
);
5145 map_name
= (char *)strtok_r(NULL
, ",", &lastparam
);
5148 return (IPQOS_CONF_SUCCESS
);
5152 * Parses the string info_str into it's components. Its format is:
5153 * SIZE','[ENUM_DEF | RANGE], where SIZE is the size of the array,
5154 * ENUM_DEF is the definition of the enumeration for this array,
5155 * and RANGE is the set of values this array can accept. In
5156 * the event this array has an enumeration definition enum_nvs is
5157 * set to point at a str_val_nd_t structure which stores the names
5158 * and values associated with this enumeration. Otherwise, if this
5159 * is not an enumerated array, lower and upper are set to the lower
5160 * and upper values of RANGE.
5161 * RETURNS: IPQOS_CONF_ERR due to unexpected parse errors, else
5162 * IPQOS_CONF_SUCCESS.
5165 read_int_array_info(
5167 str_val_nd_t
**enum_nvs
,
5178 IPQOSCDBG1(L0
, "In read_array_info: info_str: %s\n",
5179 (info_str
!= NULL
) ? info_str
: "NULL");
5181 if (info_str
== NULL
) {
5182 IPQOSCDBG0(L0
, "Null info string\n");
5189 token
= strtok(info_str
, ",");
5190 *size
= (uint32_t)strtol(token
, &end
, 10);
5192 if ((end
== token
) || (*end
!= '\0')) {
5193 IPQOSCDBG0(L0
, "Invalid size\n");
5196 IPQOSCDBG1(L0
, "read size: %u\n", *size
);
5199 * check we have another string.
5201 token
= strtok(NULL
, "\n");
5202 if (token
== NULL
) {
5203 IPQOSCDBG0(L0
, "Missing range/enum def\n");
5206 IPQOSCDBG1(L0
, "range/enum def: %s\n", token
);
5209 * check if enumeration set or integer set and read enumeration
5210 * definition or integer range respectively.
5212 tmp
= strchr(token
, CURL_BEGIN
);
5213 if (tmp
== NULL
) { /* a numeric range */
5214 res
= readrange(token
, lower
, upper
);
5215 if (res
!= IPQOS_CONF_SUCCESS
) {
5216 IPQOSCDBG0(L0
, "Failed reading range\n");
5219 } else { /* an enumeration */
5220 *enum_nvs
= read_enum_nvs(token
, module
);
5221 if (*enum_nvs
== NULL
) {
5222 IPQOSCDBG0(L0
, "Failed reading enum def\n");
5227 return (IPQOS_CONF_SUCCESS
);
5230 gettext("Types file for module %s is corrupt.\n"), module
);
5231 return (IPQOS_CONF_ERR
);
5235 * reads the value of an enumeration parameter from first_token and fp.
5236 * first_token is the first token of the value.
5237 * The format expected is NAME | { NAME1 [, NAME2 ] [, NAME3 ] }.
5238 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
5244 str_val_nd_t
*enum_vals
,
5253 int name_expected
= 0;
5255 IPQOSCDBG0(L1
, "In read_enum_value\n");
5257 /* init param val */
5260 /* first token not curl_begin, so lookup its value */
5262 if (*first_token
!= CURL_BEGIN
) {
5263 ret
= str_val_list_lookup(enum_vals
, first_token
, val
);
5264 if (ret
!= IPQOS_CONF_SUCCESS
) {
5266 gettext("Unrecognized value, %s, line %u.\n"),
5267 first_token
, lineno
);
5271 /* curl_begin, so read values till curl_end, dicing at ',' */
5279 * no leftover from pervious iteration so read new
5280 * token. This leftover happens because readtoken
5281 * doesn't interpret comma's as special characters
5282 * and thus could return 'val1,val2' as one token.
5283 * If this happens the val1 will be used in the
5284 * current iteration and what follows saved in lo
5285 * for processing by successive iterations.
5289 ret
= readtoken(fp
, &tk
);
5290 if (ret
== IPQOS_CONF_ERR
) {
5292 } else if (ret
== IPQOS_CONF_EOF
) {
5294 gettext("Unexpected EOF.\n"));
5295 return (IPQOS_CONF_ERR
);
5298 } else { /* previous leftover, so use it */
5300 IPQOSCDBG1(L1
, "Using leftover %s.\n", lo
);
5305 if (name_expected
) {
5306 if (ret
== IPQOS_CONF_CURL_END
||
5309 gettext("Malformed value list "
5310 "line %u.\n"), lineno
);
5312 return (IPQOS_CONF_ERR
);
5316 * check if this token contains a ',' and
5317 * if so store it and what follows for next
5320 cm
= strchr(tk
, ',');
5322 lo
= malloc(strlen(cm
) + 1);
5324 ipqos_msg(MT_ENOSTR
, "malloc");
5326 return (IPQOS_CONF_ERR
);
5329 (void) strcpy(lo
, cm
);
5334 /* get name value and add to total val */
5336 ret
= str_val_list_lookup(enum_vals
, tk
, &u32
);
5337 if (ret
!= IPQOS_CONF_SUCCESS
) {
5339 gettext("Unrecognized value, %s, "
5340 "line %u.\n"), tk
, lineno
);
5342 return (IPQOS_CONF_ERR
);
5348 /* comma or curl end accepted */
5351 /* we've reached curl_end so break */
5353 if (ret
== IPQOS_CONF_CURL_END
) {
5357 /* not curl end and not comma */
5359 } else if (tk
[0] != ',') {
5361 gettext("Malformed value list "
5362 "line %u.\n"), lineno
);
5364 return (IPQOS_CONF_ERR
);
5368 * store anything after the comma for next
5371 if (tk
[1] != '\0') {
5372 lo
= malloc(strlen(&tk
[1]) + 1);
5374 ipqos_msg(MT_ENOSTR
, "malloc");
5376 return (IPQOS_CONF_ERR
);
5378 (void) strcpy(lo
, &tk
[1]);
5388 IPQOSCDBG1(L1
, "value returned is: %u\n", *val
);
5390 return (IPQOS_CONF_SUCCESS
);
5394 * read the set of permanent classes/filter from the types file ref'd by tfp
5395 * and store them in a string table pointed to by perm_items,
5396 * with *nitems getting set to number of items read. perm_filters is set
5397 * to 1 if we're searching for permanent filters, else 0 for classes.
5398 * RETURNS: IPQOS_CONF_ERR if any errors, else IPQOS_CONF_SUCCESS.
5409 char lbuf
[IPQOS_CONF_TYPE_LINE_LEN
];
5411 char name
[IPQOS_CONF_NAME_LEN
+1];
5412 char foo
[IPQOS_CONF_NAME_LEN
+1];
5414 char **items
= NULL
;
5418 IPQOSCDBG0(L1
, "In read_perm_items\n");
5421 /* seek to start of types file */
5423 if (fseek(tfp
, 0, SEEK_SET
) != 0) {
5424 ipqos_msg(MT_ENOSTR
, "fseek");
5425 return (IPQOS_CONF_ERR
);
5428 /* select which marker were looking for */
5431 marker
= IPQOS_CONF_PERM_FILTER_MK
;
5433 marker
= IPQOS_CONF_PERM_CLASS_MK
;
5436 /* scan file line by line till end */
5438 while (fgets(lbuf
, IPQOS_CONF_TYPE_LINE_LEN
, tfp
) != NULL
) {
5441 * if the line is marked as containing a default item name
5442 * read the name, extend the items string array
5443 * and store the string off the array.
5445 if (strncmp(lbuf
, marker
, strlen(marker
)) == 0) {
5448 "%" VAL2STR(IPQOS_CONF_NAME_LEN
) "s"
5449 "%" VAL2STR(IPQOS_CONF_NAME_LEN
) "s",
5453 gettext("Types file for module %s is "
5454 "corrupt.\n"), module_name
);
5455 IPQOSCDBG1(L0
, "Missing name with a %s.\n",
5460 /* extend items array to accomodate new item */
5462 tmp
= reallocarray(items
, cnt
+ 1, sizeof (char *));
5464 ipqos_msg(MT_ENOSTR
, "realloc");
5470 /* copy and store item name */
5472 items
[cnt
] = malloc(strlen(name
) + 1);
5473 if (items
[cnt
] == NULL
) {
5474 ipqos_msg(MT_ENOSTR
, "malloc");
5478 (void) strcpy(items
[cnt
], name
);
5482 IPQOSCDBG1(L1
, "stored %s in perm items array\n",
5487 *perm_items
= items
;
5490 return (IPQOS_CONF_SUCCESS
);
5492 for (cnt
--; cnt
>= 0; cnt
--)
5495 return (IPQOS_CONF_ERR
);
5499 * Searches types file ref'd by tfp for the parameter named name
5500 * with the place corresponding with place parameter. The format
5501 * of the lines in the file are:
5502 * PLACE NAME TYPE [ ENUM_DEF ] [ DEFAULT_STR ]
5503 * The ENUM_DEF is an enumeration definition and is only present
5504 * for parameters of type enum. DEFAULT_STR is a default value for
5505 * this parameter. If present type is set to the appropriate type
5506 * enumeration and dfltst filled with DEFAULT_STR if one was set.
5507 * Also if the type is enum enum_nvps is made to point at a
5508 * set of name value pairs representing ENUM_DEF.
5510 * RETURNS: If any resource errors occur, or a matching parameter
5511 * isn't found IPQOS_CONF_ERR is returned, else IPQOS_CONF_SUCCESS.
5518 ipqos_nvtype_t
*type
,
5519 str_val_nd_t
**enum_nvps
,
5521 boolean_t allow_ipgpc_priv
,
5526 char lbuf
[IPQOS_CONF_TYPE_LINE_LEN
];
5527 char param
[IPQOS_CONF_PNAME_LEN
+1];
5528 char typest
[IPQOS_CONF_TYPE_LEN
+1];
5529 char place_st
[IPQOS_CONF_TYPE_LEN
+1];
5535 IPQOSCDBG1(L1
, "In readtype: param: %s\n", name
);
5539 * if allow_ipgpc_priv is true then we allow ipgpc parameters that are
5540 * private between ipqosconf and ipgpc. eg. address masks, port masks.
5542 if (allow_ipgpc_priv
&& strcmp(module_name
, IPGPC_NAME
) == 0) {
5543 ipgpc_nm
= prepend_module_name(name
, IPGPC_NAME
);
5544 if (ipgpc_nm
== NULL
) {
5545 return (IPQOS_CONF_ERR
);
5548 if (strcmp(ipgpc_nm
, IPGPC_SADDR_MASK
) == 0 ||
5549 strcmp(ipgpc_nm
, IPGPC_DADDR_MASK
) == 0) {
5550 *type
= IPQOS_DATA_TYPE_ADDRESS_MASK
;
5551 return (IPQOS_CONF_SUCCESS
);
5552 } else if (strcmp(ipgpc_nm
, IPGPC_SPORT_MASK
) == 0 ||
5553 strcmp(ipgpc_nm
, IPGPC_DPORT_MASK
) == 0) {
5554 *type
= IPQOS_DATA_TYPE_UINT16
;
5555 return (IPQOS_CONF_SUCCESS
);
5556 } else if (strcmp(ipgpc_nm
, IPGPC_FILTER_TYPE
) == 0) {
5557 *type
= IPQOS_DATA_TYPE_UINT32
;
5558 return (IPQOS_CONF_SUCCESS
);
5559 } else if (strcmp(ipgpc_nm
, IPGPC_IF_INDEX
) == 0) {
5560 *type
= IPQOS_DATA_TYPE_IFINDEX
;
5561 return (IPQOS_CONF_SUCCESS
);
5568 * read upto and including module version line.
5570 if (read_tfile_ver(tfp
, IPQOS_MOD_STR
, module_name
) == -1)
5571 return (IPQOS_CONF_ERR
);
5575 * loop reading lines of the types file until named parameter
5578 while (fgets(lbuf
, IPQOS_CONF_TYPE_LINE_LEN
, tfp
) != NULL
) {
5581 * check whether blank or commented line; if so skip
5583 for (cp
= lbuf
; isspace(*cp
) && *cp
!= '\0'; cp
++) {}
5584 if (*cp
== '\0' || *cp
== '#') {
5591 * read place, param, type and if present default str
5595 "%" VAL2STR(IPQOS_CONF_TYPE_LEN
) "s "
5596 "%" VAL2STR(IPQOS_CONF_PNAME_LEN
) "s "
5597 "%" VAL2STR(IPQOS_CONF_TYPE_LEN
) "s "
5598 "%" VAL2STR(IPQOS_VALST_MAXLEN
) "s",
5599 place_st
, param
, typest
, dfltst
);
5602 gettext("Types file for module %s is corrupt.\n"),
5604 IPQOSCDBG0(L0
, "sscanf failed to read 3 strings.\n");
5605 return (IPQOS_CONF_ERR
);
5609 * if the place and name match no need to look any further.
5611 if ((*place
== PL_ANY
) ||
5612 ((*place
== PL_PARAMS
) &&
5613 strcmp(place_st
, IPQOS_PLACE_PRM_STR
) == 0) ||
5614 ((*place
== PL_FILTER
) &&
5615 strcmp(place_st
, IPQOS_PLACE_FILTER_STR
) == 0) ||
5616 ((*place
== PL_MAP
) &&
5617 strcmp(place_st
, IPQOS_PLACE_MAP_STR
) == 0)) {
5618 if (strcmp(param
, name
) == 0) {
5626 gettext("Invalid parameter, %s, line %u.\n"), name
,
5628 return (IPQOS_CONF_ERR
);
5632 * set the place parameter to the actual place when the PL_ANY flag
5635 if (*place
== PL_ANY
) {
5636 if (strcmp(place_st
, IPQOS_PLACE_PRM_STR
) == 0) {
5638 } else if (strcmp(place_st
, IPQOS_PLACE_FILTER_STR
) == 0) {
5640 } else if (strcmp(place_st
, IPQOS_PLACE_MAP_STR
) == 0) {
5646 * get type enumeration
5648 for (x
= 0; nv_types
[x
].string
[0]; x
++) {
5649 if (strcmp(nv_types
[x
].string
, typest
) == 0) {
5654 * check that we have a type corresponding with the one the types
5657 if (nv_types
[x
].string
[0] == '\0') {
5659 gettext("Types file for module %s is corrupt.\n"),
5661 return (IPQOS_CONF_ERR
);
5663 *type
= nv_types
[x
].value
;
5666 * if enumeration type get set of name/vals and any default value
5668 if (*type
== IPQOS_DATA_TYPE_ENUM
) {
5669 *enum_nvps
= read_enum_nvs(lbuf
, module_name
);
5670 if (*enum_nvps
== NULL
) {
5671 return (IPQOS_CONF_ERR
);
5675 cp
= strchr(lbuf
, CURL_END
);
5677 "%" VAL2STR(IPQOS_VALST_MAXLEN
) "s", dfltst
);
5681 IPQOSCDBG2(L1
, "read type: %s default: %s\n", nv_types
[x
].string
,
5682 *dfltst
? dfltst
: "None");
5683 return (IPQOS_CONF_SUCCESS
);
5688 * Reads a name and a value from file ref'd by cfp into list indirectly
5689 * ref'd by nvlp; If this list is NULL it will be created to accomodate
5690 * the name/value. The name must be either a special token for
5691 * for the place, or be present in the module types file ref'd by tfp.
5692 * *type is set to the enumeration of the type of the parameter and
5693 * nvp to point at the element with the nvlp ref'd list.
5694 * RETURNS: IPQOS_CONF_CURL_END if read CURL_END as name,
5695 * IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
5703 ipqos_nvtype_t
*type
,
5712 str_val_nd_t
*enum_nvs
= NULL
;
5713 char dfltst
[IPQOS_VALST_MAXLEN
+1];
5715 IPQOSCDBG0(L1
, "in readnvpair\n");
5720 res
= readtoken(cfp
, &name
);
5723 * if reached eof, curl end or error encountered return to caller
5725 if (res
== IPQOS_CONF_EOF
) {
5726 ipqos_msg(MT_ERROR
, gettext("Unexpected EOF.\n"));
5727 return (IPQOS_CONF_ERR
);
5728 } else if (res
== IPQOS_CONF_ERR
) {
5730 } else if (res
== IPQOS_CONF_CURL_END
) {
5738 res
= readtoken(cfp
, &valst
);
5741 * check we've read a valid value
5743 if (res
!= IPQOS_CONF_SUCCESS
&& res
!= IPQOS_CONF_CURL_BEGIN
) {
5744 if (res
== IPQOS_CONF_EOF
) {
5745 ipqos_msg(MT_ERROR
, gettext("Unexpected EOF.\n"));
5746 } else if (res
== IPQOS_CONF_CURL_END
) {
5748 gettext("Missing parameter value line %u.\n"),
5751 } /* we do nothing special for IPQOS_CONF_ERR */
5753 return (IPQOS_CONF_ERR
);
5757 * check for generic parameters.
5760 if ((place
== PL_CLASS
) &&
5761 strcmp(name
, IPQOS_CONF_NEXT_ACTION_STR
) == 0) {
5762 *type
= IPQOS_DATA_TYPE_ACTION
;
5764 } else if (place
== PL_PARAMS
&&
5765 strcmp(name
, IPQOS_CONF_GLOBAL_STATS_STR
) == 0 ||
5766 place
== PL_CLASS
&&
5767 strcmp(name
, IPQOS_CONF_STATS_ENABLE_STR
) == 0) {
5768 *type
= IPQOS_DATA_TYPE_BOOLEAN
;
5770 } else if (tfp
== NULL
||
5771 ((place
!= PL_PARAMS
) && strcmp(name
, IPQOS_CONF_NAME_STR
) == 0) ||
5772 (place
== PL_FILTER
) && (strcmp(name
, IPQOS_CONF_CLASS_STR
) ==
5774 (place
== PL_ACTION
) && (strcmp(name
, IPQOS_CONF_MODULE_STR
) ==
5776 *type
= IPQOS_DATA_TYPE_STRING
;
5778 } else { /* if not generic parameter */
5780 * get type from types file
5782 if (readtype(tfp
, module_name
, name
, type
, &enum_nvs
, dfltst
,
5783 B_FALSE
, &place
) != IPQOS_CONF_SUCCESS
) {
5786 return (IPQOS_CONF_ERR
);
5790 * get full module prefix parameter name
5793 if ((name
= prepend_module_name(name
, module_name
)) == NULL
) {
5800 IPQOSCDBG3(L1
, "NVP, name: %s, str_value: %s, type: %s\n", name
,
5801 valst
, nv_types
[*type
].string
);
5805 * create nvlist if not present already
5807 if (*nvlp
== NULL
) {
5808 res
= nvlist_alloc(nvlp
, NV_UNIQUE_NAME
, 0);
5810 ipqos_msg(MT_ENOSTR
, "nvlist_alloc");
5813 return (IPQOS_CONF_ERR
);
5818 * check we haven't already read this parameter
5820 if (find_nvpair(*nvlp
, name
)) {
5821 ipqos_msg(MT_ERROR
, gettext("Duplicate parameter line %u.\n"),
5827 * convert value string to appropriate type and add to nvlist
5831 case IPQOS_DATA_TYPE_IFNAME
: {
5834 res
= readifindex(valst
, (int *)&ifidx
);
5835 if (res
== IPQOS_CONF_SUCCESS
) {
5836 res
= nvlist_add_uint32(*nvlp
, IPGPC_IF_INDEX
,
5839 ipqos_msg(MT_ENOSTR
,
5840 "nvlist_add_uint32");
5843 (void) nvlist_remove_all(*nvlp
, name
);
5845 * change name to point at the name of the
5846 * new ifindex nvlist entry as name is used
5847 * later in the function.
5850 name
= malloc(strlen(IPGPC_IF_INDEX
) + 1);
5852 ipqos_msg(MT_ENOSTR
, "malloc");
5855 (void) strcpy(name
, IPGPC_IF_INDEX
);
5859 case IPQOS_DATA_TYPE_PROTO
: {
5862 res
= readproto(valst
, &proto
);
5863 if (res
== IPQOS_CONF_SUCCESS
) {
5864 res
= nvlist_add_byte(*nvlp
, name
, proto
);
5866 ipqos_msg(MT_ENOSTR
, "nvlist_add_byte");
5872 case IPQOS_DATA_TYPE_PORT
: {
5875 res
= readport(valst
, &port
);
5876 if (res
== IPQOS_CONF_SUCCESS
) {
5880 res
= nvlist_add_uint16(*nvlp
, name
, port
);
5882 ipqos_msg(MT_ENOSTR
,
5883 "nvlist_add_uint16");
5887 /* add appropriate all ones port mask */
5889 if (strcmp(name
, IPGPC_DPORT
) == 0) {
5890 res
= nvlist_add_uint16(*nvlp
,
5891 IPGPC_DPORT_MASK
, ~0);
5893 } else if (strcmp(name
, IPGPC_SPORT
) == 0) {
5894 res
= nvlist_add_uint16(*nvlp
,
5895 IPGPC_SPORT_MASK
, ~0);
5898 ipqos_msg(MT_ENOSTR
,
5899 "nvlist_add_uint16");
5905 case IPQOS_DATA_TYPE_ADDRESS
:
5906 case IPQOS_DATA_TYPE_ACTION
:
5907 case IPQOS_DATA_TYPE_STRING
:
5908 res
= nvlist_add_string(*nvlp
, name
, valst
);
5910 ipqos_msg(MT_ENOSTR
, "nvlist_add_string");
5914 case IPQOS_DATA_TYPE_BOOLEAN
: {
5917 res
= readbool(valst
, &b
);
5918 if (res
== IPQOS_CONF_SUCCESS
) {
5919 res
= nvlist_add_uint32(*nvlp
, name
,
5922 ipqos_msg(MT_ENOSTR
,
5923 "nvlist_add_uint32");
5929 case IPQOS_DATA_TYPE_UINT8
: {
5932 res
= readuint8(valst
, &u8
, &tmp
);
5933 if (res
== IPQOS_CONF_SUCCESS
) {
5934 res
= nvlist_add_byte(*nvlp
, name
, u8
);
5936 ipqos_msg(MT_ENOSTR
, "nvlist_add_byte");
5942 case IPQOS_DATA_TYPE_INT16
: {
5945 res
= readint16(valst
, &i16
, &tmp
);
5946 if (res
== IPQOS_CONF_SUCCESS
) {
5947 res
= nvlist_add_int16(*nvlp
, name
, i16
);
5949 ipqos_msg(MT_ENOSTR
,
5950 "nvlist_add_int16");
5956 case IPQOS_DATA_TYPE_UINT16
: {
5959 res
= readuint16(valst
, &u16
, &tmp
);
5960 if (res
== IPQOS_CONF_SUCCESS
) {
5961 res
= nvlist_add_uint16(*nvlp
, name
, u16
);
5963 ipqos_msg(MT_ENOSTR
,
5964 "nvlist_add_int16");
5970 case IPQOS_DATA_TYPE_INT32
: {
5973 res
= readint32(valst
, &i32
, &tmp
);
5974 if (res
== IPQOS_CONF_SUCCESS
) {
5975 res
= nvlist_add_int32(*nvlp
, name
, i32
);
5977 ipqos_msg(MT_ENOSTR
,
5978 "nvlist_add_int32");
5984 case IPQOS_DATA_TYPE_UINT32
: {
5987 res
= readuint32(valst
, &u32
, &tmp
);
5988 if (res
== IPQOS_CONF_SUCCESS
) {
5989 res
= nvlist_add_uint32(*nvlp
, name
, u32
);
5991 ipqos_msg(MT_ENOSTR
,
5992 "nvlist_add_uint32");
5998 case IPQOS_DATA_TYPE_ENUM
: {
6001 res
= read_enum_value(cfp
, valst
, enum_nvs
, &val
);
6002 if (res
== IPQOS_CONF_SUCCESS
) {
6003 res
= nvlist_add_uint32(*nvlp
, name
, val
);
6005 ipqos_msg(MT_ENOSTR
,
6006 "nvlist_add_uint32");
6015 * For now the dfltst contains a comma separated list of the
6016 * type we need this parameter to be mapped to.
6017 * read_mapped_values will fill in all the mapped parameters
6018 * and their values in the nvlist.
6020 case IPQOS_DATA_TYPE_M_INDEX
: {
6023 res
= readuint8(valst
, &u8
, &tmp
);
6024 if (res
== IPQOS_CONF_SUCCESS
) {
6025 res
= nvlist_add_byte(*nvlp
, name
, u8
);
6027 ipqos_msg(MT_ENOSTR
,
6028 "nvlist_add_uint8");
6032 *type
= IPQOS_DATA_TYPE_UINT8
;
6035 res
= read_mapped_values(tfp
, nvlp
, module_name
,
6037 if (res
!= IPQOS_CONF_SUCCESS
) {
6042 case IPQOS_DATA_TYPE_INT_ARRAY
: {
6043 str_val_nd_t
*arr_enum_nvs
= NULL
;
6045 int llimit
= 0, ulimit
= 0;
6049 * read array info from types file.
6051 res
= read_int_array_info(dfltst
, &arr_enum_nvs
, &size
,
6052 &llimit
, &ulimit
, module_name
);
6053 if (res
!= IPQOS_CONF_SUCCESS
) {
6058 * read array contents from config file and construct
6061 res
= read_int_array(cfp
, valst
, &arr
, size
, llimit
,
6062 ulimit
, arr_enum_nvs
);
6063 if (res
!= IPQOS_CONF_SUCCESS
) {
6068 * add array to nvlist.
6070 res
= nvlist_add_int32_array(*nvlp
, name
, arr
, size
);
6072 ipqos_msg(MT_ENOSTR
, "nvlist_add_int32");
6077 * free uneeded resources.
6081 free_str_val_entrys(arr_enum_nvs
);
6085 case IPQOS_DATA_TYPE_USER
: {
6088 res
= readuser(valst
, &uid
);
6089 if (res
== IPQOS_CONF_SUCCESS
) {
6090 res
= nvlist_add_int32(*nvlp
, name
, (int)uid
);
6092 ipqos_msg(MT_ENOSTR
,
6093 "nvlist_add_int32");
6099 #ifdef _IPQOS_CONF_DEBUG
6102 * we shouldn't have a type that doesn't have a switch
6110 ipqos_msg(MT_ERROR
, gettext("Invalid %s, line %u.\n"),
6111 nv_types
[*type
].string
, lineno
);
6115 /* set the nvp parameter to point at the newly added nvlist entry */
6117 *nvp
= find_nvpair(*nvlp
, name
);
6122 free_str_val_entrys(enum_nvs
);
6123 return (IPQOS_CONF_SUCCESS
);
6127 if (enum_nvs
!= NULL
)
6128 free_str_val_entrys(enum_nvs
);
6129 return (IPQOS_CONF_ERR
);
6133 * read a parameter clause from cfp into *params.
6134 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
6141 ipqos_conf_params_t
*params
)
6146 ipqos_nvtype_t type
;
6150 char tmp
[IPQOS_CONF_PNAME_LEN
];
6153 IPQOSCDBG0(L0
, "in readparams\n");
6155 /* read beginning curl */
6157 res
= read_curl_begin(cfp
);
6158 if (res
!= IPQOS_CONF_SUCCESS
) {
6163 * loop reading nvpairs, adding to params nvlist until encounter
6169 res
= readnvpair(cfp
, tfp
, ¶ms
->nvlist
,
6170 &nvp
, &type
, PL_PARAMS
, module_name
);
6171 if (res
== IPQOS_CONF_ERR
) {
6174 /* we have finished reading params */
6176 } else if (res
== IPQOS_CONF_CURL_END
) {
6181 * read global stats - place into params struct and remove
6184 if (strcmp(nvpair_name(nvp
), IPQOS_CONF_GLOBAL_STATS_STR
) ==
6186 /* check we haven't read stats before */
6190 gettext("Duplicate parameter line %u.\n"),
6196 (void) nvpair_value_uint32(nvp
, (uint32_t *)&bl
);
6197 params
->stats_enable
= bl
;
6198 (void) nvlist_remove_all(params
->nvlist
,
6199 IPQOS_CONF_GLOBAL_STATS_STR
);
6203 * read action type parameter - add it to list of action refs.
6204 * also, if it's one of continue or drop virtual actions
6205 * change the action name to their special ipp names in
6206 * the action ref list and the nvlist.
6208 } else if (type
== IPQOS_DATA_TYPE_ACTION
) {
6210 /* get name and value from nvlist */
6212 nm
= nvpair_name(nvp
);
6213 (void) nvpair_value_string(nvp
, &action
);
6215 /* if virtual action names change to ipp name */
6217 if ((strcmp(action
, IPQOS_CONF_CONT_STR
) == 0) ||
6218 strcmp(action
, IPQOS_CONF_DROP_STR
) == 0) {
6220 * we copy nm to a seperate buffer as nv_pair
6221 * name above gave us a ptr to internal
6222 * memory which causes strange behaviour
6223 * when we re-value that nvlist element.
6225 (void) strlcpy(tmp
, nm
, sizeof (tmp
));
6229 /* modify nvlist entry and change action */
6231 if (strcmp(action
, IPQOS_CONF_CONT_STR
) == 0) {
6232 action
= IPP_ANAME_CONT
;
6233 res
= nvlist_add_string(params
->nvlist
,
6236 action
= IPP_ANAME_DROP
;
6237 res
= nvlist_add_string(params
->nvlist
,
6241 ipqos_msg(MT_ENOSTR
,
6242 "nvlist_add_string");
6247 /* add action reference to params */
6249 res
= add_aref(¶ms
->actions
, nm
, action
);
6253 return (IPQOS_CONF_SUCCESS
);
6256 if (params
->nvlist
) {
6257 nvlist_free(params
->nvlist
);
6258 params
->nvlist
= NULL
;
6260 if (params
->actions
) {
6261 free_arefs(params
->actions
);
6262 params
->actions
= NULL
;
6264 return (IPQOS_CONF_ERR
);
6267 /* ************************* class manip fns ****************************** */
6272 * make dst point at a dupicate class struct with duplicate elements to src.
6273 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
6277 ipqos_conf_class_t
*src
,
6278 ipqos_conf_class_t
**dst
)
6281 ipqos_conf_class_t
*cls
;
6284 IPQOSCDBG1(DIFF
, "In dup_class: class: %s\n", src
->name
);
6285 cls
= alloc_class();
6287 return (IPQOS_CONF_ERR
);
6293 /* we're not interested in the nvlist for a class */
6297 /* copy first action reference */
6299 res
= add_aref(&cls
->alist
, src
->alist
->field
, src
->alist
->name
);
6300 if (res
!= IPQOS_CONF_SUCCESS
) {
6307 return (IPQOS_CONF_SUCCESS
);
6311 * create a zero'd class struct and return a ptr to it.
6312 * RETURNS: ptr to struct on success, NULL otherwise.
6314 static ipqos_conf_class_t
*
6318 ipqos_conf_class_t
*class;
6320 class = malloc(sizeof (ipqos_conf_class_t
));
6322 bzero(class, sizeof (ipqos_conf_class_t
));
6324 ipqos_msg(MT_ENOSTR
, "malloc");
6330 /* frees up all memory occupied by a filter struct and its contents. */
6332 free_class(ipqos_conf_class_t
*cls
)
6338 /* free its nvlist if present */
6340 nvlist_free(cls
->nvlist
);
6342 /* free its action refs if present */
6345 free_arefs(cls
->alist
);
6347 /* finally free class itself */
6352 * Checks whether there is a class called class_nm in classes list.
6353 * RETURNS: ptr to first matched class, else if not matched NULL.
6355 static ipqos_conf_class_t
*
6358 ipqos_conf_class_t
*classes
)
6361 ipqos_conf_class_t
*cls
;
6363 IPQOSCDBG1(L1
, "In classexist: name: %s\n", class_nm
);
6365 for (cls
= classes
; cls
; cls
= cls
->next
) {
6366 if (strcmp(class_nm
, cls
->name
) == 0) {
6376 /* ************************** filter manip fns **************************** */
6381 * Checks whether there is a filter called filter_nm with instance number
6382 * instance in filters list created by us or permanent. Instance value -1
6384 * RETURNS: ptr to first matched filter, else if not matched NULL.
6386 static ipqos_conf_filter_t
*
6390 ipqos_conf_filter_t
*filters
)
6393 IPQOSCDBG2(L1
, "In filterexist: name :%s, inst: %d\n", filter_nm
,
6397 if (strcmp(filters
->name
, filter_nm
) == 0 &&
6398 (instance
== -1 || filters
->instance
== instance
) &&
6399 (filters
->originator
== IPP_CONFIG_IPQOSCONF
||
6400 filters
->originator
== IPP_CONFIG_PERMANENT
)) {
6403 filters
= filters
->next
;
6409 * allocate and zero a filter structure.
6410 * RETURNS: NULL on error, else ptr to filter struct.
6412 static ipqos_conf_filter_t
*
6416 ipqos_conf_filter_t
*flt
;
6418 flt
= malloc(sizeof (ipqos_conf_filter_t
));
6420 bzero(flt
, sizeof (ipqos_conf_filter_t
));
6423 ipqos_msg(MT_ENOSTR
, "malloc");
6429 /* free flt and all it's contents. */
6432 free_filter(ipqos_conf_filter_t
*flt
)
6435 IPQOSCDBG2(L1
, "In free_filter: filter: %s, inst: %d\n", flt
->name
,
6441 free(flt
->src_nd_name
);
6442 free(flt
->dst_nd_name
);
6443 nvlist_free(flt
->nvlist
);
6448 * makes a copy of ofilter and its contents and points nfilter at it. It
6449 * also adds an instance number to the filter and if either saddr or
6450 * daddr are non-null that address to the filters nvlist along with
6451 * an all 1s address mask and the af.
6452 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
6456 ipqos_conf_filter_t
*ofilter
,
6457 ipqos_conf_filter_t
**nfilter
,
6459 int inv6
, /* if saddr or daddr set and v4 filter are they in v6 addr */
6465 ipqos_conf_filter_t
*nf
;
6468 in6_addr_t all_1s_v6
;
6470 IPQOSCDBG4(MHME
, "In dup_filter: name: %s, af: %u, inv6: %u, ins: %d\n",
6471 ofilter
->name
, af
, inv6
, inst
);
6473 /* show src address and dst address if present */
6474 #ifdef _IPQOS_CONF_DEBUG
6475 if (ipqosconf_dbg_flgs
& MHME
) {
6479 (void) fprintf(stderr
, "saddr: %s\n",
6480 inet_ntop(inv6
? AF_INET6
: AF_INET
, saddr
, st
,
6485 (void) fprintf(stderr
, "daddr: %s\n",
6486 inet_ntop(inv6
? AF_INET6
: AF_INET
, daddr
, st
,
6490 #endif /* _IPQOS_CONF_DEBUG */
6492 /* init local v6 address to 0 */
6493 (void) bzero(&v6addr
, sizeof (in6_addr_t
));
6495 /* create an all 1s address for use as mask */
6496 (void) memset(&all_1s_v6
, ~0, sizeof (in6_addr_t
));
6498 /* create a new filter */
6500 nf
= alloc_filter();
6502 return (IPQOS_CONF_ERR
);
6505 /* struct copy old filter to new */
6508 /* copy src filters nvlist if there is one to copy */
6510 if (ofilter
->nvlist
) {
6511 res
= nvlist_dup(ofilter
->nvlist
, &nf
->nvlist
, 0);
6513 ipqos_msg(MT_ENOSTR
, "nvlist_dup");
6518 /* copy src and dst node names if present */
6520 if (ofilter
->src_nd_name
) {
6521 nf
->src_nd_name
= malloc(strlen(ofilter
->src_nd_name
) + 1);
6522 if (nf
->src_nd_name
== NULL
) {
6523 ipqos_msg(MT_ENOSTR
, "malloc");
6526 (void) strcpy(nf
->src_nd_name
, ofilter
->src_nd_name
);
6528 if (ofilter
->dst_nd_name
) {
6529 nf
->dst_nd_name
= malloc(strlen(ofilter
->dst_nd_name
) + 1);
6530 if (nf
->dst_nd_name
== NULL
) {
6531 ipqos_msg(MT_ENOSTR
, "malloc");
6534 (void) strcpy(nf
->dst_nd_name
, ofilter
->dst_nd_name
);
6537 /* add filter addresses type */
6539 res
= nvlist_add_byte(nf
->nvlist
, IPGPC_FILTER_TYPE
,
6540 af
== AF_INET
? IPGPC_V4_FLTR
: IPGPC_V6_FLTR
);
6542 ipqos_msg(MT_ENOSTR
, "nvlist_add_byte");
6545 IPQOSCDBG1(MHME
, "adding address type %s in dup filter\n",
6546 af
== AF_INET
? "AF_INET" : "AF_INET6");
6548 /* add saddr if present */
6551 if (af
== AF_INET
&& !inv6
) {
6552 V4_PART_OF_V6(v6addr
) = *(uint32_t *)saddr
;
6556 /* add address and all 1's mask */
6558 if (nvlist_add_uint32_array(nf
->nvlist
, IPGPC_SADDR
,
6559 (uint32_t *)saddr
, 4) != 0 ||
6560 nvlist_add_uint32_array(nf
->nvlist
, IPGPC_SADDR_MASK
,
6561 (uint32_t *)&all_1s_v6
, 4) != 0) {
6562 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32_array");
6568 /* add daddr if present */
6571 if (af
== AF_INET
&& !inv6
) {
6572 V4_PART_OF_V6(v6addr
) = *(uint32_t *)daddr
;
6576 /* add address and all 1's mask */
6578 if (nvlist_add_uint32_array(nf
->nvlist
, IPGPC_DADDR
,
6579 (uint32_t *)daddr
, 4) != 0 ||
6580 nvlist_add_uint32_array(nf
->nvlist
, IPGPC_DADDR_MASK
,
6581 (uint32_t *)&all_1s_v6
, 4) != 0) {
6582 ipqos_msg(MT_ENOSTR
, "nvlist_add_uint32_array");
6587 /* add filter instance */
6589 nf
->instance
= inst
;
6592 return (IPQOS_CONF_SUCCESS
);
6595 return (IPQOS_CONF_ERR
);
6600 /* ************************* action manip fns ********************** */
6605 * create and zero action structure and a params structure hung off of it.
6606 * RETURNS: ptr to allocated action on success, else NULL.
6608 static ipqos_conf_action_t
*
6612 ipqos_conf_action_t
*action
;
6614 action
= (ipqos_conf_action_t
*)malloc(sizeof (ipqos_conf_action_t
));
6615 if (action
== NULL
) {
6616 ipqos_msg(MT_ENOSTR
, "malloc");
6619 bzero(action
, sizeof (ipqos_conf_action_t
));
6621 action
->params
= (ipqos_conf_params_t
*)
6622 malloc(sizeof (ipqos_conf_params_t
));
6623 if (action
->params
== NULL
) {
6627 bzero(action
->params
, sizeof (ipqos_conf_params_t
));
6628 action
->params
->stats_enable
= B_FALSE
;
6634 * free all the memory used in all the actions in actions list.
6638 ipqos_conf_action_t
*actions
)
6641 ipqos_conf_action_t
*act
= actions
;
6642 ipqos_conf_action_t
*next
;
6643 ipqos_conf_filter_t
*flt
, *nf
;
6644 ipqos_conf_class_t
*cls
, *nc
;
6646 while (act
!= NULL
) {
6647 /* free parameters */
6649 if (act
->params
!= NULL
) {
6650 free_arefs(act
->params
->actions
);
6651 nvlist_free(act
->params
->nvlist
);
6655 /* free action nvlist */
6662 while (flt
!= NULL
) {
6671 while (cls
!= NULL
) {
6677 /* free permanent classes table */
6678 cleanup_string_table(act
->perm_classes
, act
->num_perm_classes
);
6680 /* free filters to retry */
6682 flt
= act
->retry_filters
;
6683 while (flt
!= NULL
) {
6689 /* free dependency pointers */
6690 free_arefs(act
->dependencies
);
6699 * Checks whether there is an action called action_name in actions list.
6700 * RETURNS: ptr to first matched action, else if not matched NULL.
6703 static ipqos_conf_action_t
*
6706 ipqos_conf_action_t
*actions
)
6709 IPQOSCDBG1(L1
, "In actionexist: name: %s\n", action_name
);
6712 if (strcmp(action_name
, actions
->name
) == 0) {
6715 actions
= actions
->next
;
6721 /* **************************** act ref manip fns ******************** */
6725 * add an action reference element with parameter field and action
6726 * action_name to arefs.
6727 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
6731 ipqos_conf_act_ref_t
**arefs
,
6736 ipqos_conf_act_ref_t
*aref
;
6738 IPQOSCDBG1(L1
, "add_aref: action: %s.\n", action_name
);
6740 /* allocate zero'd aref */
6742 aref
= malloc(sizeof (ipqos_conf_act_ref_t
));
6744 ipqos_msg(MT_ENOSTR
, "malloc");
6745 return (IPQOS_CONF_ERR
);
6747 (void) bzero(aref
, sizeof (ipqos_conf_act_ref_t
));
6749 /* copy parameter name if present */
6752 (void) strlcpy(aref
->field
, field
, IPQOS_CONF_PNAME_LEN
);
6754 /* copy action name */
6755 (void) strlcpy(aref
->name
, action_name
, IPQOS_CONF_NAME_LEN
);
6757 /* place at head of list */
6759 aref
->next
= *arefs
;
6762 return (IPQOS_CONF_SUCCESS
);
6766 * free all the memory used by the action references in arefs.
6770 ipqos_conf_act_ref_t
*arefs
)
6773 ipqos_conf_act_ref_t
*aref
= arefs
;
6774 ipqos_conf_act_ref_t
*next
;
6777 nvlist_free(aref
->nvlist
);
6786 /* *************************************************************** */
6791 * checks whether aname is a valid action name.
6792 * RETURNS: IPQOS_CONF_ERR if invalid, else IPQOS_CONF_SUCCESS.
6795 valid_aname(char *aname
)
6799 * dissallow the use of the name of a virtual action, either
6800 * the ipqosconf name, or the longer ipp names.
6802 if (strcmp(aname
, IPQOS_CONF_CONT_STR
) == 0 ||
6803 strcmp(aname
, IPQOS_CONF_DEFER_STR
) == 0 ||
6804 strcmp(aname
, IPQOS_CONF_DROP_STR
) == 0 ||
6805 virtual_action(aname
)) {
6806 ipqos_msg(MT_ERROR
, gettext("Invalid action name line %u.\n"),
6808 return (IPQOS_CONF_ERR
);
6811 return (IPQOS_CONF_SUCCESS
);
6815 * Opens a stream to the types file for module module_name (assuming
6816 * that the file path is TYPES_FILE_DIR/module_name.types). if
6817 * a file open failure occurs, *openerr is set to 1.
6818 * RETURNS: NULL on error, else stream ptr to module types file.
6829 IPQOSCDBG1(L1
, "In validmod: module_name: %s\n", module_name
);
6833 /* create modules type file path */
6835 path
= malloc(strlen(TYPES_FILE_DIR
) + strlen(module_name
) +
6836 strlen(".types") + 1);
6838 ipqos_msg(MT_ENOSTR
, "malloc");
6841 (void) strcpy(path
, TYPES_FILE_DIR
);
6842 (void) strcat(path
, module_name
);
6843 (void) strcat(path
, ".types");
6846 IPQOSCDBG1(L1
, "opening file %s\n", path
);
6848 /* open stream to types file */
6850 fp
= fopen(path
, "r");
6861 * read a class clause from cfp into a class struct and point class at this.
6862 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
6868 ipqos_conf_class_t
**class,
6869 char **perm_classes
,
6870 int num_perm_classes
)
6876 ipqos_nvtype_t type
;
6881 IPQOSCDBG0(L0
, "in readclass\n");
6883 /* create and zero class struct */
6885 *class = alloc_class();
6887 return (IPQOS_CONF_ERR
);
6889 (*class)->originator
= IPP_CONFIG_IPQOSCONF
;
6891 /* get starting line for error reporting */
6892 (*class)->lineno
= lineno
;
6894 /* read curl_begin */
6896 res
= read_curl_begin(cfp
);
6897 if (res
!= IPQOS_CONF_SUCCESS
) {
6901 /* loop reading parameters till read curl_end */
6903 stats
= nm
= act
= 0;
6906 res
= readnvpair(cfp
, NULL
, &(*class)->nvlist
,
6907 &nvp
, &type
, PL_CLASS
, module_name
);
6908 if (res
== IPQOS_CONF_ERR
) {
6911 /* reached end of class clause */
6912 } else if (res
== IPQOS_CONF_CURL_END
) {
6917 * catch name and action nv pairs and stats if present
6918 * and place values in class structure.
6924 strcmp(nvpair_name(nvp
), IPQOS_CONF_NAME_STR
) == 0) {
6926 (void) nvpair_value_string(nvp
, &name
);
6928 if (valid_name(name
) != IPQOS_CONF_SUCCESS
) {
6931 (void) strcpy((*class)->name
, name
);
6936 } else if (act
== 0 &&
6937 strcmp(nvpair_name(nvp
), IPQOS_CONF_NEXT_ACTION_STR
) == 0) {
6939 (void) nvpair_value_string(nvp
, &action
);
6942 * if next action string continue string set action to
6943 * IPP_ANAME_CONT, else if drop string IPP_ANAME_DROP
6945 if (strcmp(action
, IPQOS_CONF_CONT_STR
) == 0) {
6946 action
= IPP_ANAME_CONT
;
6947 } else if (strcmp(action
, IPQOS_CONF_DROP_STR
) == 0) {
6948 action
= IPP_ANAME_DROP
;
6951 /* add an action reference to action list */
6953 res
= add_aref(&(*class)->alist
,
6954 IPQOS_CONF_NEXT_ACTION_STR
, action
);
6955 if (res
!= IPQOS_CONF_SUCCESS
) {
6960 /* class stats enable */
6962 } else if (stats
== 0 &&
6963 strcmp(nvpair_name(nvp
), IPQOS_CONF_STATS_ENABLE_STR
) ==
6967 (void) nvpair_value_uint32(nvp
, (uint32_t *)&bl
);
6968 (*class)->stats_enable
= bl
;
6972 /* no other / duplicate parameters allowed */
6976 gettext("Unexpected parameter line %u.\n"), lineno
);
6980 if (nm
== 0 || act
== 0) {
6982 gettext("Missing class name/next action before line %u.\n"),
6987 /* change class originator field to permanent if permanent class */
6989 if (in_string_table(perm_classes
, num_perm_classes
, (*class)->name
)) {
6990 IPQOSCDBG1(L0
, "Setting class %s as permanent.\n", (*class)->name
);
6991 (*class)->originator
= IPP_CONFIG_PERMANENT
;
6994 return (IPQOS_CONF_SUCCESS
);
6998 return (IPQOS_CONF_ERR
);
7002 * This function assumes either src_nd_name or dst_node_nm are set in filter.
7004 * Creates one of more copies of filter according to the ip versions
7005 * requested (or assumed) and the resolution of the src and dst address
7006 * node names if spec'd. If both node names are spec'd then a filter is
7007 * created for each pair of addresses (one from each node name) that is
7008 * compatible with the chosen address family, otherwise a filter copy is
7009 * created for just each address of the single node name that is
7011 * If filter->ip_versions has been set that is used to determine the
7012 * af's we will create filters for, else if a numeric address was
7013 * added the family of that will be used, otherwise we fall back
7014 * to both v4 and v6 addresses.
7016 * Any name lookup failures that occur are checked to see whether the failure
7017 * was a soft or hard failure and the nlerr field of filter set accordingly
7018 * before the error is returned.
7020 * RETURNS: IPQOS_CONF_ERR on any error, else IPQOS_CONF_SUCCESS.
7025 ipqos_conf_filter_t
*filter
,
7026 ipqos_conf_filter_t
**flist
,
7027 boolean_t last_retry
)
7031 int v4
= 1, v6
= 1; /* default lookup family is v4 and v6 */
7033 struct hostent
*shp
= NULL
;
7034 struct hostent
*dhp
= NULL
;
7035 in6_addr_t daddr
, saddr
;
7037 ipqos_conf_filter_t
*nfilter
;
7043 IPQOSCDBG3(MHME
, "In domultihome: filter: %s, src_node: %s, "
7044 "dst_node: %s\n", filter
->name
,
7045 (filter
->src_nd_name
? filter
->src_nd_name
: "NULL"),
7046 (filter
->dst_nd_name
? filter
->dst_nd_name
: "NULL"));
7048 /* check if we've read an ip_version request to get the versions */
7050 if (filter
->ip_versions
!= 0) {
7051 v4
= VERSION_IS_V4(filter
);
7052 v6
= VERSION_IS_V6(filter
);
7054 /* otherwise check if we've read a numeric address and get versions */
7056 } else if (nvlist_lookup_uint32(filter
->nvlist
, IPGPC_FILTER_TYPE
,
7058 if (ftype
== IPGPC_V4_FLTR
) {
7065 /* read saddrs if src node name */
7067 if (filter
->src_nd_name
) {
7069 /* v4 only address */
7073 shp
= getipnodebyname(filter
->src_nd_name
, AF_INET
,
7074 AI_ADDRCONFIG
, &ernum
);
7078 } else if (v6
&& !v4
) {
7079 shp
= getipnodebyname(filter
->src_nd_name
, AF_INET6
,
7080 AI_DEFAULT
, &ernum
);
7084 } else if (v6
&& v4
) {
7085 shp
= getipnodebyname(filter
->src_nd_name
, AF_INET6
,
7086 AI_DEFAULT
|AI_ALL
, &ernum
);
7089 #ifdef TESTING_RETRY
7091 filter
->nlerr
= IPQOS_LOOKUP_RETRY
;
7097 * if lookup error determine whether it was a soft or hard
7098 * failure and mark as such in filter.
7101 if (ernum
!= TRY_AGAIN
) {
7102 ipqos_msg(MT_ERROR
, gettext("Failed to "
7103 "resolve src host name for filter at "
7104 "line %u, ignoring filter.\n"),
7106 filter
->nlerr
= IPQOS_LOOKUP_FAIL
;
7109 ipqos_msg(MT_ERROR
, gettext("Failed "
7110 "to resolve src host name for "
7111 "filter at line %u, ignoring "
7112 "filter.\n"), filter
->lineno
);
7114 filter
->nlerr
= IPQOS_LOOKUP_RETRY
;
7120 /* read daddrs if dst node name */
7121 if (filter
->dst_nd_name
) {
7123 /* v4 only address */
7127 dhp
= getipnodebyname(filter
->dst_nd_name
, AF_INET
,
7128 AI_ADDRCONFIG
, &ernum
);
7132 } else if (v6
&& !v4
) {
7133 dhp
= getipnodebyname(filter
->dst_nd_name
, AF_INET6
,
7134 AI_DEFAULT
, &ernum
);
7136 /* v6 and v4 addresses */
7139 dhp
= getipnodebyname(filter
->dst_nd_name
, AF_INET6
,
7140 AI_DEFAULT
|AI_ALL
, &ernum
);
7144 if (ernum
!= TRY_AGAIN
) {
7145 ipqos_msg(MT_ERROR
, gettext("Failed to "
7146 "resolve dst host name for filter at "
7147 "line %u, ignoring filter.\n"),
7149 filter
->nlerr
= IPQOS_LOOKUP_FAIL
;
7152 ipqos_msg(MT_ERROR
, gettext("Failed "
7153 "to resolve dst host name for "
7154 "filter at line %u, ignoring "
7155 "filter.\n"), filter
->lineno
);
7157 filter
->nlerr
= IPQOS_LOOKUP_RETRY
;
7164 * if src and dst node name, create set of filters; one for each
7165 * src and dst address of matching types.
7167 if (filter
->src_nd_name
&& filter
->dst_nd_name
) {
7169 for (sp
= shp
->h_addr_list
; *sp
!= NULL
; sp
++) {
7170 (void) bcopy(*sp
, &saddr
, shp
->h_length
);
7172 /* get saddr family */
7174 if (in32b
|| IN6_IS_ADDR_V4MAPPED(&saddr
)) {
7180 for (dp
= dhp
->h_addr_list
; *dp
!= NULL
; dp
++) {
7181 (void) bcopy(*dp
, &daddr
, dhp
->h_length
);
7183 /* get daddr family */
7185 if (in32b
|| IN6_IS_ADDR_V4MAPPED(&daddr
)) {
7192 * if saddr and daddr same af duplicate
7193 * filter adding addresses and new instance
7194 * number and add to flist filter list.
7199 res
= dup_filter(filter
, &nfilter
, saf
,
7200 !in32b
, &saddr
, &daddr
, ++idx
);
7201 if (res
!= IPQOS_CONF_SUCCESS
) {
7204 ADD_TO_LIST(flist
, nfilter
);
7209 /* if src name only create set of filters, one for each node address */
7211 } else if (filter
->src_nd_name
) {
7213 for (sp
= shp
->h_addr_list
; *sp
!= NULL
; sp
++) {
7214 (void) bcopy(*sp
, &saddr
, shp
->h_length
);
7218 if (in32b
|| IN6_IS_ADDR_V4MAPPED(&saddr
)) {
7226 * dup filter adding saddr and new instance num and
7227 * add to flist filter list.
7229 res
= dup_filter(filter
, &nfilter
, saf
, !in32b
, &saddr
,
7231 if (res
!= IPQOS_CONF_SUCCESS
) {
7235 ADD_TO_LIST(flist
, nfilter
);
7239 /* if dname only create set of filters, one for each node address */
7242 for (dp
= dhp
->h_addr_list
; *dp
!= NULL
; dp
++) {
7243 (void) bcopy(*dp
, &daddr
, dhp
->h_length
);
7247 if (in32b
|| IN6_IS_ADDR_V4MAPPED(&daddr
)) {
7254 * dup filter adding daddr and new instance num and
7255 * add to flist filter list.
7257 res
= dup_filter(filter
, &nfilter
, daf
, !in32b
, NULL
,
7259 if (res
!= IPQOS_CONF_SUCCESS
) {
7263 ADD_TO_LIST(flist
, nfilter
);
7271 return (IPQOS_CONF_SUCCESS
);
7274 * should really clean up any filters that we have created,
7275 * however, free_actions called from readaction will cleam them up.
7281 return (IPQOS_CONF_ERR
);
7286 * read a filter clause from cfp into a filter struct and point filter
7288 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
7295 ipqos_conf_filter_t
**filter
,
7296 char **perm_filters
,
7297 int num_perm_filters
)
7313 ipqos_nvtype_t type
;
7319 IPQOSCDBG0(L0
, "in readfilter\n");
7322 /* create and zero filter struct */
7324 *filter
= alloc_filter();
7325 if (*filter
== NULL
) {
7326 return (IPQOS_CONF_ERR
);
7328 (*filter
)->originator
= IPP_CONFIG_IPQOSCONF
;
7330 /* get starting line for error reporting */
7331 (*filter
)->lineno
= lineno
;
7333 /* read beginning curl */
7335 res
= read_curl_begin(cfp
);
7336 if (res
!= IPQOS_CONF_SUCCESS
) {
7342 * loop reading nvpairs onto nvlist until encounter CURL_END
7348 res
= readnvpair(cfp
, tfp
, &(*filter
)->nvlist
,
7349 &nvp
, &type
, PL_FILTER
, module_name
);
7350 if (res
== IPQOS_CONF_ERR
) {
7353 /* reached the end of filter definition */
7355 } else if (res
== IPQOS_CONF_CURL_END
) {
7360 * catch name and class and place value into filter
7364 /* read filter name */
7366 if (strcmp(nvpair_name(nvp
), IPQOS_CONF_NAME_STR
) == 0) {
7369 gettext("Duplicate parameter line %u.\n"),
7374 (void) nvpair_value_string(nvp
, &name
);
7375 if (valid_name(name
) != IPQOS_CONF_SUCCESS
) {
7379 (void) strcpy((*filter
)->name
, name
);
7380 (void) nvlist_remove_all((*filter
)->nvlist
,
7381 IPQOS_CONF_NAME_STR
);
7384 /* read class name */
7386 } else if (strcmp(nvpair_name(nvp
), IPQOS_CONF_CLASS_STR
) ==
7390 gettext("Duplicate parameter line %u.\n"),
7395 if (nvpair_value_string(nvp
, &class) != 0) {
7396 ipqos_msg(MT_ENOSTR
, "nvpair_value_string");
7399 if (valid_name(class) != IPQOS_CONF_SUCCESS
) {
7402 (void) strcpy((*filter
)->class_name
, class);
7403 (void) nvlist_remove_all((*filter
)->nvlist
,
7404 IPQOS_CONF_CLASS_STR
);
7408 * if a src or dst ip node name/address. For those that
7409 * are determined to be addresses we convert them from
7410 * strings here and add to the filter nvlist; for node names
7411 * we add the name to the filter struct for readaction to
7414 } else if (strcmp(nvpair_name(nvp
), IPGPC_SADDR
) == 0 ||
7415 strcmp(nvpair_name(nvp
), IPGPC_DADDR
) == 0) {
7419 if (strcmp(nvpair_name(nvp
), IPGPC_SADDR
) == 0) {
7423 (void) nvpair_value_string(nvp
, &addr_str
);
7426 * get the address mask if present.
7427 * make a copy so that the nvlist element that
7428 * it is part of doesn't dissapear and causes probs.
7430 sl
= strchr(addr_str
, '/');
7433 tmp
= malloc(strlen(++sl
) + 1);
7435 ipqos_msg(MT_ENOSTR
, "malloc");
7438 (void) strcpy(tmp
, sl
);
7443 /* if a numeric address */
7445 if (inet_pton(AF_INET
, addr_str
, &addr
) == 1 ||
7446 inet_pton(AF_INET6
, addr_str
, &addr
) == 1) {
7450 hp
= getipnodebyname(addr_str
, AF_INET6
,
7451 AI_DEFAULT
, &err_num
);
7453 ipqos_msg(MT_ENOSTR
,
7458 (void) bcopy(hp
->h_addr_list
[0], &v6addr
,
7462 /* determine address type */
7464 v4
= IN6_IS_ADDR_V4MAPPED(&v6addr
);
7470 * check any previous addresses have same
7473 if (nvlist_lookup_byte((*filter
)->nvlist
,
7474 IPGPC_FILTER_TYPE
, &b
) == 0) {
7475 if (v4
&& b
!= IPGPC_V4_FLTR
||
7476 v6
&& b
!= IPGPC_V6_FLTR
) {
7478 gettext("Incompatible "
7479 "address version line "
7486 * check that if ip_version spec'd it
7489 if ((*filter
)->ip_versions
!= 0) {
7490 if (v4
&& !VERSION_IS_V4(*filter
) ||
7491 v6
&& !VERSION_IS_V6(*filter
)) {
7493 gettext("Incompatible "
7494 "address version line %u"
7500 /* add the address type */
7502 res
= nvlist_add_byte(
7503 (*filter
)->nvlist
, IPGPC_FILTER_TYPE
,
7504 v4
? IPGPC_V4_FLTR
: IPGPC_V6_FLTR
);
7506 ipqos_msg(MT_ENOSTR
,
7511 /* add address to list */
7513 res
= nvlist_add_uint32_array((*filter
)->nvlist
,
7514 sa
? IPGPC_SADDR
: IPGPC_DADDR
,
7515 (uint32_t *)&v6addr
, 4);
7517 ipqos_msg(MT_ENOSTR
,
7518 "nvlist_add_uint32_array");
7524 * add mask entry in list.
7527 if (sl
) { /* have CIDR mask */
7529 res
= readuint8(sl
, &mlen
, &lo
);
7530 if (res
!= IPQOS_CONF_SUCCESS
||
7532 !v4
&& mlen
> 128 ||
7535 gettext("Invalid CIDR "
7536 "mask line %u.\n"), lineno
);
7539 setmask(mlen
, &mask
,
7540 v4
? AF_INET
: AF_INET6
);
7543 /* no CIDR mask spec'd - use all 1s */
7545 (void) memset(&mask
, ~0,
7546 sizeof (in6_addr_t
));
7548 res
= nvlist_add_uint32_array((*filter
)->nvlist
,
7549 sa
? IPGPC_SADDR_MASK
: IPGPC_DADDR_MASK
,
7550 (uint32_t *)&mask
, 4);
7552 ipqos_msg(MT_ENOSTR
,
7553 "nvlist_add_uint32_arr");
7557 /* inet_pton returns fail - we assume a node name */
7561 * doesn't make sense to have a mask
7566 gettext("Address masks aren't "
7567 "allowed for host names line "
7573 * store node name in filter struct for
7577 (*filter
)->src_nd_name
=
7578 malloc(strlen(addr_str
) + 1);
7579 (void) strcpy((*filter
)->src_nd_name
,
7582 (*filter
)->dst_nd_name
=
7583 malloc(strlen(addr_str
) + 1);
7584 (void) strcpy((*filter
)->dst_nd_name
,
7589 /* ip_version enumeration */
7591 } else if (strcmp(nvpair_name(nvp
), IPQOS_CONF_IP_VERSION
) ==
7593 /* check we haven't read ip_version before */
7596 gettext("Duplicate parameter line %u.\n"),
7602 /* get bitmask value */
7604 (void) nvpair_value_uint32(nvp
,
7605 &(*filter
)->ip_versions
);
7608 * check that if either ip address is spec'd it
7611 if (v4
&& !VERSION_IS_V4(*filter
) ||
7612 v6
&& !VERSION_IS_V6(*filter
)) {
7613 ipqos_msg(MT_ERROR
, gettext("Incompatible "
7614 "address version line %u.\n"), lineno
);
7618 /* remove ip_version from nvlist */
7620 (void) nvlist_remove_all((*filter
)->nvlist
,
7621 IPQOS_CONF_IP_VERSION
);
7624 if (nm
== 0 || cls
== 0) {
7625 ipqos_msg(MT_ERROR
, gettext("Missing filter/class name "
7626 "before line %u.\n"), lineno
);
7630 if (in_string_table(perm_filters
, num_perm_filters
, (*filter
)->name
)) {
7631 IPQOSCDBG1(L0
, "Setting filter %s as permanent.\n",
7634 (*filter
)->originator
= IPP_CONFIG_PERMANENT
;
7637 return (IPQOS_CONF_SUCCESS
);
7640 free_filter(*filter
);
7645 return (IPQOS_CONF_ERR
);
7649 * reads the curl begin token from cfp stream.
7650 * RETURNS: IPQOS_CONF_ERR if not read successfully, else IPQOS_CONF_SUCCES.
7653 read_curl_begin(FILE *cfp
)
7659 res
= readtoken(cfp
, &st
);
7661 if (res
!= IPQOS_CONF_CURL_BEGIN
) {
7662 if (res
== IPQOS_CONF_EOF
) {
7663 ipqos_msg(MT_ERROR
, gettext("Unexpected EOF.\n"));
7665 /* if CURL_END or something else */
7666 } else if (res
!= IPQOS_CONF_ERR
) {
7668 ipqos_msg(MT_ERROR
, gettext("\'{\' missing at line "
7671 return (IPQOS_CONF_ERR
);
7675 return (IPQOS_CONF_SUCCESS
);
7679 * This function parses the parameter string version into a version of the
7680 * form "%u.%u" (as a sscanf format string). It then encodes this into an
7681 * int and returns this encoding.
7682 * RETURNS: -1 if an invalid string, else the integer encoding.
7688 uint32_t major
, minor
;
7691 if (sscanf(version
, "%u.%u", &major
, &minor
) != 2) {
7692 IPQOSCDBG0(L0
, "Failed to process version number string\n");
7696 ver
= (int)((major
* 10000) + minor
);
7701 * This function scans through the stream fp line by line looking for
7702 * a line beginning with version_tag and returns a integer encoding of
7703 * the version following it.
7705 * RETURNS: If the version definition isn't found or the version is not
7706 * a valid version (%u.%u) then -1 is returned, else an integer encoding
7707 * of the read version.
7715 char lbuf
[IPQOS_CONF_LINEBUF_SZ
];
7716 char buf
[IPQOS_CONF_LINEBUF_SZ
+1];
7717 char buf2
[IPQOS_CONF_LINEBUF_SZ
+1];
7722 * reset to file start
7724 if (fseek(fp
, 0, SEEK_SET
) != 0) {
7725 ipqos_msg(MT_ENOSTR
, "fseek");
7730 * loop reading lines till found the one beginning with version_tag.
7732 while (fgets(lbuf
, IPQOS_CONF_LINEBUF_SZ
, fp
) != NULL
) {
7734 "%" VAL2STR(IPQOS_CONF_LINEBUF_SZ
) "s"
7735 "%" VAL2STR(IPQOS_CONF_LINEBUF_SZ
) "s",
7737 (strcmp(buf
, version_tag
) == 0)) {
7743 ipqos_msg(MT_ERROR
, gettext("Types file for module %s is "
7744 "corrupt.\n"), module_name
);
7745 IPQOSCDBG1(L1
, "Couldn't find %s in types file\n",
7751 * convert version string into int.
7753 if ((version
= ver_str_to_int(buf2
)) == -1) {
7754 ipqos_msg(MT_ERROR
, gettext("Types file for module %s is "
7755 "corrupt.\n"), module_name
);
7763 * read action clause and params/classes/filters clauses within and
7764 * store in and hang off an action structure, and point action at it.
7765 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
7770 ipqos_conf_action_t
**action
)
7781 ipqos_nvtype_t type
;
7782 ipqos_conf_filter_t
*filter
;
7783 ipqos_conf_class_t
*class;
7785 char **perm_filters
;
7786 int num_perm_filters
;
7789 IPQOSCDBG0(L0
, "in readaction\n");
7791 res
= readtoken(cfp
, &st
);
7792 if (res
== IPQOS_CONF_ERR
|| res
== IPQOS_CONF_EOF
) {
7794 } else if (strcmp(st
, IPQOS_CONF_ACTION_STR
) != 0) {
7795 ipqos_msg(MT_ERROR
, gettext("Missing %s token line "
7796 "%u.\n"), IPQOS_CONF_ACTION_STR
, lineno
);
7798 return (IPQOS_CONF_ERR
);
7802 /* create action structure */
7804 *action
= alloc_action();
7805 if (*action
== NULL
) {
7806 return (IPQOS_CONF_ERR
);
7808 (*action
)->params
->originator
= IPP_CONFIG_IPQOSCONF
;
7811 /* get starting line for error reporting */
7812 (*action
)->lineno
= lineno
;
7814 /* read beginning curl */
7816 res
= read_curl_begin(cfp
);
7817 if (res
!= IPQOS_CONF_SUCCESS
) {
7821 /* loop till read both action name and module */
7827 res
= readnvpair(cfp
, NULL
, &(*action
)->nvlist
, &nvp
, &type
,
7829 if (res
== IPQOS_CONF_ERR
) {
7834 } else if (res
== IPQOS_CONF_CURL_END
) {
7835 if (nm
== 0 || md
== 0) {
7837 gettext("Missing action name/ module "
7838 "before line %u.\n"), lineno
);
7844 /* store name and module in action structure */
7846 name
= nvpair_name(nvp
);
7848 /* read action name */
7850 if (nm
== 0 && strcmp(name
, IPQOS_CONF_NAME_STR
) == 0) {
7852 (void) nvpair_value_string(nvp
, &strval
);
7854 /* check name is valid */
7856 if (valid_name(strval
) != IPQOS_CONF_SUCCESS
||
7857 valid_aname(strval
) != IPQOS_CONF_SUCCESS
) {
7861 /* store and remove from list */
7863 (void) strcpy((*action
)->name
, strval
);
7864 /* remove name from nvlist */
7865 (void) nvlist_remove_all((*action
)->nvlist
,
7866 IPQOS_CONF_NAME_STR
);
7870 /* read module name */
7872 } else if (md
== 0 &&
7873 strcmp(name
, IPQOS_CONF_MODULE_STR
) == 0) {
7875 * check that module has a type file and get
7876 * open stream to it.
7878 (void) nvpair_value_string(nvp
, &strval
);
7879 if ((tfp
= validmod(strval
, &oe
)) == NULL
) {
7881 if (errno
== ENOENT
) {
7884 "module name line %u.\n"),
7887 ipqos_msg(MT_ENOSTR
, "fopen");
7894 * move module name to action struct
7896 (void) strlcpy((*action
)->module
, strval
,
7897 IPQOS_CONF_NAME_LEN
);
7898 (void) nvlist_remove_all((*action
)->nvlist
,
7899 IPQOS_CONF_MODULE_STR
);
7902 /* duplicate/other parameter */
7906 gettext("Unexpected parameter line %u.\n"),
7911 } while (nm
== 0 || md
== 0);
7914 * check that if the ipgpc action it is named correctly
7916 if ((strcmp((*action
)->module
, IPGPC_NAME
) == 0) &&
7917 (strcmp((*action
)->name
, IPGPC_CLASSIFY
) != 0)) {
7919 gettext("%s action has incorrect name line %u.\n"),
7920 IPGPC_NAME
, (*action
)->lineno
);
7924 /* get list of permanent classes */
7926 res
= read_perm_items(0, tfp
, (*action
)->module
,
7927 &(*action
)->perm_classes
, &(*action
)->num_perm_classes
);
7928 if (res
!= IPQOS_CONF_SUCCESS
) {
7932 /* get list of permanent filters */
7934 res
= read_perm_items(1, tfp
, (*action
)->module
,
7935 &perm_filters
, &num_perm_filters
);
7936 if (res
!= IPQOS_CONF_SUCCESS
) {
7941 * get types file format version and check its supported.
7943 if ((tf_fmt_ver
= read_tfile_ver(tfp
, IPQOS_FMT_STR
,
7944 (*action
)->module
)) == -1)
7946 if (IPP_MAJOR_MODULE_VER(tf_fmt_ver
) > 1 ||
7947 IPP_MINOR_MODULE_VER(tf_fmt_ver
) > 0) {
7948 ipqos_msg(MT_ERROR
, gettext("Types file for module %s is "
7949 "incompatible.\n"), (*action
)->module
);
7950 IPQOSCDBG0(L1
, "Unsupported fmt major/minor version\n");
7955 * get module version
7957 if (((*action
)->module_version
= read_tfile_ver(tfp
, IPQOS_MOD_STR
,
7958 (*action
)->module
)) == -1)
7961 /* read filter/class/params blocks until CURL_END */
7965 res
= readtoken(cfp
, &st
);
7967 if (res
== IPQOS_CONF_ERR
) {
7969 } else if (res
== IPQOS_CONF_EOF
) {
7970 ipqos_msg(MT_ERROR
, gettext("Unexpected EOF.\n"));
7973 /* read CURL_END - end of action definition */
7975 } else if (res
== IPQOS_CONF_CURL_END
) {
7982 * read in either a filter/class or parameter block.
7987 if (strcmp(st
, IPQOS_CONF_FILTER_STR
) == 0) {
7990 res
= readfilter(cfp
, tfp
, (*action
)->module
, &filter
,
7991 perm_filters
, num_perm_filters
);
7992 if (res
!= IPQOS_CONF_SUCCESS
) {
7997 * if we read a host name for either src or dst addr
7998 * resolve the hostnames and create the appropriate
7999 * number of filters.
8002 if (filter
->src_nd_name
|| filter
->dst_nd_name
) {
8004 res
= domultihome(filter
, &(*action
)->filters
,
8007 * if a lookup fails and the filters
8008 * marked as retry we add it to a list
8009 * for another attempt later, otherwise
8010 * it is thrown away.
8012 if (res
!= IPQOS_CONF_SUCCESS
) {
8014 /* if not name lookup problem */
8016 if (filter
->nlerr
== 0) {
8017 free_filter(filter
);
8020 /* name lookup problem */
8023 * if intermitent lookup failure
8024 * add to list of filters to
8027 } else if (filter
->nlerr
==
8028 IPQOS_LOOKUP_RETRY
) {
8031 &(*action
)->retry_filters
,
8034 * for non-existing names
8035 * ignore the filter.
8038 free_filter(filter
);
8041 /* creation of new filters successful */
8044 free_filter(filter
);
8047 /* non-node name filter */
8050 ADD_TO_LIST(&(*action
)->filters
, filter
);
8055 } else if (strcmp(st
, IPQOS_CONF_CLASS_STR
) == 0) {
8057 res
= readclass(cfp
, (*action
)->module
, &class,
8058 (*action
)->perm_classes
,
8059 (*action
)->num_perm_classes
);
8060 if (res
!= IPQOS_CONF_SUCCESS
) {
8064 ADD_TO_LIST(&(*action
)->classes
, class);
8068 } else if (strcmp(st
, IPQOS_CONF_PARAMS_STR
) == 0) {
8072 gettext("Second parameter clause not "
8073 "supported line %u.\n"), lineno
);
8076 res
= readparams(cfp
, tfp
, (*action
)->module
,
8078 if (res
!= IPQOS_CONF_SUCCESS
) {
8083 /* something unexpected */
8087 gettext("Params/filter/class clause expected "
8088 "line %u.\n"), lineno
);
8094 return (IPQOS_CONF_SUCCESS
);
8100 free_actions(*action
);
8103 return (IPQOS_CONF_ERR
);
8107 * check that each of the actions in actions is uniquely named. If one isn't
8108 * set *name to point at the name of the duplicate action.
8109 * RETURNS: IPQOS_CONF_ERR if a non-unique action, else IPQOS_CONF_SUCCESS.
8112 actions_unique(ipqos_conf_action_t
*actions
, char **name
)
8115 IPQOSCDBG0(L1
, "In actions_unique.\n");
8118 if (actionexist(actions
->name
, actions
->next
)) {
8119 *name
= actions
->name
;
8120 return (IPQOS_CONF_ERR
);
8122 actions
= actions
->next
;
8125 return (IPQOS_CONF_SUCCESS
);
8129 * checks whether the action parameter is involved in an action cycle.
8130 * RETURNS: 1 if involved in a cycle, 0 otherwise.
8134 ipqos_conf_action_t
*action
)
8137 ipqos_conf_act_ref_t
*aref
;
8138 ipqos_conf_class_t
*c
;
8140 IPQOSCDBG1(L0
, "in_cycle: visiting action %s\n", action
->name
);
8143 /* have we visited this action before? */
8145 if (action
->visited
== INCYCLE_VISITED
) {
8146 action
->visited
= 0;
8149 action
->visited
= INCYCLE_VISITED
;
8152 * recurse down the child actions of this action through the
8153 * classes next action and parameter actions.
8156 for (aref
= action
->params
->actions
; aref
!= NULL
; aref
= aref
->next
) {
8158 /* skip virtual actions - they can't be in a cycle */
8160 if (virtual_action(aref
->name
)) {
8164 if (in_cycle(aref
->action
)) {
8165 action
->visited
= 0;
8170 for (c
= action
->classes
; c
!= NULL
; c
= c
->next
) {
8173 if (virtual_action(aref
->name
)) {
8177 if (in_cycle(aref
->action
)) {
8178 action
->visited
= 0;
8183 IPQOSCDBG0(L0
, "in_cycle: return\n");
8184 action
->visited
= 0;
8189 * checks that the configuration in actions is a valid whole, that
8190 * all actions are unique, all filters and classes are unique within
8191 * their action, that classes referenced by filters exist and actions
8192 * referenced by classes and params exist. Also checks that there are no root
8193 * actions but ipgpc and that no actions are involved in cycles. As
8194 * a consequence of checking that the actions exist two way pointers
8195 * are created between the dependee and dependant actions.
8197 * In the case the the userconf flag is zero only this link creation is
8198 * set as we trust the kernel to return a valid configuration.
8200 * RETURNS: IPQOS_CONF_ERR if config isn't valid, else IPQOS_CONF_SUCCESS.
8206 ipqos_conf_action_t
*actions
,
8207 int userconf
) /* are we checking a conf file ? */
8210 ipqos_conf_action_t
*act
;
8212 ipqos_conf_action_t
*dact
;
8213 ipqos_conf_filter_t
*flt
;
8214 ipqos_conf_class_t
*cls
;
8215 ipqos_conf_params_t
*params
;
8216 ipqos_conf_act_ref_t
*aref
;
8218 IPQOSCDBG0(L0
, "In validconf\n");
8220 /* check actions are unique */
8222 if (userconf
&& actions_unique(actions
, &name
) != IPQOS_CONF_SUCCESS
) {
8223 ipqos_msg(MT_ERROR
, gettext("Duplicate named action %s.\n"),
8225 return (IPQOS_CONF_ERR
);
8228 for (act
= actions
; act
; act
= act
->next
) {
8231 * check filters (for user land configs only).
8232 * check they are unique in this action and their class exists.
8235 for (flt
= act
->filters
; flt
; flt
= flt
->next
) {
8237 /* check unique name */
8239 if (filterexist(flt
->name
, flt
->instance
,
8242 gettext("Duplicate named filter "
8243 "%s in action %s.\n"), flt
->name
,
8245 return (IPQOS_CONF_ERR
);
8249 * check existence of class and error if
8250 * class doesn't exist and not a perm class
8253 if (!classexist(flt
->class_name
,
8255 if (!in_string_table(act
->perm_classes
,
8256 act
->num_perm_classes
,
8259 gettext("Undefined "
8260 "class in filter %s, "
8261 "action %s.\n"), flt
->name
,
8263 return (IPQOS_CONF_ERR
);
8271 for (cls
= act
->classes
; cls
; cls
= cls
->next
) {
8273 /* check if class name unique (userland only) */
8275 if (userconf
&& classexist(cls
->name
, cls
->next
)) {
8277 gettext("Duplicate named class %s in "
8278 "action %s.\n"), cls
->name
, act
->name
);
8279 return (IPQOS_CONF_ERR
);
8283 * virtual actions always exist so don't check for next
8286 if (virtual_action(cls
->alist
->name
)) {
8291 * check existance of next action and create link to
8294 if ((cls
->alist
->action
=
8295 actionexist(cls
->alist
->name
, actions
)) == NULL
) {
8297 gettext("Undefined action in class %s, "
8298 "action %s.\n"), cls
->name
, act
->name
);
8299 return (IPQOS_CONF_ERR
);
8302 /* create backwards link - used for deletions */
8304 dact
= cls
->alist
->action
;
8305 res
= add_aref(&dact
->dependencies
, NULL
, act
->name
);
8306 if (res
!= IPQOS_CONF_SUCCESS
) {
8307 return (IPQOS_CONF_ERR
);
8309 dact
->dependencies
->action
= act
;
8313 /* check actions exist for action type parameters */
8315 params
= act
->params
;
8316 for (aref
= params
->actions
; aref
; aref
= aref
->next
) {
8320 if (virtual_action(aref
->name
)) {
8325 * check existance of action in this ref
8326 * and if present create a ptr to it.
8328 aref
->action
= actionexist(aref
->name
, actions
);
8329 if (aref
->action
== NULL
) {
8331 gettext("Undefined action in parameter "
8332 "%s, action %s.\n"),
8333 SHORT_NAME(aref
->field
), act
->name
);
8334 return (IPQOS_CONF_ERR
);
8337 /* create backwards link */
8339 dact
= aref
->action
;
8340 res
= add_aref(&dact
->dependencies
, NULL
,
8342 if (res
!= IPQOS_CONF_SUCCESS
) {
8343 return (IPQOS_CONF_ERR
);
8345 dact
->dependencies
->action
= act
;
8349 /* for kernel retrieved configs we don't do the following checks. */
8351 return (IPQOS_CONF_SUCCESS
);
8354 /* check for cycles in config and orphaned actions other than ipgpc */
8356 for (act
= actions
; act
; act
= act
->next
) {
8358 /* check if involved in cycle */
8360 if (in_cycle(act
)) {
8362 gettext("Action %s involved in cycle.\n"),
8364 return (IPQOS_CONF_ERR
);
8367 /* check that this action has a parent (except ipgpc) */
8369 if (act
->dependencies
== NULL
&&
8370 strcmp(act
->name
, IPGPC_CLASSIFY
) != 0) {
8371 ipqos_msg(MT_ERROR
, gettext("Action %s isn't "
8372 "referenced by any other actions.\n"), act
->name
);
8373 return (IPQOS_CONF_ERR
);
8377 return (IPQOS_CONF_SUCCESS
);
8381 * Read the version from the config file with stream cfp with
8382 * the tag version_tag. The tag-value pair should be the first tokens
8385 * RETURNS: -1 if a missing or invalid version or a read error,
8386 * else an integer encoding of the version.
8397 IPQOSCDBG0(L1
, "In read_cfile_ver:\n");
8400 * read version tag string.
8402 res
= readtoken(cfp
, &sp
);
8403 if (res
!= IPQOS_CONF_SUCCESS
) {
8405 } else if (strcasecmp(sp
, version_tag
) != 0) {
8412 * read version number string.
8414 res
= readtoken(cfp
, &sp
);
8415 if (res
!= IPQOS_CONF_SUCCESS
) {
8420 * encode version into int.
8422 if ((version
= ver_str_to_int(sp
)) == -1) {
8430 gettext("Missing/Invalid config file %s.\n"), version_tag
);
8436 * read the set of actions definitions from the stream cfp and store
8437 * them in a list pointed to by conf.
8438 * RETURNS: IPQOS_CONF_ERR if any errors, else IPQOS_CONF_SUCCESS.
8443 ipqos_conf_action_t
**conf
)
8447 ipqos_conf_action_t
*action
;
8448 boolean_t ipgpc_action
= B_FALSE
;
8451 IPQOSCDBG0(L0
, "In readconf\n");
8456 * get config file format version.
8458 fmt_ver
= read_cfile_ver(cfp
, IPQOS_FMT_VERSION_STR
);
8459 if (fmt_ver
== -1) {
8460 return (IPQOS_CONF_ERR
);
8463 * check version is valid
8465 if ((IPP_MAJOR_MODULE_VER(fmt_ver
) > 1) ||
8466 (IPP_MINOR_MODULE_VER(fmt_ver
) > 0)) {
8467 ipqos_msg(MT_ERROR
, gettext("Unsupported config file "
8468 "format version.\n"));
8469 return (IPQOS_CONF_ERR
);
8473 /* loop reading actions adding to conf till EOF */
8480 res
= readaction(cfp
, &action
);
8481 if (res
== IPQOS_CONF_ERR
) {
8485 /* reached eof, finish */
8487 if (res
== IPQOS_CONF_EOF
) {
8491 ADD_TO_LIST(conf
, action
);
8493 /* check if we just read an ipgpc action */
8495 if (strcmp(action
->name
, IPGPC_CLASSIFY
) == 0)
8496 ipgpc_action
= B_TRUE
;
8499 /* check that there is one or more actions and that one is ipgpc */
8501 if (ipgpc_action
== B_FALSE
) {
8502 ipqos_msg(MT_ERROR
, gettext("No %s action defined.\n"),
8507 return (IPQOS_CONF_SUCCESS
);
8509 free_actions(*conf
);
8511 return (IPQOS_CONF_ERR
);
8514 /* ************************ kernel config retrieval ************************ */
8518 * read the current configuration from the kernel and make *conf a ptr to it.
8519 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
8522 readkconf(ipqos_conf_action_t
**conf
)
8526 char **modnames
= NULL
;
8528 char **actnames
= NULL
;
8533 ipqos_actinfo_prm_t ai_prm
;
8536 IPQOSCDBG0(L0
, "In readkconf\n");
8538 /* initialise conf to NULL */
8541 /* get list of modules currently loaded */
8543 res
= ipp_list_mods(&modnames
, &nmods
);
8545 ipqos_msg(MT_ENOSTR
, "ipp_list_mods");
8546 return (IPQOS_CONF_ERR
);
8550 * iterate through all loaded modules retrieving their list of actions
8551 * and then retrieving the configuration of each of these
8552 * and attatching it to conf.
8554 for (x
= 0; x
< nmods
; x
++) {
8556 /* skip actions of modules that we can't open types file of */
8558 if ((tfp
= validmod(modnames
[x
], &openerr
)) == NULL
) {
8566 * fopen fail - if we failed because the file didn't
8567 * exist we assume this is an unknown module and
8568 * ignore this module, otherwise error.
8571 if (errno
== ENOENT
) {
8574 ipqos_msg(MT_ENOSTR
, "fopen");
8581 /* get action list for this module */
8583 res
= ipp_mod_list_actions(modnames
[x
], &actnames
, &nacts
);
8585 ipqos_msg(MT_ENOSTR
, "ipp_mod_list_actions");
8589 /* read config of each action of this module */
8591 for (y
= 0; y
< nacts
; y
++) {
8592 ai_prm
.action
= alloc_action();
8593 if (ai_prm
.action
== NULL
) {
8597 /* copy action name into action struct */
8599 (void) strlcpy(ai_prm
.action
->name
, actnames
[y
],
8600 IPQOS_CONF_NAME_LEN
);
8602 /* copy module name into action struct */
8604 (void) strlcpy(ai_prm
.action
->module
, modnames
[x
],
8605 IPQOS_CONF_NAME_LEN
);
8607 /* get action info */
8609 res
= ipp_action_info(actnames
[y
],
8610 (int (*)(nvlist_t
*, void *))parse_kaction
,
8611 (void *)&ai_prm
, 0);
8613 /* was this an ipp error */
8614 if (ai_prm
.intl_ret
== IPQOS_CONF_SUCCESS
) {
8615 ipqos_msg(MT_ENOSTR
,
8621 ADD_TO_LIST(conf
, ai_prm
.action
);
8624 cleanup_string_table(actnames
, nacts
);
8627 cleanup_string_table(modnames
, nmods
);
8628 return (IPQOS_CONF_SUCCESS
);
8630 free_actions(*conf
);
8632 cleanup_string_table(modnames
, nmods
);
8633 cleanup_string_table(actnames
, nacts
);
8634 return (IPQOS_CONF_ERR
);
8638 * This is passed as a parameter to ipp_action_info() in readkaction and
8639 * is called back one for each configuration element within the action
8640 * specified. This results in filters and classes being created and chained
8641 * off of action, and action having its params set.
8642 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
8647 ipqos_actinfo_prm_t
*ai_prm
)
8652 ipqos_conf_filter_t
*filter
= NULL
;
8653 ipqos_conf_class_t
*class = NULL
;
8654 ipqos_conf_action_t
*action
= ai_prm
->action
;
8657 IPQOSCDBG1(KRET
, "In parse_kaction: action_name: %s\n", action
->name
);
8659 /* get config type */
8661 (void) nvlist_lookup_byte(nvl
, IPP_CONFIG_TYPE
, &cfgtype
);
8662 (void) nvlist_remove_all(nvl
, IPP_CONFIG_TYPE
);
8665 case CLASSIFIER_ADD_FILTER
: {
8667 * parse the passed filter nvlist
8668 * and add result to action's filter list.
8670 filter
= alloc_filter();
8671 if (filter
== NULL
) {
8672 ai_prm
->intl_ret
= IPQOS_CONF_ERR
;
8673 return (IPQOS_CONF_ERR
);
8676 ret
= parse_kfilter(filter
, nvl
);
8677 if (ret
!= IPQOS_CONF_SUCCESS
) {
8678 free_filter(filter
);
8679 ai_prm
->intl_ret
= IPQOS_CONF_ERR
;
8683 ADD_TO_LIST(&action
->filters
, filter
);
8686 case CLASSIFIER_ADD_CLASS
:
8687 case CLASSIFIER_MODIFY_CLASS
: {
8689 * parse the passed class nvlist
8690 * and add result to action's class list.
8692 class = alloc_class();
8693 if (class == NULL
) {
8694 ai_prm
->intl_ret
= IPQOS_CONF_ERR
;
8695 return (IPQOS_CONF_ERR
);
8698 ret
= parse_kclass(class, nvl
);
8699 if (ret
!= IPQOS_CONF_SUCCESS
) {
8701 ai_prm
->intl_ret
= IPQOS_CONF_ERR
;
8705 ADD_TO_LIST(&action
->classes
, class);
8710 * we don't alloc a params struct as it is created
8711 * as part of an action.
8714 /* parse the passed params nvlist */
8716 ret
= parse_kparams(action
->module
, action
->params
,
8718 if (ret
!= IPQOS_CONF_SUCCESS
) {
8719 ai_prm
->intl_ret
= IPQOS_CONF_ERR
;
8725 ai_prm
->intl_ret
= IPQOS_CONF_SUCCESS
;
8726 return (IPQOS_CONF_SUCCESS
);
8730 * parses a params nvlist returned from the kernel.
8731 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
8736 ipqos_conf_params_t
*params
,
8740 ipqos_nvtype_t type
;
8746 char dfltst
[IPQOS_VALST_MAXLEN
];
8752 IPQOSCDBG0(KRET
, "In parse_kparams:\n");
8754 /* get stream to module types file */
8756 tfp
= validmod(module
, &openerr
);
8759 ipqos_msg(MT_ENOSTR
, "fopen");
8761 return (IPQOS_CONF_ERR
);
8764 /* make copy of passed in nvlist as it is freed by the caller */
8766 ret
= nvlist_dup(nvl
, &nvlcp
, 0);
8768 return (IPQOS_CONF_ERR
);
8772 * get config originator and remove from nvlist. If no owner we
8775 ret
= nvlist_lookup_uint32(nvlcp
, IPP_CONFIG_ORIGINATOR
, &u32
);
8777 params
->originator
= u32
;
8778 (void) nvlist_remove_all(nvlcp
, IPP_CONFIG_ORIGINATOR
);
8780 params
->originator
= IPP_CONFIG_IPQOSCONF
;
8783 /* get action stats and remove from nvlist */
8785 ret
= nvlist_lookup_uint32(nvlcp
, IPP_ACTION_STATS_ENABLE
, &u32
);
8787 params
->stats_enable
= *(boolean_t
*)&u32
;
8788 (void) nvlist_remove_all(nvlcp
, IPP_ACTION_STATS_ENABLE
);
8792 * loop throught nvlist elements and for those that are actions create
8793 * action ref entrys for them.
8795 nvp
= nvlist_next_nvpair(nvlcp
, NULL
);
8796 while (nvp
!= NULL
) {
8797 param
= SHORT_NAME(nvpair_name(nvp
));
8799 ret
= readtype(tfp
, module
, param
, &type
, &tmp
, dfltst
,
8801 if (ret
!= IPQOS_CONF_SUCCESS
) {
8805 if ((place
== PL_PARAMS
) && /* avoid map entries */
8806 (type
== IPQOS_DATA_TYPE_ACTION
)) {
8807 (void) nvpair_value_string(nvp
, &act
);
8808 ret
= add_aref(¶ms
->actions
, nvpair_name(nvp
), act
);
8809 if (ret
!= IPQOS_CONF_SUCCESS
) {
8814 nvp
= nvlist_next_nvpair(nvlcp
, nvp
);
8817 /* assign copied nvlist to params struct */
8819 params
->nvlist
= nvlcp
;
8822 return (IPQOS_CONF_SUCCESS
);
8825 free_arefs(params
->actions
);
8826 params
->actions
= NULL
;
8828 return (IPQOS_CONF_ERR
);
8832 * parses a classes nvlist returned from the kernel.
8833 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
8837 ipqos_conf_class_t
*class,
8845 IPQOSCDBG0(KRET
, "In parse_kclass:\n");
8847 /* lookup object originator */
8849 ret
= nvlist_lookup_uint32(nvl
, IPP_CONFIG_ORIGINATOR
, &u32
);
8851 class->originator
= u32
;
8853 class->originator
= IPP_CONFIG_IPQOSCONF
;
8858 (void) nvlist_lookup_string(nvl
, CLASSIFIER_CLASS_NAME
, &str
);
8859 (void) strlcpy(class->name
, str
, IPQOS_CONF_NAME_LEN
);
8860 IPQOSCDBG1(KRET
, "reading class %s\n", class->name
);
8862 /* lookup next action */
8864 (void) nvlist_lookup_string(nvl
, CLASSIFIER_NEXT_ACTION
, &str
);
8865 ret
= add_aref(&class->alist
, NULL
, str
);
8866 if (ret
!= IPQOS_CONF_SUCCESS
) {
8867 return (IPQOS_CONF_ERR
);
8870 /* lookup stats enable */
8872 ret
= nvlist_lookup_uint32(nvl
, CLASSIFIER_CLASS_STATS_ENABLE
, &u32
);
8874 class->stats_enable
= *(boolean_t
*)&u32
;
8877 return (IPQOS_CONF_SUCCESS
);
8881 * parses a filters nvlist returned from the kernel.
8882 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
8886 ipqos_conf_filter_t
*filter
,
8896 IPQOSCDBG0(KRET
, "In parse_kfilter:\n");
8898 /* make copy of passed in nvlist as it is freed by the caller */
8900 ret
= nvlist_dup(nvl
, &nvlcp
, 0);
8902 return (IPQOS_CONF_ERR
);
8905 /* lookup originator */
8907 ret
= nvlist_lookup_uint32(nvlcp
, IPP_CONFIG_ORIGINATOR
, &u32
);
8909 filter
->originator
= u32
;
8910 (void) nvlist_remove_all(nvlcp
, IPP_CONFIG_ORIGINATOR
);
8912 filter
->originator
= IPP_CONFIG_IPQOSCONF
;
8915 /* lookup filter name */
8917 (void) nvlist_lookup_string(nvlcp
, CLASSIFIER_FILTER_NAME
, &str
);
8918 (void) strlcpy(filter
->name
, str
, IPQOS_CONF_NAME_LEN
);
8919 (void) nvlist_remove_all(nvlcp
, CLASSIFIER_FILTER_NAME
);
8921 /* lookup class name */
8923 (void) nvlist_lookup_string(nvlcp
, CLASSIFIER_CLASS_NAME
, &str
);
8924 (void) strlcpy(filter
->class_name
, str
, IPQOS_CONF_NAME_LEN
);
8925 (void) nvlist_remove_all(nvlcp
, CLASSIFIER_CLASS_NAME
);
8927 /* lookup src and dst host names if present */
8929 if (nvlist_lookup_string(nvlcp
, IPGPC_SADDR_HOSTNAME
, &str
) == 0) {
8930 filter
->src_nd_name
= malloc(strlen(str
) + 1);
8931 if (filter
->src_nd_name
) {
8932 (void) strcpy(filter
->src_nd_name
, str
);
8933 (void) nvlist_remove_all(nvlcp
, IPGPC_SADDR_HOSTNAME
);
8935 ipqos_msg(MT_ENOSTR
, "malloc");
8937 return (IPQOS_CONF_ERR
);
8940 if (nvlist_lookup_string(nvlcp
, IPGPC_DADDR_HOSTNAME
, &str
) == 0) {
8941 filter
->dst_nd_name
= malloc(strlen(str
) + 1);
8942 if (filter
->dst_nd_name
) {
8943 (void) strcpy(filter
->dst_nd_name
, str
);
8944 (void) nvlist_remove_all(nvlcp
, IPGPC_DADDR_HOSTNAME
);
8946 ipqos_msg(MT_ENOSTR
, "malloc");
8948 return (IPQOS_CONF_ERR
);
8952 /* lookup ip_version if present */
8954 if (nvlist_lookup_string(nvlcp
, IPGPC_FILTER_PRIVATE
, &str
) == 0) {
8955 filter
->ip_versions
= (uint32_t)strtol(str
, &end
, 0);
8957 (void) nvlist_remove_all(nvlcp
, IPGPC_FILTER_PRIVATE
);
8960 gettext("Corrupted ip_version returned from "
8963 return (IPQOS_CONF_ERR
);
8967 /* lookup filter instance if present */
8969 ret
= nvlist_lookup_int32(nvlcp
, IPGPC_FILTER_INSTANCE
,
8972 filter
->instance
= -1;
8974 (void) nvlist_remove_all(nvlcp
, IPGPC_FILTER_INSTANCE
);
8977 /* attach new trimmed nvlist to filter */
8978 filter
->nvlist
= nvlcp
;
8980 return (IPQOS_CONF_SUCCESS
);
8985 * determines whether action_name is a virtual action name.
8986 * RETURNS: if virtual action 1, else 0.
8989 virtual_action(char *action_name
)
8992 if (strcmp(action_name
, IPP_ANAME_CONT
) == 0 ||
8993 strcmp(action_name
, IPP_ANAME_DEFER
) == 0 ||
8994 strcmp(action_name
, IPP_ANAME_DROP
) == 0) {
9002 * remove all the actions within the kernel. If there is a failure
9003 * modified is set to represent whether the attempt to flush modified
9004 * the configuration in any way.
9005 * RETURNS: IPQOS_CONF_ERR if the ipp_* functions return any errors,
9006 * else IPQOS_CONF_SUCCESS.
9010 boolean_t
*modified
)
9014 char **modnames
= NULL
;
9016 char **actnames
= NULL
;
9020 IPQOSCDBG0(L0
, "In flush\n");
9022 *modified
= B_FALSE
;
9025 * get list of modules currently loaded.
9027 res
= ipp_list_mods(&modnames
, &nmods
);
9029 ipqos_msg(MT_ENOSTR
, "ipp_list_mods");
9030 return (IPQOS_CONF_ERR
);
9034 * iterate through all the modules listing their actions and
9035 * deleting all of them.
9037 for (x
= 0; x
< nmods
; x
++) {
9038 IPQOSCDBG1(APPLY
, "Getting actions of module %s.\n",
9040 res
= ipp_mod_list_actions(modnames
[x
], &actnames
, &nacts
);
9042 ipqos_msg(MT_ENOSTR
, "ipp_mod_list_actions");
9043 cleanup_string_table(modnames
, nmods
);
9044 return (IPQOS_CONF_ERR
);
9047 for (y
= 0; y
< nacts
; y
++) {
9048 IPQOSCDBG1(APPLY
, "deleting action %s\n", actnames
[y
]);
9049 res
= ipp_action_destroy(actnames
[y
], IPP_DESTROY_REF
);
9051 * if fails for reason other than action doesn't
9052 * exist or action has dependency.
9054 if (res
!= 0 && errno
!= ENOENT
&& errno
!= EBUSY
) {
9055 ipqos_msg(MT_ENOSTR
, "ipp_action_destroy");
9056 cleanup_string_table(modnames
, nmods
);
9057 cleanup_string_table(actnames
, nacts
);
9058 return (IPQOS_CONF_ERR
);
9064 cleanup_string_table(actnames
, nacts
);
9066 cleanup_string_table(modnames
, nmods
);
9068 return (IPQOS_CONF_SUCCESS
);
9072 * Trys to flush the configuration. If it fails and nothing has been modified
9073 * and force_flush is false just return an error, otherwise persist trying to
9075 * RETURNS: IPQOS_CONF_ERR if flush attempt failed without modifying anything
9076 * and force_flush was set to false, otherwise IPQOS_CONF_SUCCESS.
9080 boolean_t force_flush
)
9084 boolean_t modified
= B_FALSE
;
9087 * attempt first flush of config.
9089 res
= flush(&modified
);
9090 if ((force_flush
== B_FALSE
) && (res
!= IPQOS_CONF_SUCCESS
) &&
9091 (modified
== B_FALSE
)) {
9092 return (IPQOS_CONF_ERR
);
9093 } else if (res
== IPQOS_CONF_SUCCESS
) {
9094 return (IPQOS_CONF_SUCCESS
);
9098 * failed flush that modified config, or force flush set; loop till
9101 while (res
!= IPQOS_CONF_SUCCESS
) {
9102 if (x
== 5) { /* 10 secs since start/last message. */
9104 gettext("Retrying configuration flush.\n"));
9109 res
= flush(&modified
);
9112 return (IPQOS_CONF_SUCCESS
);
9116 * Performs a flush of the configuration within a signal blocking region
9117 * so that there's minimal chance of it being killed and the flush only
9118 * partially completing.
9119 * RETURNS: IPQOS_CONF_SUCCESS (for symmetry with the other main functions).
9127 * make sure that flush is as atomic as possible.
9129 if ((res
= block_all_signals()) == -1)
9130 return (IPQOS_CONF_ERR
);
9132 res
= atomic_flush(B_FALSE
);
9137 (void) restore_all_signals();
9139 if (res
== IPQOS_CONF_SUCCESS
) {
9140 ipqos_msg(MT_LOG
, gettext("Configuration flushed.\n"));
9142 ipqos_msg(MT_ENOSTR
, "atomic_flush");
9149 in_string_table(char *stable
[], int size
, char *string
)
9152 IPQOSCDBG1(L1
, "In in_string_table: search string %s\n", string
);
9154 for (--size
; size
>= 0; size
--) {
9155 if (strcmp(stable
[size
], string
) == 0) {
9156 IPQOSCDBG1(L1
, "Found %s in string table\n", string
);
9164 /* free the memory occupied by the string table ctable and its contents. */
9166 cleanup_string_table(char *ctable
[], int size
)
9172 for (x
= 0; x
< size
; x
++) {
9182 * makes a copy of a string table and returns a ptr to it.
9183 * RETURNS: NULL on error or if size was 0, else ptr to copied table.
9186 copy_string_table(char *stable1
[], int size
)
9192 /* create char ptr array */
9194 st
= malloc(size
* sizeof (char *));
9196 ipqos_msg(MT_ENOSTR
, "malloc");
9200 /* create copy of each string from stable1 in array */
9202 for (pos
= size
- 1; pos
>= 0; pos
--) {
9203 st
[pos
] = malloc(strlen(stable1
[pos
] + 1));
9204 if (st
[pos
] == NULL
) {
9205 for (pos
++; pos
< size
; pos
++)
9208 ipqos_msg(MT_ENOSTR
, "malloc");
9212 (void) strcpy(st
[pos
], stable1
[pos
]);
9220 * retry lookups on filters that soft failed a previous lookup and
9221 * were put on the retry list.
9222 * RETURNS: IPQOS_CONF_ERR on any errors, else IPQOS_CONF_SUCCESS.
9226 ipqos_conf_action_t
*actions
)
9229 ipqos_conf_action_t
*act
;
9230 ipqos_conf_filter_t
**new_filters
;
9231 ipqos_conf_filter_t
*flt
;
9233 IPQOSCDBG0(APPLY
, "In retry_name_lookups:\n");
9235 for (act
= actions
; act
!= NULL
; act
= act
->next
) {
9237 /* store start of new resolved filters */
9238 GET_LIST_END(&act
->filters
, &new_filters
);
9241 * do name resolution on retry list adding resolved filters
9242 * to end of actions filters.
9244 for (flt
= act
->retry_filters
; flt
!= NULL
; flt
= flt
->next
) {
9246 if (domultihome(flt
, new_filters
, B_TRUE
) !=
9247 IPQOS_CONF_SUCCESS
) {
9249 /* if resource failure */
9251 if (flt
->nlerr
== 0) {
9252 return (IPQOS_CONF_ERR
);
9257 /* add the newly resolved filters to the kernel action */
9259 for (flt
= *new_filters
; flt
!= NULL
; flt
= flt
->next
) {
9260 if (add_filter(act
->name
, flt
, act
->module_version
) !=
9261 IPQOS_CONF_SUCCESS
) {
9262 return (IPQOS_CONF_ERR
);
9267 return (IPQOS_CONF_SUCCESS
);
9271 * write the configuration in conf to the file given in dstpath. This
9272 * is done by writing first to a temporary file and then renaming that
9273 * file to dstpath. This assures an atomic write.
9274 * RETURNS: IPQOS_CONF_ERR on any errors, else IPQOS_CONF_SUCCESS.
9278 ipqos_conf_action_t
*conf
,
9285 ipqos_conf_action_t
*act
;
9288 IPQOSCDBG0(L0
, "in writeconf\n");
9290 /* construct tmp file path so we can use rename() */
9292 pathend
= strrchr(dstpath
, '/');
9294 /* dstpath in current dir */
9296 if (pathend
== NULL
) {
9297 tmppath
= malloc(strlen("ipqosconf.tmp") + 1);
9298 if (tmppath
== NULL
) {
9299 ipqos_msg(MT_ENOSTR
, "malloc");
9300 return (IPQOS_CONF_ERR
);
9302 (void) strcpy(tmppath
, "ipqosconf.tmp");
9304 /* dstpath in root dir */
9306 } else if (pathend
== dstpath
) {
9307 tmppath
= malloc(strlen("/ipqosconf.tmp") + 1);
9308 if (tmppath
== NULL
) {
9309 ipqos_msg(MT_ENOSTR
, "malloc");
9310 return (IPQOS_CONF_ERR
);
9312 (void) strcpy(tmppath
, "/ipqosconf.tmp");
9314 /* not pwd or root */
9318 tmppath
= malloc(strlen(dstpath
) + strlen("/ipqosconf.tmp") +
9320 if (tmppath
== NULL
) {
9321 ipqos_msg(MT_ENOSTR
, "malloc");
9322 return (IPQOS_CONF_ERR
);
9324 (void) strcpy(tmppath
, dstpath
);
9325 (void) strcat(tmppath
, "/ipqosconf.tmp");
9332 tmpfp
= fopen(tmppath
, "w");
9333 if (tmpfp
== NULL
) {
9334 ipqos_msg(MT_ENOSTR
, "fopen");
9336 return (IPQOS_CONF_ERR
);
9339 /* write out format version */
9341 (void) fprintf(tmpfp
, "%s %d.%d\n\n", IPQOS_FMT_VERSION_STR
,
9342 IPQOS_CUR_FMT_MAJOR_VER
, IPQOS_CUR_FMT_MINOR_VER
);
9345 * loop through actions in list writing ipqosconf originated
9346 * ones out to the tmp file.
9348 for (act
= conf
; act
!= NULL
; act
= act
->next
) {
9349 if (act
->params
->originator
== IPP_CONFIG_IPQOSCONF
) {
9350 res
= printaction(tmpfp
, act
, 0, 0);
9351 if (res
!= IPQOS_CONF_SUCCESS
) {
9353 (void) fclose(tmpfp
);
9358 (void) fclose(tmpfp
);
9360 /* rename tmp file to dst file */
9362 if (rename(tmppath
, dstpath
) != 0) {
9363 ipqos_msg(MT_ENOSTR
, "rename");
9365 return (IPQOS_CONF_ERR
);
9369 return (IPQOS_CONF_SUCCESS
);
9373 * read the configuration back from the kernel and then write each of the
9374 * actions read to IPQOS_CONF_INIT_PATH.
9375 * RETURNS: IPQOS_CONF_ERR if error, else IPQOS_CONF_SUCCESS.
9382 ipqos_conf_action_t
*conf
;
9384 IPQOSCDBG0(L0
, "In commitconf\n");
9386 /* read the configuration from the kernel */
9388 ret
= readkconf(&conf
);
9389 if (ret
!= IPQOS_CONF_SUCCESS
) {
9390 return (IPQOS_CONF_ERR
);
9393 /* dissallow a null config to be stored (we can't read one in) */
9397 gettext("Can't commit a null configuration.\n"));
9398 return (IPQOS_CONF_ERR
);
9401 /* make sure if we create file that perms are 644 */
9403 (void) umask(S_IXUSR
| S_IWGRP
| S_IXGRP
| S_IWOTH
| S_IXOTH
);
9405 /* write the configuration to the init file */
9407 ret
= writeconf(conf
, IPQOS_CONF_INIT_PATH
);
9408 if (ret
!= IPQOS_CONF_SUCCESS
) {
9409 return (IPQOS_CONF_ERR
);
9413 gettext("Current configuration saved to init file.\n"));
9415 return (IPQOS_CONF_SUCCESS
);
9419 * Called in the event of a failed rollback. It first flushes the
9420 * current configuration, then attempts to apply the oconf (the old
9421 * one), and if that fails flushes again.
9423 * RETURNS: IPQOS_CONF_ERR if the application of old config fails,
9424 * else IPQOS_CONF_SUCCESS.
9428 ipqos_conf_action_t
*oconf
)
9432 IPQOSCDBG0(RBK
, "In rollback_recover\n");
9435 * flush configuration.
9437 (void) atomic_flush(B_TRUE
);
9440 * mark all elements of old config for application.
9442 mark_config_new(oconf
);
9445 * attempt to apply old config.
9447 res
= applydiff(oconf
, NULL
);
9449 * if failed force flush of config.
9451 if (res
!= IPQOS_CONF_SUCCESS
) {
9452 (void) atomic_flush(B_TRUE
);
9453 return (IPQOS_CONF_ERR
);
9456 return (IPQOS_CONF_SUCCESS
);
9460 * read and apply the configuration contained if file ifile to the kernel.
9461 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
9464 applyconf(char *ifile
)
9468 ipqos_conf_action_t
*conf
= NULL
;
9469 ipqos_conf_action_t
*oconf
= NULL
;
9470 ipqos_conf_action_t
*act
, *oact
;
9473 IPQOSCDBG0(L0
, "In applyconf:\n");
9476 /* if filename '-' read from stdin */
9478 if (strcmp(ifile
, "-") == 0) {
9481 ifp
= fopen(ifile
, "r");
9484 gettext("Opening file %s for read: %s.\n"),
9485 ifile
, strerror(errno
));
9486 return (IPQOS_CONF_ERR
);
9490 /* read in new configuration */
9492 res
= readconf(ifp
, &conf
);
9493 if (res
!= IPQOS_CONF_SUCCESS
) {
9497 /* check configuration is valid */
9499 res
= validconf(conf
, 1);
9500 if (res
!= IPQOS_CONF_SUCCESS
) {
9504 /* read in kernel configuration */
9506 res
= readkconf(&oconf
);
9507 if (res
!= IPQOS_CONF_SUCCESS
) {
9512 * check there are no same named actions in both config file and the
9513 * the kernel that are for a different module. The application
9514 * system can't handle these as we would try to add the new
9515 * action before we deleted the old one and because actions
9516 * in the kernel are indexed solely on their name (their module
9517 * isn't included) the kernel would return an error. We want
9518 * to avoid this error and the resulting rollback.
9520 for (act
= conf
; act
!= NULL
; act
= act
->next
) {
9521 for (oact
= oconf
; oact
!= NULL
; oact
= oact
->next
) {
9523 if (strcmp(act
->name
, oact
->name
) == 0) {
9524 /* different module */
9525 if (strcmp(act
->module
, oact
->module
) != 0) {
9527 gettext("Action at line %u has "
9528 "same name as currently "
9529 "installed action, but is for a "
9530 "different module.\n"),
9533 /* same module - stop search */
9542 /* create links between actions for use with deletions etc.. */
9544 res
= validconf(oconf
, 0);
9545 if (res
!= IPQOS_CONF_SUCCESS
) {
9549 /* diff conf file against kernel */
9551 res
= diffconf(oconf
, conf
);
9552 if (res
!= IPQOS_CONF_SUCCESS
) {
9556 /* make kernel mods as atomic as possible */
9558 if ((res
= block_all_signals()) == -1) {
9559 res
= IPQOS_CONF_ERR
;
9563 /* apply difference to kernel */
9565 res
= applydiff(conf
, oconf
);
9566 #ifdef _IPQOS_CONF_DEBUG
9567 if (force_rback
|| res
!= IPQOS_CONF_SUCCESS
) {
9569 if (res
!= IPQOS_CONF_SUCCESS
) {
9570 #endif /* _IPQOS_CONF_DEBUG */
9572 res
= rollback(conf
, oconf
);
9573 if (res
!= IPQOS_CONF_SUCCESS
) {
9574 res
= rollback_recover(oconf
);
9575 if (res
!= IPQOS_CONF_SUCCESS
) {
9576 /* system left flushed */
9578 gettext("Failed to rollback from failed "
9579 "configuration, configuration flushed.\n"));
9580 res
= IPQOS_CONF_RECOVER_ERR
;
9581 } else { /* old config re-applied */
9583 gettext("Configuration failed, system "
9584 "state unchanged.\n"));
9585 res
= IPQOS_CONF_ERR
;
9589 gettext("Configuration failed, system "
9590 "state unchanged.\n"));
9591 res
= IPQOS_CONF_ERR
;
9596 /* retry any soft name lookup failures */
9598 res
= retry_name_lookups(conf
);
9599 if (res
!= IPQOS_CONF_SUCCESS
) {
9600 res
= rollback(conf
, oconf
);
9601 if (res
!= IPQOS_CONF_SUCCESS
) {
9602 res
= rollback_recover(oconf
);
9603 if (res
!= IPQOS_CONF_SUCCESS
) {
9604 /* system left flushed */
9606 gettext("Failed to rollback from failed "
9607 "configuration, configuration flushed.\n"));
9608 res
= IPQOS_CONF_RECOVER_ERR
;
9609 } else { /* old config re-applied */
9611 gettext("Configuration failed, system "
9612 "state unchanged.\n"));
9613 res
= IPQOS_CONF_ERR
;
9617 gettext("Configuration failed, system "
9618 "state unchanged.\n"));
9619 res
= IPQOS_CONF_ERR
;
9625 ipqos_msg(MT_LOG
, gettext("IPQoS configuration applied.\n"));
9627 /* re-enable signals */
9628 (void) restore_all_signals();
9632 free_actions(oconf
);
9633 return (IPQOS_CONF_SUCCESS
);
9636 (void) restore_all_signals();
9640 free_actions(oconf
);
9641 if (res
== IPQOS_CONF_RECOVER_ERR
)
9642 ipqos_msg(MT_LOG
, gettext("Configuration flushed.\n"));
9646 static sigset_t set
, oset
;
9651 if (sigfillset(&set
) == -1) {
9652 ipqos_msg(MT_ENOSTR
, "sigfillset");
9655 if (sigprocmask(SIG_SETMASK
, &set
, &oset
) == -1) {
9656 ipqos_msg(MT_ENOSTR
, "sigprocmask");
9663 restore_all_signals()
9665 if (sigprocmask(SIG_SETMASK
, &oset
, NULL
) == -1) {
9666 ipqos_msg(MT_ENOSTR
, "sigprocmask");
9675 if (lockf(fd
, F_ULOCK
, 0) == -1) {
9676 ipqos_msg(MT_ENOSTR
, "lockf");
9690 * Open the file with O_CREAT|O_EXCL. If it exists already, it
9691 * will fail. If it already exists, check whether it looks like
9692 * the one we created.
9695 if ((fd
= open(IPQOS_CONF_LOCK_FILE
, O_EXCL
|O_CREAT
|O_RDWR
,
9696 S_IRUSR
|S_IWUSR
)) == -1) {
9697 if (errno
!= EEXIST
) {
9698 /* Some other problem. */
9699 ipqos_msg(MT_ENOSTR
,
9700 gettext("Cannot open lock file %s"),
9701 IPQOS_CONF_LOCK_FILE
);
9706 * open() returned an EEXIST error. We don't fail yet
9707 * as it could be a residual from a previous
9708 * execution. However, we need to clear errno here.
9709 * If we don't and print_cmd_buf() is later invoked
9710 * as the result of a parsing error, it
9711 * will assume that the current error is EEXIST and
9712 * that a corresponding error message has already been
9713 * printed, which results in an incomplete error
9714 * message. If errno is zero, print_cmd_buf() will
9715 * assume that it is called as a result of a
9716 * parsing error and will print the appropriate
9722 * File exists. make sure it is OK. We need to lstat()
9723 * as fstat() stats the file pointed to by the symbolic
9726 if (lstat(IPQOS_CONF_LOCK_FILE
, &sbuf1
) == -1) {
9727 ipqos_msg(MT_ENOSTR
,
9728 gettext("Cannot lstat lock file %s\n"),
9729 IPQOS_CONF_LOCK_FILE
);
9733 * Check whether it is a regular file and not a symbolic
9734 * link. Its link count should be 1. The owner should be
9735 * root and the file should be empty.
9737 if (!S_ISREG(sbuf1
.st_mode
) ||
9738 sbuf1
.st_nlink
!= 1 ||
9739 sbuf1
.st_uid
!= 0 ||
9740 sbuf1
.st_size
!= 0) {
9741 ipqos_msg(MT_ERROR
, gettext("Bad lock file %s.\n"),
9742 IPQOS_CONF_LOCK_FILE
);
9745 if ((fd
= open(IPQOS_CONF_LOCK_FILE
, O_CREAT
|O_RDWR
,
9746 S_IRUSR
|S_IWUSR
)) == -1) {
9747 ipqos_msg(MT_ENOSTR
,
9748 gettext("Cannot open lock file %s"),
9749 IPQOS_CONF_LOCK_FILE
);
9753 /* Check whether we opened the file that we lstat()ed. */
9754 if (fstat(fd
, &sbuf2
) == -1) {
9755 ipqos_msg(MT_ENOSTR
,
9756 gettext("Cannot fstat lock file %s\n"),
9757 IPQOS_CONF_LOCK_FILE
);
9760 if (sbuf1
.st_dev
!= sbuf2
.st_dev
||
9761 sbuf1
.st_ino
!= sbuf2
.st_ino
) {
9762 /* File changed after we did the lstat() above */
9763 ipqos_msg(MT_ERROR
, gettext("Bad lock file %s.\n"),
9764 IPQOS_CONF_LOCK_FILE
);
9768 if (lockf(fd
, F_LOCK
, 0) == -1) {
9769 ipqos_msg(MT_ENOSTR
, "lockf");
9776 * print the current kernel configuration out to stdout. If viewall
9777 * is set this causes more verbose configuration listing including
9778 * showing objects we didn't create, each instance of a mhome filter,
9779 * etc.. see printaction().
9780 * RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
9784 viewconf(int viewall
)
9787 ipqos_conf_action_t
*conf
= NULL
;
9788 ipqos_conf_action_t
*act
;
9791 IPQOSCDBG0(L0
, "In viewconf\n");
9793 /* get kernel configuration */
9795 ret
= readkconf(&conf
);
9796 if (ret
!= IPQOS_CONF_SUCCESS
) {
9797 return (IPQOS_CONF_ERR
);
9800 /* write out format version */
9803 (void) fprintf(stdout
, "%s %d.%d\n\n", IPQOS_FMT_VERSION_STR
,
9804 IPQOS_CUR_FMT_MAJOR_VER
, IPQOS_CUR_FMT_MINOR_VER
);
9807 /* print each of the actions in the kernel config to stdout */
9809 for (act
= conf
; act
!= NULL
; act
= act
->next
) {
9810 ret
= printaction(stdout
, act
, viewall
, 0);
9811 if (ret
!= IPQOS_CONF_SUCCESS
) {
9815 (void) fprintf(stdout
, "\n");
9820 return (IPQOS_CONF_SUCCESS
);
9825 * debug function that reads the config file and prints it out after
9826 * interpreting to stdout.
9828 #ifdef _IPQOS_CONF_DEBUG
9830 viewcfile(char *cfile
)
9833 ipqos_conf_action_t
*conf
;
9834 ipqos_conf_action_t
*act
;
9839 IPQOSCDBG0(L0
, "In viewcfile\n");
9840 ifp
= fopen(cfile
, "r");
9842 ipqos_msg(MT_ERROR
, gettext("Opening file %s for read: %s.\n"),
9843 cfile
, strerror(errno
));
9844 return (IPQOS_CONF_ERR
);
9847 res
= readconf(ifp
, &conf
);
9848 if (res
!= IPQOS_CONF_SUCCESS
) {
9850 return (IPQOS_CONF_ERR
);
9853 /* print each of the actions in the kernel config to stdout */
9854 for (act
= conf
; act
!= NULL
; act
= act
->next
) {
9855 res
= printaction(stdout
, act
, viewall
, 0);
9856 if (res
!= IPQOS_CONF_SUCCESS
) {
9861 (void) fprintf(stdout
, "\n");
9864 (void) fprintf(stdout
, "\n");
9867 return (IPQOS_CONF_SUCCESS
);
9869 #endif /* _IPQOS_CONF_DEBUG */
9874 (void) fprintf(stderr
, gettext("usage:\n"
9875 "\tipqosconf [-sv] -a file|-\n"
9879 "\tipqosconf -f\n"));
9883 main(int argc
, char *argv
[])
9894 /* init global flags */
9895 use_syslog
= verbose
= 0;
9897 /* init current line number */
9900 /* setup internationalisation */
9902 (void) setlocale(LC_ALL
, "");
9903 #if !defined(TEXT_DOMAIN)
9904 #define TEXT_DOMAIN "SYS_TEST"
9906 (void) textdomain(TEXT_DOMAIN
);
9908 /* setup syslog parameters */
9909 openlog("ipqosconf", 0, LOG_USER
);
9913 /* enable debug options */
9915 #ifdef _IPQOS_CONF_DEBUG
9916 #define DBGOPTS "rz:"
9919 #endif /* _IPQOS_CONF_DEBUG */
9921 while ((c
= getopt(argc
, argv
, "sca:vflL" DBGOPTS
)) != EOF
) {
9923 #ifdef _IPQOS_CONF_DEBUG
9927 if (*ifile
== '\0') {
9936 #endif /* _IPQOS_CONF_DEBUG */
9938 cmd
= IPQOS_CONF_COMMIT
;
9942 cmd
= IPQOS_CONF_APPLY
;
9944 if (*ifile
== '\0') {
9951 cmd
= IPQOS_CONF_FLUSH
;
9955 cmd
= IPQOS_CONF_VIEW
;
9959 cmd
= IPQOS_CONF_VIEW
;
9976 * dissallow non-option args, > 1 cmd args and syslog/verbose flags set
9977 * for anything but apply.
9979 if (optind
!= argc
|| args
> 1 ||
9980 use_syslog
&& cmd
!= IPQOS_CONF_APPLY
||
9981 verbose
&& cmd
!= IPQOS_CONF_APPLY
) {
9986 /* if no cmd option then show config */
9989 cmd
= IPQOS_CONF_VIEW
;
9992 /* stop concurrent ipqosconf invocations */
9999 #ifdef _IPQOS_CONF_DEBUG
10001 ret
= viewcfile(ifile
);
10003 #endif /* _IPQOS_CONF_DEBUG */
10004 case IPQOS_CONF_APPLY
:
10005 ret
= applyconf(ifile
);
10007 case IPQOS_CONF_COMMIT
:
10008 ret
= commitconf();
10010 case IPQOS_CONF_VIEW
:
10011 ret
= viewconf(viewall
);
10013 case IPQOS_CONF_FLUSH
:
10018 (void) unlock(lfp
);