/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* enable debug output and some debug asserts */
#include <stdlib.h>
#include <unistd.h>
#include <libintl.h>
#include <signal.h>
#include <strings.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <libipp.h>
#include <ipp/ipp_config.h>
#ifdef _IPQOS_CONF_DEBUG
#include <assert.h>
#endif
#include <syslog.h>
#include <stdarg.h>
#include <libintl.h>
#include <locale.h>
#include <pwd.h>
#include "ipqosconf.h"
#if defined(_IPQOS_CONF_DEBUG)
/* debug level */
static int ipqosconf_dbg_flgs =
/*
*/
RBK |
MHME |
KRET |
DIFF |
APPLY |
L2 |
L1 |
L0 |
0;
if (lvl & ipqosconf_dbg_flgs)\
if (lvl & ipqosconf_dbg_flgs)\
if (lvl & ipqosconf_dbg_flgs)\
if (lvl & ipqosconf_dbg_flgs)\
if (lvl & ipqosconf_dbg_flgs)\
if (lvl & ipqosconf_dbg_flgs)\
#else /* defined(_IPQOS_CONF_DEBUG) && !defined(lint) */
#endif /* defined(_IPQOS_CONF_DEBUG) */
/* function prototypes */
static int modify_class(char *, char *, int, boolean_t, char *,
enum ipp_flags);
static int remove_class(char *, char *, int, enum ipp_flags);
static int add_filter(char *, ipqos_conf_filter_t *, int);
static int modify_filter(char *, ipqos_conf_filter_t *, int);
static int remove_filter(char *, char *, int, int);
static int modify_items(ipqos_conf_action_t *);
static int rollback_recover(ipqos_conf_action_t *);
static int readllong(char *, long long *, char **);
static int readuint16(char *, uint16_t *, char **);
static int readint32(char *, int *, char **);
static int readuint32(char *, uint32_t *, char **);
static void setmask(int, in6_addr_t *, int);
static char *prepend_module_name(char *, char *);
ipqos_nvtype_t *, place_t, char *);
static int add_aref(ipqos_conf_act_ref_t **, char *, char *);
int);
static int actions_unique(ipqos_conf_action_t *, char **);
static int validconf(ipqos_conf_action_t *, int);
static int atomic_flush(boolean_t);
static int flushconf();
static int writeconf(ipqos_conf_action_t *, char *);
static int commitconf();
static int block_all_signals();
static int restore_all_signals();
static int lock();
static int viewconf(int);
static void usage();
static int valid_name(char *);
static int in_cycle(ipqos_conf_action_t *);
int *, char *);
static str_val_nd_t *read_enum_nvs(char *, char *);
static void free_str_val_entrys(str_val_nd_t *);
static void get_str_val_value_range(str_val_nd_t *, int *, int *);
int);
str_val_nd_t *);
static int readkconf(ipqos_conf_action_t **);
int);
int, place_t);
static int virtual_action(char *);
static void free_arefs(ipqos_conf_act_ref_t *);
static void print_action_nm(FILE *, char *);
static int add_orig_ipqosconf(nvlist_t *);
static char *get_originator_nm(uint32_t);
static void mark_classes_filters_new(ipqos_conf_action_t *);
static void mark_classes_filters_del(ipqos_conf_action_t *);
static void mark_config_new(ipqos_conf_action_t *);
static int printifname(FILE *, int);
static int readifindex(char *, int *);
static void cleanup_string_table(char **, int);
void *, void *, int);
static void free_actions(ipqos_conf_action_t *);
static ipqos_conf_filter_t *alloc_filter();
static void free_filter(ipqos_conf_filter_t *);
static int read_curl_begin(FILE *);
static ipqos_conf_class_t *alloc_class(void);
static int read_perm_items(int, FILE *, char *, char ***, int *);
static int read_cfile_ver(FILE *, char *);
static char *quote_ws_string(const char *);
static int read_tfile_ver(FILE *, char *, char *);
static int ver_str_to_int(char *);
/*
* macros to call list functions with the more complex list element type
* cast to the skeletal type iqpos_list_el_t.
*/
/*
* Macros to produce a quoted string containing the value of a
* preprocessor macro. For example, if SIZE is defined to be 256,
* VAL2STR(SIZE) is "256". This is used to construct format
* strings for scanf-family functions below.
*/
#define QUOTE(x) #x
/* globals */
/* table of supported parameter types and enum value */
{"uint8", IPQOS_DATA_TYPE_UINT8},
{"int16", IPQOS_DATA_TYPE_INT16},
{"uint16", IPQOS_DATA_TYPE_UINT16},
{"int32", IPQOS_DATA_TYPE_INT32},
{"uint32", IPQOS_DATA_TYPE_UINT32},
{"boolean", IPQOS_DATA_TYPE_BOOLEAN},
{"string", IPQOS_DATA_TYPE_STRING},
{"action", IPQOS_DATA_TYPE_ACTION},
{"address", IPQOS_DATA_TYPE_ADDRESS},
{"port", IPQOS_DATA_TYPE_PORT},
{"protocol", IPQOS_DATA_TYPE_PROTO},
{"enum", IPQOS_DATA_TYPE_ENUM},
{"ifname", IPQOS_DATA_TYPE_IFNAME},
{"mindex", IPQOS_DATA_TYPE_M_INDEX},
{"int_array", IPQOS_DATA_TYPE_INT_ARRAY},
{"user", IPQOS_DATA_TYPE_USER},
{"", 0}
};
/* table of name to id mappings for originator field */
{"", -1}
};
/* current parse line */
static int lineno;
/* verbose output flag */
static int verbose;
/* use syslog for msg reporting flag */
static int use_syslog;
#ifdef _IPQOS_CONF_DEBUG
/*
* flag used to indicate that a rollback should be carried out regardless.
* Only settable during debug.
*/
static int force_rback = 0;
#endif /* _IPQOS_CONF_DEBUG */
/*
* delivers messages to either syslog or stderr, dependant upon the
* the state of the flags use_syslog and verbose. The type
* of the msg as given in msg_type is indicated in the output msg.
*
* valid message types are:
* o MT_ERROR (standard error message)
* o MT_ENOSTR (error message with system error string appended)
* o MT_WARNING (warning message)
* o MT_LOG (logging message)
*
* Log messages only go to syslog. Warning messages only go to stderr
* and only when the verbose flag is set. All other messages go by default
* to the console; to syslog if syslog flag set, and to both if both
* syslog and verbose are set.
*
*/
/*PRINTFLIKE2*/
static void
{
char *cp;
/*
* send msgs to syslog if use_syslog set (except warning msgs),
* or a log msg.
*/
/* fill in format string */
/*
* print message to syslog with appropriate severity
*/
/*
* for errno message type suffix with %m for syslog to
* interpret.
*/
/*
* remove any newline in message parameter.
* syslog will reapply a newline for us later.
*/
*cp = '\0';
}
}
/*
* send msgs to stderr if use_syslog not set (except log msgs), or
* if verbose set.
*/
/*
* prefix message with appropriate severity string
*/
} else if (msgt == MT_WARNING) {
if (!verbose) { /* don't show warn msg if !verbose */
return;
}
}
/*
* for errno message type suffix message with errno string
*/
/*
* get rid of any newline in passed message.
* we'll apply another later.
*/
*cp = '\0';
}
/*
* append a newline to message if not one already.
*/
}
}
/*
* modify the kernel parameters of the action action_nm using the nvlist
* parameter nvl and setting the stats according to stats_enable.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
char *action_name,
int module_version,
{
int res;
int created = 0;
/* create nvlist if NULL */
created++;
if (res != 0) {
return (IPQOS_CONF_ERR);
}
}
/* add params modify config type */
if (res != 0) {
goto fail;
}
/*
* add module version
*/
(uint32_t)module_version) != 0) {
goto fail;
}
/* add stats_enable */
if (res != 0) {
goto fail;
}
/* add ipqosconf as originator */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/* call lib to do modify */
if (res != 0) {
/* invalid parameters */
gettext("Invalid parameters for action %s.\n"),
gettext("Mandatory parameter missing for "
"action %s.\n"), action_name);
} else { /* unexpected error */
"%s parameters: %s.\n"), action_name,
}
goto fail;
}
return (IPQOS_CONF_SUCCESS);
fail:
nvlist_free(*nvl);
}
return (IPQOS_CONF_ERR);
}
/*
* add a class to the kernel action action_name called class_name with
* stats set according to stats_enable and the first action set to
* first_action.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
char *action_name,
char *class_name,
int module_version,
char *first_action)
{
/* create nvlist */
return (IPQOS_CONF_ERR);
}
/* add 'add class' config type */
goto fail;
}
/*
* add module version
*/
(uint32_t)module_version) != 0) {
goto fail;
}
/* add class name */
goto fail;
}
/* add next action */
goto fail;
}
/* add stats_enable */
(uint32_t)stats_enable) != 0) {
goto fail;
}
/* add ipqosconf as originator */
goto fail;
}
/* call lib to do modify */
/* ipgpc max classes */
gettext("Max number of classes reached in %s.\n"),
/* other errors */
} else {
gettext("Failed to create class %s in action "
}
goto fail;
}
return (IPQOS_CONF_SUCCESS);
fail:
return (IPQOS_CONF_ERR);
}
/*
* modify the class in the kernel action action_name called class_name with
* stats set according to stats_enable and the first action set to
* first_action.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
char *action_name,
char *class_name,
int module_version,
char *first_action,
{
/* create nvlist */
return (IPQOS_CONF_ERR);
}
/* add 'modify class' config type */
0) {
goto fail;
}
/*
* add module version
*/
(uint32_t)module_version) != 0) {
goto fail;
}
/* add class name */
goto fail;
}
/* add next action */
goto fail;
}
/* add stats enable */
(uint32_t)stats_enable) != 0) {
goto fail;
}
/* add originator ipqosconf */
goto fail;
}
/* call lib to do modify */
/* generic error message */
gettext("Modifying class %s in action %s failed: %s.\n"),
goto fail;
}
return (IPQOS_CONF_SUCCESS);
fail:
return (IPQOS_CONF_ERR);
}
/*
* removes the class class_name from the kernel action action_name. The
* flags argument can currently be set to IPP_ACTION_DESTROY which will
* result in the action this class references being destroyed.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
char *action_name,
char *class_name,
int module_version,
{
/* allocate nvlist */
return (IPQOS_CONF_ERR);
}
/* add 'remove class' config type */
0) {
goto fail;
}
/*
* add module version
*/
(uint32_t)module_version) != 0) {
goto fail;
}
/* add class name */
goto fail;
}
/* generic error message */
gettext("Removing class %s in action %s failed: %s.\n"),
goto fail;
}
return (IPQOS_CONF_SUCCESS);
fail:
return (IPQOS_CONF_ERR);
}
/*
* add the filter flt to the kernel action named action_name.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
char *action_name,
int module_version)
{
/* add 'add filter' config type to filter nvlist */
return (IPQOS_CONF_ERR);
}
/*
* add module version
*/
(uint32_t)module_version) != 0) {
return (IPQOS_CONF_ERR);
}
/* add filter name to nvlist */
return (IPQOS_CONF_ERR);
}
/* add class name to nvlist */
0) {
return (IPQOS_CONF_ERR);
}
/* add ipqosconf as originator to nvlist */
return (IPQOS_CONF_ERR);
}
/* add ipgpc specific nv entrys */
/* add src and dst nodes to nvlist if present */
flt->src_nd_name) != 0) {
return (IPQOS_CONF_ERR);
}
flt->dst_nd_name) != 0) {
return (IPQOS_CONF_ERR);
}
/*
* add ip_version to private list element if present.
* NOTE: this value is of only real use to ipqosconf so
* it is placed in this opaque private field.
*/
if (flt->ip_versions != 0) {
ipvsbuf) != 0) {
return (IPQOS_CONF_ERR);
}
}
/* add filter instance if present */
return (IPQOS_CONF_ERR);
}
}
/* invalid parameters */
"reached in action %s.\n"), IPGPC_NAME);
/* anything other errnos */
} else {
gettext("Failed to create filter %s in action "
}
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* modify the filter flt in the kernel action named action_name.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
char *action_name,
int module_version)
{
/* show src address and dst address if present */
#ifdef _IPQOS_CONF_DEBUG
if (ipqosconf_dbg_flgs & APPLY) {
}
}
}
#endif /* _IPQOS_CONF_DEBUG */
/* add 'modify filter' config type to filters nvlist */
CLASSIFIER_MODIFY_FILTER) != 0) {
return (IPQOS_CONF_ERR);
}
/*
* add module version
*/
(uint32_t)module_version) != 0) {
return (IPQOS_CONF_ERR);
}
/* add filter name to nvlist */
return (IPQOS_CONF_ERR);
}
/* add class name to nvlist */
0) {
return (IPQOS_CONF_ERR);
}
/* add originator ipqosconf to nvlist */
return (IPQOS_CONF_ERR);
}
/* add ipgpc specific nvpairs */
/* add src and dst nodes to nvlist if present */
if (flt->src_nd_name &&
flt->src_nd_name) != 0) {
return (IPQOS_CONF_ERR);
}
if (flt->dst_nd_name &&
flt->dst_nd_name) != 0) {
return (IPQOS_CONF_ERR);
}
/*
* add ip_version to private list element if present.
* NOTE: this value is of only real use to ipqosconf so
* it is placed in this opaque private field.
*/
if (flt->ip_versions != 0) {
ipvsbuf) != 0) {
return (IPQOS_CONF_ERR);
}
}
/* add filter instance if present */
return (IPQOS_CONF_ERR);
}
}
/* invalid parameters */
"parameter for filter %s in action %s.\n"),
/* any other errnos */
} else {
gettext("Failed to modify filter %s in action %s: "
}
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* remove the filter named filter_name instance number instance from the
* kernel action action_name.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
char *action_name,
char *filter_name,
int instance,
int module_version)
{
/* create nvlist */
return (IPQOS_CONF_ERR);
}
/* add 'remove filter' config type to list */
!= 0) {
return (IPQOS_CONF_ERR);
}
/*
* add module version
*/
(uint32_t)module_version) != 0) {
return (IPQOS_CONF_ERR);
}
/* add filter name to list */
return (IPQOS_CONF_ERR);
}
/* add instance number if part of multi-instance filter */
instance) != 0) {
return (IPQOS_CONF_ERR);
}
/* call into lib to remove */
/* generic error message */
gettext("Removing filter %s in action %s failed: %s.\n"),
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/* ******************************************************************* */
/*
* add originator nvpair set to ipqosconf to nvl.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
{
IPP_CONFIG_IPQOSCONF) != 0) {
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/* ************************* differencing functions ************************ */
/*
* compares the contents of arrays array1 and array2, both of size size, and
* returns B_TRUE or B_FALSE if they're equal or not respectively.
* RETURNS: B_TRUE if equal, else B_FALSE.
*/
static boolean_t
int array1[],
int array2[],
{
int x;
for (x = 0; x < size; x++) {
return (B_FALSE);
}
return (B_TRUE);
}
/*
* difference class old against class new. It marks the new class as
* modified if it is different.
* RETURNS: IPQOS_CONF_SUCCESS.
*/
static int
{
/* two different spec'd actions */
return (IPQOS_CONF_SUCCESS);
}
/* different stats values */
return (IPQOS_CONF_SUCCESS);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* difference params set old against params set new of module module_name. It
* marks the new params as modified if different.
* RETURNS: if error IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
*/
static int
char *module_name)
{
int diff;
int res;
/* diff stats */
return (IPQOS_CONF_SUCCESS);
}
/* diff module specific params */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
if (diff) {
}
return (IPQOS_CONF_SUCCESS);
}
/*
* differences filter old against filter new of module module_name. It marks
* filter new as different if so.
* RETURNS: if error IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
*/
static int
char *module_name)
{
int res;
int diff;
/* compare class name */
return (IPQOS_CONF_SUCCESS);
}
/* compare module specific params */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
if (diff) {
}
return (IPQOS_CONF_SUCCESS);
}
/*
* mark all the filters and classes in parameter action either
* for deletion (if they are ipqosconf originated) or for modification.
*/
static void
{
/* mark all non-permanent filters for del and permanent to modify */
} else {
}
}
/* mark all non-permanent classes for del and permanent to modify */
} else {
}
}
}
/*
* mark all classes and filters either new (non-permanent) or modified.
*/
static void
{
/* mark all permanent filters as modified and all others new */
} else {
}
}
/* mark all permanent classes as modified and all others new */
} else {
}
}
}
/*
* Marks all the actions and their constituent elements in conf
* as new.
*/
static void
{
}
}
/*
* differences the configuration in new against old marking the actions
* and their contents appropriately.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/* check the new actions against the old */
/* if action not in old mark it and it's contents as new */
continue;
}
/* if action in old diff old against new */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
/*
* mark actions, and their contents, in old but not new that were
* created by us for del.
*/
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* differences action old against action new, comparing its classes, filters
* and parameters. If it is different the new action is marked as modified
* and it's different sub-objects are also marked approriately.
* RETURNS: IPQOS_CONF_ERR if error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/* compare and mark classes */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/* compare and mark filters */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/* compare and mark parameters */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/* mark action as modified if params are */
}
return (IPQOS_CONF_SUCCESS);
}
/*
* differences the set of classes in new against those in old, marking any
* in the old class appropriately. Also marks the action which has had an
* object within marked, as modified.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/* loop through old classes checking for classes not present in new */
/* if we created original class mark for deletion */
/* mark old action */
/*
* if permanent class and next action created by us
* copy it, set it's next action to continue and
* add it to new action. This will cause the class
* to be marked as and modified. This returns the class
* to an assumed default state and prevents the
* case where the class is pointing at an action
* we want to remove and therefore couldn't without
* this forced modify.
*/
/* copy class */
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
/* set next action to continue */
/* add to news classes to be diffed below */
}
}
}
/* loop through new classes checking for new / modified classes */
/* new ipqosconf class */
continue;
} else {
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* differences the set of filters in new against those in old, marking any
* in the old filter appropriately. Also marks the action which has had an
* object within marked, as modified.
* RETURNS: IPQOS_CONF_SUCCESS (we return an int for symmetry with diffclasses
* and difffparams).
*/
static int
{
int maxi;
int newi;
int res;
/* new ipqosconf filter */
/* mark all instances of this filter as new */
for (;;) {
break;
}
}
} else {
/*
* if ip node name force filter refresh - ie. mark
* all old filter instances as todel and all new new.
*/
/* init max previous filter instance */
/* mark old instances for deletion */
do {
"%s, instance %d for del\n",
/*
* check and update previous instance
* max.
*/
}
/*
* use the max previous instance + 1 for
* the start of the new instance numbers.
*/
/*
* mark new instances for addition and
* give new instance number.
*/
for (;;) {
"%s, instance %d as new\n",
break;
}
}
/* mark old action */
/* non-node name filter */
} else {
/* compare and mark as modified if diff */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/* mark action if diff */
}
}
}
}
/*
* Check for deleted ipqosconf created filters and mark
* any found for deletion.
* For non-ipqosconf generated filters, including permanent
* ones (none of these exist at the moment) we just leave
* the filter unmarked.
*/
/* mark all old instances for deletions */
for (;;) {
break;
}
}
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* differences the elements of nvlists old and new using the types file
* for module name to interpret the element types. It sets pdiff to either
* 0 or 1 if they are the same or different respectively.
* RETURNS: IPQOS_CONF_ERR if any errors, else IPQOS_CONF_SUCCESS.
*/
static int
char *module_name,
int *pdiff,
{
int res;
char *lo;
char *nme;
int diff;
int openerr;
/* open stream to types file */
if (openerr) {
}
return (IPQOS_CONF_ERR);
}
/*
* loop through each of the elements of the new list comparing
* it with the old one if present. If the old one isn't present
* then it is compared with the default value for that type (if
* set). Any time the values are determined to be different
* or the default value is to be used but isn't present the diff
* param is set to 1 and we return.
*
* If the loop runs its course then the new and old nvlists are
* reversed and the loop is entered for a second time.
*/
/* get name */
/*
* get type.
*/
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/* init diff to 1 */
diff = 1;
switch (type) {
/* interface name */
case IPQOS_DATA_TYPE_IFINDEX: {
/* get new value */
/* compare against old if present */
if (res == 0) {
/* diff values */
/* not in old so see if new value is default */
} else {
}
break;
}
/* protocol */
case IPQOS_DATA_TYPE_PROTO: {
if (res == 0) {
} else {
}
break;
}
/* port */
case IPQOS_DATA_TYPE_PORT: {
if (res == 0) {
} else {
}
break;
}
/* action name / string */
case IPQOS_DATA_TYPE_ACTION:
case IPQOS_DATA_TYPE_STRING: {
char *str;
char *ostr;
if (res == 0) {
} else if (*dfltst) {
}
break;
}
/* address mask / address */
case IPQOS_DATA_TYPE_ADDRESS: {
uint_t x;
/*
* all addresses are stored as v6 addresses, so
* a uint32_t[4] array is used.
*/
/* lookup new value */
(void) nvpair_value_uint32_array(nvp,
/* see if there's an old value and diff it */
if (res == 0) {
/* diff each of the 16 v6 address bytes */
for (x = 0; x < 16; x++) {
diff++;
break;
}
}
}
break;
}
/* boolean */
case IPQOS_DATA_TYPE_BOOLEAN: {
/* see if there's an old value and diff it */
if (res == 0) {
/* compare against default if present */
} else if (*dfltst) {
if (res == IPQOS_CONF_SUCCESS) {
}
}
break;
}
/* uint 8 */
case IPQOS_DATA_TYPE_UINT8: {
if (res == 0) {
} else if (*dfltst) {
if (res == IPQOS_CONF_SUCCESS) {
}
}
break;
}
/* int 16 */
case IPQOS_DATA_TYPE_INT16: {
if (res == 0) {
} else if (*dfltst) {
if (res == IPQOS_CONF_SUCCESS) {
}
}
break;
}
/* uint16 */
case IPQOS_DATA_TYPE_UINT16: {
if (res == 0) {
} else if (*dfltst) {
if (res == IPQOS_CONF_SUCCESS) {
}
}
break;
}
/*
* int32 and user.
* Since user uids are stored in an int32 nvpair we can use
* the same comparison code.
*/
case IPQOS_DATA_TYPE_USER:
case IPQOS_DATA_TYPE_INT32: {
if (res == 0) {
} else if (*dfltst) {
if (res == IPQOS_CONF_SUCCESS) {
}
}
break;
}
/* uint32 */
case IPQOS_DATA_TYPE_UINT32: {
if (res == 0) {
} else if (*dfltst) {
if (res == IPQOS_CONF_SUCCESS) {
}
}
break;
}
/* enumeration */
case IPQOS_DATA_TYPE_ENUM: {
if (res == 0) {
} else if (*dfltst) {
if (res == IPQOS_CONF_SUCCESS) {
}
}
break;
}
case IPQOS_DATA_TYPE_M_INDEX: {
if (res == 0)
break;
}
case IPQOS_DATA_TYPE_INT_ARRAY: {
&osize);
if (res == 0)
B_FALSE);
break;
}
#ifdef _IPQOS_CONF_DEBUG
default: {
/* shouldn't get here as all types should be covered */
assert(1);
}
#endif
} /* switch */
if (diff != 0) {
*pdiff = 1;
return (IPQOS_CONF_SUCCESS);
}
}
/* now compare all the stuff in the second list with the first */
if (first_pass) {
first_pass = 0;
goto start;
}
*pdiff = 0;
return (IPQOS_CONF_SUCCESS);
}
/* ************************** difference application *********************** */
/*
* causes all items marked as requiring change in actions and old_actions
* to have the change applied.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/* add each item marked as new */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/* modify items marked for modification */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/* delete items marked for deletion */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
return (IPQOS_CONF_SUCCESS);
}
static int
{
int res;
/*
* we need to create ipgpc action before any others as some actions
* such as ftpcl which make calls to it depend on it being there on
* their creation.
*/
if (act &&
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
/*
* loop though action list and add any actions marked as
*/
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
*
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/* if already visited return immediately */
return (IPQOS_CONF_SUCCESS);
}
/* recurse to last action in tree */
/* if not virtual action */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
/* if not virtual */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
/* if action marked as new and not ipgpc, create */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
/* add any classes and filters marked as new */
rem_undo) != IPQOS_CONF_SUCCESS ||
rem_undo) != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Uses the contents of acts params nvlist and adds an originator
* element set to ipqosconf and the stats parameter. This list
* is then used as the parameter to a call to ipp_action_create to create
* this action in the kernel.
* RETURNS: IPQOS_CONF_ERR on err, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/* alloc params nvlist if not already one */
if (res != 0) {
return (IPQOS_CONF_ERR);
}
}
/*
* add module version
*/
return (IPQOS_CONF_ERR);
}
/* add action stats */
return (IPQOS_CONF_ERR);
}
/* add ipqosconf originator id */
return (IPQOS_CONF_ERR);
}
/* call into lib to create action */
if (res != 0) {
/* invalid params */
gettext("Invalid Parameters for action %s.\n"),
gettext("Missing required parameter for action "
} else { /* unexpected error */
}
return (IPQOS_CONF_ERR);
}
/* mark action as created */
return (IPQOS_CONF_SUCCESS);
}
/*
* for each of the filters in parameter filters if rem_undo is false and
* the filter is marked as new or if rem_undo is true and the filter is
* marked as deleted then add the filter to the kernel action named by action
* and if successful mark as created.
* RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
*/
static int
char *action,
int module_version,
{
/* loop through filters in filters param */
/*
* skip filter if in normal mode and not new filter or
* if doing rollback and filter wasn't previously deleted.
*/
continue;
}
/* add filter to action */
return (IPQOS_CONF_ERR);
}
/* mark as created */
}
return (IPQOS_CONF_SUCCESS);
}
/*
* for each of the classes in parameter classes if rem_undo is false and
* the class is marked as new or if rem_undo is true and the class is
* marked as deleted then add the class to the kernel action named by action
* and if successful mark as created.
* RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
*/
int
char *action,
int module_version,
int res;
/* for each class */
/*
* skip class if in normal mode and not new class or
* if doing rollback and class wasn't deleted.
*/
continue;
}
/* add class to action */
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
/* mark class as created */
}
return (IPQOS_CONF_SUCCESS);
}
/*
* For each of the actions in actions remove the action if marked as
* such or remove any objects within marked as such.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/*
* loop through actions removing any actions, or action contents
* that are marked as such.
*/
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Deletes this action if marked for deletion or any of it's contents marked
* for deletion. If the action is marked for deletion any actions referencing
* this action are destroyed first if marked or have their contents destroyed
* if marked. This is recursive.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/* return immmediately if previously visited in remove phase */
return (IPQOS_CONF_SUCCESS);
}
/* if this action is to be deleted */
/* modify parent actions first */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
/* delete this action */
if (res != 0) {
return (IPQOS_CONF_ERR);
}
/* flag as deleted */
/* if modified action */
/* loop through removing any filters marked for del */
/* do deletion */
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
/* flag deleted */
}
}
/* remove any classes marked for del */
/* do deletion */
act->module_version, 0);
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
/* flag deleted */
}
}
/* mark action as having been modified */
}
return (IPQOS_CONF_SUCCESS);
}
/*
* for each of the actions in parameter actions apply any objects marked as
* modified as a modification to the kernel action represented.
* RETURNS: IPQOS_CONF_ERR on err, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/* loop through actions in parameter actions */
/* skip unchanged actions */
continue;
}
/* apply any parameter mods */
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
}
/* apply any class mods */
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
/* mark modification done */
}
}
/* apply any filter mods */
if (res != 0) {
return (IPQOS_CONF_ERR);
}
/* mark modification done */
}
}
/* mark action modified */
}
return (IPQOS_CONF_SUCCESS);
}
/*
* For each of the objects of each of the actions in nactions that are
* marked as having been modified the object modification is done in
* reverse using the same named object from oactions.
* RETURNS: IPQOS_CONF_ERR on error, IPQOS_CONF_SUCCESS otherwise.
*/
static int
{
int res;
/* loop throught new actions */
/*
* if the action was new then it will be removed and
* any permamanent items that were marked for modify
* will dissappear, so ignore action.
*/
continue;
}
/* if parameters were modified switch them back */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
/* for each filter in action if filter modified switch back */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
/* for each class in action if class modified switch back */
}
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
}
/*
* Go through the old actions modifying perm filters and classes
* whose action was deleted.
*
*/
continue;
}
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* causes all changes marked as being done in actions and old_actions
* to be undone.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/* re-add items that were deleted */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/* change modified items back how they were */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/* remove new items that were added */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
return (IPQOS_CONF_SUCCESS);
}
/* ******************************* print config **************************** */
/*
* Prints the username of the user with uid 'uid' to 'fp' if the uid belongs
* to a known user on the system, otherwise just print 'uid'.
*/
static void
{
} else {
}
}
/*
* print either a single value of start to fp (if start equals end), else
* print start'-'end if start is the smaller of the two values, otherwise
* print end'-'start.
*/
static void
{
}
}
/*
* print the contents of the array arr to fp in the form:
* {0-6:1;7-12:2;13:3.....} or {0-6:GREEN;7-12:YELLOW:...}
* dependant upon whether this is an integer or enumerated array resectively
* (if enum_nvs isn't set to NULL this is assumed to be an enumerated array);
* where 0-6 is the range of indexes with value 1 (or GREEN), 7-12 the range
* with value 2 (or YELLOW), and so forth. size is the array size and llimit
* and ulimit are the lower and upper limits of the array values printed
* respectively. For enumerated arrays enum_nvs carries the list of name
* and value pairs and ulimit and llimit parameters are ignored and instead
* determined from the enum_nvs list.
*/
static void
int arr[],
int llimit,
int ulimit,
int tab_inserts)
{
int x, y;
/*
* if an enumeration retrieve value range.
*/
/*
* print opening curl.
*/
/*
* for each value in range.
*/
y = 0;
/*
* scan array and print ranges of indexes with value x.
*/
while (y < size) {
/*
* get first occurence of value for this range.
*/
y++;
if (y == size) {
break;
} else {
}
first = y;
/*
* get last occurence of value for this range.
*/
y++;
last = y - 1;
/*
* print entry delimiter (semi-colon)? It must be
* the first range for this value and this mustn't
* be the first 'ranges:value' entry.
*/
if (!first_entry && first_range) {
} else {
}
/*
* print comma (range delimeter) only if there was
* a previous range for this value.
*/
if (!first_range) {
} else {
}
/*
* print range.
*/
}
/*
* only print a colon and value if we found a range with
* this value.
*/
if (found_range) {
/*
*/
if (enum_nvs) {
} else {
}
}
}
/*
* print closing curl.
*/
}
/* print the protocol name for proto, or if unknown protocol number proto. */
static void
{
} else {
}
}
/*
* prints the name associated with interface with index ifindex to fp.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
int ifindex)
{
int s;
char *buf;
int len;
char *cp;
int ret;
int x;
int idx;
/* open socket */
return (IPQOS_CONF_ERR);
}
/* get number of lifreq structs that need to be alloc'd for */
ln.lifn_flags = 0;
if (ret < 0) {
(void) close(s);
return (IPQOS_CONF_ERR);
}
/* allocate buffer for SIOGLIFCONF ioctl */
(void) close(s);
return (IPQOS_CONF_ERR);
}
/* setup lifconf params for ioctl */
lc.lifc_flags = 0;
/* do SIOCGLIFCONF ioctl */
if (ret < 0) {
(void) close(s);
return (IPQOS_CONF_ERR);
}
(void) close(s);
/*
* for each interface name given in the returned lifreq list get
* it's index and compare with ifindex param. Break if equal.
*/
if (ret != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
break;
}
}
if (x == 0) {
"if list.\n", ifindex);
return (IPQOS_CONF_ERR);
}
/* truncate any logical suffix */
}
/* print interface name */
return (IPQOS_CONF_SUCCESS);
}
/*
* print to fp the enumeration clause evaluating to the value val using the
*/
static void
{
/* for each value in enum_nvs if same bit set in val print name */
while (name_val) {
if (isfirstval == B_TRUE) {
} else {
}
}
}
}
/* prints the service name of port, or if unknown the number to fp. */
static void
{
} else {
}
}
/*
* prints tp fp the name and value of all user specifiable parameters in the
* nvlist.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
char *module,
int printall, /* are we want ip addresses printing if node name */
int tab_inserts,
{
char *name;
int ret;
char *param;
int openerr;
int res;
/* open stream to types file */
if (openerr) {
}
return (IPQOS_CONF_ERR);
}
/* go through list getting param name and type and printing it */
while (nvp) {
/* get nvpair name */
/* skip ipgpc params that are not explicitly user settable */
continue;
}
/*
* get parameter type from types file.
*/
if (ret != IPQOS_CONF_SUCCESS) {
return (ret);
}
/*
* for map entries we don't print the map value, only
* the index value it was derived from.
*/
continue;
}
/*
* the ifindex is converted to the name and printed out
* so print the parameter name as ifname.
*/
/*
* we may not print the address due to us instead printing
* the node name in printfilter, therefore we leave the
* printing of the parameter in the addresses switch case code.
*/
}
switch (type) {
case IPQOS_DATA_TYPE_IFINDEX: {
break;
}
case IPQOS_DATA_TYPE_BOOLEAN: {
(void) nvpair_value_uint32(nvp,
break;
}
case IPQOS_DATA_TYPE_ACTION: {
char *strval;
break;
}
case IPQOS_DATA_TYPE_STRING: {
char *strval;
break;
}
case IPQOS_DATA_TYPE_ADDRESS: {
int af;
/*
* skip addresses that have node names for
* non printall listings.
*/
if (printall == 0 &&
0 && flt->src_nd_name ||
0 && flt->dst_nd_name)) {
break;
}
/* we skipped this above */
(void) nvpair_value_uint32_array(nvp,
/* get filter type */
(void) nvlist_lookup_byte(nvl,
if (ftype == IPGPC_V4_FLTR) {
addr = (in6_addr_t *)
&V4_PART_OF_V6((*addr));
} else {
}
/* get mask */
0) {
} else {
}
break;
}
case IPQOS_DATA_TYPE_ENUM: {
/*
* print list of tokens resulting in val
*/
break;
}
case IPQOS_DATA_TYPE_PORT: {
break;
}
case IPQOS_DATA_TYPE_PROTO: {
break;
}
case IPQOS_DATA_TYPE_M_INDEX:
case IPQOS_DATA_TYPE_UINT8: {
break;
}
case IPQOS_DATA_TYPE_UINT16: {
break;
}
case IPQOS_DATA_TYPE_INT16: {
break;
}
case IPQOS_DATA_TYPE_UINT32: {
break;
}
case IPQOS_DATA_TYPE_INT32: {
int i32;
break;
}
case IPQOS_DATA_TYPE_INT_ARRAY: {
int *arr;
&size);
/*
* read array info from types file.
*/
module);
/*
* print array with numbers, or symbols
* if enumerated.
*/
if (res == IPQOS_CONF_SUCCESS) {
if (arr_enum_nvs != NULL) {
}
}
break;
}
case IPQOS_DATA_TYPE_USER: {
break;
}
#ifdef _IPQOS_CONF_DEBUG
default: {
/*
* we should have catered for all used data
* types that readtype returns.
*/
assert(1);
}
#endif
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* print a parameter clause for the parmeters given in params to fp.
* If printall is set, then the originator of the parameter object is printed.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
char *module,
int printall,
int tab_inserts)
{
int res;
/* print opening clause */
/* print originator name if printall flag set */
if (printall) {
}
/* print global stats */
/* print module specific parameters */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* print the interpreted name of the action_nm parameter if it is a special
* action, else action_nm verbatim to fp parameter.
*/
static void
{
} else {
}
}
/*
* print a class clause for class to fp. If printall is set the originator
* is printed.
*/
static void
int printall,
int tab_inserts)
{
/* print opening clause */
/* if printall flag print originator name */
if (printall) {
}
/* print name, next action and stats enable */
}
/*
* Returns a ptr to the originator name associated with origid. If unknown
* id returns ptr to "unknown".
* RETURNS: ptr to originator name, or if id not known "unknown".
*/
static char *
{
int x;
/* scan originators table for origid */
/* if we've reached end of array due to unknown type return "unknown" */
return ("unknown");
}
return (originators[x].string);
}
/*
* print a filter clause for filter pointed to by filter out to fp. If printall
* is set then the originator is printed, for filters with node names instance
* numbers are printed, and the filter pointer isn't advanced to point at the
* last instance of the printed filter.
* RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
*/
static int
char *module,
int printall,
int tab_inserts)
{
int res;
/* print opening clause */
/* print originator if printall flag set */
if (printall) {
}
/* print name and class */
/* print the instance if printall and potential mhomed addresses */
}
/* print node names if any */
if ((*filter)->src_nd_name) {
(*filter)->src_nd_name);
}
if ((*filter)->dst_nd_name) {
(*filter)->dst_nd_name);
}
/* print ip_version enumeration if set */
if ((*filter)->ip_versions != 0) {
if (VERSION_IS_V4(*filter)) {
}
if (VERSION_IS_V6(*filter)) {
}
}
/* print other module specific parameters parameters */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/*
* if not printall advance filter parameter to last instance of this
* filter.
*/
if (!printall) {
for (;;) {
0) {
break;
}
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Returns a pointer to str if no whitespace is present, else it returns
* a pointer to a string with the contents of str enclose in double quotes.
* This returned strings contents may change in subsequent calls so a copy
* should be made of it if the caller wishes to retain it.
*/
static char *
{
/*
* Just return str if no whitespace.
*/
;
if (*cp == '\0')
return ((char *)str);
/*
* if first run just allocate buffer of
* strlen(str) + 2 quote characters + NULL terminator.
*/
/*
* Not first run, so check if we have a big enough buffer
* and if not reallocate the buffer to a sufficient size.
*/
}
return ("");
/*
* copy string into buffer with quotes.
*/
return (buf);
}
/*
* print an action clause for action to fp. If the printall flag is set
* then all filters and classes (regardless of their originator) and
* their originators are displayed.
* RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
*/
static int
int printall,
int tab_inserts)
{
int res;
/* print opening clause, module and name */
/* print params clause */
tab_inserts + 1);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/*
* print classes clause for each class if printall is set, else
* just ipqosconf created or permanent classes.
*/
if (printall ||
}
}
/*
* print filter clause for each filter if printall is set, else
* just ipqosconf created or permanent filters.
*/
if (printall ||
tab_inserts + 1);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
return (IPQOS_CONF_SUCCESS);
}
/* *************************************************************** */
static void
{
}
}
static void
{
}
/*
* given mask calculates the number of bits it spans. The mask must be
* continuous.
* RETURNS: number of bits spanned.
*/
static int
int af,
{
int zeros = 0;
int byte;
int cidr;
/*
* loop through from lowest byte to highest byte counting the
* number of zero bits till hitting a one bit.
*/
/*
* zero byte, so add 8 to zeros.
*/
zeros += 8;
/*
* non-zero byte, add zero count to zeros.
*/
} else {
break;
}
}
/*
* translate zero bits to 32 or 128 bit mask based on af.
*/
} else {
}
return (cidr);
}
/*
* Sets the first prefix_len bits in the v4 or v6 address (based upon af)
* contained in the v6 address referenced by addr to 1.
*/
static void
{
int i;
int shift;
int end_u32;
/* zero addr */
/* set which 32bits in *addr are relevant to this af */
end_u32 = 3;
/* AF_INET6 */
} else {
end_u32 = 0;
}
/*
* go through each of the 32bit quantities in 128 bit in6_addr_t
* and set appropriate bits according to prefix_len.
*/
for (i = 3; i >= end_u32; i--) {
/* does the prefix apply to this 32bits? */
/* is this 32bits fully masked? */
shift = 0;
} else {
}
}
/* translate to NBO */
}
}
/*
* search nvlist for an element with the name specified and return a ptr
* to it if found.
* RETURNS: pointer to nvpair named name if found, else NULL.
*/
static nvpair_t *
{
char *nvp_name;
while (nvp) {
}
}
return (match);
}
/*
* returns a string containing module_name '.' name.
* RETURNS: IPQOS_CONF_ERR if error, else IPQOS_CONF_SUCCESS.
*/
static char *
char *name,
char *module)
{
char *ret;
return (NULL);
}
return (ret);
}
#if 0
/*
* check if element with matching s1 and s2 string is in table table.
* RETURNS: 1 if found else 0.
*/
static int
char *s1,
char *s2)
{
/* loop through table till matched or end */
ss++;
}
return (1);
}
return (0);
}
#endif /* 0 */
/*
* RETURNS: IPQOS_CONF_ERR if invalid name else IPQOS_CONF_SUCCESS.
*/
static int
{
/* first char can't be '!' */
if (name[0] == '!') {
"'!', line %u.\n"), lineno);
return (IPQOS_CONF_ERR);
}
/* can't exceed IPQOS_CONF_NAME_LEN size */
"line %u.\n"), lineno);
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/* ********************* string value manip fns ************************** */
/*
* searches through the str_val_nd_t list of string value pairs finding
* the minimum and maximum values for value and places them in the
* integers pointed at by min and max.
*/
static void
int *min,
int *max)
{
}
}
}
/*
* add an entry with string string and value val to sv_entrys.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
char *string,
{
val);
/* alloc new node */
return (IPQOS_CONF_ERR);
}
/* populate node */
return (IPQOS_CONF_ERR);
} else {
}
/* place at start of sv_entrys list */
return (IPQOS_CONF_SUCCESS);
}
/* frees all the elements of sv_entrys. */
static void
{
while (sve) {
}
}
/*
* finds the value associated with string and assigns it to value ref'd by
* val.
* RETURNS: IPQOS_CONF_ERR if string not found, else IPQOS_CONF_SUCCESS.
*/
static int
char *string,
{
/* loop through list and exit when found or list end */
break;
}
}
/* ret error if not found */
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/* ************************ conf file read fns ***************************** */
/*
* Reads a uid or username from string 'str' and assigns either the uid
* or associated uid respectively to storage pointed at by 'uid'. The
* function determines whether to read a uid by checking whether the first
* character of 'str' is numeric, in which case it reads a uid; otherwise it
* assumes a username.
* RETURNS: IPQOS_CONF_ERR if a NULL string pointer is passed, the read uid
* doesn't have an entry on the system, or the read username doesn't have an
* entry on the system.
*/
static int
char *str,
{
char *lo;
return (IPQOS_CONF_ERR);
/*
* Check if this appears to be a uid, and if so check that a
* corresponding user exists.
*/
/*
* Read a 32bit integer and check in doing so that
* we have consumed the whole string.
*/
*lo != '\0')
return (IPQOS_CONF_ERR);
return (IPQOS_CONF_ERR);
} else { /* This must be a username, so lookup the uid. */
return (IPQOS_CONF_ERR);
} else {
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Reads a range from range_st, either of form 'a-b' or simply 'a'.
* In the former case lower and upper have their values set to a
* and b respectively; in the later lower and upper have both
* their values set to a.
* RETURNS: IPQOS_CONF_ERR if there's a parse error, else IPQOS_CONF_SUCCESS.
*/
static int
char *range_st,
int *lower,
int *upper)
{
char *cp;
/*
* get range boundarys.
*/
*cp++ = '\0';
return (IPQOS_CONF_ERR);
}
} else { /* single value */
return (IPQOS_CONF_ERR);
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Reads the values of an integer array from fp whose format is:
* '{'RANGE[,RANGE[..]]:VALUE[;RANGE:VALUE[..]]'}', creates an array of size
* arr_size, applies the values to it and points arrp at this array.
* RANGE is one set of array indexes over which this value is to
* be applied, and VALUE either an integer within the range
* llimit - ulimit, or if enum_nvs isn't NULL, an enumeration value
* found in the list enum_nvs. Those values which aren't explicity set
* will be set to -1.
*
* RETURNS: IPQOS_CONF_ERR on resource or parse error, else IPQOS_CONF_SUCCESS.
*/
static int
char *first_token,
int **arrp,
int llimit,
int ulimit,
{
char *token;
char *range;
char *ranges;
char *svalue;
int value;
int res;
char *entry;
char *tmp;
char *end;
int x;
/*
* read beginning curl.
*/
if (first_token[0] != CURL_BEGIN) {
"%u.\n"), lineno);
return (IPQOS_CONF_ERR);
}
/*
* allocate and initialise array for holding read values.
*/
return (IPQOS_CONF_ERR);
}
/*
* read whole array declaration string into buffer.
* this is because readtoken doesn't interpret our
* delimeter values specially and may return them
* within another string.
*/
buf[0] = '\0';
(res != IPQOS_CONF_EOF)) {
}
if (res != IPQOS_CONF_CURL_END) {
goto array_err;
}
/*
* loop reading "ranges ':' value;" till end of buffer.
*/
goto array_err;
}
*svalue++ = '\0';
/*
* get value of number or enumerated symbol.
*/
if (enum_nvs) {
/*
* get rid of surrounding whitespace so as not to
* confuse read_enum_value.
*/
while (*tmp != '\0') {
*tmp = '\0';
break;
} else {
tmp++;
}
}
/*
* read enumeration value.
*/
if (res != IPQOS_CONF_SUCCESS)
goto array_err;
} else {
goto array_err;
}
/*
* check value within valid range.
*/
goto array_err;
}
}
/*
* loop reading ranges for this value.
*/
if (res != IPQOS_CONF_SUCCESS)
goto array_err;
upper = u;
}
/*
* check range valid for array size.
*/
"dimensions\n");
goto array_err;
}
/*
* add this value to array indexes within range.
*/
/*
* get next range.
*/
}
}
return (IPQOS_CONF_SUCCESS);
return (IPQOS_CONF_ERR);
}
static int
{
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
{
long long tmp;
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
{
long long tmp;
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
{
long long tmp;
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
{
long long tmp;
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
{
long long tmp;
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* retrieves the index associated with the interface named ifname and assigns
* it to the int pointed to by ifindex.
* RETURNS: IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
*/
static int
char *ifname,
int *ifindex)
{
int s;
/* open socket */
return (IPQOS_CONF_ERR);
}
/* copy ifname into lifreq */
/* do SIOGLIFINDEX ioctl */
(void) close(s);
return (IPQOS_CONF_ERR);
}
/* Warn if a virtual interface is specified */
}
(void) close(s);
return (IPQOS_CONF_SUCCESS);
}
/*
* Case insensitively compares the string in str with IPQOS_CONF_TRUE_STR
* and IPQOS_CONF_FALSE_STR and sets boolean pointed to by bool accordingly.
* RETURNS: if failure to match either IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
*/
static int
{
*bool = B_TRUE;
*bool = B_FALSE;
} else {
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* to the uint8 ref'd by proto.
* RETURNS: If not a valid name or protocol number IPQOS_CONF_ERR, else
* IPQOS_CONF_SUCCESS.
*/
static int
{
char *lo;
int res;
/* try name lookup */
if (pent) {
/* check valid protocol number */
} else {
return (IPQOS_CONF_ERR);
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* reads either a port service, or a port number from port_str and assigns
* the associated port number to short ref'd by port.
* RETURNS: If invalid name and number IPQOS_CONF_ERR, else IPQOS_CONF_SUCCESS.
*/
static int
{
char *tmp;
/* try service name lookup */
/* failed name lookup so read port number */
*port == 0) {
return (IPQOS_CONF_ERR);
}
} else {
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Reads a curly brace, a string enclosed in double quotes, or a whitespace/
* curly brace delimited string. If a double quote enclosed string the
* closing quotes need to be on the same line.
* RETURNS:
* on reading a CURL_BEGIN token it returns IPQOS_CONF_CURL_BEGIN,
* on reading a CURL_END token it returns IPQOS_CONF_CURL_END,
* on reading another valid token it returns IPQOS_CONF_SUCCESS.
* for each of these token is set to point at the read string.
* at EOF it returns IPQOS_CONF_EOF and if errors it returns IPQOS_CONF_ERR.
*/
static int
char **token)
{
int len;
int quoted = 0;
char *cmnt;
char *bpos;
int rembuf;
static char *lo;
static int bufsize;
/* if first call initialize line buf to default size */
return (IPQOS_CONF_ERR);
}
}
/* set buffer postition and size to use whole buffer */
/*
* loop reading lines until we've read a line with a non-whitespace
* char.
*/
do {
/* if no leftover from previous invocation */
/*
* loop reading into buffer doubling if necessary until
* we have either read a complete line or reached the
* end of file.
*/
for (;;) {
/* if read error */
"fgets");
return (IPQOS_CONF_ERR);
/* end of file */
} else {
return (IPQOS_CONF_EOF);
}
} else {
/* if read a newline */
lineno++;
break;
/* if read the last line */
break;
/*
* not read a full line so buffer size
* is too small, double it and retry.
*/
} else {
bufsize *= 2;
"realloc");
return (IPQOS_CONF_ERR);
} else {
}
/*
* make parameters to fgets read
* into centre of doubled buffer
* so we retain what we've
* already read.
*/
}
}
}
/* previous leftover, assign to st */
} else {
}
/* truncate at comment */
if (cmnt) {
*cmnt = '\0';
}
/* Skip any whitespace */
st++;
}
} while (*st == '\0');
/* find end of token */
/* if curl advance 1 char */
tmp++;
/* if dbl quote read until matching quote */
} else if (*tmp == '"') {
quoted++;
tmp++;
}
if (*tmp != '"') {
"line, line %u.\n"), lineno);
return (IPQOS_CONF_ERR);
}
/* normal token */
} else {
/* find first whitespace, curl, newline or string end */
tmp++;
}
}
/* copy token to return */
if (!*token) {
return (IPQOS_CONF_ERR);
}
/* if just read quoted string remove quote from remaining string */
if (quoted) {
tmp++;
}
/* if not end of string, store rest for latter parsing */
}
/* for curl_end and curl_begin return special ret codes */
if (**token == CURL_BEGIN) {
return (IPQOS_CONF_CURL_BEGIN);
return (IPQOS_CONF_CURL_END);
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Reads an enumeration bitmask definition from line. The format is:
* { NAME=VAL, NAME2=VAL2 }. The resulting names and values are returned.
*/
static str_val_nd_t *
{
char *cp;
char *start;
int len;
int ret;
int readc;
/* read opening brace */
goto fail;
} else {
}
/*
* loop reading 'name = value' entrys seperated by comma until
* reach closing brace.
*/
for (;;) {
if (*start == '\0') {
goto fail;
}
/*
* read name - read until whitespace, '=', closing curl,
* or string end.
*/
if (*cp == '\0') {
goto fail;
/* finished definition, exit loop */
break;
}
/* store name */
goto fail;
}
/* read assignment */
goto fail;
}
/* read value */
if (ret != 1) {
cp);
goto fail;
}
/* add name value to set */
if (ret != IPQOS_CONF_SUCCESS) {
goto fail;
}
/* try reading comma */
/* no comma, advance to char past value last read */
} else {
}
}
return (enum_vals);
fail:
/* if a parse error */
if (errno == 0) {
"corrupt.\n"), module_name);
}
return (NULL);
}
/*
* Given mapped_list with is a comma seperated list of map names, and value,
* which is used to index into these maps, the function creates x new entries
* in nvpp, where x is the number of map names specified. Each of these
* entries has the value from the map in the position indexed by value and
* with name module.${MAP_NAME}. The maps are contained in the modules config
* file and have the form:
* map map1 uint32 1,23,32,45,3
* As you can see the map values are uint32, and along with uint8 are the
* only supported types at the moment.
*
* RETURNS: IPQOS_CONF_ERR if one of the maps specified in mapped_list
* doesn't exist, if value is not a valid map position for a map, or if
* there's a resource failure. otherwise IPQOS_CONF_SUCCESS is returned.
*/
static int
char *module,
char *mapped_list,
int value)
{
int res;
int index = 0;
/*
* get map info from types file.
*/
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
/*
* Just keep browsing the list till we get to the element
* with the index from the value parameter or the end.
*/
for (;;) {
gettext("Invalid value, %u, line %u.\n"),
return (IPQOS_CONF_ERR);
}
break;
}
}
/*
* create fully qualified parameter name for map value.
*/
return (IPQOS_CONF_ERR);
}
/*
* add map value with fqn to parameter nvlist.
*/
switch (type) {
case IPQOS_DATA_TYPE_UINT8: {
if (res != 0) {
"nvlist_add_uint8");
return (IPQOS_CONF_ERR);
}
break;
}
case IPQOS_DATA_TYPE_UINT32: {
if (res != 0) {
"nvlist_add_uint32");
return (IPQOS_CONF_ERR);
}
break;
}
default: {
gettext("Types file for module %s is "
"corrupt.\n"), module);
"parameter %s given in types file.\n",
map_name);
return (IPQOS_CONF_ERR);
}
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Parses the string info_str into it's components. Its format is:
* SIZE','[ENUM_DEF | RANGE], where SIZE is the size of the array,
* ENUM_DEF is the definition of the enumeration for this array,
* and RANGE is the set of values this array can accept. In
* the event this array has an enumeration definition enum_nvs is
* set to point at a str_val_nd_t structure which stores the names
* and values associated with this enumeration. Otherwise, if this
* is not an enumerated array, lower and upper are set to the lower
* and upper values of RANGE.
* RETURNS: IPQOS_CONF_ERR due to unexpected parse errors, else
* IPQOS_CONF_SUCCESS.
*/
static int
char *info_str,
int *lower,
int *upper,
char *module)
{
int res;
char *end;
char *token;
char *tmp;
goto fail;
}
/*
* read size.
*/
goto fail;
}
/*
* check we have another string.
*/
goto fail;
}
/*
* check if enumeration set or integer set and read enumeration
* definition or integer range respectively.
*/
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
} else { /* an enumeration */
goto fail;
}
}
return (IPQOS_CONF_SUCCESS);
fail:
return (IPQOS_CONF_ERR);
}
/*
* reads the value of an enumeration parameter from first_token and fp.
* first_token is the first token of the value.
* The format expected is NAME | { NAME1 [, NAME2 ] [, NAME3 ] }.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
char *first_token,
{
int ret;
char *tk;
char *cm;
int name_expected = 0;
/* init param val */
*val = 0;
/* first token not curl_begin, so lookup its value */
if (*first_token != CURL_BEGIN) {
if (ret != IPQOS_CONF_SUCCESS) {
gettext("Unrecognized value, %s, line %u.\n"),
return (ret);
}
/* curl_begin, so read values till curl_end, dicing at ',' */
} else {
for (;;) {
/*
* no leftover from pervious iteration so read new
* token. This leftover happens because readtoken
* doesn't interpret comma's as special characters
* and thus could return 'val1,val2' as one token.
* If this happens the val1 will be used in the
* current iteration and what follows saved in lo
* for processing by successive iterations.
*/
if (ret == IPQOS_CONF_ERR) {
return (ret);
} else if (ret == IPQOS_CONF_EOF) {
gettext("Unexpected EOF.\n"));
return (IPQOS_CONF_ERR);
}
} else { /* previous leftover, so use it */
}
if (name_expected) {
if (ret == IPQOS_CONF_CURL_END ||
tk[0] == ',') {
gettext("Malformed value list "
"line %u.\n"), lineno);
return (IPQOS_CONF_ERR);
}
/*
* check if this token contains a ',' and
* if so store it and what follows for next
* iteration.
*/
return (IPQOS_CONF_ERR);
}
*cm = '\0';
}
/* get name value and add to total val */
if (ret != IPQOS_CONF_SUCCESS) {
gettext("Unrecognized value, %s, "
return (IPQOS_CONF_ERR);
}
/* comma or curl end accepted */
} else {
/* we've reached curl_end so break */
if (ret == IPQOS_CONF_CURL_END) {
break;
/* not curl end and not comma */
} else if (tk[0] != ',') {
gettext("Malformed value list "
"line %u.\n"), lineno);
return (IPQOS_CONF_ERR);
}
/*
* store anything after the comma for next
* iteration.
*/
return (IPQOS_CONF_ERR);
}
}
}
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* and store them in a string table pointed to by perm_items,
* with *nitems getting set to number of items read. perm_filters is set
* to 1 if we're searching for permanent filters, else 0 for classes.
* RETURNS: IPQOS_CONF_ERR if any errors, else IPQOS_CONF_SUCCESS.
*/
static int
int perm_filters,
char *module_name,
char ***perm_items,
int *nitems)
{
int cnt = 0;
int res;
char **tmp;
char *marker;
/* seek to start of types file */
return (IPQOS_CONF_ERR);
}
/* select which marker were looking for */
if (perm_filters) {
} else {
}
/* scan file line by line till end */
/*
* if the line is marked as containing a default item name
* read the name, extend the items string array
* and store the string off the array.
*/
if (res < 2) {
gettext("Types file for module %s is "
"corrupt.\n"), module_name);
marker);
goto fail;
}
/* extend items array to accomodate new item */
goto fail;
} else {
}
/* copy and store item name */
goto fail;
}
cnt++;
name);
}
}
*perm_items = items;
return (IPQOS_CONF_SUCCESS);
fail:
return (IPQOS_CONF_ERR);
}
/*
* Searches types file ref'd by tfp for the parameter named name
* with the place corresponding with place parameter. The format
* of the lines in the file are:
* PLACE NAME TYPE [ ENUM_DEF ] [ DEFAULT_STR ]
* The ENUM_DEF is an enumeration definition and is only present
* for parameters of type enum. DEFAULT_STR is a default value for
* this parameter. If present type is set to the appropriate type
* enumeration and dfltst filled with DEFAULT_STR if one was set.
* Also if the type is enum enum_nvps is made to point at a
* set of name value pairs representing ENUM_DEF.
*
* RETURNS: If any resource errors occur, or a matching parameter
* isn't found IPQOS_CONF_ERR is returned, else IPQOS_CONF_SUCCESS.
*/
static int
char *module_name,
char *name,
char *dfltst,
{
int ac;
char *cp;
int x;
char *ipgpc_nm;
int found = 0;
/*
* if allow_ipgpc_priv is true then we allow ipgpc parameters that are
* private between ipqosconf and ipgpc. eg. address masks, port masks.
*/
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
return (IPQOS_CONF_SUCCESS);
return (IPQOS_CONF_SUCCESS);
return (IPQOS_CONF_SUCCESS);
}
}
/*
* read upto and including module version line.
*/
return (IPQOS_CONF_ERR);
/*
* loop reading lines of the types file until named parameter
* found or EOF.
*/
/*
* check whether blank or commented line; if so skip
*/
continue;
}
dfltst[0] = '\0';
/*
* read place, param, type and if present default str
* from line.
*/
if (ac < 3) {
gettext("Types file for module %s is corrupt.\n"),
return (IPQOS_CONF_ERR);
}
/*
* if the place and name match no need to look any further.
*/
found++;
break;
}
}
}
if (found == 0) {
lineno);
return (IPQOS_CONF_ERR);
}
/*
* set the place parameter to the actual place when the PL_ANY flag
* was set.
*/
}
}
/*
* get type enumeration
*/
break;
}
}
/*
* check that we have a type corresponding with the one the types
* file specifies.
*/
gettext("Types file for module %s is corrupt.\n"),
return (IPQOS_CONF_ERR);
}
/*
*/
if (*type == IPQOS_DATA_TYPE_ENUM) {
return (IPQOS_CONF_ERR);
}
dfltst[0] = '\0';
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Reads a name and a value from file ref'd by cfp into list indirectly
* ref'd by nvlp; If this list is NULL it will be created to accomodate
* for the place, or be present in the module types file ref'd by tfp.
* *type is set to the enumeration of the type of the parameter and
* nvp to point at the element with the nvlp ref'd list.
* RETURNS: IPQOS_CONF_CURL_END if read CURL_END as name,
* IPQOS_CONF_ERR on errors, else IPQOS_CONF_SUCCESS.
*/
static int
char *module_name)
{
int res;
char *tmp;
/*
* read nvpair name
*/
/*
* if reached eof, curl end or error encountered return to caller
*/
if (res == IPQOS_CONF_EOF) {
return (IPQOS_CONF_ERR);
} else if (res == IPQOS_CONF_ERR) {
return (res);
} else if (res == IPQOS_CONF_CURL_END) {
return (res);
}
/*
* read nvpair value
*/
/*
* check we've read a valid value
*/
if (res == IPQOS_CONF_EOF) {
} else if (res == IPQOS_CONF_CURL_END) {
gettext("Missing parameter value line %u.\n"),
lineno);
} /* we do nothing special for IPQOS_CONF_ERR */
return (IPQOS_CONF_ERR);
}
/*
* check for generic parameters.
*/
0) ||
0)) {
} else { /* if not generic parameter */
/*
* get type from types file
*/
return (IPQOS_CONF_ERR);
}
/*
* get full module prefix parameter name
*/
goto fail;
}
}
/*
* create nvlist if not present already
*/
if (res != 0) {
return (IPQOS_CONF_ERR);
}
}
/*
* check we haven't already read this parameter
*/
lineno);
goto fail;
}
/*
* convert value string to appropriate type and add to nvlist
*/
switch (*type) {
case IPQOS_DATA_TYPE_IFNAME: {
if (res == IPQOS_CONF_SUCCESS) {
ifidx);
if (res != 0) {
"nvlist_add_uint32");
goto fail;
}
/*
* change name to point at the name of the
* new ifindex nvlist entry as name is used
* later in the function.
*/
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_PROTO: {
if (res == IPQOS_CONF_SUCCESS) {
if (res != 0) {
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_PORT: {
if (res == IPQOS_CONF_SUCCESS) {
/* add port */
if (res != 0) {
"nvlist_add_uint16");
goto fail;
}
/* add appropriate all ones port mask */
IPGPC_DPORT_MASK, ~0);
IPGPC_SPORT_MASK, ~0);
}
if (res != 0) {
"nvlist_add_uint16");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_ADDRESS:
case IPQOS_DATA_TYPE_ACTION:
case IPQOS_DATA_TYPE_STRING:
if (res != 0) {
goto fail;
}
break;
case IPQOS_DATA_TYPE_BOOLEAN: {
boolean_t b;
if (res == IPQOS_CONF_SUCCESS) {
(uint32_t)b);
if (res != 0) {
"nvlist_add_uint32");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_UINT8: {
if (res == IPQOS_CONF_SUCCESS) {
if (res != 0) {
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_INT16: {
if (res == IPQOS_CONF_SUCCESS) {
if (res != 0) {
"nvlist_add_int16");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_UINT16: {
if (res == IPQOS_CONF_SUCCESS) {
if (res != 0) {
"nvlist_add_int16");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_INT32: {
int i32;
if (res == IPQOS_CONF_SUCCESS) {
if (res != 0) {
"nvlist_add_int32");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_UINT32: {
if (res == IPQOS_CONF_SUCCESS) {
if (res != 0) {
"nvlist_add_uint32");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_ENUM: {
if (res == IPQOS_CONF_SUCCESS) {
if (res != 0) {
"nvlist_add_uint32");
goto fail;
}
} else {
goto fail;
}
break;
}
/*
* For now the dfltst contains a comma separated list of the
* type we need this parameter to be mapped to.
* read_mapped_values will fill in all the mapped parameters
* and their values in the nvlist.
*/
case IPQOS_DATA_TYPE_M_INDEX: {
if (res == IPQOS_CONF_SUCCESS) {
if (res != 0) {
"nvlist_add_uint8");
goto fail;
}
} else {
break;
}
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
break;
}
case IPQOS_DATA_TYPE_INT_ARRAY: {
int *arr;
/*
* read array info from types file.
*/
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/*
* read array contents from config file and construct
* array with them.
*/
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/*
* add array to nvlist.
*/
if (res != 0) {
goto fail;
}
/*
* free uneeded resources.
*/
if (arr_enum_nvs)
break;
}
case IPQOS_DATA_TYPE_USER: {
if (res == IPQOS_CONF_SUCCESS) {
if (res != 0) {
"nvlist_add_int32");
goto fail;
}
}
break;
}
#ifdef _IPQOS_CONF_DEBUG
default: {
/*
* we shouldn't have a type that doesn't have a switch
* entry.
*/
assert(1);
}
#endif
}
if (res != 0) {
goto fail;
}
/* set the nvp parameter to point at the newly added nvlist entry */
if (enum_nvs)
return (IPQOS_CONF_SUCCESS);
fail:
return (IPQOS_CONF_ERR);
}
/*
* read a parameter clause from cfp into *params.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
char *module_name,
{
int res;
char *nm;
char *action;
int read_stats = 0;
/* read beginning curl */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
/*
* loop reading nvpairs, adding to params nvlist until encounter
* CURL_END.
*/
for (;;) {
/* read nvpair */
if (res == IPQOS_CONF_ERR) {
goto fail;
/* we have finished reading params */
} else if (res == IPQOS_CONF_CURL_END) {
break;
}
/*
* read global stats - place into params struct and remove
* from nvlist.
*/
0) {
/* check we haven't read stats before */
if (read_stats) {
gettext("Duplicate parameter line %u.\n"),
lineno);
goto fail;
}
read_stats++;
/*
* read action type parameter - add it to list of action refs.
* also, if it's one of continue or drop virtual actions
* change the action name to their special ipp names in
* the action ref list and the nvlist.
*/
} else if (type == IPQOS_DATA_TYPE_ACTION) {
/* get name and value from nvlist */
/* if virtual action names change to ipp name */
/*
* we copy nm to a seperate buffer as nv_pair
* name above gave us a ptr to internal
* memory which causes strange behaviour
* when we re-value that nvlist element.
*/
/* modify nvlist entry and change action */
} else {
}
if (res != 0) {
"nvlist_add_string");
goto fail;
}
}
/* add action reference to params */
}
}
return (IPQOS_CONF_SUCCESS);
fail:
}
}
return (IPQOS_CONF_ERR);
}
/* ************************* class manip fns ****************************** */
/*
* make dst point at a dupicate class struct with duplicate elements to src.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
cls = alloc_class();
return (IPQOS_CONF_ERR);
}
/* struct copy */
/* we're not interested in the nvlist for a class */
/* copy first action reference */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* create a zero'd class struct and return a ptr to it.
* RETURNS: ptr to struct on success, NULL otherwise.
*/
static ipqos_conf_class_t *
{
if (class) {
} else {
}
return (class);
}
/* frees up all memory occupied by a filter struct and its contents. */
static void
{
return;
/* free its nvlist if present */
/* free its action refs if present */
/* finally free class itself */
}
/*
* Checks whether there is a class called class_nm in classes list.
* RETURNS: ptr to first matched class, else if not matched NULL.
*/
static ipqos_conf_class_t *
char *class_nm,
{
break;
}
}
return (cls);
}
/* ************************** filter manip fns **************************** */
/*
* Checks whether there is a filter called filter_nm with instance number
* instance in filters list created by us or permanent. Instance value -1
* is a wildcard.
* RETURNS: ptr to first matched filter, else if not matched NULL.
*/
static ipqos_conf_filter_t *
char *filter_nm,
int instance,
{
instance);
while (filters) {
break;
}
}
return (filters);
}
/*
* allocate and zero a filter structure.
* RETURNS: NULL on error, else ptr to filter struct.
*/
static ipqos_conf_filter_t *
{
if (flt) {
} else {
}
return (flt);
}
/* free flt and all it's contents. */
static void
{
return;
if (flt->src_nd_name)
if (flt->dst_nd_name)
}
}
/*
* makes a copy of ofilter and its contents and points nfilter at it. It
* also adds an instance number to the filter and if either saddr or
* daddr are non-null that address to the filters nvlist along with
* an all 1s address mask and the af.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
int af,
int inv6, /* if saddr or daddr set and v4 filter are they in v6 addr */
void *saddr,
void *daddr,
int inst)
{
int res;
/* show src address and dst address if present */
#ifdef _IPQOS_CONF_DEBUG
if (ipqosconf_dbg_flgs & MHME) {
if (saddr) {
100));
}
if (daddr) {
100));
}
}
#endif /* _IPQOS_CONF_DEBUG */
/* init local v6 address to 0 */
/* create an all 1s address for use as mask */
/* create a new filter */
nf = alloc_filter();
return (IPQOS_CONF_ERR);
}
/* struct copy old filter to new */
/* copy src filters nvlist if there is one to copy */
if (res != 0) {
goto fail;
}
}
/* copy src and dst node names if present */
if (ofilter->src_nd_name) {
goto fail;
}
}
if (ofilter->dst_nd_name) {
goto fail;
}
}
/* add filter addresses type */
if (res != 0) {
goto fail;
}
/* add saddr if present */
if (saddr) {
}
/* add address and all 1's mask */
goto fail;
}
}
/* add daddr if present */
if (daddr) {
}
/* add address and all 1's mask */
goto fail;
}
}
/* add filter instance */
return (IPQOS_CONF_SUCCESS);
fail:
return (IPQOS_CONF_ERR);
}
/* ************************* action manip fns ********************** */
/*
* create and zero action structure and a params structure hung off of it.
* RETURNS: ptr to allocated action on success, else NULL.
*/
static ipqos_conf_action_t *
{
return (action);
}
malloc(sizeof (ipqos_conf_params_t));
return (NULL);
}
return (action);
}
/*
* free all the memory used in all the actions in actions list.
*/
static void
{
/* free parameters */
}
}
/* free action nvlist */
/* free filters */
}
/* free classes */
}
/* free permanent classes table */
/* free filters to retry */
}
/* free dependency pointers */
}
}
/*
* Checks whether there is an action called action_name in actions list.
* RETURNS: ptr to first matched action, else if not matched NULL.
*
*/
static ipqos_conf_action_t *
char *action_name,
{
while (actions) {
break;
}
}
return (actions);
}
/* **************************** act ref manip fns ******************** */
/*
* add an action reference element with parameter field and action
* action_name to arefs.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
char *field,
char *action_name)
{
/* allocate zero'd aref */
return (IPQOS_CONF_ERR);
}
/* copy parameter name if present */
if (field)
/* copy action name */
/* place at head of list */
return (IPQOS_CONF_SUCCESS);
}
/*
* free all the memory used by the action references in arefs.
*/
static void
{
while (aref) {
}
}
/* *************************************************************** */
/*
* checks whether aname is a valid action name.
* RETURNS: IPQOS_CONF_ERR if invalid, else IPQOS_CONF_SUCCESS.
*/
static int
{
/*
* dissallow the use of the name of a virtual action, either
* the ipqosconf name, or the longer ipp names.
*/
virtual_action(aname)) {
lineno);
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Opens a stream to the types file for module module_name (assuming
* that the file path is TYPES_FILE_DIR/module_name.types). if
* a file open failure occurs, *openerr is set to 1.
* RETURNS: NULL on error, else stream ptr to module types file.
*/
static FILE *
char *module_name,
int *openerr)
{
char *path;
*openerr = 0;
/* create modules type file path */
return (NULL);
}
/* open stream to types file */
(*openerr)++;
}
return (fp);
}
/*
* read a class clause from cfp into a class struct and point class at this.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
char *module_name,
char **perm_classes,
int num_perm_classes)
{
int res;
char *name;
char *action;
int stats;
/* create and zero class struct */
*class = alloc_class();
if (!*class) {
return (IPQOS_CONF_ERR);
}
/* get starting line for error reporting */
/* read curl_begin */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/* loop reading parameters till read curl_end */
for (;;) {
/* read nvpair */
if (res == IPQOS_CONF_ERR) {
goto fail;
/* reached end of class clause */
} else if (res == IPQOS_CONF_CURL_END) {
break;
}
/*
* catch name and action nv pairs and stats if present
* and place values in class structure.
*/
/* name */
if (nm == 0 &&
goto fail;
}
nm++;
/* next action */
} else if (act == 0 &&
/*
* if next action string continue string set action to
* IPP_ANAME_CONT, else if drop string IPP_ANAME_DROP
*/
}
/* add an action reference to action list */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
act++;
/* class stats enable */
} else if (stats == 0 &&
0) {
stats++;
/* no other / duplicate parameters allowed */
} else {
goto fail;
}
}
lineno);
goto fail;
}
/* change class originator field to permanent if permanent class */
}
return (IPQOS_CONF_SUCCESS);
fail:
if (*class)
free_class(*class);
return (IPQOS_CONF_ERR);
}
/*
* This function assumes either src_nd_name or dst_node_nm are set in filter.
*
* Creates one of more copies of filter according to the ip versions
* requested (or assumed) and the resolution of the src and dst address
* node names if spec'd. If both node names are spec'd then a filter is
* created for each pair of addresses (one from each node name) that is
* compatible with the chosen address family, otherwise a filter copy is
* created for just each address of the single node name that is
* compatible.
* If filter->ip_versions has been set that is used to determine the
* af's we will create filters for, else if a numeric address was
* added the family of that will be used, otherwise we fall back
* to both v4 and v6 addresses.
*
* Any name lookup failures that occur are checked to see whether the failure
* was a soft or hard failure and the nlerr field of filter set accordingly
* before the error is returned.
*
* RETURNS: IPQOS_CONF_ERR on any error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int idx = 0;
int res;
int ernum;
int in32b = 0;
/* check if we've read an ip_version request to get the versions */
if (filter->ip_versions != 0) {
/* otherwise check if we've read a numeric address and get versions */
&ftype) == 0) {
if (ftype == IPGPC_V4_FLTR) {
v6--;
} else {
v4--;
}
}
/* read saddrs if src node name */
if (filter->src_nd_name) {
/* v4 only address */
in32b++;
AI_ADDRCONFIG, &ernum);
/* v6 only */
AI_DEFAULT, &ernum);
/* v4 and v6 */
}
#ifdef TESTING_RETRY
if (!last_retry) {
goto fail;
}
#endif
/*
* if lookup error determine whether it was a soft or hard
* failure and mark as such in filter.
*/
"resolve src host name for filter at "
"line %u, ignoring filter.\n"),
} else {
if (last_retry) {
"to resolve src host name for "
"filter at line %u, ignoring "
}
}
goto fail;
}
}
/* read daddrs if dst node name */
if (filter->dst_nd_name) {
/* v4 only address */
in32b++;
AI_ADDRCONFIG, &ernum);
/* v6 only */
AI_DEFAULT, &ernum);
/* v6 and v4 addresses */
} else {
}
"resolve dst host name for filter at "
"line %u, ignoring filter.\n"),
} else {
if (last_retry) {
"to resolve dst host name for "
"filter at line %u, ignoring "
}
}
goto fail;
}
}
/*
* if src and dst node name, create set of filters; one for each
* src and dst address of matching types.
*/
/* get saddr family */
} else {
}
/* get daddr family */
} else {
}
/*
* if saddr and daddr same af duplicate
* filter adding addresses and new instance
* number and add to flist filter list.
*/
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
}
}
}
/* if src name only create set of filters, one for each node address */
} else if (filter->src_nd_name) {
/* get af */
} else {
}
/*
* dup filter adding saddr and new instance num and
* add to flist filter list.
*/
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
}
/* if dname only create set of filters, one for each node address */
} else {
/* get af */
} else {
}
/*
* dup filter adding daddr and new instance num and
* add to flist filter list.
*/
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
}
}
if (shp)
if (dhp)
return (IPQOS_CONF_SUCCESS);
fail:
/*
* should really clean up any filters that we have created,
* however, free_actions called from readaction will cleam them up.
*/
if (shp)
if (dhp)
return (IPQOS_CONF_ERR);
}
/*
* read a filter clause from cfp into a filter struct and point filter
* at this.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
char *module_name,
char **perm_filters,
int num_perm_filters)
{
int res;
char *addr_str;
int sa;
int err_num;
char *tmp;
char *name;
char *class;
uchar_t b;
/* create and zero filter struct */
*filter = alloc_filter();
return (IPQOS_CONF_ERR);
}
/* get starting line for error reporting */
/* read beginning curl */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/*
* loop reading nvpairs onto nvlist until encounter CURL_END
*/
for (;;) {
/* read nvpair */
if (res == IPQOS_CONF_ERR) {
goto fail;
/* reached the end of filter definition */
} else if (res == IPQOS_CONF_CURL_END) {
break;
}
/*
* catch name and class and place value into filter
* structure.
*/
/* read filter name */
if (nm != 0) {
gettext("Duplicate parameter line %u.\n"),
lineno);
goto fail;
}
goto fail;
}
nm++;
/* read class name */
0) {
if (cls != 0) {
gettext("Duplicate parameter line %u.\n"),
lineno);
goto fail;
}
break;
}
goto fail;
}
cls++;
/*
* are determined to be addresses we convert them from
* strings here and add to the filter nvlist; for node names
* we add the name to the filter struct for readaction to
* process.
*/
sa = 0;
sa++;
}
/*
* get the address mask if present.
* make a copy so that the nvlist element that
* it is part of doesn't dissapear and causes probs.
*/
if (sl) {
*sl = '\0';
goto fail;
}
}
/* if a numeric address */
/* get address */
AI_DEFAULT, &err_num);
"getipnodebyname");
goto fail;
}
/* determine address type */
if (!v4) {
v6++;
}
/*
* check any previous addresses have same
* version.
*/
IPGPC_FILTER_TYPE, &b) == 0) {
if (v4 && b != IPGPC_V4_FLTR ||
v6 && b != IPGPC_V6_FLTR) {
gettext("Incompatible "
"address version line "
"%u.\n"), lineno);
goto fail;
}
}
/*
* check that if ip_version spec'd it
* corresponds.
*/
if ((*filter)->ip_versions != 0) {
gettext("Incompatible "
"address version line %u"
".\n"), lineno);
goto fail;
}
}
/* add the address type */
if (res != 0) {
"nvlist_add_byte");
goto fail;
}
/* add address to list */
if (res != 0) {
"nvlist_add_uint32_array");
goto fail;
}
/*
* add mask entry in list.
*/
if (sl) { /* have CIDR mask */
char *lo;
if (res != IPQOS_CONF_SUCCESS ||
mlen == 0) {
gettext("Invalid CIDR "
"mask line %u.\n"), lineno);
goto fail;
}
} else {
/* no CIDR mask spec'd - use all 1s */
sizeof (in6_addr_t));
}
if (res != 0) {
"nvlist_add_uint32_arr");
goto fail;
}
/* inet_pton returns fail - we assume a node name */
} else {
/*
* doesn't make sense to have a mask
* with a node name.
*/
if (sl) {
gettext("Address masks aren't "
"allowed for host names line "
"%u.\n"), lineno);
goto fail;
}
/*
* store node name in filter struct for
* later resolution.
*/
if (sa) {
(*filter)->src_nd_name =
addr_str);
} else {
(*filter)->dst_nd_name =
addr_str);
}
}
/* ip_version enumeration */
0) {
/* check we haven't read ip_version before */
if (ipv) {
gettext("Duplicate parameter line %u.\n"),
lineno);
goto fail;
}
ipv++;
/* get bitmask value */
(void) nvpair_value_uint32(nvp,
&(*filter)->ip_versions);
/*
* check that if either ip address is spec'd it
* corresponds.
*/
"address version line %u.\n"), lineno);
goto fail;
}
/* remove ip_version from nvlist */
}
}
"before line %u.\n"), lineno);
goto fail;
}
}
return (IPQOS_CONF_SUCCESS);
fail:
if (*filter)
if (hp)
if (sl)
return (IPQOS_CONF_ERR);
}
/*
* reads the curl begin token from cfp stream.
* RETURNS: IPQOS_CONF_ERR if not read successfully, else IPQOS_CONF_SUCCES.
*/
static int
{
int res;
char *st;
if (res != IPQOS_CONF_CURL_BEGIN) {
if (res == IPQOS_CONF_EOF) {
/* if CURL_END or something else */
} else if (res != IPQOS_CONF_ERR) {
"%u.\n"), lineno);
}
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* This function parses the parameter string version into a version of the
* form "%u.%u" (as a sscanf format string). It then encodes this into an
* int and returns this encoding.
* RETURNS: -1 if an invalid string, else the integer encoding.
*/
static int
char *version)
{
int ver;
return (-1);
}
return (ver);
}
/*
* This function scans through the stream fp line by line looking for
* a line beginning with version_tag and returns a integer encoding of
* the version following it.
*
* RETURNS: If the version definition isn't found or the version is not
* a valid version (%u.%u) then -1 is returned, else an integer encoding
* of the read version.
*/
static int
char *version_tag,
char *module_name)
{
int found = 0;
int version;
/*
* reset to file start
*/
return (-1);
}
/*
* loop reading lines till found the one beginning with version_tag.
*/
found++;
break;
}
}
if (found == 0) {
"corrupt.\n"), module_name);
return (-1);
}
/*
* convert version string into int.
*/
"corrupt.\n"), module_name);
return (-1);
}
return (version);
}
/*
* store in and hang off an action structure, and point action at it.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
{
char *st;
int readprms = 0;
int res;
char *strval;
char *name;
int oe;
char **perm_filters;
int num_perm_filters;
int tf_fmt_ver;
return (res);
return (IPQOS_CONF_ERR);
}
/* create action structure */
*action = alloc_action();
return (IPQOS_CONF_ERR);
}
/* get starting line for error reporting */
/* read beginning curl */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/* loop till read both action name and module */
do {
/* read nvpair */
if (res == IPQOS_CONF_ERR) {
goto fail;
/* read curl_end */
} else if (res == IPQOS_CONF_CURL_END) {
gettext("Missing action name/ module "
"before line %u.\n"), lineno);
goto fail;
}
}
/* store name and module in action structure */
/* read action name */
/* check name is valid */
goto fail;
}
/* store and remove from list */
/* remove name from nvlist */
nm++;
/* read module name */
} else if (md == 0 &&
/*
* check that module has a type file and get
* open stream to it.
*/
if (oe) {
gettext("Invalid "
"module name line %u.\n"),
lineno);
} else {
}
}
goto fail;
}
/*
* move module name to action struct
*/
md++;
} else {
gettext("Unexpected parameter line %u.\n"),
lineno);
goto fail;
}
/*
* check that if the ipgpc action it is named correctly
*/
gettext("%s action has incorrect name line %u.\n"),
goto fail;
}
/* get list of permanent classes */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/* get list of permanent filters */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/*
* get types file format version and check its supported.
*/
goto fail;
IPP_MINOR_MODULE_VER(tf_fmt_ver) > 0) {
goto fail;
}
/*
* get module version
*/
goto fail;
for (;;) {
/* read token */
if (res == IPQOS_CONF_ERR) {
goto fail;
} else if (res == IPQOS_CONF_EOF) {
goto fail;
/* read CURL_END - end of action definition */
} else if (res == IPQOS_CONF_CURL_END) {
break;
}
/*
*/
/* read filter */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/*
* if we read a host name for either src or dst addr
* resolve the hostnames and create the appropriate
* number of filters.
*/
B_FALSE);
/*
* if a lookup fails and the filters
* marked as retry we add it to a list
* for another attempt later, otherwise
* it is thrown away.
*/
if (res != IPQOS_CONF_SUCCESS) {
/* if not name lookup problem */
goto fail;
/* name lookup problem */
/*
* if intermitent lookup failure
* add to list of filters to
* retry later.
*/
&(*action)->retry_filters,
filter);
/*
* for non-existing names
* ignore the filter.
*/
} else {
}
/* creation of new filters successful */
} else {
}
/* non-node name filter */
} else {
}
/* read class */
(*action)->perm_classes,
(*action)->num_perm_classes);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/* read params */
if (readprms) {
gettext("Second parameter clause not "
"supported line %u.\n"), lineno);
goto fail;
}
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
readprms++;
/* something unexpected */
} else {
"line %u.\n"), lineno);
goto fail;
}
}
return (IPQOS_CONF_SUCCESS);
fail:
if (tfp)
if (*action) {
}
return (IPQOS_CONF_ERR);
}
/*
* check that each of the actions in actions is uniquely named. If one isn't
* set *name to point at the name of the duplicate action.
* RETURNS: IPQOS_CONF_ERR if a non-unique action, else IPQOS_CONF_SUCCESS.
*/
static int
{
while (actions) {
return (IPQOS_CONF_ERR);
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* checks whether the action parameter is involved in an action cycle.
* RETURNS: 1 if involved in a cycle, 0 otherwise.
*/
static int
{
/* have we visited this action before? */
return (1);
}
/*
* recurse down the child actions of this action through the
* classes next action and parameter actions.
*/
/* skip virtual actions - they can't be in a cycle */
continue;
}
return (1);
}
}
continue;
}
return (1);
}
}
return (0);
}
/*
* checks that the configuration in actions is a valid whole, that
* all actions are unique, all filters and classes are unique within
* their action, that classes referenced by filters exist and actions
* referenced by classes and params exist. Also checks that there are no root
* actions but ipgpc and that no actions are involved in cycles. As
* a consequence of checking that the actions exist two way pointers
* are created between the dependee and dependant actions.
*
* In the case the the userconf flag is zero only this link creation is
* set as we trust the kernel to return a valid configuration.
*
* RETURNS: IPQOS_CONF_ERR if config isn't valid, else IPQOS_CONF_SUCCESS.
*
*/
static int
int userconf) /* are we checking a conf file ? */
{
char *name;
int res;
/* check actions are unique */
name);
return (IPQOS_CONF_ERR);
}
/*
* check filters (for user land configs only).
* check they are unique in this action and their class exists.
*/
if (userconf) {
/* check unique name */
gettext("Duplicate named filter "
return (IPQOS_CONF_ERR);
}
/*
* check existence of class and error if
* class doesn't exist and not a perm class
*/
flt->class_name)) {
gettext("Undefined "
"class in filter %s, "
return (IPQOS_CONF_ERR);
}
}
}
}
/* check classes */
/* check if class name unique (userland only) */
gettext("Duplicate named class %s in "
return (IPQOS_CONF_ERR);
}
/*
* virtual actions always exist so don't check for next
* action.
*/
continue;
}
/*
* check existance of next action and create link to
* it.
*/
gettext("Undefined action in class %s, "
return (IPQOS_CONF_ERR);
}
/* create backwards link - used for deletions */
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
}
/* check actions exist for action type parameters */
/* skip virtuals */
continue;
}
/*
* check existance of action in this ref
* and if present create a ptr to it.
*/
gettext("Undefined action in parameter "
"%s, action %s.\n"),
return (IPQOS_CONF_ERR);
}
/* create backwards link */
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
}
}
/* for kernel retrieved configs we don't do the following checks. */
if (!userconf) {
return (IPQOS_CONF_SUCCESS);
}
/* check for cycles in config and orphaned actions other than ipgpc */
/* check if involved in cycle */
gettext("Action %s involved in cycle.\n"),
return (IPQOS_CONF_ERR);
}
/* check that this action has a parent (except ipgpc) */
return (IPQOS_CONF_ERR);
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Read the version from the config file with stream cfp with
* the tag version_tag. The tag-value pair should be the first tokens
* encountered.
*
* RETURNS: -1 if a missing or invalid version or a read error,
* else an integer encoding of the version.
*/
static int
char *version_tag)
{
int res;
int version;
/*
* read version tag string.
*/
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
goto fail;
}
/*
* read version number string.
*/
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/*
* encode version into int.
*/
goto fail;
}
return (version);
fail:
return (-1);
}
/*
* read the set of actions definitions from the stream cfp and store
* them in a list pointed to by conf.
* RETURNS: IPQOS_CONF_ERR if any errors, else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
int fmt_ver;
/*
* get config file format version.
*/
if (fmt_ver == -1) {
return (IPQOS_CONF_ERR);
} else {
/*
* check version is valid
*/
(IPP_MINOR_MODULE_VER(fmt_ver) > 0)) {
"format version.\n"));
return (IPQOS_CONF_ERR);
}
}
/* loop reading actions adding to conf till EOF */
for (;;) {
/* readaction */
if (res == IPQOS_CONF_ERR) {
goto fail;
}
/* reached eof, finish */
if (res == IPQOS_CONF_EOF) {
break;
}
/* check if we just read an ipgpc action */
}
/* check that there is one or more actions and that one is ipgpc */
if (ipgpc_action == B_FALSE) {
goto fail;
}
return (IPQOS_CONF_SUCCESS);
fail:
free_actions(*conf);
return (IPQOS_CONF_ERR);
}
/* ************************ kernel config retrieval ************************ */
/*
* read the current configuration from the kernel and make *conf a ptr to it.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
{
int res;
int nmods;
int nacts;
int x, y;
int openerr;
/* initialise conf to NULL */
/* get list of modules currently loaded */
if (res != 0) {
return (IPQOS_CONF_ERR);
}
/*
* iterate through all loaded modules retrieving their list of actions
* and then retrieving the configuration of each of these
* and attatching it to conf.
*/
for (x = 0; x < nmods; x++) {
/* skip actions of modules that we can't open types file of */
/* mem error */
if (!openerr) {
goto fail;
/*
* fopen fail - if we failed because the file didn't
* exist we assume this is an unknown module and
* ignore this module, otherwise error.
*/
} else {
continue;
} else {
goto fail;
}
}
}
/* get action list for this module */
if (res != 0) {
goto fail;
}
/* read config of each action of this module */
for (y = 0; y < nacts; y++) {
goto fail;
}
/* copy action name into action struct */
/* copy module name into action struct */
/* get action info */
(int (*)(nvlist_t *, void *))parse_kaction,
(void *)&ai_prm, 0);
if (res != 0) {
/* was this an ipp error */
"ipp_action_info");
}
goto fail;
}
}
}
return (IPQOS_CONF_SUCCESS);
fail:
free_actions(*conf);
return (IPQOS_CONF_ERR);
}
/*
* This is passed as a parameter to ipp_action_info() in readkaction and
* is called back one for each configuration element within the action
* specified. This results in filters and classes being created and chained
* off of action, and action having its params set.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int ret;
/* get config type */
switch (cfgtype) {
case CLASSIFIER_ADD_FILTER: {
/*
* parse the passed filter nvlist
* and add result to action's filter list.
*/
filter = alloc_filter();
return (IPQOS_CONF_ERR);
}
if (ret != IPQOS_CONF_SUCCESS) {
return (ret);
}
break;
}
case CLASSIFIER_ADD_CLASS:
case CLASSIFIER_MODIFY_CLASS: {
/*
* parse the passed class nvlist
* and add result to action's class list.
*/
class = alloc_class();
return (IPQOS_CONF_ERR);
}
if (ret != IPQOS_CONF_SUCCESS) {
return (ret);
}
break;
}
case IPP_SET: {
/*
* we don't alloc a params struct as it is created
* as part of an action.
*/
/* parse the passed params nvlist */
nvl);
if (ret != IPQOS_CONF_SUCCESS) {
return (ret);
}
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* parses a params nvlist returned from the kernel.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
int
char *module,
int ret;
char *act;
char *param;
int openerr;
/* get stream to module types file */
if (openerr) {
}
return (IPQOS_CONF_ERR);
}
/* make copy of passed in nvlist as it is freed by the caller */
if (ret != 0) {
return (IPQOS_CONF_ERR);
}
/*
* get config originator and remove from nvlist. If no owner we
* assume ownership.
*/
if (ret == 0) {
} else {
}
/* get action stats and remove from nvlist */
if (ret == 0) {
}
/*
* loop throught nvlist elements and for those that are actions create
* action ref entrys for them.
*/
if (ret != IPQOS_CONF_SUCCESS) {
goto fail;
}
(type == IPQOS_DATA_TYPE_ACTION)) {
if (ret != IPQOS_CONF_SUCCESS) {
goto fail;
}
}
}
/* assign copied nvlist to params struct */
return (IPQOS_CONF_SUCCESS);
fail:
return (IPQOS_CONF_ERR);
}
/*
* parses a classes nvlist returned from the kernel.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
{
int ret;
char *str;
/* lookup object originator */
if (ret == 0) {
} else {
}
/* lookup name */
/* lookup next action */
if (ret != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
/* lookup stats enable */
if (ret == 0) {
}
return (IPQOS_CONF_SUCCESS);
}
/*
* parses a filters nvlist returned from the kernel.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
{
int ret;
char *str;
char *end;
/* make copy of passed in nvlist as it is freed by the caller */
if (ret != 0) {
return (IPQOS_CONF_ERR);
}
/* lookup originator */
if (ret == 0) {
} else {
}
/* lookup filter name */
/* lookup class name */
/* lookup src and dst host names if present */
if (filter->src_nd_name) {
} else {
return (IPQOS_CONF_ERR);
}
}
if (filter->dst_nd_name) {
} else {
return (IPQOS_CONF_ERR);
}
}
/* lookup ip_version if present */
} else {
gettext("Corrupted ip_version returned from "
"kernel.\n"));
return (IPQOS_CONF_ERR);
}
}
/* lookup filter instance if present */
if (ret != 0) {
} else {
}
/* attach new trimmed nvlist to filter */
return (IPQOS_CONF_SUCCESS);
}
/*
* determines whether action_name is a virtual action name.
* RETURNS: if virtual action 1, else 0.
*/
static int
{
return (1);
}
return (0);
}
/*
* remove all the actions within the kernel. If there is a failure
* modified is set to represent whether the attempt to flush modified
* the configuration in any way.
* RETURNS: IPQOS_CONF_ERR if the ipp_* functions return any errors,
* else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
int nmods;
int nacts;
int x, y;
/*
* get list of modules currently loaded.
*/
if (res != 0) {
return (IPQOS_CONF_ERR);
}
/*
* iterate through all the modules listing their actions and
* deleting all of them.
*/
for (x = 0; x < nmods; x++) {
modnames[x]);
if (res != 0) {
return (IPQOS_CONF_ERR);
}
for (y = 0; y < nacts; y++) {
/*
* if fails for reason other than action doesn't
* exist or action has dependency.
*/
return (IPQOS_CONF_ERR);
}
if (res == 0)
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Trys to flush the configuration. If it fails and nothing has been modified
* and force_flush is false just return an error, otherwise persist trying to
* completion.
* RETURNS: IPQOS_CONF_ERR if flush attempt failed without modifying anything
* and force_flush was set to false, otherwise IPQOS_CONF_SUCCESS.
*/
static int
{
int x = 0;
int res;
/*
* attempt first flush of config.
*/
return (IPQOS_CONF_ERR);
} else if (res == IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_SUCCESS);
}
/*
* failed flush that modified config, or force flush set; loop till
* successful flush.
*/
while (res != IPQOS_CONF_SUCCESS) {
gettext("Retrying configuration flush.\n"));
x = 0;
}
(void) sleep(2);
x++;
}
return (IPQOS_CONF_SUCCESS);
}
/*
* Performs a flush of the configuration within a signal blocking region
* so that there's minimal chance of it being killed and the flush only
* partially completing.
* RETURNS: IPQOS_CONF_SUCCESS (for symmetry with the other main functions).
*/
static int
{
int res;
/*
* make sure that flush is as atomic as possible.
*/
return (IPQOS_CONF_ERR);
/*
* restore signals.
*/
(void) restore_all_signals();
if (res == IPQOS_CONF_SUCCESS) {
} else {
}
return (res);
}
static int
{
return (1);
}
}
return (0);
}
/* free the memory occupied by the string table ctable and its contents. */
static void
{
int x;
if (ctable) {
for (x = 0; x < size; x++) {
}
}
}
#if 0
/*
* makes a copy of a string table and returns a ptr to it.
* RETURNS: NULL on error or if size was 0, else ptr to copied table.
*/
static char **
{
int pos;
/* create char ptr array */
return (st);
}
/* create copy of each string from stable1 in array */
return (NULL);
}
}
return (st);
}
#endif /* 0 */
/*
* retry lookups on filters that soft failed a previous lookup and
* were put on the retry list.
* RETURNS: IPQOS_CONF_ERR on any errors, else IPQOS_CONF_SUCCESS.
*/
static int
{
/* store start of new resolved filters */
/*
* do name resolution on retry list adding resolved filters
* to end of actions filters.
*/
/* if resource failure */
return (IPQOS_CONF_ERR);
}
}
}
/* add the newly resolved filters to the kernel action */
return (IPQOS_CONF_ERR);
}
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* write the configuration in conf to the file given in dstpath. This
* is done by writing first to a temporary file and then renaming that
* file to dstpath. This assures an atomic write.
* RETURNS: IPQOS_CONF_ERR on any errors, else IPQOS_CONF_SUCCESS.
*/
static int
char *dstpath)
{
char *tmppath;
char *pathend;
int res;
/* construct tmp file path so we can use rename() */
/* dstpath in current dir */
return (IPQOS_CONF_ERR);
}
/* dstpath in root dir */
return (IPQOS_CONF_ERR);
}
/* not pwd or root */
} else {
1);
return (IPQOS_CONF_ERR);
}
*pathend = '/';
}
/* open tmp file */
return (IPQOS_CONF_ERR);
}
/* write out format version */
/*
* loop through actions in list writing ipqosconf originated
* ones out to the tmp file.
*/
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
/* rename tmp file to dst file */
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* read the configuration back from the kernel and then write each of the
* actions read to IPQOS_CONF_INIT_PATH.
* RETURNS: IPQOS_CONF_ERR if error, else IPQOS_CONF_SUCCESS.
*/
static int
{
int ret;
/* read the configuration from the kernel */
if (ret != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
/* dissallow a null config to be stored (we can't read one in) */
gettext("Can't commit a null configuration.\n"));
return (IPQOS_CONF_ERR);
}
/* make sure if we create file that perms are 644 */
/* write the configuration to the init file */
if (ret != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
gettext("Current configuration saved to init file.\n"));
return (IPQOS_CONF_SUCCESS);
}
/*
* Called in the event of a failed rollback. It first flushes the
* current configuration, then attempts to apply the oconf (the old
* one), and if that fails flushes again.
*
* RETURNS: IPQOS_CONF_ERR if the application of old config fails,
* else IPQOS_CONF_SUCCESS.
*/
static int
{
int res;
/*
* flush configuration.
*/
(void) atomic_flush(B_TRUE);
/*
* mark all elements of old config for application.
*/
/*
* attempt to apply old config.
*/
/*
* if failed force flush of config.
*/
if (res != IPQOS_CONF_SUCCESS) {
(void) atomic_flush(B_TRUE);
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
/*
* read and apply the configuration contained if file ifile to the kernel.
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
{
int res;
/* if filename '-' read from stdin */
} else {
gettext("Opening file %s for read: %s.\n"),
return (IPQOS_CONF_ERR);
}
}
/* read in new configuration */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/* check configuration is valid */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/* read in kernel configuration */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/*
* check there are no same named actions in both config file and the
* the kernel that are for a different module. The application
* system can't handle these as we would try to add the new
* action before we deleted the old one and because actions
* in the kernel are indexed solely on their name (their module
* isn't included) the kernel would return an error. We want
* to avoid this error and the resulting rollback.
*/
/* found action */
/* different module */
gettext("Action at line %u has "
"same name as currently "
"installed action, but is for a "
"different module.\n"),
goto fail;
/* same module - stop search */
} else {
break;
}
}
}
}
/* create links between actions for use with deletions etc.. */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/* diff conf file against kernel */
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
/* make kernel mods as atomic as possible */
goto fail;
}
/* apply difference to kernel */
#ifdef _IPQOS_CONF_DEBUG
#else
if (res != IPQOS_CONF_SUCCESS) {
#endif /* _IPQOS_CONF_DEBUG */
if (res != IPQOS_CONF_SUCCESS) {
if (res != IPQOS_CONF_SUCCESS) {
/* system left flushed */
gettext("Failed to rollback from failed "
"configuration, configuration flushed.\n"));
} else { /* old config re-applied */
gettext("Configuration failed, system "
"state unchanged.\n"));
}
} else {
gettext("Configuration failed, system "
"state unchanged.\n"));
}
goto fail;
}
/* retry any soft name lookup failures */
if (res != IPQOS_CONF_SUCCESS) {
if (res != IPQOS_CONF_SUCCESS) {
if (res != IPQOS_CONF_SUCCESS) {
/* system left flushed */
gettext("Failed to rollback from failed "
"configuration, configuration flushed.\n"));
} else { /* old config re-applied */
gettext("Configuration failed, system "
"state unchanged.\n"));
}
} else {
gettext("Configuration failed, system "
"state unchanged.\n"));
}
goto fail;
}
/* re-enable signals */
(void) restore_all_signals();
return (IPQOS_CONF_SUCCESS);
fail:
(void) restore_all_signals();
if (conf)
if (oconf)
if (res == IPQOS_CONF_RECOVER_ERR)
return (res);
}
static int
{
return (-1);
}
return (-1);
}
return (0);
}
static int
{
return (-1);
}
return (0);
}
static int
{
return (-1);
}
return (0);
}
static int
lock()
{
int fd;
/*
* Open the file with O_CREAT|O_EXCL. If it exists already, it
* will fail. If it already exists, check whether it looks like
* the one we created.
*/
(void) umask(0077);
/* Some other problem. */
gettext("Cannot open lock file %s"),
return (-1);
}
/*
* open() returned an EEXIST error. We don't fail yet
* as it could be a residual from a previous
* execution. However, we need to clear errno here.
* If we don't and print_cmd_buf() is later invoked
* as the result of a parsing error, it
* will assume that the current error is EEXIST and
* that a corresponding error message has already been
* printed, which results in an incomplete error
* message. If errno is zero, print_cmd_buf() will
* assume that it is called as a result of a
* parsing error and will print the appropriate
* error message.
*/
errno = 0;
/*
* File exists. make sure it is OK. We need to lstat()
* as fstat() stats the file pointed to by the symbolic
* link.
*/
gettext("Cannot lstat lock file %s\n"),
return (-1);
}
/*
* Check whether it is a regular file and not a symbolic
* link. Its link count should be 1. The owner should be
* root and the file should be empty.
*/
return (-1);
}
gettext("Cannot open lock file %s"),
return (-1);
}
/* Check whether we opened the file that we lstat()ed. */
gettext("Cannot fstat lock file %s\n"),
return (-1);
}
/* File changed after we did the lstat() above */
return (-1);
}
}
return (-1);
}
return (fd);
}
/*
* print the current kernel configuration out to stdout. If viewall
* is set this causes more verbose configuration listing including
* showing objects we didn't create, each instance of a mhome filter,
* etc.. see printaction().
* RETURNS: IPQOS_CONF_ERR on error, else IPQOS_CONF_SUCCES.
*/
static int
{
int ret;
/* get kernel configuration */
if (ret != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
/* write out format version */
}
/* print each of the actions in the kernel config to stdout */
if (ret != IPQOS_CONF_SUCCESS) {
return (ret);
}
}
return (IPQOS_CONF_SUCCESS);
}
/*
* debug function that reads the config file and prints it out after
* interpreting to stdout.
*/
#ifdef _IPQOS_CONF_DEBUG
static int
{
int res;
return (IPQOS_CONF_ERR);
}
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
/* print each of the actions in the kernel config to stdout */
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
return (IPQOS_CONF_SUCCESS);
}
#endif /* _IPQOS_CONF_DEBUG */
static void
usage(void)
{
"\tipqosconf [-sv] -a file|-\n"
"\tipqosconf -c\n"
"\tipqosconf -l\n"
"\tipqosconf -L\n"
"\tipqosconf -f\n"));
}
int
{
int c;
int args;
int ret;
int cmd;
int viewall = 0;
int lfp;
/* init global flags */
use_syslog = verbose = 0;
/* init current line number */
lineno = 0;
/* setup internationalisation */
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
/* setup syslog parameters */
args = 0;
/* enable debug options */
#ifdef _IPQOS_CONF_DEBUG
#else
#define DBGOPTS
#endif /* _IPQOS_CONF_DEBUG */
switch (c) {
#ifdef _IPQOS_CONF_DEBUG
case 'z':
cmd = -1;
if (*ifile == '\0') {
usage();
exit(1);
}
args++;
break;
case 'r':
force_rback++;
break;
#endif /* _IPQOS_CONF_DEBUG */
case 'c':
args++;
break;
case 'a':
if (*ifile == '\0') {
usage();
exit(1);
}
args++;
break;
case 'f':
args++;
break;
case 'l':
args++;
break;
case 'L':
viewall++;
args++;
break;
case 'v':
verbose++;
break;
case 's':
use_syslog++;
break;
case '?':
usage();
return (1);
}
}
/*
* for anything but apply.
*/
usage();
exit(1);
}
/* if no cmd option then show config */
if (args == 0) {
}
/* stop concurrent ipqosconf invocations */
if (lfp == -1) {
exit(1);
}
switch (cmd) {
#ifdef _IPQOS_CONF_DEBUG
case -1:
break;
#endif /* _IPQOS_CONF_DEBUG */
case IPQOS_CONF_APPLY:
break;
case IPQOS_CONF_COMMIT:
ret = commitconf();
break;
case IPQOS_CONF_VIEW:
break;
case IPQOS_CONF_FLUSH:
break;
}
return (ret);
}