#undef _IPQOS_CONF_DEBUG
#include <stdlib.h>
#include <unistd.h>
#include <libintl.h>
#include <signal.h>
#include <strings.h>
#include <sys/nvpair.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/socket.h>
#include <limits.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <libipp.h>
#include <ipp/ipp_config.h>
#include <ipp/ipgpc/ipgpc.h>
#include <ipp/ipp.h>
#ifdef _IPQOS_CONF_DEBUG
#include <assert.h>
#endif
#include <sys/sockio.h>
#include <syslog.h>
#include <stdarg.h>
#include <libintl.h>
#include <locale.h>
#include <pwd.h>
#include "ipqosconf.h"
#if defined(_IPQOS_CONF_DEBUG)
static int ipqosconf_dbg_flgs =
RBK |
MHME |
KRET |
DIFF |
APPLY |
L2 |
L1 |
L0 |
0;
#define IPQOSCDBG0(lvl, x)\
if (lvl & ipqosconf_dbg_flgs)\
(void) fprintf(stderr, x)
#define IPQOSCDBG1(lvl, x, y)\
if (lvl & ipqosconf_dbg_flgs)\
(void) fprintf(stderr, x, y)
#define IPQOSCDBG2(lvl, x, y, z)\
if (lvl & ipqosconf_dbg_flgs)\
(void) fprintf(stderr, x, y, z)
#define IPQOSCDBG3(lvl, x, y, z, a)\
if (lvl & ipqosconf_dbg_flgs)\
(void) fprintf(stderr, x, y, z, a)
#define IPQOSCDBG4(lvl, x, y, z, a, b)\
if (lvl & ipqosconf_dbg_flgs)\
(void) fprintf(stderr, x, y, z, a, b)
#define IPQOSCDBG5(lvl, x, y, z, a, b, c)\
if (lvl & ipqosconf_dbg_flgs)\
(void) fprintf(stderr, x, y, z, a, b, c)
#else
#define IPQOSCDBG0(lvl, x)
#define IPQOSCDBG1(lvl, x, y)
#define IPQOSCDBG2(lvl, x, y, z)
#define IPQOSCDBG3(lvl, x, y, z, a)
#define IPQOSCDBG4(lvl, x, y, z, a, b)
#define IPQOSCDBG5(lvl, x, y, z, a, b, c)
#endif
static int modify_params(char *, nvlist_t **, int, boolean_t);
static int add_class(char *, char *, int, boolean_t, char *);
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 boolean_t arrays_equal(int *, int *, uint32_t);
static int diffclass(ipqos_conf_class_t *, ipqos_conf_class_t *);
static int diffparams(ipqos_conf_params_t *, ipqos_conf_params_t *, char *);
static int difffilter(ipqos_conf_filter_t *, ipqos_conf_filter_t *, char *);
static int add_filters(ipqos_conf_filter_t *, char *, int, boolean_t);
static int add_classes(ipqos_conf_class_t *, char *, int, boolean_t);
static int modify_items(ipqos_conf_action_t *);
static int add_items(ipqos_conf_action_t *, boolean_t);
static int add_item(ipqos_conf_action_t *, boolean_t);
static int remove_items(ipqos_conf_action_t *, boolean_t);
static int remove_item(ipqos_conf_action_t *, boolean_t);
static int undo_modifys(ipqos_conf_action_t *, ipqos_conf_action_t *);
static int applydiff(ipqos_conf_action_t *, ipqos_conf_action_t *);
static int rollback(ipqos_conf_action_t *, ipqos_conf_action_t *);
static int rollback_recover(ipqos_conf_action_t *);
static ipqos_conf_class_t *classexist(char *, ipqos_conf_class_t *);
static ipqos_conf_filter_t *filterexist(char *, int, ipqos_conf_filter_t *);
static ipqos_conf_action_t *actionexist(char *, ipqos_conf_action_t *);
static int diffnvlists(nvlist_t *, nvlist_t *, char *, int *, place_t);
static int diffaction(ipqos_conf_action_t *, ipqos_conf_action_t *);
static int diffconf(ipqos_conf_action_t *, ipqos_conf_action_t *);
static int readllong(char *, long long *, char **);
static int readuint8(char *, uint8_t *, char **);
static int readuint16(char *, uint16_t *, char **);
static int readint16(char *, int16_t *, char **);
static int readint32(char *, int *, char **);
static int readuint32(char *, uint32_t *, char **);
static int readbool(char *, boolean_t *);
static void setmask(int, in6_addr_t *, int);
static int readtoken(FILE *, char **);
static nvpair_t *find_nvpair(nvlist_t *, char *);
static char *prepend_module_name(char *, char *);
static int readnvpair(FILE *, FILE *, nvlist_t **, nvpair_t **,
ipqos_nvtype_t *, place_t, char *);
static int add_aref(ipqos_conf_act_ref_t **, char *, char *);
static int readparams(FILE *, FILE *, char *, ipqos_conf_params_t *);
static int readclass(FILE *, char *, ipqos_conf_class_t **, char **, int);
static int readfilter(FILE *, FILE *, char *, ipqos_conf_filter_t **, char **,
int);
static FILE *validmod(char *, int *);
static int readaction(FILE *, ipqos_conf_action_t **);
static int actions_unique(ipqos_conf_action_t *, char **);
static int validconf(ipqos_conf_action_t *, int);
static int readconf(FILE *, ipqos_conf_action_t **);
static int flush(boolean_t *);
static int atomic_flush(boolean_t);
static int flushconf();
static int writeconf(ipqos_conf_action_t *, char *);
static int commitconf();
static int applyconf(char *ifile);
static int block_all_signals();
static int restore_all_signals();
static int unlock(int fd);
static int lock();
static int viewconf(int);
static void usage();
static int valid_name(char *);
static int in_cycle(ipqos_conf_action_t *);
static int readtype(FILE *, char *, char *, ipqos_nvtype_t *, str_val_nd_t **,
char *, boolean_t, place_t *);
static int read_int_array_info(char *, str_val_nd_t **, uint32_t *, int *,
int *, char *);
static str_val_nd_t *read_enum_nvs(char *, char *);
static int add_str_val_entry(str_val_nd_t **, char *, uint32_t);
static void free_str_val_entrys(str_val_nd_t *);
static void get_str_val_value_range(str_val_nd_t *, int *, int *);
static int read_enum_value(FILE *, char *, str_val_nd_t *, uint32_t *);
static int read_mapped_values(FILE *, nvlist_t **, char *, char *,
int);
static int read_int_array(FILE *, char *, int **, uint32_t, int, int,
str_val_nd_t *);
static int str_val_list_lookup(str_val_nd_t *, char *, uint32_t *);
static int parse_kparams(char *, ipqos_conf_params_t *, nvlist_t *);
static int parse_kclass(ipqos_conf_class_t *, nvlist_t *);
static int parse_kfilter(ipqos_conf_filter_t *, nvlist_t *);
static int parse_kaction(nvlist_t *, ipqos_actinfo_prm_t *);
static int readkconf(ipqos_conf_action_t **);
static void print_int_array(FILE *, int *, uint32_t, int, int, str_val_nd_t *,
int);
static void printrange(FILE *fp, uint32_t, uint32_t);
static void printenum(FILE *, uint32_t, str_val_nd_t *);
static void printproto(FILE *, uint8_t);
static void printport(FILE *, uint16_t);
static int printnvlist(FILE *, char *, nvlist_t *, int, ipqos_conf_filter_t *,
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);
static int domultihome(ipqos_conf_filter_t *, ipqos_conf_filter_t **,
boolean_t);
static int dup_filter(ipqos_conf_filter_t *, ipqos_conf_filter_t **, int, 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 diffclasses(ipqos_conf_action_t *old, ipqos_conf_action_t *new);
static int difffilters(ipqos_conf_action_t *old, ipqos_conf_action_t *new);
static int dup_class(ipqos_conf_class_t *src, ipqos_conf_class_t **dst);
static int add_action(ipqos_conf_action_t *act);
static int masktocidr(int af, in6_addr_t *mask);
static int read_perm_items(int, FILE *, char *, char ***, int *);
static int in_string_table(char *stable[], int size, char *string);
static void list_end(ipqos_list_el_t **listp, ipqos_list_el_t ***lendpp);
static void add_to_list(ipqos_list_el_t **listp, ipqos_list_el_t *el);
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 *);
static void printuser(FILE *fp, uid_t uid);
static int readuser(char *str, uid_t *uid);
#define GET_LIST_END(list, end)\
list_end((ipqos_list_el_t **)list, (ipqos_list_el_t ***)end)
#define ADD_TO_LIST(list, el)\
add_to_list((ipqos_list_el_t **)list, (ipqos_list_el_t *)el)
#define QUOTE(x) #x
#define VAL2STR(x) QUOTE(x)
static str_val_t nv_types[] = {
{"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}
};
static str_val_t originators[] = {
{IPP_CONFIG_NAME_PERMANENT, IPP_CONFIG_PERMANENT},
{IPP_CONFIG_NAME_IPQOSCONF, IPP_CONFIG_IPQOSCONF},
{IPP_CONFIG_NAME_FTPCL, IPP_CONFIG_FTPCL},
{"", -1}
};
static int lineno;
static int verbose;
static int use_syslog;
#ifdef _IPQOS_CONF_DEBUG
static int force_rback = 0;
#endif
static void
ipqos_msg(enum msg_type msgt, char *format, ...)
{
va_list ap;
char str_buf[IPQOS_MSG_BUF_SZ];
char fmt_buf[IPQOS_MSG_BUF_SZ];
char *cp;
IPQOSCDBG0(L1, "In ipqos_msg:\n");
va_start(ap, format);
if ((use_syslog && (msgt != MT_WARNING)) || msgt == MT_LOG) {
(void) vsnprintf(str_buf, IPQOS_MSG_BUF_SZ, format, ap);
if (msgt == MT_ERROR) {
syslog(LOG_ERR, str_buf);
} else if (msgt == MT_LOG) {
syslog(LOG_INFO, str_buf);
} else if (msgt == MT_ENOSTR) {
if ((cp = strchr(str_buf, '\n')) != NULL)
*cp = '\0';
(void) strlcat(str_buf, ": %m", IPQOS_MSG_BUF_SZ);
syslog(LOG_ERR, str_buf);
}
}
if ((!use_syslog && (msgt != MT_LOG)) || (verbose)) {
if (msgt == MT_ERROR) {
(void) strlcpy(fmt_buf, gettext("Error: "),
IPQOS_MSG_BUF_SZ);
} else if (msgt == MT_WARNING) {
if (!verbose) {
va_end(ap);
return;
}
(void) strlcpy(fmt_buf, gettext("Warning: "),
IPQOS_MSG_BUF_SZ);
} else if (msgt == MT_ENOSTR) {
(void) strlcpy(fmt_buf, gettext("Error: "),
IPQOS_MSG_BUF_SZ);
} else if (msgt == MT_LOG) {
(void) strlcpy(fmt_buf, gettext("Notice: "),
IPQOS_MSG_BUF_SZ);
}
(void) strlcat(fmt_buf, format, IPQOS_MSG_BUF_SZ);
if (msgt == MT_ENOSTR) {
if ((cp = strchr(fmt_buf, '\n')) != NULL)
*cp = '\0';
(void) strlcat(fmt_buf, ": ", IPQOS_MSG_BUF_SZ);
(void) strlcat(fmt_buf, strerror(errno),
IPQOS_MSG_BUF_SZ);
}
if ((cp = strchr(fmt_buf, '\n')) == NULL)
(void) strlcat(fmt_buf, "\n", IPQOS_MSG_BUF_SZ);
(void) vfprintf(stderr, fmt_buf, ap);
}
va_end(ap);
}
static int
modify_params(
char *action_name,
nvlist_t **nvl,
int module_version,
boolean_t stats_enable)
{
int res;
int created = 0;
IPQOSCDBG1(APPLY, "In modify_params: action: %s\n", action_name);
if (*nvl == NULL) {
created++;
res = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_alloc");
return (IPQOS_CONF_ERR);
}
}
res = nvlist_add_byte(*nvl, IPP_CONFIG_TYPE, IPP_SET);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
goto fail;
}
if (nvlist_add_uint32(*nvl, IPP_MODULE_VERSION,
(uint32_t)module_version) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
goto fail;
}
res = nvlist_add_uint32(*nvl, IPP_ACTION_STATS_ENABLE,
(uint32_t)stats_enable);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
goto fail;
}
res = add_orig_ipqosconf(*nvl);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
res = ipp_action_modify(action_name, nvl, 0);
if (res != 0) {
if (errno == EINVAL) {
ipqos_msg(MT_ERROR,
gettext("Invalid parameters for action %s.\n"),
action_name);
} else if (errno == ENOENT) {
ipqos_msg(MT_ERROR,
gettext("Mandatory parameter missing for "
"action %s.\n"), action_name);
} else {
ipqos_msg(MT_ERROR, gettext("Failed to modify action "
"%s parameters: %s.\n"), action_name,
strerror(errno));
}
goto fail;
}
return (IPQOS_CONF_SUCCESS);
fail:
if (created && *nvl != NULL) {
nvlist_free(*nvl);
*nvl = NULL;
}
return (IPQOS_CONF_ERR);
}
static int
add_class(
char *action_name,
char *class_name,
int module_version,
boolean_t stats_enable,
char *first_action)
{
nvlist_t *nvl;
IPQOSCDBG4(APPLY, "add_class: action: %s, class: %s, "
"first_action: %s, stats: %s\n", action_name, class_name,
first_action, (stats_enable == B_TRUE ? "true" : "false"));
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_alloc");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE, CLASSIFIER_ADD_CLASS) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
goto fail;
}
if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
(uint32_t)module_version) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
goto fail;
}
if (nvlist_add_string(nvl, CLASSIFIER_CLASS_NAME, class_name) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
goto fail;
}
if (nvlist_add_string(nvl, CLASSIFIER_NEXT_ACTION, first_action) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
goto fail;
}
if (nvlist_add_uint32(nvl, CLASSIFIER_CLASS_STATS_ENABLE,
(uint32_t)stats_enable) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
goto fail;
}
if (add_orig_ipqosconf(nvl) != IPQOS_CONF_SUCCESS) {
goto fail;
}
if (ipp_action_modify(action_name, &nvl, 0) != 0) {
if (errno == ENOSPC &&
strcmp(action_name, IPGPC_CLASSIFY) == 0) {
ipqos_msg(MT_ERROR,
gettext("Max number of classes reached in %s.\n"),
IPGPC_NAME);
} else {
ipqos_msg(MT_ERROR,
gettext("Failed to create class %s in action "
"%s: %s.\n"), class_name, action_name,
strerror(errno));
}
goto fail;
}
return (IPQOS_CONF_SUCCESS);
fail:
nvlist_free(nvl);
return (IPQOS_CONF_ERR);
}
static int
modify_class(
char *action_name,
char *class_name,
int module_version,
boolean_t stats_enable,
char *first_action,
enum ipp_flags flags)
{
nvlist_t *nvl;
IPQOSCDBG5(APPLY, "modify_class: action: %s, class: %s, first: %s, "
"stats: %s, flags: %x\n", action_name, class_name, first_action,
stats_enable == B_TRUE ? "true" : "false", flags);
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_alloc");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE, CLASSIFIER_MODIFY_CLASS) !=
0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
goto fail;
}
if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
(uint32_t)module_version) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
goto fail;
}
if (nvlist_add_string(nvl, CLASSIFIER_CLASS_NAME, class_name) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
goto fail;
}
if (nvlist_add_string(nvl, CLASSIFIER_NEXT_ACTION, first_action) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
goto fail;
}
if (nvlist_add_uint32(nvl, CLASSIFIER_CLASS_STATS_ENABLE,
(uint32_t)stats_enable) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
goto fail;
}
if (add_orig_ipqosconf(nvl) != IPQOS_CONF_SUCCESS) {
goto fail;
}
if (ipp_action_modify(action_name, &nvl, flags) != 0) {
ipqos_msg(MT_ERROR,
gettext("Modifying class %s in action %s failed: %s.\n"),
class_name, action_name, strerror(errno));
goto fail;
}
return (IPQOS_CONF_SUCCESS);
fail:
nvlist_free(nvl);
return (IPQOS_CONF_ERR);
}
static int
remove_class(
char *action_name,
char *class_name,
int module_version,
enum ipp_flags flags)
{
nvlist_t *nvl;
IPQOSCDBG3(APPLY, "remove_class: action: %s, class: %s, "
"flags: %x\n", action_name, class_name, flags);
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_alloc");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE, CLASSIFIER_REMOVE_CLASS) !=
0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
goto fail;
}
if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
(uint32_t)module_version) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
goto fail;
}
if (nvlist_add_string(nvl, CLASSIFIER_CLASS_NAME, class_name) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
goto fail;
}
if (ipp_action_modify(action_name, &nvl, flags) != 0) {
ipqos_msg(MT_ERROR,
gettext("Removing class %s in action %s failed: %s.\n"),
class_name, action_name, strerror(errno));
goto fail;
}
return (IPQOS_CONF_SUCCESS);
fail:
nvlist_free(nvl);
return (IPQOS_CONF_ERR);
}
static int
add_filter(
char *action_name,
ipqos_conf_filter_t *flt,
int module_version)
{
nvlist_t *nvl = flt->nvlist;
char ipvsbuf[IPQOS_INT_STR_LEN];
IPQOSCDBG4(APPLY, "add_filter: action: %s, filter: %s, "
"instance: %d, class: %s\n", action_name, flt->name,
flt->instance, flt->class_name);
if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE, CLASSIFIER_ADD_FILTER) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
(uint32_t)module_version) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_string(nvl, CLASSIFIER_FILTER_NAME, flt->name) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_string(nvl, CLASSIFIER_CLASS_NAME, flt->class_name) !=
0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
if (add_orig_ipqosconf(nvl) != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
if (strcmp(action_name, IPGPC_CLASSIFY) == 0) {
if (flt->src_nd_name != NULL &&
nvlist_add_string(nvl, IPGPC_SADDR_HOSTNAME,
flt->src_nd_name) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
if (flt->dst_nd_name != NULL &&
nvlist_add_string(nvl, IPGPC_DADDR_HOSTNAME,
flt->dst_nd_name) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
if (flt->ip_versions != 0) {
(void) sprintf(ipvsbuf, "%d", flt->ip_versions);
if (nvlist_add_string(nvl, IPGPC_FILTER_PRIVATE,
ipvsbuf) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
}
if (nvlist_add_int32(nvl, IPGPC_FILTER_INSTANCE,
flt->instance) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_int32");
return (IPQOS_CONF_ERR);
}
}
if (ipp_action_modify(action_name, &flt->nvlist, 0) != 0) {
if (errno == EINVAL) {
ipqos_msg(MT_ERROR,
gettext("Invalid/missing parameters for filter "
"%s in action %s.\n"), flt->name, action_name);
} else if (errno == ENOSPC &&
strcmp(action_name, IPGPC_CLASSIFY) == 0) {
ipqos_msg(MT_ERROR, gettext("Max number of filters "
"reached in action %s.\n"), IPGPC_NAME);
} else {
ipqos_msg(MT_ERROR,
gettext("Failed to create filter %s in action "
"%s: %s.\n"), flt->name, action_name,
strerror(errno));
}
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
modify_filter(
char *action_name,
ipqos_conf_filter_t *flt,
int module_version)
{
nvlist_t *nvl = flt->nvlist;
char ipvsbuf[IPQOS_INT_STR_LEN];
IPQOSCDBG4(APPLY, "modify_filter: action: %s, filter: %s, "
"instance: %d, class: %s\n", action_name, flt->name,
flt->instance, flt->class_name);
#ifdef _IPQOS_CONF_DEBUG
if (ipqosconf_dbg_flgs & APPLY) {
uint_t tmp;
in6_addr_t *add;
char st[100];
if (nvlist_lookup_uint32_array(nvl, IPGPC_SADDR,
(uint32_t **)&add, &tmp) == 0) {
(void) fprintf(stderr, "saddr: %s\n",
inet_ntop(AF_INET6, add, st, 100));
}
if (nvlist_lookup_uint32_array(nvl, IPGPC_DADDR,
(uint32_t **)&add, &tmp) == 0) {
(void) fprintf(stderr, "daddr: %s\n",
inet_ntop(AF_INET6, add, st, 100));
}
}
#endif
if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE,
CLASSIFIER_MODIFY_FILTER) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
(uint32_t)module_version) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_string(nvl, CLASSIFIER_FILTER_NAME, flt->name) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_string(nvl, CLASSIFIER_CLASS_NAME, flt->class_name) !=
0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
if (add_orig_ipqosconf(nvl) != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
if (strcmp(action_name, IPGPC_CLASSIFY) == 0) {
if (flt->src_nd_name &&
nvlist_add_string(nvl, IPGPC_SADDR_HOSTNAME,
flt->src_nd_name) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
if (flt->dst_nd_name &&
nvlist_add_string(nvl, IPGPC_DADDR_HOSTNAME,
flt->dst_nd_name) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
if (flt->ip_versions != 0) {
(void) sprintf(ipvsbuf, "%d", flt->ip_versions);
if (nvlist_add_string(nvl, IPGPC_FILTER_PRIVATE,
ipvsbuf) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
}
if (nvlist_add_int32(nvl, IPGPC_FILTER_INSTANCE,
flt->instance) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_int32");
return (IPQOS_CONF_ERR);
}
}
if (ipp_action_modify(action_name, &flt->nvlist, 0) != 0) {
if (errno == EINVAL) {
ipqos_msg(MT_ERROR, gettext("Missing/Invalid "
"parameter for filter %s in action %s.\n"),
flt->name, action_name);
} else {
ipqos_msg(MT_ERROR,
gettext("Failed to modify filter %s in action %s: "
"%s.\n"), flt->name, action_name, strerror(errno));
}
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
remove_filter(
char *action_name,
char *filter_name,
int instance,
int module_version)
{
nvlist_t *nvl;
IPQOSCDBG2(APPLY, "remove_filter: action: %s, filter: %s\n",
action_name, filter_name);
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_alloc");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_byte(nvl, IPP_CONFIG_TYPE, CLASSIFIER_REMOVE_FILTER)
!= 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_uint32(nvl, IPP_MODULE_VERSION,
(uint32_t)module_version) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_string(nvl, CLASSIFIER_FILTER_NAME, filter_name) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
return (IPQOS_CONF_ERR);
}
if (instance != -1 && nvlist_add_int32(nvl, IPGPC_FILTER_INSTANCE,
instance) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_int32");
return (IPQOS_CONF_ERR);
}
if (ipp_action_modify(action_name, &nvl, 0) != 0) {
ipqos_msg(MT_ERROR,
gettext("Removing filter %s in action %s failed: %s.\n"),
filter_name, action_name, strerror(errno));
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
add_orig_ipqosconf(nvlist_t *nvl)
{
if (nvlist_add_uint32(nvl, IPP_CONFIG_ORIGINATOR,
IPP_CONFIG_IPQOSCONF) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32: originator:");
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static boolean_t
arrays_equal(
int array1[],
int array2[],
uint32_t size)
{
int x;
for (x = 0; x < size; x++) {
if (array1[x] != array2[x])
return (B_FALSE);
}
return (B_TRUE);
}
static int
diffclass(
ipqos_conf_class_t *old,
ipqos_conf_class_t *new)
{
IPQOSCDBG0(L0, "In diffclass:\n");
if (strcmp(old->alist->name, new->alist->name) != 0) {
IPQOSCDBG1(DIFF, "marking class %s as modified\n", new->name);
new->modified = B_TRUE;
return (IPQOS_CONF_SUCCESS);
}
if (old->stats_enable != new->stats_enable) {
IPQOSCDBG1(DIFF, "marking class %s as modified\n", new->name);
new->modified = B_TRUE;
return (IPQOS_CONF_SUCCESS);
}
return (IPQOS_CONF_SUCCESS);
}
static int
diffparams(
ipqos_conf_params_t *old,
ipqos_conf_params_t *new,
char *module_name)
{
int diff;
int res;
IPQOSCDBG0(L0, "In diffparams\n");
if (old->stats_enable != new->stats_enable) {
new->modified = B_TRUE;
return (IPQOS_CONF_SUCCESS);
}
res = diffnvlists(old->nvlist, new->nvlist, module_name, &diff,
PL_PARAMS);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
if (diff) {
new->modified = B_TRUE;
}
return (IPQOS_CONF_SUCCESS);
}
static int
difffilter(
ipqos_conf_filter_t *old,
ipqos_conf_filter_t *new,
char *module_name)
{
int res;
int diff;
IPQOSCDBG0(L0, "In difffilter\n");
if (strcmp(old->class_name, new->class_name) != 0) {
IPQOSCDBG1(DIFF, "Marking filter %s as modified\n", new->name);
new->modified = B_TRUE;
return (IPQOS_CONF_SUCCESS);
}
res = diffnvlists(old->nvlist, new->nvlist, module_name, &diff,
PL_FILTER);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
if (diff) {
IPQOSCDBG1(DIFF, "Marking filter %s as modified\n", new->name);
new->modified = B_TRUE;
}
return (IPQOS_CONF_SUCCESS);
}
static void
mark_classes_filters_del(ipqos_conf_action_t *action)
{
ipqos_conf_filter_t *flt;
ipqos_conf_class_t *cls;
IPQOSCDBG1(L1, "In mark_classes_filters_del: action: %s\n",
action->name);
for (flt = action->filters; flt; flt = flt->next) {
if (flt->originator == IPP_CONFIG_PERMANENT) {
IPQOSCDBG1(DIFF, "Marking prm filter %s as modified.\n",
flt->name);
flt->modified = B_TRUE;
} else {
IPQOSCDBG1(DIFF, "Marking filter %s as del.\n",
flt->name);
flt->todel = B_TRUE;
}
}
for (cls = action->classes; cls; cls = cls->next) {
if (cls->originator == IPP_CONFIG_PERMANENT) {
IPQOSCDBG1(DIFF, "Marking prm class %s as modified.\n",
cls->name);
cls->modified = B_TRUE;
} else {
IPQOSCDBG1(DIFF, "Marking class %s as del.\n",
cls->name);
cls->todel = B_TRUE;
}
}
}
static void
mark_classes_filters_new(ipqos_conf_action_t *action)
{
ipqos_conf_filter_t *flt;
ipqos_conf_class_t *cls;
IPQOSCDBG1(L1, "In mark_classes_filters_new: action: %s\n",
action->name);
for (flt = action->filters; flt; flt = flt->next) {
if (flt->originator == IPP_CONFIG_PERMANENT) {
IPQOSCDBG1(DIFF, "Marking prm filter %s as modified.\n",
flt->name);
flt->modified = B_TRUE;
action->modified = B_TRUE;
} else {
IPQOSCDBG1(DIFF, "Marking filter %s as new.\n",
flt->name);
flt->new = B_TRUE;
}
}
for (cls = action->classes; cls; cls = cls->next) {
if (cls->originator == IPP_CONFIG_PERMANENT) {
IPQOSCDBG1(DIFF, "Marking prm class %s as modified.\n",
cls->name);
cls->modified = B_TRUE;
action->modified = B_TRUE;
} else {
IPQOSCDBG1(DIFF, "Marking class %s as new.\n",
cls->name);
cls->new = B_TRUE;
}
}
}
static void
mark_config_new(
ipqos_conf_action_t *conf)
{
while (conf != NULL) {
IPQOSCDBG1(DIFF, "Marking action %s as new\n", conf->name);
mark_classes_filters_new(conf);
conf->new = B_TRUE;
conf->visited = 0;
conf = conf->next;
}
}
static int
diffconf(
ipqos_conf_action_t *old,
ipqos_conf_action_t *new)
{
int res;
ipqos_conf_action_t *act;
ipqos_conf_action_t *tmp;
IPQOSCDBG0((L0 | DIFF), "In diffconf\n");
for (act = new; act; act = act->next) {
if ((tmp = actionexist(act->name, old)) == NULL) {
IPQOSCDBG1(DIFF, "marking act %s as new\n", act->name);
act->new = B_TRUE;
mark_classes_filters_new(act);
continue;
}
res = diffaction(tmp, act);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
for (act = old; act; act = act->next) {
if (act->params->originator == IPP_CONFIG_IPQOSCONF &&
actionexist(act->name, new) == NULL) {
IPQOSCDBG1(DIFF, "marking act %s for del\n", act->name);
act->todel = B_TRUE;
mark_classes_filters_del(act);
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
diffaction(
ipqos_conf_action_t *old,
ipqos_conf_action_t *new)
{
int res;
IPQOSCDBG0(L0, "In diffaction\n");
res = diffclasses(old, new);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
res = difffilters(old, new);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
res = diffparams(old->params, new->params, old->module);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
if (new->params->modified == B_TRUE) {
IPQOSCDBG1(DIFF, "Marking params for action %s modified\n",
new->name);
new->modified = B_TRUE;
}
return (IPQOS_CONF_SUCCESS);
}
static int
diffclasses(
ipqos_conf_action_t *old,
ipqos_conf_action_t *new)
{
ipqos_conf_class_t *cls;
ipqos_conf_class_t *tmpc;
ipqos_conf_class_t *ncls;
int res;
for (cls = old->classes; cls; cls = cls->next) {
if (classexist(cls->name, new->classes) == NULL) {
if (cls->originator == IPP_CONFIG_IPQOSCONF) {
IPQOSCDBG1(DIFF, "marking class %s for del\n",
cls->name);
cls->todel = B_TRUE;
old->modified = B_TRUE;
} else if (cls->originator == IPP_CONFIG_PERMANENT &&
cls->alist->action &&
cls->alist->action->params->originator ==
IPP_CONFIG_IPQOSCONF) {
res = dup_class(cls, &ncls);
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
(void) strcpy(ncls->alist->name,
IPP_ANAME_CONT);
ADD_TO_LIST(&new->classes, ncls);
}
}
}
for (cls = new->classes; cls; cls = cls->next) {
if ((tmpc = classexist(cls->name, old->classes)) == NULL ||
(tmpc->originator != IPP_CONFIG_IPQOSCONF &&
tmpc->originator != IPP_CONFIG_PERMANENT)) {
IPQOSCDBG1(DIFF, "marking class %s new\n",
cls->name);
cls->new = B_TRUE;
new->modified = B_TRUE;
continue;
} else {
res = diffclass(tmpc, cls);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
if (cls->modified == B_TRUE) {
new->modified = B_TRUE;
}
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
difffilters(
ipqos_conf_action_t *old,
ipqos_conf_action_t *new)
{
ipqos_conf_filter_t *flt;
ipqos_conf_filter_t *tmpf;
int maxi;
int newi;
int res;
for (flt = new->filters; flt; flt = flt->next) {
if ((tmpf = filterexist(flt->name, -1, old->filters)) == NULL) {
for (;;) {
IPQOSCDBG1(DIFF, "Marking filter %s as "
"new\n", flt->name);
flt->new = B_TRUE;
if (flt->next == NULL ||
strcmp(flt->next->name, flt->name) != 0) {
break;
}
flt = flt->next;
}
new->modified = B_TRUE;
} else {
if (tmpf->src_nd_name || tmpf->dst_nd_name ||
flt->src_nd_name || flt->dst_nd_name) {
maxi = tmpf->instance;
do {
IPQOSCDBG2(DIFF, "Marking filter "
"%s, instance %d for del\n",
tmpf->name, tmpf->instance);
tmpf->todel = B_TRUE;
if (tmpf->instance > maxi) {
maxi = tmpf->instance;
}
tmpf = tmpf->next;
} while (tmpf != NULL &&
strcmp(tmpf->name, flt->name) == 0);
newi = (uint32_t)++maxi % INT_MAX;
for (;;) {
IPQOSCDBG2(DIFF, "Marking filter "
"%s, instance %d as new\n",
flt->name, newi);
flt->new = B_TRUE;
flt->instance = newi++;
if (flt->next == NULL ||
strcmp(flt->next->name,
flt->name) != 0) {
break;
}
flt = flt->next;
}
new->modified = B_TRUE;
old->modified = B_TRUE;
} else {
res = difffilter(tmpf, flt, new->module);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
if (flt->modified == B_TRUE) {
new->modified = B_TRUE;
}
}
}
}
for (flt = old->filters; flt; flt = flt->next) {
if (flt->originator == IPP_CONFIG_IPQOSCONF &&
filterexist(flt->name, -1, new->filters) == NULL) {
for (;;) {
IPQOSCDBG2(DIFF, "marking flt %s, inst %d "
"for del\n", flt->name, flt->instance);
flt->todel = B_TRUE;
old->modified = B_TRUE;
if (flt->next == NULL ||
strcmp(flt->next->name, flt->name) != 0) {
break;
}
flt = flt->next;
}
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
diffnvlists(
nvlist_t *old,
nvlist_t *new,
char *module_name,
int *pdiff,
place_t place)
{
int first_pass = 1;
nvlist_t *tmp;
int res;
nvpair_t *nvp;
FILE *tfp;
str_val_nd_t *enum_nvs;
char dfltst[IPQOS_VALST_MAXLEN+1] = "";
char *lo;
ipqos_nvtype_t type;
char *nme;
int diff;
int openerr;
IPQOSCDBG0(L0, "In diffnvlists\n");
tfp = validmod(module_name, &openerr);
if (tfp == NULL) {
if (openerr) {
ipqos_msg(MT_ENOSTR, "fopen");
}
return (IPQOS_CONF_ERR);
}
start:
nvp = nvlist_next_nvpair(new, NULL);
while (nvp != NULL) {
nme = nvpair_name(nvp);
place = PL_ANY;
res = readtype(tfp, module_name, SHORT_NAME(nme), &type,
&enum_nvs, dfltst, B_TRUE, &place);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
diff = 1;
switch (type) {
case IPQOS_DATA_TYPE_IFINDEX: {
uint32_t ifidx;
uint32_t oifidx;
(void) nvpair_value_uint32(nvp, &ifidx);
res = nvlist_lookup_uint32(old, nme, &oifidx);
if (res == 0) {
diff = (ifidx != oifidx);
} else {
diff = (ifidx != 0);
}
break;
}
case IPQOS_DATA_TYPE_PROTO: {
uchar_t proto;
uchar_t oproto;
(void) nvpair_value_byte(nvp, &proto);
res = nvlist_lookup_byte(old, nme, &oproto);
if (res == 0) {
diff = (proto != oproto);
} else {
diff = (proto != 0);
}
break;
}
case IPQOS_DATA_TYPE_PORT: {
uint16_t port;
uint16_t oport;
(void) nvpair_value_uint16(nvp, &port);
res = nvlist_lookup_uint16(old, nme, &oport);
if (res == 0) {
diff = (port != oport);
} else {
diff = (port != 0);
}
break;
}
case IPQOS_DATA_TYPE_ACTION:
case IPQOS_DATA_TYPE_STRING: {
char *str;
char *ostr;
(void) nvpair_value_string(nvp, &str);
res = nvlist_lookup_string(old, nme, &ostr);
if (res == 0) {
diff = strcmp(str, ostr);
} else if (*dfltst) {
diff = strcmp(str, dfltst);
}
break;
}
case IPQOS_DATA_TYPE_ADDRESS_MASK:
case IPQOS_DATA_TYPE_ADDRESS: {
in6_addr_t *in6;
in6_addr_t *oin6;
uint_t x;
(void) nvpair_value_uint32_array(nvp,
(uint32_t **)&in6, &x);
res = nvlist_lookup_uint32_array(old, nme,
(uint32_t **)&oin6, &x);
if (res == 0) {
for (x = 0; x < 16; x++) {
if (in6->s6_addr[x] !=
oin6->s6_addr[x]) {
diff++;
break;
}
}
}
break;
}
case IPQOS_DATA_TYPE_BOOLEAN: {
boolean_t bl;
boolean_t obl;
(void) nvpair_value_uint32(nvp, (uint32_t *)&bl);
res = nvlist_lookup_uint32(old, nme, (uint32_t *)&obl);
if (res == 0) {
diff = (bl != obl);
} else if (*dfltst) {
res = readbool(dfltst, &obl);
if (res == IPQOS_CONF_SUCCESS) {
diff = (bl != obl);
}
}
break;
}
case IPQOS_DATA_TYPE_UINT8: {
uint8_t u8;
uint8_t ou8;
(void) nvpair_value_byte(nvp, (uchar_t *)&u8);
res = nvlist_lookup_byte(old, nme, (uchar_t *)&ou8);
if (res == 0) {
diff = (u8 != ou8);
} else if (*dfltst) {
res = readuint8(dfltst, &ou8, &lo);
if (res == IPQOS_CONF_SUCCESS) {
diff = (u8 != ou8);
}
}
break;
}
case IPQOS_DATA_TYPE_INT16: {
int16_t i16;
int16_t oi16;
(void) nvpair_value_int16(nvp, &i16);
res = nvlist_lookup_int16(old, nme, &oi16);
if (res == 0) {
diff = (i16 != oi16);
} else if (*dfltst) {
res = readint16(dfltst, &oi16, &lo);
if (res == IPQOS_CONF_SUCCESS) {
diff = (i16 != oi16);
}
}
break;
}
case IPQOS_DATA_TYPE_UINT16: {
uint16_t ui16;
uint16_t oui16;
(void) nvpair_value_uint16(nvp, &ui16);
res = nvlist_lookup_uint16(old, nme, &oui16);
if (res == 0) {
diff = (ui16 != oui16);
} else if (*dfltst) {
res = readuint16(dfltst, &oui16, &lo);
if (res == IPQOS_CONF_SUCCESS) {
diff = (ui16 != oui16);
}
}
break;
}
case IPQOS_DATA_TYPE_USER:
case IPQOS_DATA_TYPE_INT32: {
int32_t i32;
int32_t oi32;
(void) nvpair_value_int32(nvp, &i32);
res = nvlist_lookup_int32(old, nme, &oi32);
if (res == 0) {
diff = (i32 != oi32);
} else if (*dfltst) {
res = readint32(dfltst, &oi32, &lo);
if (res == IPQOS_CONF_SUCCESS) {
diff = (i32 != oi32);
}
}
break;
}
case IPQOS_DATA_TYPE_UINT32: {
uint32_t ui32;
uint32_t oui32;
(void) nvpair_value_uint32(nvp, &ui32);
res = nvlist_lookup_uint32(old, nme, &oui32);
if (res == 0) {
diff = (ui32 != oui32);
} else if (*dfltst) {
res = readuint32(dfltst, &oui32, &lo);
if (res == IPQOS_CONF_SUCCESS) {
diff = (ui32 != oui32);
}
}
break;
}
case IPQOS_DATA_TYPE_ENUM: {
uint32_t eval;
uint32_t oeval;
(void) nvpair_value_uint32(nvp, &eval);
res = nvlist_lookup_uint32(old, nme, &oeval);
if (res == 0) {
diff = (eval != oeval);
} else if (*dfltst) {
res = readuint32(dfltst, &oeval, &lo);
if (res == IPQOS_CONF_SUCCESS) {
diff = (eval != oeval);
}
}
break;
}
case IPQOS_DATA_TYPE_M_INDEX: {
uint8_t idx, oidx;
(void) nvpair_value_byte(nvp, &idx);
res = nvlist_lookup_byte(old, nme, &oidx);
if (res == 0)
diff = (idx != oidx);
break;
}
case IPQOS_DATA_TYPE_INT_ARRAY: {
int *oarr, *arr;
uint32_t osize, size;
(void) nvpair_value_int32_array(nvp, &arr, &size);
res = nvlist_lookup_int32_array(old, nme, &oarr,
&osize);
if (res == 0)
diff = (arrays_equal(arr, oarr, size) ==
B_FALSE);
break;
}
#ifdef _IPQOS_CONF_DEBUG
default: {
assert(1);
}
#endif
}
if (diff != 0) {
IPQOSCDBG1(DIFF, "parameter %s different\n", nme);
*pdiff = 1;
(void) fclose(tfp);
return (IPQOS_CONF_SUCCESS);
}
nvp = nvlist_next_nvpair(new, nvp);
}
if (first_pass) {
tmp = old;
old = new;
new = tmp;
first_pass = 0;
goto start;
}
(void) fclose(tfp);
*pdiff = 0;
return (IPQOS_CONF_SUCCESS);
}
static int
applydiff(
ipqos_conf_action_t *actions,
ipqos_conf_action_t *old_actions)
{
int res;
IPQOSCDBG0(L1, "In applydiff:\n");
res = add_items(actions, B_FALSE);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
res = modify_items(actions);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
res = remove_items(old_actions, B_FALSE);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
return (IPQOS_CONF_SUCCESS);
}
static int
add_items(
ipqos_conf_action_t *actions,
boolean_t rem_undo)
{
int res;
ipqos_conf_action_t *act;
IPQOSCDBG1(L1, "In add_items, rem_undo: %u\n", rem_undo);
act = actionexist(IPGPC_CLASSIFY, actions);
if (act &&
(rem_undo == B_FALSE && act->new == B_TRUE ||
rem_undo == B_TRUE && act->deleted == B_TRUE)) {
res = add_action(act);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
for (act = actions; act; act = act->next) {
res = add_item(act, rem_undo);
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
add_item(
ipqos_conf_action_t *actions,
boolean_t rem_undo)
{
ipqos_conf_action_t *act = actions;
int res;
ipqos_conf_class_t *cls;
ipqos_conf_act_ref_t *pact;
IPQOSCDBG2(L1, "In add_item: action: %s, rem_undo: %u\n",
actions->name, rem_undo);
if (act->visited == ADD_VISITED) {
IPQOSCDBG0(L1, "Early exit due to visited\n");
return (IPQOS_CONF_SUCCESS);
}
act->visited = ADD_VISITED;
for (cls = act->classes; cls; cls = cls->next) {
if (cls->alist->action) {
res = add_item(cls->alist->action, rem_undo);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
for (pact = act->params->actions; pact; pact = pact->next) {
if (pact->action) {
res = add_item(pact->action, rem_undo);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
if (((rem_undo == B_FALSE && act->new == B_TRUE) ||
(rem_undo == B_TRUE && act->deleted == B_TRUE)) &&
strcmp(act->name, IPGPC_CLASSIFY) != 0) {
res = add_action(act);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
if (add_classes(act->classes, act->name, act->module_version,
rem_undo) != IPQOS_CONF_SUCCESS ||
add_filters(act->filters, act->name, act->module_version,
rem_undo) != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
add_action(ipqos_conf_action_t *act)
{
int res;
nvlist_t **nvl;
IPQOSCDBG2(APPLY, "add_action: action: %s, module: %s\n", act->name,
act->module);
nvl = &act->params->nvlist;
if (*nvl == NULL) {
res = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_alloc");
return (IPQOS_CONF_ERR);
}
}
if (nvlist_add_uint32(*nvl, IPP_MODULE_VERSION,
(uint32_t)act->module_version) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32");
return (IPQOS_CONF_ERR);
}
if (nvlist_add_uint32(*nvl, IPP_ACTION_STATS_ENABLE,
(uint32_t)act->params->stats_enable) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32: action stats");
return (IPQOS_CONF_ERR);
}
if (add_orig_ipqosconf(*nvl) != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
res = ipp_action_create(act->module, act->name, nvl, 0);
if (res != 0) {
IPQOSCDBG2(APPLY, "Create action %s, module %s failed\n",
act->name, act->module);
if (errno == EINVAL) {
ipqos_msg(MT_ERROR,
gettext("Invalid Parameters for action %s.\n"),
act->name);
} else if (errno == ENOENT) {
ipqos_msg(MT_ERROR,
gettext("Missing required parameter for action "
"%s.\n"), act->name);
} else {
ipqos_msg(MT_ERROR, gettext("Failed to create action "
"%s: %s.\n"), act->name, strerror(errno));
}
return (IPQOS_CONF_ERR);
}
act->cr_mod = B_TRUE;
return (IPQOS_CONF_SUCCESS);
}
static int
add_filters(
ipqos_conf_filter_t *filters,
char *action,
int module_version,
boolean_t rem_undo)
{
ipqos_conf_filter_t *flt;
IPQOSCDBG0(L1, "In add_filters\n");
for (flt = filters; flt; flt = flt->next) {
if ((rem_undo == B_FALSE && flt->new == B_FALSE) ||
(rem_undo == B_TRUE && flt->deleted == B_FALSE)) {
continue;
}
if (add_filter(action, flt, module_version) !=
IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
flt->cr_mod = B_TRUE;
}
return (IPQOS_CONF_SUCCESS);
}
int
add_classes(
ipqos_conf_class_t *classes,
char *action,
int module_version,
boolean_t rem_undo) {
int res;
ipqos_conf_class_t *cls;
IPQOSCDBG0(L1, "In add_classes\n");
for (cls = classes; cls; cls = cls->next) {
if ((rem_undo == B_FALSE && cls->new == B_FALSE) ||
(rem_undo == B_TRUE && cls->deleted == B_FALSE)) {
continue;
}
res = add_class(action, cls->name, module_version,
cls->stats_enable, cls->alist->name);
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
cls->cr_mod = B_TRUE;
}
return (IPQOS_CONF_SUCCESS);
}
static int
remove_items(
ipqos_conf_action_t *actions,
boolean_t add_undo)
{
int res;
ipqos_conf_action_t *act;
IPQOSCDBG1(L0, "In remove_items, add_undo: %u\n", add_undo);
for (act = actions; act; act = act->next) {
res = remove_item(act, add_undo);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
remove_item(
ipqos_conf_action_t *act,
boolean_t add_undo)
{
ipqos_conf_class_t *cls;
ipqos_conf_filter_t *flt;
ipqos_conf_act_ref_t *dep;
int res;
IPQOSCDBG3(L1, "In remove_item: action: %s, add_undo: %u, mod: %u\n",
act->name, add_undo, act->modified);
if (act->visited == REM_VISITED) {
IPQOSCDBG0(L1, "Exit due to REM_VISITED set\n");
return (IPQOS_CONF_SUCCESS);
}
act->visited = REM_VISITED;
if (add_undo == B_FALSE && act->todel == B_TRUE ||
add_undo == B_TRUE && act->new == B_TRUE &&
act->cr_mod == B_TRUE) {
for (dep = act->dependencies; dep; dep = dep->next) {
res = remove_item(dep->action, add_undo);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
IPQOSCDBG1(APPLY, "deleting action %s\n", act->name);
res = ipp_action_destroy(act->name, 0);
if (res != 0) {
IPQOSCDBG1(APPLY, "failed to destroy action %s\n",
act->name);
return (IPQOS_CONF_ERR);
}
act->deleted = B_TRUE;
} else if (act->modified == B_TRUE) {
for (flt = act->filters; flt; flt = flt->next) {
if ((add_undo == B_FALSE && flt->todel == B_TRUE) ||
(add_undo == B_TRUE && flt->new == B_TRUE &&
flt->cr_mod == B_TRUE)) {
res = remove_filter(act->name, flt->name,
flt->instance, act->module_version);
if (res != IPQOS_CONF_SUCCESS) {
IPQOSCDBG2(APPLY, "failed to destroy "
"filter %s, inst: %d\n", flt->name,
flt->instance);
return (IPQOS_CONF_ERR);
}
flt->deleted = B_TRUE;
}
}
for (cls = act->classes; cls; cls = cls->next) {
if ((add_undo == B_FALSE && cls->todel == B_TRUE) ||
(add_undo == B_TRUE && cls->new == B_TRUE &&
cls->cr_mod == B_TRUE)) {
res = remove_class(act->name, cls->name,
act->module_version, 0);
if (res != IPQOS_CONF_SUCCESS) {
IPQOSCDBG1(APPLY, "failed to destroy "
"class %s\n", cls->name);
return (IPQOS_CONF_ERR);
}
cls->deleted = B_TRUE;
}
}
act->cr_mod = B_TRUE;
}
return (IPQOS_CONF_SUCCESS);
}
static int
modify_items(ipqos_conf_action_t *actions)
{
ipqos_conf_action_t *act;
int res;
ipqos_conf_filter_t *flt;
ipqos_conf_class_t *cls;
IPQOSCDBG0(L1, "In modify_items\n");
for (act = actions; act; act = act->next) {
if (act->modified == B_FALSE) {
continue;
}
if (act->params->modified) {
res = modify_params(act->name,
&act->params->nvlist,
act->module_version, act->params->stats_enable);
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
act->params->cr_mod = B_TRUE;
}
for (cls = act->classes; cls; cls = cls->next) {
if (cls->modified) {
res = modify_class(act->name, cls->name,
act->module_version, cls->stats_enable,
cls->alist->name, 0);
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
cls->cr_mod = B_TRUE;
}
}
for (flt = act->filters; flt; flt = flt->next) {
if (flt->modified) {
res = modify_filter(act->name, flt,
act->module_version);
if (res != 0) {
return (IPQOS_CONF_ERR);
}
flt->cr_mod = B_TRUE;
}
}
act->cr_mod = B_TRUE;
}
return (IPQOS_CONF_SUCCESS);
}
static int
undo_modifys(
ipqos_conf_action_t *oactions,
ipqos_conf_action_t *nactions)
{
ipqos_conf_filter_t *flt;
ipqos_conf_class_t *cls;
ipqos_conf_action_t *act;
ipqos_conf_action_t *oldact;
ipqos_conf_filter_t *oldflt;
ipqos_conf_class_t *oldcls;
int res;
IPQOSCDBG0(L1, "In undo_modifys:\n");
for (act = nactions; act; act = act->next) {
oldact = actionexist(act->name, oactions);
if (oldact == NULL) {
continue;
}
if (act->params->modified == B_TRUE &&
act->params->cr_mod == B_TRUE) {
res = modify_params(act->name,
&oldact->params->nvlist,
act->module_version, act->params->stats_enable);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
for (flt = act->filters; flt; flt = flt->next) {
if (flt->modified == B_TRUE &&
flt->cr_mod == B_TRUE) {
oldflt = filterexist(flt->name, -1,
oldact->filters);
res = modify_filter(act->name, oldflt,
act->module_version);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
for (cls = act->classes; cls; cls = cls->next) {
if (cls->modified == B_TRUE &&
cls->cr_mod == B_TRUE) {
oldcls = classexist(cls->name, oldact->classes);
if (oldcls->alist) {
res = modify_class(act->name,
cls->name, act->module_version,
oldcls->stats_enable,
oldcls->alist->name, 0);
}
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
}
for (act = oactions; act != NULL; act = act->next) {
if (act->deleted == B_FALSE) {
continue;
}
for (flt = act->filters; flt != NULL; flt = flt->next) {
if (flt->originator == IPP_CONFIG_PERMANENT) {
res = modify_filter(act->name, flt,
act->module_version);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
for (cls = act->classes; cls != NULL; cls = cls->next) {
if (cls->originator == IPP_CONFIG_PERMANENT) {
res = modify_class(act->name, cls->name,
act->module_version, cls->stats_enable,
cls->alist->name, 0);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
rollback(
ipqos_conf_action_t *actions,
ipqos_conf_action_t *old_actions)
{
int res;
IPQOSCDBG0(RBK, "In rollback:\n");
res = add_items(old_actions, B_TRUE);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
res = undo_modifys(old_actions, actions);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
res = remove_items(actions, B_TRUE);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
return (IPQOS_CONF_SUCCESS);
}
static void
printuser(
FILE *fp,
uid_t uid)
{
struct passwd *pwd;
IPQOSCDBG0(L0, "In printuser\n");
pwd = getpwuid(uid);
if (pwd != NULL) {
(void) fprintf(fp, "%s\n", pwd->pw_name);
} else {
(void) fprintf(fp, "%u\n", (int)uid);
}
}
static void
printrange(
FILE *fp,
uint32_t start,
uint32_t end)
{
uint32_t tmp;
if (start > end) {
tmp = start;
start = end;
end = tmp;
}
(void) fprintf(fp, "%u", start);
if (end != start)
(void) fprintf(fp, "-%u", end);
}
static void
print_int_array(
FILE *fp,
int arr[],
uint32_t size,
int llimit,
int ulimit,
str_val_nd_t *enum_nvs,
int tab_inserts)
{
int x, y;
uint32_t first, last;
boolean_t first_entry;
boolean_t first_range;
boolean_t found_range;
IPQOSCDBG4(L0, "In print_int_array: size: %u, llimit: %u, ulimit: %u, "
"enum_nvs: %x \n", size, llimit, ulimit, enum_nvs);
if (enum_nvs != NULL)
get_str_val_value_range(enum_nvs, &llimit, &ulimit);
(void) fprintf(fp, "%c\n", CURL_BEGIN);
PRINT_TABS(fp, tab_inserts + 1);
first_entry = B_TRUE;
for (x = llimit; x <= ulimit; x++) {
found_range = B_FALSE;
first_range = B_TRUE;
y = 0;
while (y < size) {
while ((arr[y] != x) && (y < size))
y++;
if (y == size) {
break;
} else {
found_range = B_TRUE;
}
first = y;
while ((arr[y] == x) && (y < size))
y++;
last = y - 1;
if (!first_entry && first_range) {
(void) fprintf(fp, ";\n");
PRINT_TABS(fp, tab_inserts + 1);
} else {
first_entry = B_FALSE;
}
if (!first_range) {
(void) fprintf(fp, ",");
} else {
first_range = B_FALSE;
}
printrange(fp, first, last);
}
if (found_range) {
(void) fprintf(fp, ":");
if (enum_nvs) {
printenum(fp, x, enum_nvs);
} else {
(void) fprintf(fp, "%d", x);
}
}
}
(void) fprintf(fp, "\n");
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, "%c\n", CURL_END);
}
static void
printproto(
FILE *fp,
uint8_t proto)
{
struct protoent *pent;
pent = getprotobynumber(proto);
if (pent != NULL) {
(void) fprintf(fp, "%s\n", pent->p_name);
} else {
(void) fprintf(fp, "%u\n", proto);
}
}
static int
printifname(
FILE *fp,
int ifindex)
{
int s;
struct lifconf lc;
struct lifnum ln;
struct lifreq *lr;
char *buf;
int len;
char *cp;
int ret;
int x;
int idx;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
ipqos_msg(MT_ENOSTR, gettext("opening AF_INET socket"));
return (IPQOS_CONF_ERR);
}
ln.lifn_family = AF_UNSPEC;
ln.lifn_flags = 0;
ret = ioctl(s, SIOCGLIFNUM, &ln);
if (ret < 0) {
ipqos_msg(MT_ENOSTR, "SIOCLIFNUM ioctl");
(void) close(s);
return (IPQOS_CONF_ERR);
}
len = ln.lifn_count * sizeof (struct lifreq);
buf = malloc(len);
if (buf == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
(void) close(s);
return (IPQOS_CONF_ERR);
}
lc.lifc_family = AF_UNSPEC;
lc.lifc_flags = 0;
lc.lifc_len = len;
lc.lifc_buf = buf;
ret = ioctl(s, SIOCGLIFCONF, &lc);
if (ret < 0) {
ipqos_msg(MT_ENOSTR, "SIGLIFCONF");
(void) close(s);
free(buf);
return (IPQOS_CONF_ERR);
}
(void) close(s);
for (x = ln.lifn_count, lr = lc.lifc_req; x > 0; x--, lr++) {
ret = readifindex(lr->lifr_name, &idx);
if (ret != IPQOS_CONF_SUCCESS) {
free(buf);
return (IPQOS_CONF_ERR);
}
if (idx == ifindex) {
break;
}
}
free(buf);
if (x == 0) {
IPQOSCDBG1(L1, "Failed to find if index %u in returned "
"if list.\n", ifindex);
return (IPQOS_CONF_ERR);
}
if ((cp = strchr(lr->lifr_name, '@')) != NULL) {
*cp = '\0';
}
(void) fprintf(fp, "%s\n", lr->lifr_name);
return (IPQOS_CONF_SUCCESS);
}
static void
printenum(
FILE *fp,
uint32_t val,
str_val_nd_t *enum_nvs)
{
boolean_t isfirstval = B_TRUE;
str_val_nd_t *name_val = enum_nvs;
while (name_val) {
if ((name_val->sv.value & val) == name_val->sv.value) {
if (isfirstval == B_TRUE) {
(void) fprintf(fp, "%s", name_val->sv.string);
isfirstval = B_FALSE;
} else {
(void) fprintf(fp, ", %s", name_val->sv.string);
}
}
name_val = name_val->next;
}
}
static void
printport(
FILE *fp,
uint16_t port)
{
struct servent *sent;
sent = getservbyport(port, NULL);
if (sent != NULL) {
(void) fprintf(fp, "%s\n", sent->s_name);
} else {
(void) fprintf(fp, "%u\n", ntohs(port));
}
}
static int
printnvlist(
FILE *fp,
char *module,
nvlist_t *nvl,
int printall,
ipqos_conf_filter_t *flt,
int tab_inserts,
place_t place)
{
FILE *tfp;
nvpair_t *nvp;
char *name;
ipqos_nvtype_t type;
str_val_nd_t *enum_nvs;
int ret;
char dfltst[IPQOS_VALST_MAXLEN+1];
char *param;
int openerr;
int res;
IPQOSCDBG0(L1, "In printnvlist\n");
tfp = validmod(module, &openerr);
if (tfp == NULL) {
if (openerr) {
ipqos_msg(MT_ENOSTR, "fopen");
}
return (IPQOS_CONF_ERR);
}
nvp = nvlist_next_nvpair(nvl, NULL);
while (nvp) {
name = nvpair_name(nvp);
IPQOSCDBG1(L0, "processing element %s.\n", name);
if (strcmp(name, IPGPC_FILTER_TYPE) == 0 ||
strcmp(name, IPGPC_SADDR_MASK) == 0 ||
strcmp(name, IPGPC_DADDR_MASK) == 0 ||
strcmp(name, IPGPC_SPORT_MASK) == 0 ||
strcmp(name, IPGPC_DPORT_MASK) == 0) {
nvp = nvlist_next_nvpair(nvl, nvp);
continue;
}
param = SHORT_NAME(name);
place = PL_ANY;
ret = readtype(tfp, module, param, &type, &enum_nvs, dfltst,
B_TRUE, &place);
if (ret != IPQOS_CONF_SUCCESS) {
return (ret);
}
if (place == PL_MAP) {
nvp = nvlist_next_nvpair(nvl, nvp);
continue;
}
if (strcmp(name, IPGPC_IF_INDEX) == 0) {
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, "%s ", IPQOS_IFNAME_STR);
} else if ((strcmp(name, IPGPC_SADDR) != 0 &&
strcmp(name, IPGPC_DADDR) != 0)) {
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, "%s ", param);
}
switch (type) {
case IPQOS_DATA_TYPE_IFINDEX: {
uint32_t ifidx;
(void) nvpair_value_uint32(nvp, &ifidx);
(void) printifname(fp, ifidx);
break;
}
case IPQOS_DATA_TYPE_BOOLEAN: {
boolean_t bl;
(void) nvpair_value_uint32(nvp,
(uint32_t *)&bl);
(void) fprintf(fp, "%s\n",
bl == B_TRUE ? "true" : "false");
break;
}
case IPQOS_DATA_TYPE_ACTION: {
char *strval;
(void) nvpair_value_string(nvp, &strval);
print_action_nm(fp, strval);
break;
}
case IPQOS_DATA_TYPE_STRING: {
char *strval;
(void) nvpair_value_string(nvp, &strval);
(void) fprintf(fp, "%s\n",
quote_ws_string(strval));
break;
}
case IPQOS_DATA_TYPE_ADDRESS: {
uint_t tmp;
in6_addr_t *addr;
char addrstr[INET6_ADDRSTRLEN];
uchar_t ftype;
int af;
in6_addr_t *mask;
if (printall == 0 &&
(strcmp(nvpair_name(nvp), IPGPC_SADDR) ==
0 && flt->src_nd_name ||
strcmp(nvpair_name(nvp), IPGPC_DADDR) ==
0 && flt->dst_nd_name)) {
break;
}
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, "%s ", param);
(void) nvpair_value_uint32_array(nvp,
(uint32_t **)&addr, &tmp);
(void) nvlist_lookup_byte(nvl,
IPGPC_FILTER_TYPE, &ftype);
if (ftype == IPGPC_V4_FLTR) {
af = AF_INET;
addr = (in6_addr_t *)
&V4_PART_OF_V6((*addr));
} else {
af = AF_INET6;
}
if (strcmp(nvpair_name(nvp), IPGPC_SADDR) ==
0) {
ret = nvlist_lookup_uint32_array(nvl,
IPGPC_SADDR_MASK,
(uint32_t **)&mask, &tmp);
} else {
ret = nvlist_lookup_uint32_array(nvl,
IPGPC_DADDR_MASK,
(uint32_t **)&mask, &tmp);
}
(void) fprintf(fp, "%s/%u\n",
inet_ntop(af, addr, addrstr,
INET6_ADDRSTRLEN), masktocidr(af, mask));
break;
}
case IPQOS_DATA_TYPE_ENUM: {
uint32_t val;
(void) nvpair_value_uint32(nvp, &val);
(void) fprintf(fp, "{ ");
printenum(fp, val, enum_nvs);
(void) fprintf(fp, " }\n");
break;
}
case IPQOS_DATA_TYPE_PORT: {
uint16_t port;
(void) nvpair_value_uint16(nvp, &port);
printport(fp, port);
break;
}
case IPQOS_DATA_TYPE_PROTO: {
uint8_t proto;
(void) nvpair_value_byte(nvp, &proto);
printproto(fp, proto);
break;
}
case IPQOS_DATA_TYPE_M_INDEX:
case IPQOS_DATA_TYPE_UINT8: {
uchar_t u8;
(void) nvpair_value_byte(nvp, &u8);
(void) fprintf(fp, "%u\n", u8);
break;
}
case IPQOS_DATA_TYPE_UINT16: {
uint16_t u16;
(void) nvpair_value_uint16(nvp, &u16);
(void) fprintf(fp, "%u\n", u16);
break;
}
case IPQOS_DATA_TYPE_INT16: {
int16_t i16;
(void) nvpair_value_int16(nvp, &i16);
(void) fprintf(fp, "%d\n", i16);
break;
}
case IPQOS_DATA_TYPE_UINT32: {
uint32_t u32;
(void) nvpair_value_uint32(nvp, &u32);
(void) fprintf(fp, "%u\n", u32);
break;
}
case IPQOS_DATA_TYPE_INT32: {
int i32;
(void) nvpair_value_int32(nvp, &i32);
(void) fprintf(fp, "%d\n", i32);
break;
}
case IPQOS_DATA_TYPE_INT_ARRAY: {
str_val_nd_t *arr_enum_nvs = NULL;
uint32_t size;
int llimit, ulimit;
int *arr;
(void) nvpair_value_int32_array(nvp, &arr,
&size);
res = read_int_array_info(dfltst,
&arr_enum_nvs, &size, &llimit, &ulimit,
module);
if (res == IPQOS_CONF_SUCCESS) {
print_int_array(fp, arr, size,
llimit, ulimit, arr_enum_nvs,
tab_inserts);
if (arr_enum_nvs != NULL) {
free_str_val_entrys(
arr_enum_nvs);
}
}
break;
}
case IPQOS_DATA_TYPE_USER: {
uid_t uid;
(void) nvpair_value_int32(nvp, (int *)&uid);
printuser(fp, uid);
break;
}
#ifdef _IPQOS_CONF_DEBUG
default: {
assert(1);
}
#endif
}
nvp = nvlist_next_nvpair(nvl, nvp);
}
(void) fclose(tfp);
return (IPQOS_CONF_SUCCESS);
}
static int
printparams(
FILE *fp,
char *module,
ipqos_conf_params_t *params,
int printall,
int tab_inserts)
{
int res;
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, IPQOS_CONF_PARAMS_STR " {\n");
if (printall) {
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(stdout, "Originator %s\n",
quote_ws_string(get_originator_nm(params->originator)));
}
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, IPQOS_CONF_GLOBAL_STATS_STR " %s\n",
params->stats_enable == B_TRUE ? "true" : "false");
res = printnvlist(fp, module, params->nvlist, printall, NULL,
tab_inserts + 1, PL_PARAMS);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, "}\n");
return (IPQOS_CONF_SUCCESS);
}
static void
print_action_nm(FILE *fp, char *action_nm)
{
if (strcmp(action_nm, IPP_ANAME_CONT) == 0) {
(void) fprintf(fp, IPQOS_CONF_CONT_STR "\n");
} else if (strcmp(action_nm, IPP_ANAME_DEFER) == 0) {
(void) fprintf(fp, IPQOS_CONF_DEFER_STR "\n");
} else if (strcmp(action_nm, IPP_ANAME_DROP) == 0) {
(void) fprintf(fp, IPQOS_CONF_DROP_STR "\n");
} else {
(void) fprintf(fp, "%s\n", quote_ws_string(action_nm));
}
}
static void
printclass(
FILE *fp,
ipqos_conf_class_t *class,
int printall,
int tab_inserts)
{
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, IPQOS_CONF_CLASS_STR " {\n");
if (printall) {
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(stdout, "Originator %s\n",
get_originator_nm(class->originator));
}
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, IPQOS_CONF_NAME_STR " %s\n",
quote_ws_string(class->name));
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, IPQOS_CONF_NEXT_ACTION_STR " ");
print_action_nm(fp, class->alist->name);
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, IPQOS_CONF_STATS_ENABLE_STR " %s\n",
class->stats_enable == B_TRUE ? "true" : "false");
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, "}\n");
}
static char *
get_originator_nm(uint32_t origid)
{
int x;
for (x = 0; originators[x].value != -1 &&
originators[x].value != origid; x++) {}
if (originators[x].value == -1) {
return ("unknown");
}
return (originators[x].string);
}
static int
printfilter(
FILE *fp,
char *module,
ipqos_conf_filter_t **filter,
int printall,
int tab_inserts)
{
int res;
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, IPQOS_CONF_FILTER_STR " {\n");
if (printall) {
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(stdout, "Originator %s\n",
quote_ws_string(get_originator_nm((*filter)->originator)));
}
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, IPQOS_CONF_NAME_STR " %s\n",
quote_ws_string((*filter)->name));
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, IPQOS_CONF_CLASS_STR " %s\n",
quote_ws_string((*filter)->class_name));
if (printall && ((*filter)->src_nd_name || (*filter)->dst_nd_name)) {
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, "Instance %u\n", (*filter)->instance);
}
if ((*filter)->src_nd_name) {
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, "%s %s\n", strchr(IPGPC_SADDR, '.') + 1,
(*filter)->src_nd_name);
}
if ((*filter)->dst_nd_name) {
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, "%s %s\n", strchr(IPGPC_DADDR, '.') + 1,
(*filter)->dst_nd_name);
}
if ((*filter)->ip_versions != 0) {
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, IPQOS_CONF_IP_VERSION_STR " {");
if (VERSION_IS_V4(*filter)) {
(void) fprintf(fp, " V4");
}
if (VERSION_IS_V6(*filter)) {
(void) fprintf(fp, " V6");
}
(void) fprintf(fp, " }\n");
}
res = printnvlist(fp, module, (*filter)->nvlist, printall, *filter,
tab_inserts + 1, PL_FILTER);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, "}\n");
if (!printall) {
for (;;) {
if ((*filter)->next == NULL ||
strcmp((*filter)->name, (*filter)->next->name) !=
0) {
break;
}
*filter = (*filter)->next;
}
}
return (IPQOS_CONF_SUCCESS);
}
static char *
quote_ws_string(const char *str)
{
static char *buf = NULL;
const char *cp;
IPQOSCDBG0(L0, "In quote_ws_string\n");
for (cp = str; (*cp != '\0') && !isspace(*cp); cp++)
;
if (*cp == '\0')
return ((char *)str);
if (buf == NULL) {
buf = malloc(strlen(str) + 3);
} else if ((strlen(str) + 2) > strlen(buf)) {
buf = realloc(buf, strlen(str) + 3);
}
if (buf == NULL)
return ("");
(void) strcpy(buf, "\"");
(void) strcat(buf, str);
(void) strcat(buf, "\"");
return (buf);
}
static int
printaction(
FILE *fp,
ipqos_conf_action_t *action,
int printall,
int tab_inserts)
{
ipqos_conf_filter_t *flt;
ipqos_conf_class_t *cls;
int res;
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, IPQOS_CONF_ACTION_STR " {\n");
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, IPQOS_CONF_MODULE_STR " %s\n",
quote_ws_string(action->module));
PRINT_TABS(fp, tab_inserts + 1);
(void) fprintf(fp, "name %s\n", quote_ws_string(action->name));
(void) fprintf(fp, "\n");
res = printparams(fp, action->module, action->params, printall,
tab_inserts + 1);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
for (cls = action->classes; cls != NULL; cls = cls->next) {
if (printall ||
cls->originator == IPP_CONFIG_IPQOSCONF ||
cls->originator == IPP_CONFIG_PERMANENT) {
(void) fprintf(fp, "\n");
printclass(fp, cls, printall, tab_inserts + 1);
}
}
for (flt = action->filters; flt != NULL; flt = flt->next) {
if (printall ||
flt->originator == IPP_CONFIG_IPQOSCONF ||
flt->originator == IPP_CONFIG_PERMANENT) {
(void) fprintf(fp, "\n");
res = printfilter(fp, action->module, &flt, printall,
tab_inserts + 1);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
}
}
PRINT_TABS(fp, tab_inserts);
(void) fprintf(fp, "}\n");
return (IPQOS_CONF_SUCCESS);
}
static void
list_end(
ipqos_list_el_t **listp,
ipqos_list_el_t ***lendpp)
{
*lendpp = listp;
while (**lendpp != NULL) {
*lendpp = &(**lendpp)->next;
}
}
static void
add_to_list(
ipqos_list_el_t **listp,
ipqos_list_el_t *el)
{
el->next = *listp;
*listp = el;
}
static int
masktocidr(
int af,
in6_addr_t *mask)
{
int zeros = 0;
int byte;
int cidr;
for (byte = 15; byte >= 0; byte--) {
if (mask->s6_addr[byte] == 0) {
zeros += 8;
} else {
zeros += (ffs((int)mask->s6_addr[byte]) - 1);
break;
}
}
if (af == AF_INET) {
cidr = 32 - zeros;
} else {
cidr = 128 - zeros;
}
return (cidr);
}
static void
setmask(int prefix_len, in6_addr_t *addr, int af)
{
int i;
int shift;
int maskstartbit = 128 - prefix_len;
int end_u32;
IPQOSCDBG2(L1, "In setmask, prefix_len: %u, af: %s\n", prefix_len,
af == AF_INET ? "AF_INET" : "AF_INET6");
bzero(addr, sizeof (in6_addr_t));
if (af == AF_INET) {
end_u32 = 3;
maskstartbit = 32 - prefix_len;
} else {
end_u32 = 0;
}
for (i = 3; i >= end_u32; i--) {
if (maskstartbit < ((4 - i) * 32)) {
if (maskstartbit <= ((3 - i) * 32)) {
shift = 0;
} else {
shift = maskstartbit % 32;
}
addr->_S6_un._S6_u32[i] = (uint32_t)~0;
addr->_S6_un._S6_u32[i] =
addr->_S6_un._S6_u32[i] >> shift;
addr->_S6_un._S6_u32[i] =
addr->_S6_un._S6_u32[i] << shift;
}
addr->_S6_un._S6_u32[i] = htonl(addr->_S6_un._S6_u32[i]);
}
}
static nvpair_t *
find_nvpair(nvlist_t *nvl, char *name)
{
nvpair_t *nvp;
nvpair_t *match = NULL;
char *nvp_name;
IPQOSCDBG0(L1, "In find_nvpair\n");
nvp = nvlist_next_nvpair(nvl, NULL);
while (nvp) {
nvp_name = nvpair_name(nvp);
if (strcmp(name, nvp_name) == 0) {
match = nvp;
}
nvp = nvlist_next_nvpair(nvl, nvp);
}
return (match);
}
static char *
prepend_module_name(
char *name,
char *module)
{
char *ret;
IPQOSCDBG0(L2, "In prepend_module_name\n");
ret = malloc(strlen(module) + strlen(".") + strlen(name) + 1);
if (ret == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
return (NULL);
}
(void) strcpy(ret, module);
(void) strcat(ret, ".");
(void) strcat(ret, name);
return (ret);
}
#if 0
static int
in_str_str_table(
str_str_t *table,
char *s1,
char *s2)
{
str_str_t *ss = table;
while (ss->s1[0] != '\0' &&
(strcmp(ss->s1, s1) != 0 || strcmp(ss->s2, s2) != 0)) {
ss++;
}
if (ss->s1[0] != '\0') {
return (1);
}
return (0);
}
#endif
static int
valid_name(char *name)
{
IPQOSCDBG1(L1, "In valid_name: name: %s\n", name);
if (name[0] == '!') {
ipqos_msg(MT_ERROR, gettext("Name not allowed to start with "
"'!', line %u.\n"), lineno);
return (IPQOS_CONF_ERR);
}
if (strlen(name) >= IPQOS_CONF_NAME_LEN) {
ipqos_msg(MT_ERROR, gettext("Name exceeds maximum name length "
"line %u.\n"), lineno);
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static void
get_str_val_value_range(
str_val_nd_t *svnp,
int *min,
int *max)
{
if (svnp != NULL) {
*min = *max = svnp->sv.value;
svnp = svnp->next;
}
while (svnp != NULL) {
if (svnp->sv.value > *max)
*max = svnp->sv.value;
if (svnp->sv.value < *min)
*min = svnp->sv.value;
svnp = svnp->next;
}
}
static int
add_str_val_entry(
str_val_nd_t **sv_entrys,
char *string,
uint32_t val)
{
str_val_nd_t *sv_entry;
IPQOSCDBG2(L1, "In add_str_val_entry: string: %s, val: %u\n", string,
val);
sv_entry = malloc(sizeof (str_val_nd_t));
if (sv_entry == NULL) {
return (IPQOS_CONF_ERR);
}
sv_entry->sv.string = malloc(strlen(string) + 1);
if (sv_entry->sv.string == NULL) {
free(sv_entry);
ipqos_msg(MT_ENOSTR, "malloc");
return (IPQOS_CONF_ERR);
} else {
(void) strcpy(sv_entry->sv.string, string);
}
sv_entry->sv.value = val;
sv_entry->next = *sv_entrys;
*sv_entrys = sv_entry;
return (IPQOS_CONF_SUCCESS);
}
static void
free_str_val_entrys(
str_val_nd_t *sv_entrys)
{
str_val_nd_t *sve = sv_entrys;
str_val_nd_t *tmp;
IPQOSCDBG0(L1, "In free_str_val_entrys\n");
while (sve) {
free(sve->sv.string);
tmp = sve->next;
free(sve);
sve = tmp;
}
}
static int
str_val_list_lookup(
str_val_nd_t *svs,
char *string,
uint32_t *val)
{
str_val_nd_t *sv = svs;
IPQOSCDBG1(L1, "In str_val_list_lookup: %s\n", string);
while (sv != NULL) {
if (strcmp(sv->sv.string, string) == 0) {
break;
}
sv = sv->next;
}
if (sv == NULL) {
return (IPQOS_CONF_ERR);
}
*val = sv->sv.value;
IPQOSCDBG1(L1, "svll: Value returned is %u\n", *val);
return (IPQOS_CONF_SUCCESS);
}
static int
readuser(
char *str,
uid_t *uid)
{
struct passwd *pwd;
char *lo;
IPQOSCDBG1(L0, "In readuser, str: %s\n", str);
if (str == NULL)
return (IPQOS_CONF_ERR);
if (isdigit((int)str[0])) {
if (readint32(str, (int *)uid, &lo) != IPQOS_CONF_SUCCESS ||
*lo != '\0')
return (IPQOS_CONF_ERR);
if (getpwuid(*uid) == NULL)
return (IPQOS_CONF_ERR);
} else {
pwd = getpwnam(str);
if (pwd == NULL) {
return (IPQOS_CONF_ERR);
} else {
*uid = pwd->pw_uid;
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
readrange(
char *range_st,
int *lower,
int *upper)
{
char *cp;
char *end, *end2;
IPQOSCDBG1(L0, "In readrange: string: %s\n", range_st);
cp = strchr(range_st, '-');
if (cp != NULL) {
*cp++ = '\0';
*lower = (int)strtol(range_st, &end, 10);
*upper = (int)strtol(cp, &end2, 10);
SKIPWS(end);
SKIPWS(end2);
if ((range_st == end) || (*end != '\0') ||
(cp == end) || (*end2 != '\0')) {
IPQOSCDBG0(L0, "Failed reading a-b\n");
return (IPQOS_CONF_ERR);
}
} else {
*lower = *upper = (int)strtol(range_st, &end, 10);
SKIPWS(end);
if ((range_st == end) || (*end != '\0')) {
IPQOSCDBG0(L0, "Failed reading a\n");
return (IPQOS_CONF_ERR);
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
read_int_array(
FILE *fp,
char *first_token,
int **arrp,
uint32_t arr_size,
int llimit,
int ulimit,
str_val_nd_t *enum_nvs)
{
char buf[5 * IPQOS_CONF_LINEBUF_SZ];
char *token;
char *range;
char *ranges;
char *svalue;
int value;
int res;
char *entry;
char *tmp;
char *end;
int lower, upper;
int x;
uint32_t startln;
IPQOSCDBG4(L0, "In read_int_array: size: %u, lower: %u, upper: %u, "
"first_token: %s\n", arr_size, llimit, ulimit, first_token);
if (first_token[0] != CURL_BEGIN) {
ipqos_msg(MT_ERROR, gettext("\'{\' missing at line "
"%u.\n"), lineno);
return (IPQOS_CONF_ERR);
}
*arrp = malloc(arr_size * sizeof (int));
if (*arrp == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
return (IPQOS_CONF_ERR);
}
(void) memset(*arrp, -1, arr_size * sizeof (int));
startln = lineno;
buf[0] = '\0';
res = readtoken(fp, &token);
while ((res != IPQOS_CONF_CURL_END) && (res != IPQOS_CONF_ERR) &&
(res != IPQOS_CONF_EOF)) {
(void) strlcat(buf, token, sizeof (buf));
free(token);
res = readtoken(fp, &token);
}
if (res != IPQOS_CONF_CURL_END) {
goto array_err;
}
IPQOSCDBG1(L0, "array declaration buffer contains: %s\n", buf);
entry = strtok(buf, ";");
while (entry != NULL) {
svalue = strchr(entry, ':');
if (svalue == NULL) {
IPQOSCDBG0(L0, "Missing value string\n");
goto array_err;
}
*svalue++ = '\0';
ranges = entry;
if (enum_nvs) {
SKIPWS(svalue);
tmp = svalue;
while (*tmp != '\0') {
if (isspace(*tmp)) {
*tmp = '\0';
break;
} else {
tmp++;
}
}
res = read_enum_value(NULL, svalue, enum_nvs,
(uint32_t *)&value);
if (res != IPQOS_CONF_SUCCESS)
goto array_err;
} else {
value = (int)strtol(svalue, &end, 10);
SKIPWS(end);
if ((svalue == end) || (*end != '\0')) {
IPQOSCDBG0(L0, "Invalid value\n");
goto array_err;
}
IPQOSCDBG1(L0, "value: %u\n", value);
if ((value < llimit) || (value > ulimit)) {
IPQOSCDBG0(L0, "value out of range\n");
goto array_err;
}
}
range = strtok_r(ranges, ",", &tmp);
while (range != NULL) {
res = readrange(range, &lower, &upper);
if (res != IPQOS_CONF_SUCCESS)
goto array_err;
IPQOSCDBG2(L0, "range: %u - %u\n", lower, upper);
if (upper < lower) {
uint32_t u = lower;
lower = upper;
upper = u;
}
if ((lower < 0) || (upper > arr_size)) {
IPQOSCDBG0(L0, "Range out of array "
"dimensions\n");
goto array_err;
}
for (x = lower; x <= upper; x++)
(*arrp)[x] = value;
range = strtok_r(NULL, ",", &tmp);
}
entry = strtok(NULL, ";");
}
return (IPQOS_CONF_SUCCESS);
array_err:
ipqos_msg(MT_ERROR,
gettext("Array declaration line %u is invalid.\n"), startln);
free(*arrp);
return (IPQOS_CONF_ERR);
}
static int
readllong(char *str, long long *llp, char **lo)
{
*llp = strtoll(str, lo, 0);
if (*lo == str) {
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
readuint8(char *str, uint8_t *ui8, char **lo)
{
long long tmp;
if (readllong(str, &tmp, lo) != 0) {
return (IPQOS_CONF_ERR);
}
if (tmp > UCHAR_MAX || tmp < 0) {
return (IPQOS_CONF_ERR);
}
*ui8 = (uint8_t)tmp;
return (IPQOS_CONF_SUCCESS);
}
static int
readuint16(char *str, uint16_t *ui16, char **lo)
{
long long tmp;
if (readllong(str, &tmp, lo) != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
if (tmp > USHRT_MAX || tmp < 0) {
return (IPQOS_CONF_ERR);
}
*ui16 = (uint16_t)tmp;
return (IPQOS_CONF_SUCCESS);
}
static int
readint16(char *str, int16_t *i16, char **lo)
{
long long tmp;
if (readllong(str, &tmp, lo) != 0) {
return (IPQOS_CONF_ERR);
}
if (tmp > SHRT_MAX || tmp < SHRT_MIN) {
return (IPQOS_CONF_ERR);
}
*i16 = (int16_t)tmp;
return (IPQOS_CONF_SUCCESS);
}
static int
readint32(char *str, int *i32, char **lo)
{
long long tmp;
if (readllong(str, &tmp, lo) != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
if (tmp > INT_MAX || tmp < INT_MIN) {
return (IPQOS_CONF_ERR);
}
*i32 = tmp;
return (IPQOS_CONF_SUCCESS);
}
static int
readuint32(char *str, uint32_t *ui32, char **lo)
{
long long tmp;
if (readllong(str, &tmp, lo) != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
if (tmp > UINT_MAX || tmp < 0) {
return (IPQOS_CONF_ERR);
}
*ui32 = (uint32_t)tmp;
return (IPQOS_CONF_SUCCESS);
}
static int
readifindex(
char *ifname,
int *ifindex)
{
int s;
struct lifreq lifrq;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
ipqos_msg(MT_ENOSTR, gettext("opening AF_INET socket"));
return (IPQOS_CONF_ERR);
}
(void) strlcpy(lifrq.lifr_name, ifname, LIFNAMSIZ);
if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifrq) == -1) {
(void) close(s);
return (IPQOS_CONF_ERR);
}
if ((ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrq) != -1) &&
(lifrq.lifr_flags & IFF_VIRTUAL)) {
ipqos_msg(MT_WARNING, gettext("Invalid interface"));
}
(void) close(s);
*ifindex = lifrq.lifr_index;
return (IPQOS_CONF_SUCCESS);
}
static int
readbool(char *str, boolean_t *bool)
{
if (strcasecmp(str, IPQOS_CONF_TRUE_STR) == 0) {
*bool = B_TRUE;
} else if (strcasecmp(str, IPQOS_CONF_FALSE_STR) == 0) {
*bool = B_FALSE;
} else {
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
readproto(char *proto_str, uint8_t *proto)
{
struct protoent *pent;
char *lo;
int res;
IPQOSCDBG1(L1, "In readproto: string: %s\n", proto_str);
pent = getprotobyname(proto_str);
if (pent) {
*proto = pent->p_proto;
} else {
res = readuint8(proto_str, proto, &lo);
if (res != IPQOS_CONF_SUCCESS || proto == 0) {
return (IPQOS_CONF_ERR);
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
readport(char *port_str, uint16_t *port)
{
struct servent *sent;
char *tmp;
IPQOSCDBG1(L1, "In readport: string: %s\n", port_str);
sent = getservbyname(port_str, NULL);
if (sent == NULL) {
if (readuint16(port_str, port, &tmp) != IPQOS_CONF_SUCCESS ||
*port == 0) {
return (IPQOS_CONF_ERR);
}
*port = htons(*port);
} else {
*port = sent->s_port;
}
return (IPQOS_CONF_SUCCESS);
}
static int
readtoken(
FILE *fp,
char **token)
{
char *st, *tmp;
int len;
int quoted = 0;
char *cmnt;
char *bpos;
int rembuf;
static char *lo;
static char *buf = NULL;
static int bufsize;
if (buf == NULL) {
bufsize = IPQOS_CONF_LINEBUF_SZ;
buf = malloc(bufsize);
if (buf == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
return (IPQOS_CONF_ERR);
}
}
bpos = buf;
rembuf = bufsize;
do {
if (lo == NULL) {
for (;;) {
st = fgets(bpos, rembuf, fp);
if (st == NULL) {
if (ferror(fp)) {
free(buf);
buf = NULL;
ipqos_msg(MT_ENOSTR,
"fgets");
return (IPQOS_CONF_ERR);
} else {
free(buf);
buf = NULL;
*token = NULL;
return (IPQOS_CONF_EOF);
}
} else {
if (buf[strlen(buf) - 1] == '\n') {
lineno++;
break;
} else if (feof(fp)) {
break;
} else {
bufsize *= 2;
tmp = realloc(buf, bufsize);
if (tmp == NULL) {
ipqos_msg(MT_ENOSTR,
"realloc");
free(buf);
return (IPQOS_CONF_ERR);
} else {
buf = tmp;
}
bpos = &buf[(bufsize / 2) - 1];
rembuf = (bufsize / 2) + 1;
}
}
}
st = buf;
} else {
st = lo;
lo = NULL;
}
cmnt = strchr(st, '#');
if (cmnt) {
*cmnt = '\0';
}
while (isspace(*st) && *st != '\0') {
st++;
}
} while (*st == '\0');
tmp = st;
if (*tmp == CURL_BEGIN || *tmp == CURL_END) {
tmp++;
} else if (*tmp == '"') {
quoted++;
tmp = ++st;
while (*tmp != '"' && *tmp != '\n' && *tmp != '\0') {
tmp++;
}
if (*tmp != '"') {
ipqos_msg(MT_ERROR, gettext("Quoted string exceeds "
"line, line %u.\n"), lineno);
free(buf);
return (IPQOS_CONF_ERR);
}
} else {
while (!isspace(*tmp) && *tmp != CURL_BEGIN &&
*tmp != CURL_END && *tmp != '\n' && *tmp != '\0') {
tmp++;
}
}
len = tmp - st;
*token = malloc(len + 1);
if (!*token) {
free(buf);
ipqos_msg(MT_ENOSTR, "malloc");
return (IPQOS_CONF_ERR);
}
bcopy(st, *token, len);
(*token)[len] = '\0';
if (quoted) {
tmp++;
}
if (*tmp != '\0' && *tmp != '\n') {
lo = tmp;
}
if ((*token)[1] == '\0') {
if (**token == CURL_BEGIN) {
return (IPQOS_CONF_CURL_BEGIN);
} else if (**token == CURL_END) {
return (IPQOS_CONF_CURL_END);
}
}
return (IPQOS_CONF_SUCCESS);
}
static str_val_nd_t *
read_enum_nvs(char *line, char *module_name)
{
str_val_nd_t *enum_vals = NULL;
char *cp;
char *start;
char *name = NULL;
int len;
uint32_t val;
int ret;
int readc;
IPQOSCDBG1(L1, "In read_enum_nvs, line: %s\n", line);
cp = strchr(line, CURL_BEGIN);
if (cp == NULL) {
IPQOSCDBG0(L1, "missing curl begin\n");
goto fail;
} else {
start = cp + 1;
}
for (;;) {
SKIPWS(start);
if (*start == '\0') {
IPQOSCDBG0(L1, "missing closing bracket\n");
goto fail;
}
for (cp = start;
!isspace(*cp) && *cp != '=' && *cp != CURL_END &&
*cp != '\0'; cp++) {}
if (*cp == '\0') {
IPQOSCDBG0(L1, "Unexpected line end in enum def'n\n");
goto fail;
} else if (*cp == CURL_END) {
break;
}
len = cp - start;
name = malloc(len + 1);
if (name == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
goto fail;
}
bcopy(start, name, len);
name[len] = '\0';
IPQOSCDBG1(L0, "Stored name: %s\n", name);
start = strchr(cp, '=');
if (start == NULL) {
IPQOSCDBG0(L1, "Missing = in enum def'n\n");
goto fail;
}
ret = sscanf(++start, "%x%n", &val, &readc);
if (ret != 1) {
IPQOSCDBG1(L1, "sscanf of value failed, string: %s\n",
cp);
goto fail;
}
ret = add_str_val_entry(&enum_vals, name, val);
if (ret != IPQOS_CONF_SUCCESS) {
IPQOSCDBG0(L1, "Failed to add str_val entry\n");
goto fail;
}
free(name);
name = NULL;
cp = strchr(start, ',');
if (cp != NULL) {
start = cp + 1;
} else {
start += readc;
}
}
return (enum_vals);
fail:
free_str_val_entrys(enum_vals);
if (name != NULL)
free(name);
if (errno == 0) {
ipqos_msg(MT_ERROR, gettext("Types file for module %s is "
"corrupt.\n"), module_name);
}
return (NULL);
}
static int
read_mapped_values(
FILE *tfp,
nvlist_t **nvlp,
char *module,
char *mapped_list,
int value)
{
char *map_name, *lastparam, *tmpname;
int res;
ipqos_nvtype_t type;
char dfltst[IPQOS_VALST_MAXLEN+1] = "";
str_val_nd_t *enum_nvs;
place_t place;
IPQOSCDBG0(L1, "In read_mapped_values\n");
map_name = (char *)strtok_r(mapped_list, ",", &lastparam);
while (map_name != NULL) {
char *tokval, *lastval;
int index = 0;
place = PL_MAP;
res = readtype(tfp, module, map_name, &type, &enum_nvs,
dfltst, B_FALSE, &place);
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
tokval = (char *)strtok_r(dfltst, ",", &lastval);
for (;;) {
if (tokval == NULL) {
ipqos_msg(MT_ERROR,
gettext("Invalid value, %u, line %u.\n"),
value, lineno);
return (IPQOS_CONF_ERR);
}
if (index++ == value) {
break;
}
tokval = (char *)strtok_r(NULL, ",", &lastval);
}
tmpname = prepend_module_name(map_name, module);
if (tmpname == NULL) {
return (IPQOS_CONF_ERR);
}
IPQOSCDBG2(L0, "Adding map %s, value %u to nvlist\n",
tmpname, atoi(tokval));
switch (type) {
case IPQOS_DATA_TYPE_UINT8: {
res = nvlist_add_byte(*nvlp, tmpname,
(uint8_t)atoi(tokval));
if (res != 0) {
free(tmpname);
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint8");
return (IPQOS_CONF_ERR);
}
break;
}
case IPQOS_DATA_TYPE_UINT32: {
res = nvlist_add_uint32(*nvlp, tmpname,
(uint32_t)atoi(tokval));
if (res != 0) {
free(tmpname);
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint32");
return (IPQOS_CONF_ERR);
}
break;
}
default: {
ipqos_msg(MT_ERROR,
gettext("Types file for module %s is "
"corrupt.\n"), module);
IPQOSCDBG1(L0, "Unsupported map type for "
"parameter %s given in types file.\n",
map_name);
return (IPQOS_CONF_ERR);
}
}
free(tmpname);
map_name = (char *)strtok_r(NULL, ",", &lastparam);
}
return (IPQOS_CONF_SUCCESS);
}
static int
read_int_array_info(
char *info_str,
str_val_nd_t **enum_nvs,
uint32_t *size,
int *lower,
int *upper,
char *module)
{
int res;
char *end;
char *token;
char *tmp;
IPQOSCDBG1(L0, "In read_array_info: info_str: %s\n",
(info_str != NULL) ? info_str : "NULL");
if (info_str == NULL) {
IPQOSCDBG0(L0, "Null info string\n");
goto fail;
}
token = strtok(info_str, ",");
*size = (uint32_t)strtol(token, &end, 10);
SKIPWS(end);
if ((end == token) || (*end != '\0')) {
IPQOSCDBG0(L0, "Invalid size\n");
goto fail;
}
IPQOSCDBG1(L0, "read size: %u\n", *size);
token = strtok(NULL, "\n");
if (token == NULL) {
IPQOSCDBG0(L0, "Missing range/enum def\n");
goto fail;
}
IPQOSCDBG1(L0, "range/enum def: %s\n", token);
tmp = strchr(token, CURL_BEGIN);
if (tmp == NULL) {
res = readrange(token, lower, upper);
if (res != IPQOS_CONF_SUCCESS) {
IPQOSCDBG0(L0, "Failed reading range\n");
goto fail;
}
} else {
*enum_nvs = read_enum_nvs(token, module);
if (*enum_nvs == NULL) {
IPQOSCDBG0(L0, "Failed reading enum def\n");
goto fail;
}
}
return (IPQOS_CONF_SUCCESS);
fail:
ipqos_msg(MT_ERROR,
gettext("Types file for module %s is corrupt.\n"), module);
return (IPQOS_CONF_ERR);
}
static int
read_enum_value(
FILE *fp,
char *first_token,
str_val_nd_t *enum_vals,
uint32_t *val)
{
uint32_t u32;
int ret;
char *tk;
char *lo = NULL;
char *cm;
int name_expected = 0;
IPQOSCDBG0(L1, "In read_enum_value\n");
*val = 0;
if (*first_token != CURL_BEGIN) {
ret = str_val_list_lookup(enum_vals, first_token, val);
if (ret != IPQOS_CONF_SUCCESS) {
ipqos_msg(MT_ERROR,
gettext("Unrecognized value, %s, line %u.\n"),
first_token, lineno);
return (ret);
}
} else {
name_expected++;
for (;;) {
if (lo == NULL) {
ret = readtoken(fp, &tk);
if (ret == IPQOS_CONF_ERR) {
return (ret);
} else if (ret == IPQOS_CONF_EOF) {
ipqos_msg(MT_ERROR,
gettext("Unexpected EOF.\n"));
return (IPQOS_CONF_ERR);
}
} else {
IPQOSCDBG1(L1, "Using leftover %s.\n", lo);
tk = lo;
lo = NULL;
}
if (name_expected) {
if (ret == IPQOS_CONF_CURL_END ||
tk[0] == ',') {
ipqos_msg(MT_ERROR,
gettext("Malformed value list "
"line %u.\n"), lineno);
free(tk);
return (IPQOS_CONF_ERR);
}
cm = strchr(tk, ',');
if (cm != NULL) {
lo = malloc(strlen(cm) + 1);
if (lo == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
free(tk);
return (IPQOS_CONF_ERR);
}
(void) strcpy(lo, cm);
*cm = '\0';
}
ret = str_val_list_lookup(enum_vals, tk, &u32);
if (ret != IPQOS_CONF_SUCCESS) {
ipqos_msg(MT_ERROR,
gettext("Unrecognized value, %s, "
"line %u.\n"), tk, lineno);
free(tk);
return (IPQOS_CONF_ERR);
}
*val = *val | u32;
name_expected--;
} else {
if (ret == IPQOS_CONF_CURL_END) {
free(tk);
break;
} else if (tk[0] != ',') {
ipqos_msg(MT_ERROR,
gettext("Malformed value list "
"line %u.\n"), lineno);
free(tk);
return (IPQOS_CONF_ERR);
}
if (tk[1] != '\0') {
lo = malloc(strlen(&tk[1]) + 1);
if (lo == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
free(tk);
return (IPQOS_CONF_ERR);
}
(void) strcpy(lo, &tk[1]);
}
name_expected++;
}
free(tk);
}
}
IPQOSCDBG1(L1, "value returned is: %u\n", *val);
return (IPQOS_CONF_SUCCESS);
}
static int
read_perm_items(
int perm_filters,
FILE *tfp,
char *module_name,
char ***perm_items,
int *nitems)
{
char lbuf[IPQOS_CONF_TYPE_LINE_LEN];
int cnt = 0;
char name[IPQOS_CONF_NAME_LEN+1];
char foo[IPQOS_CONF_NAME_LEN+1];
int res;
char **items = NULL;
char **tmp;
char *marker;
IPQOSCDBG0(L1, "In read_perm_items\n");
if (fseek(tfp, 0, SEEK_SET) != 0) {
ipqos_msg(MT_ENOSTR, "fseek");
return (IPQOS_CONF_ERR);
}
if (perm_filters) {
marker = IPQOS_CONF_PERM_FILTER_MK;
} else {
marker = IPQOS_CONF_PERM_CLASS_MK;
}
while (fgets(lbuf, IPQOS_CONF_TYPE_LINE_LEN, tfp) != NULL) {
if (strncmp(lbuf, marker, strlen(marker)) == 0) {
res = sscanf(lbuf,
"%" VAL2STR(IPQOS_CONF_NAME_LEN) "s"
"%" VAL2STR(IPQOS_CONF_NAME_LEN) "s",
foo, name);
if (res < 2) {
ipqos_msg(MT_ERROR,
gettext("Types file for module %s is "
"corrupt.\n"), module_name);
IPQOSCDBG1(L0, "Missing name with a %s.\n",
marker);
goto fail;
}
tmp = realloc(items, (cnt + 1) * sizeof (char *));
if (tmp == NULL) {
ipqos_msg(MT_ENOSTR, "realloc");
goto fail;
} else {
items = tmp;
}
items[cnt] = malloc(strlen(name) + 1);
if (items[cnt] == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
goto fail;
}
(void) strcpy(items[cnt], name);
cnt++;
IPQOSCDBG1(L1, "stored %s in perm items array\n",
name);
}
}
*perm_items = items;
*nitems = cnt;
return (IPQOS_CONF_SUCCESS);
fail:
for (cnt--; cnt >= 0; cnt--)
free(items[cnt]);
free(items);
return (IPQOS_CONF_ERR);
}
static int
readtype(
FILE *tfp,
char *module_name,
char *name,
ipqos_nvtype_t *type,
str_val_nd_t **enum_nvps,
char *dfltst,
boolean_t allow_ipgpc_priv,
place_t *place)
{
int ac;
char lbuf[IPQOS_CONF_TYPE_LINE_LEN];
char param[IPQOS_CONF_PNAME_LEN+1];
char typest[IPQOS_CONF_TYPE_LEN+1];
char place_st[IPQOS_CONF_TYPE_LEN+1];
char *cp;
int x;
char *ipgpc_nm;
int found = 0;
IPQOSCDBG1(L1, "In readtype: param: %s\n", name);
if (allow_ipgpc_priv && strcmp(module_name, IPGPC_NAME) == 0) {
ipgpc_nm = prepend_module_name(name, IPGPC_NAME);
if (ipgpc_nm == NULL) {
return (IPQOS_CONF_ERR);
}
if (strcmp(ipgpc_nm, IPGPC_SADDR_MASK) == 0 ||
strcmp(ipgpc_nm, IPGPC_DADDR_MASK) == 0) {
*type = IPQOS_DATA_TYPE_ADDRESS_MASK;
return (IPQOS_CONF_SUCCESS);
} else if (strcmp(ipgpc_nm, IPGPC_SPORT_MASK) == 0 ||
strcmp(ipgpc_nm, IPGPC_DPORT_MASK) == 0) {
*type = IPQOS_DATA_TYPE_UINT16;
return (IPQOS_CONF_SUCCESS);
} else if (strcmp(ipgpc_nm, IPGPC_FILTER_TYPE) == 0) {
*type = IPQOS_DATA_TYPE_UINT32;
return (IPQOS_CONF_SUCCESS);
} else if (strcmp(ipgpc_nm, IPGPC_IF_INDEX) == 0) {
*type = IPQOS_DATA_TYPE_IFINDEX;
return (IPQOS_CONF_SUCCESS);
}
free(ipgpc_nm);
}
if (read_tfile_ver(tfp, IPQOS_MOD_STR, module_name) == -1)
return (IPQOS_CONF_ERR);
while (fgets(lbuf, IPQOS_CONF_TYPE_LINE_LEN, tfp) != NULL) {
for (cp = lbuf; isspace(*cp) && *cp != '\0'; cp++) {}
if (*cp == '\0' || *cp == '#') {
continue;
}
dfltst[0] = '\0';
ac = sscanf(lbuf,
"%" VAL2STR(IPQOS_CONF_TYPE_LEN) "s "
"%" VAL2STR(IPQOS_CONF_PNAME_LEN) "s "
"%" VAL2STR(IPQOS_CONF_TYPE_LEN) "s "
"%" VAL2STR(IPQOS_VALST_MAXLEN) "s",
place_st, param, typest, dfltst);
if (ac < 3) {
ipqos_msg(MT_ERROR,
gettext("Types file for module %s is corrupt.\n"),
module_name);
IPQOSCDBG0(L0, "sscanf failed to read 3 strings.\n");
return (IPQOS_CONF_ERR);
}
if ((*place == PL_ANY) ||
((*place == PL_PARAMS) &&
strcmp(place_st, IPQOS_PLACE_PRM_STR) == 0) ||
((*place == PL_FILTER) &&
strcmp(place_st, IPQOS_PLACE_FILTER_STR) == 0) ||
((*place == PL_MAP) &&
strcmp(place_st, IPQOS_PLACE_MAP_STR) == 0)) {
if (strcmp(param, name) == 0) {
found++;
break;
}
}
}
if (found == 0) {
ipqos_msg(MT_ERROR,
gettext("Invalid parameter, %s, line %u.\n"), name,
lineno);
return (IPQOS_CONF_ERR);
}
if (*place == PL_ANY) {
if (strcmp(place_st, IPQOS_PLACE_PRM_STR) == 0) {
*place = PL_PARAMS;
} else if (strcmp(place_st, IPQOS_PLACE_FILTER_STR) == 0) {
*place = PL_FILTER;
} else if (strcmp(place_st, IPQOS_PLACE_MAP_STR) == 0) {
*place = PL_MAP;
}
}
for (x = 0; nv_types[x].string[0]; x++) {
if (strcmp(nv_types[x].string, typest) == 0) {
break;
}
}
if (nv_types[x].string[0] == '\0') {
ipqos_msg(MT_ERROR,
gettext("Types file for module %s is corrupt.\n"),
module_name);
return (IPQOS_CONF_ERR);
}
*type = nv_types[x].value;
if (*type == IPQOS_DATA_TYPE_ENUM) {
*enum_nvps = read_enum_nvs(lbuf, module_name);
if (*enum_nvps == NULL) {
return (IPQOS_CONF_ERR);
}
dfltst[0] = '\0';
cp = strchr(lbuf, CURL_END);
(void) sscanf(++cp,
"%" VAL2STR(IPQOS_VALST_MAXLEN) "s", dfltst);
}
IPQOSCDBG2(L1, "read type: %s default: %s\n", nv_types[x].string,
*dfltst ? dfltst : "None");
return (IPQOS_CONF_SUCCESS);
}
static int
readnvpair(
FILE *cfp,
FILE *tfp,
nvlist_t **nvlp,
nvpair_t **nvp,
ipqos_nvtype_t *type,
place_t place,
char *module_name)
{
char *name = NULL;
char *valst = NULL;
int res;
char *tmp;
str_val_nd_t *enum_nvs = NULL;
char dfltst[IPQOS_VALST_MAXLEN+1];
IPQOSCDBG0(L1, "in readnvpair\n");
res = readtoken(cfp, &name);
if (res == IPQOS_CONF_EOF) {
ipqos_msg(MT_ERROR, gettext("Unexpected EOF.\n"));
return (IPQOS_CONF_ERR);
} else if (res == IPQOS_CONF_ERR) {
return (res);
} else if (res == IPQOS_CONF_CURL_END) {
free(name);
return (res);
}
res = readtoken(cfp, &valst);
if (res != IPQOS_CONF_SUCCESS && res != IPQOS_CONF_CURL_BEGIN) {
if (res == IPQOS_CONF_EOF) {
ipqos_msg(MT_ERROR, gettext("Unexpected EOF.\n"));
} else if (res == IPQOS_CONF_CURL_END) {
ipqos_msg(MT_ERROR,
gettext("Missing parameter value line %u.\n"),
lineno);
free(valst);
}
free(name);
return (IPQOS_CONF_ERR);
}
if ((place == PL_CLASS) &&
strcmp(name, IPQOS_CONF_NEXT_ACTION_STR) == 0) {
*type = IPQOS_DATA_TYPE_ACTION;
} else if (place == PL_PARAMS &&
strcmp(name, IPQOS_CONF_GLOBAL_STATS_STR) == 0 ||
place == PL_CLASS &&
strcmp(name, IPQOS_CONF_STATS_ENABLE_STR) == 0) {
*type = IPQOS_DATA_TYPE_BOOLEAN;
} else if (tfp == NULL ||
((place != PL_PARAMS) && strcmp(name, IPQOS_CONF_NAME_STR) == 0) ||
(place == PL_FILTER) && (strcmp(name, IPQOS_CONF_CLASS_STR) ==
0) ||
(place == PL_ACTION) && (strcmp(name, IPQOS_CONF_MODULE_STR) ==
0)) {
*type = IPQOS_DATA_TYPE_STRING;
} else {
if (readtype(tfp, module_name, name, type, &enum_nvs, dfltst,
B_FALSE, &place) != IPQOS_CONF_SUCCESS) {
free(name);
free(valst);
return (IPQOS_CONF_ERR);
}
tmp = name;
if ((name = prepend_module_name(name, module_name)) == NULL) {
name = tmp;
goto fail;
}
free(tmp);
}
IPQOSCDBG3(L1, "NVP, name: %s, str_value: %s, type: %s\n", name,
valst, nv_types[*type].string);
if (*nvlp == NULL) {
res = nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_alloc");
free(name);
free(valst);
return (IPQOS_CONF_ERR);
}
}
if (find_nvpair(*nvlp, name)) {
ipqos_msg(MT_ERROR, gettext("Duplicate parameter line %u.\n"),
lineno);
goto fail;
}
switch (*type) {
case IPQOS_DATA_TYPE_IFNAME: {
uint32_t ifidx;
res = readifindex(valst, (int *)&ifidx);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_uint32(*nvlp, IPGPC_IF_INDEX,
ifidx);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint32");
goto fail;
}
(void) nvlist_remove_all(*nvlp, name);
free(name);
name = malloc(strlen(IPGPC_IF_INDEX) + 1);
if (name == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
goto fail;
}
(void) strcpy(name, IPGPC_IF_INDEX);
}
break;
}
case IPQOS_DATA_TYPE_PROTO: {
uint8_t proto;
res = readproto(valst, &proto);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_byte(*nvlp, name, proto);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_PORT: {
uint16_t port;
res = readport(valst, &port);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_uint16(*nvlp, name, port);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint16");
goto fail;
}
if (strcmp(name, IPGPC_DPORT) == 0) {
res = nvlist_add_uint16(*nvlp,
IPGPC_DPORT_MASK, ~0);
} else if (strcmp(name, IPGPC_SPORT) == 0) {
res = nvlist_add_uint16(*nvlp,
IPGPC_SPORT_MASK, ~0);
}
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint16");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_ADDRESS:
case IPQOS_DATA_TYPE_ACTION:
case IPQOS_DATA_TYPE_STRING:
res = nvlist_add_string(*nvlp, name, valst);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_string");
goto fail;
}
break;
case IPQOS_DATA_TYPE_BOOLEAN: {
boolean_t b;
res = readbool(valst, &b);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_uint32(*nvlp, name,
(uint32_t)b);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint32");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_UINT8: {
uint8_t u8;
res = readuint8(valst, &u8, &tmp);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_byte(*nvlp, name, u8);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_INT16: {
int16_t i16;
res = readint16(valst, &i16, &tmp);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_int16(*nvlp, name, i16);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_int16");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_UINT16: {
uint16_t u16;
res = readuint16(valst, &u16, &tmp);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_uint16(*nvlp, name, u16);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_int16");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_INT32: {
int i32;
res = readint32(valst, &i32, &tmp);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_int32(*nvlp, name, i32);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_int32");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_UINT32: {
uint32_t u32;
res = readuint32(valst, &u32, &tmp);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_uint32(*nvlp, name, u32);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint32");
goto fail;
}
}
break;
}
case IPQOS_DATA_TYPE_ENUM: {
uint32_t val;
res = read_enum_value(cfp, valst, enum_nvs, &val);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_uint32(*nvlp, name, val);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint32");
goto fail;
}
} else {
goto fail;
}
break;
}
case IPQOS_DATA_TYPE_M_INDEX: {
uint8_t u8;
res = readuint8(valst, &u8, &tmp);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_byte(*nvlp, name, u8);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint8");
goto fail;
}
} else {
*type = IPQOS_DATA_TYPE_UINT8;
break;
}
res = read_mapped_values(tfp, nvlp, module_name,
dfltst, u8);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
break;
}
case IPQOS_DATA_TYPE_INT_ARRAY: {
str_val_nd_t *arr_enum_nvs = NULL;
uint32_t size;
int llimit = 0, ulimit = 0;
int *arr;
res = read_int_array_info(dfltst, &arr_enum_nvs, &size,
&llimit, &ulimit, module_name);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
res = read_int_array(cfp, valst, &arr, size, llimit,
ulimit, arr_enum_nvs);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
res = nvlist_add_int32_array(*nvlp, name, arr, size);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_int32");
goto fail;
}
free(arr);
if (arr_enum_nvs)
free_str_val_entrys(arr_enum_nvs);
break;
}
case IPQOS_DATA_TYPE_USER: {
uid_t uid;
res = readuser(valst, &uid);
if (res == IPQOS_CONF_SUCCESS) {
res = nvlist_add_int32(*nvlp, name, (int)uid);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_int32");
goto fail;
}
}
break;
}
#ifdef _IPQOS_CONF_DEBUG
default: {
assert(1);
}
#endif
}
if (res != 0) {
ipqos_msg(MT_ERROR, gettext("Invalid %s, line %u.\n"),
nv_types[*type].string, lineno);
goto fail;
}
*nvp = find_nvpair(*nvlp, name);
free(name);
free(valst);
if (enum_nvs)
free_str_val_entrys(enum_nvs);
return (IPQOS_CONF_SUCCESS);
fail:
if (name != NULL)
free(name);
if (valst != NULL)
free(valst);
if (enum_nvs != NULL)
free_str_val_entrys(enum_nvs);
return (IPQOS_CONF_ERR);
}
static int
readparams(
FILE *cfp,
FILE *tfp,
char *module_name,
ipqos_conf_params_t *params)
{
int res;
nvpair_t *nvp;
ipqos_nvtype_t type;
boolean_t bl;
char *nm;
char *action;
char tmp[IPQOS_CONF_PNAME_LEN];
int read_stats = 0;
IPQOSCDBG0(L0, "in readparams\n");
res = read_curl_begin(cfp);
if (res != IPQOS_CONF_SUCCESS) {
return (res);
}
for (;;) {
res = readnvpair(cfp, tfp, ¶ms->nvlist,
&nvp, &type, PL_PARAMS, module_name);
if (res == IPQOS_CONF_ERR) {
goto fail;
} else if (res == IPQOS_CONF_CURL_END) {
break;
}
if (strcmp(nvpair_name(nvp), IPQOS_CONF_GLOBAL_STATS_STR) ==
0) {
if (read_stats) {
ipqos_msg(MT_ERROR,
gettext("Duplicate parameter line %u.\n"),
lineno);
goto fail;
}
read_stats++;
(void) nvpair_value_uint32(nvp, (uint32_t *)&bl);
params->stats_enable = bl;
(void) nvlist_remove_all(params->nvlist,
IPQOS_CONF_GLOBAL_STATS_STR);
} else if (type == IPQOS_DATA_TYPE_ACTION) {
nm = nvpair_name(nvp);
(void) nvpair_value_string(nvp, &action);
if ((strcmp(action, IPQOS_CONF_CONT_STR) == 0) ||
strcmp(action, IPQOS_CONF_DROP_STR) == 0) {
(void) strlcpy(tmp, nm, sizeof (tmp));
nm = tmp;
if (strcmp(action, IPQOS_CONF_CONT_STR) == 0) {
action = IPP_ANAME_CONT;
res = nvlist_add_string(params->nvlist,
nm, action);
} else {
action = IPP_ANAME_DROP;
res = nvlist_add_string(params->nvlist,
nm, action);
}
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_string");
goto fail;
}
}
res = add_aref(¶ms->actions, nm, action);
}
}
return (IPQOS_CONF_SUCCESS);
fail:
if (params->nvlist) {
nvlist_free(params->nvlist);
params->nvlist = NULL;
}
if (params->actions) {
free_arefs(params->actions);
params->actions = NULL;
}
return (IPQOS_CONF_ERR);
}
static int
dup_class(
ipqos_conf_class_t *src,
ipqos_conf_class_t **dst)
{
ipqos_conf_class_t *cls;
int res;
IPQOSCDBG1(DIFF, "In dup_class: class: %s\n", src->name);
cls = alloc_class();
if (cls == NULL) {
return (IPQOS_CONF_ERR);
}
*cls = *src;
cls->nvlist = NULL;
cls->alist = NULL;
res = add_aref(&cls->alist, src->alist->field, src->alist->name);
if (res != IPQOS_CONF_SUCCESS) {
free(cls);
return (res);
}
*dst = cls;
return (IPQOS_CONF_SUCCESS);
}
static ipqos_conf_class_t *
alloc_class()
{
ipqos_conf_class_t *class;
class = malloc(sizeof (ipqos_conf_class_t));
if (class) {
bzero(class, sizeof (ipqos_conf_class_t));
} else {
ipqos_msg(MT_ENOSTR, "malloc");
}
return (class);
}
static void
free_class(ipqos_conf_class_t *cls)
{
if (cls == NULL)
return;
nvlist_free(cls->nvlist);
if (cls->alist)
free_arefs(cls->alist);
free(cls);
}
static ipqos_conf_class_t *
classexist(
char *class_nm,
ipqos_conf_class_t *classes)
{
ipqos_conf_class_t *cls;
IPQOSCDBG1(L1, "In classexist: name: %s\n", class_nm);
for (cls = classes; cls; cls = cls->next) {
if (strcmp(class_nm, cls->name) == 0) {
break;
}
}
return (cls);
}
static ipqos_conf_filter_t *
filterexist(
char *filter_nm,
int instance,
ipqos_conf_filter_t *filters)
{
IPQOSCDBG2(L1, "In filterexist: name :%s, inst: %d\n", filter_nm,
instance);
while (filters) {
if (strcmp(filters->name, filter_nm) == 0 &&
(instance == -1 || filters->instance == instance) &&
(filters->originator == IPP_CONFIG_IPQOSCONF ||
filters->originator == IPP_CONFIG_PERMANENT)) {
break;
}
filters = filters->next;
}
return (filters);
}
static ipqos_conf_filter_t *
alloc_filter()
{
ipqos_conf_filter_t *flt;
flt = malloc(sizeof (ipqos_conf_filter_t));
if (flt) {
bzero(flt, sizeof (ipqos_conf_filter_t));
flt->instance = -1;
} else {
ipqos_msg(MT_ENOSTR, "malloc");
}
return (flt);
}
static void
free_filter(ipqos_conf_filter_t *flt)
{
IPQOSCDBG2(L1, "In free_filter: filter: %s, inst: %d\n", flt->name,
flt->instance);
if (flt == NULL)
return;
if (flt->src_nd_name)
free(flt->src_nd_name);
if (flt->dst_nd_name)
free(flt->dst_nd_name);
if (flt->nvlist) {
nvlist_free(flt->nvlist);
}
free(flt);
}
static int
dup_filter(
ipqos_conf_filter_t *ofilter,
ipqos_conf_filter_t **nfilter,
int af,
int inv6,
void *saddr,
void *daddr,
int inst)
{
ipqos_conf_filter_t *nf;
int res;
in6_addr_t v6addr;
in6_addr_t all_1s_v6;
IPQOSCDBG4(MHME, "In dup_filter: name: %s, af: %u, inv6: %u, ins: %d\n",
ofilter->name, af, inv6, inst);
#ifdef _IPQOS_CONF_DEBUG
if (ipqosconf_dbg_flgs & MHME) {
char st[100];
if (saddr) {
(void) fprintf(stderr, "saddr: %s\n",
inet_ntop(inv6 ? AF_INET6 : AF_INET, saddr, st,
100));
}
if (daddr) {
(void) fprintf(stderr, "daddr: %s\n",
inet_ntop(inv6 ? AF_INET6 : AF_INET, daddr, st,
100));
}
}
#endif
(void) bzero(&v6addr, sizeof (in6_addr_t));
(void) memset(&all_1s_v6, ~0, sizeof (in6_addr_t));
nf = alloc_filter();
if (nf == NULL) {
return (IPQOS_CONF_ERR);
}
*nf = *ofilter;
if (ofilter->nvlist) {
res = nvlist_dup(ofilter->nvlist, &nf->nvlist, 0);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_dup");
goto fail;
}
}
if (ofilter->src_nd_name) {
nf->src_nd_name = malloc(strlen(ofilter->src_nd_name) + 1);
if (nf->src_nd_name == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
goto fail;
}
(void) strcpy(nf->src_nd_name, ofilter->src_nd_name);
}
if (ofilter->dst_nd_name) {
nf->dst_nd_name = malloc(strlen(ofilter->dst_nd_name) + 1);
if (nf->dst_nd_name == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
goto fail;
}
(void) strcpy(nf->dst_nd_name, ofilter->dst_nd_name);
}
res = nvlist_add_byte(nf->nvlist, IPGPC_FILTER_TYPE,
af == AF_INET ? IPGPC_V4_FLTR : IPGPC_V6_FLTR);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_byte");
goto fail;
}
IPQOSCDBG1(MHME, "adding address type %s in dup filter\n",
af == AF_INET ? "AF_INET" : "AF_INET6");
if (saddr) {
if (af == AF_INET && !inv6) {
V4_PART_OF_V6(v6addr) = *(uint32_t *)saddr;
saddr = &v6addr;
}
if (nvlist_add_uint32_array(nf->nvlist, IPGPC_SADDR,
(uint32_t *)saddr, 4) != 0 ||
nvlist_add_uint32_array(nf->nvlist, IPGPC_SADDR_MASK,
(uint32_t *)&all_1s_v6, 4) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32_array");
goto fail;
}
}
if (daddr) {
if (af == AF_INET && !inv6) {
V4_PART_OF_V6(v6addr) = *(uint32_t *)daddr;
daddr = &v6addr;
}
if (nvlist_add_uint32_array(nf->nvlist, IPGPC_DADDR,
(uint32_t *)daddr, 4) != 0 ||
nvlist_add_uint32_array(nf->nvlist, IPGPC_DADDR_MASK,
(uint32_t *)&all_1s_v6, 4) != 0) {
ipqos_msg(MT_ENOSTR, "nvlist_add_uint32_array");
goto fail;
}
}
nf->instance = inst;
*nfilter = nf;
return (IPQOS_CONF_SUCCESS);
fail:
free_filter(nf);
return (IPQOS_CONF_ERR);
}
static ipqos_conf_action_t *
alloc_action()
{
ipqos_conf_action_t *action;
action = (ipqos_conf_action_t *)malloc(sizeof (ipqos_conf_action_t));
if (action == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
return (action);
}
bzero(action, sizeof (ipqos_conf_action_t));
action->params = (ipqos_conf_params_t *)
malloc(sizeof (ipqos_conf_params_t));
if (action->params == NULL) {
free(action);
return (NULL);
}
bzero(action->params, sizeof (ipqos_conf_params_t));
action->params->stats_enable = B_FALSE;
return (action);
}
static void
free_actions(
ipqos_conf_action_t *actions)
{
ipqos_conf_action_t *act = actions;
ipqos_conf_action_t *next;
ipqos_conf_filter_t *flt, *nf;
ipqos_conf_class_t *cls, *nc;
while (act != NULL) {
if (act->params != NULL) {
free_arefs(act->params->actions);
if (act->params->nvlist != NULL) {
nvlist_free(act->params->nvlist);
}
free(act->params);
}
if (act->nvlist != NULL)
free(act->nvlist);
flt = act->filters;
while (flt != NULL) {
nf = flt->next;
free_filter(flt);
flt = nf;
}
cls = act->classes;
while (cls != NULL) {
nc = cls->next;
free_class(cls);
cls = nc;
}
cleanup_string_table(act->perm_classes, act->num_perm_classes);
flt = act->retry_filters;
while (flt != NULL) {
nf = flt->next;
free_filter(flt);
flt = nf;
}
free_arefs(act->dependencies);
next = act->next;
free(act);
act = next;
}
}
static ipqos_conf_action_t *
actionexist(
char *action_name,
ipqos_conf_action_t *actions)
{
IPQOSCDBG1(L1, "In actionexist: name: %s\n", action_name);
while (actions) {
if (strcmp(action_name, actions->name) == 0) {
break;
}
actions = actions->next;
}
return (actions);
}
static int
add_aref(
ipqos_conf_act_ref_t **arefs,
char *field,
char *action_name)
{
ipqos_conf_act_ref_t *aref;
IPQOSCDBG1(L1, "add_aref: action: %s.\n", action_name);
aref = malloc(sizeof (ipqos_conf_act_ref_t));
if (aref == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
return (IPQOS_CONF_ERR);
}
(void) bzero(aref, sizeof (ipqos_conf_act_ref_t));
if (field)
(void) strlcpy(aref->field, field, IPQOS_CONF_PNAME_LEN);
(void) strlcpy(aref->name, action_name, IPQOS_CONF_NAME_LEN);
aref->next = *arefs;
*arefs = aref;
return (IPQOS_CONF_SUCCESS);
}
static void
free_arefs(
ipqos_conf_act_ref_t *arefs)
{
ipqos_conf_act_ref_t *aref = arefs;
ipqos_conf_act_ref_t *next;
while (aref) {
nvlist_free(aref->nvlist);
next = aref->next;
free(aref);
aref = next;
}
}
static int
valid_aname(char *aname)
{
if (strcmp(aname, IPQOS_CONF_CONT_STR) == 0 ||
strcmp(aname, IPQOS_CONF_DEFER_STR) == 0 ||
strcmp(aname, IPQOS_CONF_DROP_STR) == 0 ||
virtual_action(aname)) {
ipqos_msg(MT_ERROR, gettext("Invalid action name line %u.\n"),
lineno);
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static FILE *
validmod(
char *module_name,
int *openerr)
{
FILE *fp;
char *path;
IPQOSCDBG1(L1, "In validmod: module_name: %s\n", module_name);
*openerr = 0;
path = malloc(strlen(TYPES_FILE_DIR) + strlen(module_name) +
strlen(".types") + 1);
if (path == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
return (NULL);
}
(void) strcpy(path, TYPES_FILE_DIR);
(void) strcat(path, module_name);
(void) strcat(path, ".types");
IPQOSCDBG1(L1, "opening file %s\n", path);
fp = fopen(path, "r");
if (fp == NULL) {
(*openerr)++;
}
free(path);
return (fp);
}
static int
readclass(
FILE *cfp,
char *module_name,
ipqos_conf_class_t **class,
char **perm_classes,
int num_perm_classes)
{
int nm, act;
int res;
nvpair_t *nvp;
ipqos_nvtype_t type;
char *name;
char *action;
int stats;
IPQOSCDBG0(L0, "in readclass\n");
*class = alloc_class();
if (!*class) {
return (IPQOS_CONF_ERR);
}
(*class)->originator = IPP_CONFIG_IPQOSCONF;
(*class)->lineno = lineno;
res = read_curl_begin(cfp);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
stats = nm = act = 0;
for (;;) {
res = readnvpair(cfp, NULL, &(*class)->nvlist,
&nvp, &type, PL_CLASS, module_name);
if (res == IPQOS_CONF_ERR) {
goto fail;
} else if (res == IPQOS_CONF_CURL_END) {
break;
}
if (nm == 0 &&
strcmp(nvpair_name(nvp), IPQOS_CONF_NAME_STR) == 0) {
(void) nvpair_value_string(nvp, &name);
if (valid_name(name) != IPQOS_CONF_SUCCESS) {
goto fail;
}
(void) strcpy((*class)->name, name);
nm++;
} else if (act == 0 &&
strcmp(nvpair_name(nvp), IPQOS_CONF_NEXT_ACTION_STR) == 0) {
(void) nvpair_value_string(nvp, &action);
if (strcmp(action, IPQOS_CONF_CONT_STR) == 0) {
action = IPP_ANAME_CONT;
} else if (strcmp(action, IPQOS_CONF_DROP_STR) == 0) {
action = IPP_ANAME_DROP;
}
res = add_aref(&(*class)->alist,
IPQOS_CONF_NEXT_ACTION_STR, action);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
act++;
} else if (stats == 0 &&
strcmp(nvpair_name(nvp), IPQOS_CONF_STATS_ENABLE_STR) ==
0) {
boolean_t bl;
(void) nvpair_value_uint32(nvp, (uint32_t *)&bl);
(*class)->stats_enable = bl;
stats++;
} else {
ipqos_msg(MT_ERROR,
gettext("Unexpected parameter line %u.\n"), lineno);
goto fail;
}
}
if (nm == 0 || act == 0) {
ipqos_msg(MT_ERROR,
gettext("Missing class name/next action before line %u.\n"),
lineno);
goto fail;
}
if (in_string_table(perm_classes, num_perm_classes, (*class)->name)) {
IPQOSCDBG1(L0, "Setting class %s as permanent.\n", (*class)->name);
(*class)->originator = IPP_CONFIG_PERMANENT;
}
return (IPQOS_CONF_SUCCESS);
fail:
if (*class)
free_class(*class);
return (IPQOS_CONF_ERR);
}
static int
domultihome(
ipqos_conf_filter_t *filter,
ipqos_conf_filter_t **flist,
boolean_t last_retry)
{
uint32_t ftype;
int v4 = 1, v6 = 1;
int saf, daf;
struct hostent *shp = NULL;
struct hostent *dhp = NULL;
in6_addr_t daddr, saddr;
int idx = 0;
ipqos_conf_filter_t *nfilter;
int res;
int ernum;
int in32b = 0;
char **sp, **dp;
IPQOSCDBG3(MHME, "In domultihome: filter: %s, src_node: %s, "
"dst_node: %s\n", filter->name,
(filter->src_nd_name ? filter->src_nd_name : "NULL"),
(filter->dst_nd_name ? filter->dst_nd_name : "NULL"));
if (filter->ip_versions != 0) {
v4 = VERSION_IS_V4(filter);
v6 = VERSION_IS_V6(filter);
} else if (nvlist_lookup_uint32(filter->nvlist, IPGPC_FILTER_TYPE,
&ftype) == 0) {
if (ftype == IPGPC_V4_FLTR) {
v6--;
} else {
v4--;
}
}
if (filter->src_nd_name) {
if (v4 && !v6) {
in32b++;
shp = getipnodebyname(filter->src_nd_name, AF_INET,
AI_ADDRCONFIG, &ernum);
} else if (v6 && !v4) {
shp = getipnodebyname(filter->src_nd_name, AF_INET6,
AI_DEFAULT, &ernum);
} else if (v6 && v4) {
shp = getipnodebyname(filter->src_nd_name, AF_INET6,
AI_DEFAULT|AI_ALL, &ernum);
}
#ifdef TESTING_RETRY
if (!last_retry) {
filter->nlerr = IPQOS_LOOKUP_RETRY;
goto fail;
}
#endif
if (shp == NULL) {
if (ernum != TRY_AGAIN) {
ipqos_msg(MT_ERROR, gettext("Failed to "
"resolve src host name for filter at "
"line %u, ignoring filter.\n"),
filter->lineno);
filter->nlerr = IPQOS_LOOKUP_FAIL;
} else {
if (last_retry) {
ipqos_msg(MT_ERROR, gettext("Failed "
"to resolve src host name for "
"filter at line %u, ignoring "
"filter.\n"), filter->lineno);
}
filter->nlerr = IPQOS_LOOKUP_RETRY;
}
goto fail;
}
}
if (filter->dst_nd_name) {
if (v4 && !v6) {
in32b++;
dhp = getipnodebyname(filter->dst_nd_name, AF_INET,
AI_ADDRCONFIG, &ernum);
} else if (v6 && !v4) {
dhp = getipnodebyname(filter->dst_nd_name, AF_INET6,
AI_DEFAULT, &ernum);
} else {
dhp = getipnodebyname(filter->dst_nd_name, AF_INET6,
AI_DEFAULT|AI_ALL, &ernum);
}
if (dhp == NULL) {
if (ernum != TRY_AGAIN) {
ipqos_msg(MT_ERROR, gettext("Failed to "
"resolve dst host name for filter at "
"line %u, ignoring filter.\n"),
filter->lineno);
filter->nlerr = IPQOS_LOOKUP_FAIL;
} else {
if (last_retry) {
ipqos_msg(MT_ERROR, gettext("Failed "
"to resolve dst host name for "
"filter at line %u, ignoring "
"filter.\n"), filter->lineno);
}
filter->nlerr = IPQOS_LOOKUP_RETRY;
}
goto fail;
}
}
if (filter->src_nd_name && filter->dst_nd_name) {
for (sp = shp->h_addr_list; *sp != NULL; sp++) {
(void) bcopy(*sp, &saddr, shp->h_length);
if (in32b || IN6_IS_ADDR_V4MAPPED(&saddr)) {
saf = AF_INET;
} else {
saf = AF_INET6;
}
for (dp = dhp->h_addr_list; *dp != NULL; dp++) {
(void) bcopy(*dp, &daddr, dhp->h_length);
if (in32b || IN6_IS_ADDR_V4MAPPED(&daddr)) {
daf = AF_INET;
} else {
daf = AF_INET6;
}
if (daf == saf) {
res = dup_filter(filter, &nfilter, saf,
!in32b, &saddr, &daddr, ++idx);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
ADD_TO_LIST(flist, nfilter);
}
}
}
} else if (filter->src_nd_name) {
for (sp = shp->h_addr_list; *sp != NULL; sp++) {
(void) bcopy(*sp, &saddr, shp->h_length);
if (in32b || IN6_IS_ADDR_V4MAPPED(&saddr)) {
saf = AF_INET;
} else {
saf = AF_INET6;
}
res = dup_filter(filter, &nfilter, saf, !in32b, &saddr,
NULL, ++idx);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
ADD_TO_LIST(flist, nfilter);
}
} else {
for (dp = dhp->h_addr_list; *dp != NULL; dp++) {
(void) bcopy(*dp, &daddr, dhp->h_length);
if (in32b || IN6_IS_ADDR_V4MAPPED(&daddr)) {
daf = AF_INET;
} else {
daf = AF_INET6;
}
res = dup_filter(filter, &nfilter, daf, !in32b, NULL,
&daddr, ++idx);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
ADD_TO_LIST(flist, nfilter);
}
}
if (shp)
freehostent(shp);
if (dhp)
freehostent(dhp);
return (IPQOS_CONF_SUCCESS);
fail:
if (shp)
freehostent(shp);
if (dhp)
freehostent(dhp);
return (IPQOS_CONF_ERR);
}
static int
readfilter(
FILE *cfp,
FILE *tfp,
char *module_name,
ipqos_conf_filter_t **filter,
char **perm_filters,
int num_perm_filters)
{
int res;
int nm, cls, ipv;
in6_addr_t mask;
char *addr_str;
char *sl = NULL;
in6_addr_t addr;
int sa;
struct hostent *hp;
int err_num;
int v4 = 0, v6 = 0;
uchar_t mlen;
char *tmp;
nvpair_t *nvp;
ipqos_nvtype_t type;
char *name;
char *class;
uchar_t b;
in6_addr_t v6addr;
IPQOSCDBG0(L0, "in readfilter\n");
*filter = alloc_filter();
if (*filter == NULL) {
return (IPQOS_CONF_ERR);
}
(*filter)->originator = IPP_CONFIG_IPQOSCONF;
(*filter)->lineno = lineno;
res = read_curl_begin(cfp);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
ipv = nm = cls = 0;
for (;;) {
res = readnvpair(cfp, tfp, &(*filter)->nvlist,
&nvp, &type, PL_FILTER, module_name);
if (res == IPQOS_CONF_ERR) {
goto fail;
} else if (res == IPQOS_CONF_CURL_END) {
break;
}
if (strcmp(nvpair_name(nvp), IPQOS_CONF_NAME_STR) == 0) {
if (nm != 0) {
ipqos_msg(MT_ERROR,
gettext("Duplicate parameter line %u.\n"),
lineno);
goto fail;
}
(void) nvpair_value_string(nvp, &name);
if (valid_name(name) != IPQOS_CONF_SUCCESS) {
goto fail;
}
(void) strcpy((*filter)->name, name);
(void) nvlist_remove_all((*filter)->nvlist,
IPQOS_CONF_NAME_STR);
nm++;
} else if (strcmp(nvpair_name(nvp), IPQOS_CONF_CLASS_STR) ==
0) {
if (cls != 0) {
ipqos_msg(MT_ERROR,
gettext("Duplicate parameter line %u.\n"),
lineno);
goto fail;
}
if (nvpair_value_string(nvp, &class) != 0) {
ipqos_msg(MT_ENOSTR, "nvpair_value_string");
break;
}
if (valid_name(class) != IPQOS_CONF_SUCCESS) {
goto fail;
}
(void) strcpy((*filter)->class_name, class);
(void) nvlist_remove_all((*filter)->nvlist,
IPQOS_CONF_CLASS_STR);
cls++;
} else if (strcmp(nvpair_name(nvp), IPGPC_SADDR) == 0 ||
strcmp(nvpair_name(nvp), IPGPC_DADDR) == 0) {
sa = 0;
if (strcmp(nvpair_name(nvp), IPGPC_SADDR) == 0) {
sa++;
}
(void) nvpair_value_string(nvp, &addr_str);
sl = strchr(addr_str, '/');
if (sl) {
*sl = '\0';
tmp = malloc(strlen(++sl) + 1);
if (tmp == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
goto fail;
}
(void) strcpy(tmp, sl);
sl = tmp;
}
if (inet_pton(AF_INET, addr_str, &addr) == 1 ||
inet_pton(AF_INET6, addr_str, &addr) == 1) {
hp = getipnodebyname(addr_str, AF_INET6,
AI_DEFAULT, &err_num);
if (hp == NULL) {
ipqos_msg(MT_ENOSTR,
"getipnodebyname");
goto fail;
}
(void) bcopy(hp->h_addr_list[0], &v6addr,
hp->h_length);
freehostent(hp);
v4 = IN6_IS_ADDR_V4MAPPED(&v6addr);
if (!v4) {
v6++;
}
if (nvlist_lookup_byte((*filter)->nvlist,
IPGPC_FILTER_TYPE, &b) == 0) {
if (v4 && b != IPGPC_V4_FLTR ||
v6 && b != IPGPC_V6_FLTR) {
ipqos_msg(MT_ERROR,
gettext("Incompatible "
"address version line "
"%u.\n"), lineno);
goto fail;
}
}
if ((*filter)->ip_versions != 0) {
if (v4 && !VERSION_IS_V4(*filter) ||
v6 && !VERSION_IS_V6(*filter)) {
ipqos_msg(MT_ERROR,
gettext("Incompatible "
"address version line %u"
".\n"), lineno);
goto fail;
}
}
res = nvlist_add_byte(
(*filter)->nvlist, IPGPC_FILTER_TYPE,
v4 ? IPGPC_V4_FLTR : IPGPC_V6_FLTR);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_byte");
goto fail;
}
res = nvlist_add_uint32_array((*filter)->nvlist,
sa ? IPGPC_SADDR : IPGPC_DADDR,
(uint32_t *)&v6addr, 4);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint32_array");
goto fail;
}
if (sl) {
char *lo;
res = readuint8(sl, &mlen, &lo);
if (res != IPQOS_CONF_SUCCESS ||
v4 && mlen > 32 ||
!v4 && mlen > 128 ||
mlen == 0) {
ipqos_msg(MT_ERROR,
gettext("Invalid CIDR "
"mask line %u.\n"), lineno);
goto fail;
}
setmask(mlen, &mask,
v4 ? AF_INET : AF_INET6);
free(sl);
} else {
(void) memset(&mask, ~0,
sizeof (in6_addr_t));
}
res = nvlist_add_uint32_array((*filter)->nvlist,
sa ? IPGPC_SADDR_MASK : IPGPC_DADDR_MASK,
(uint32_t *)&mask, 4);
if (res != 0) {
ipqos_msg(MT_ENOSTR,
"nvlist_add_uint32_arr");
goto fail;
}
} else {
if (sl) {
ipqos_msg(MT_ERROR,
gettext("Address masks aren't "
"allowed for host names line "
"%u.\n"), lineno);
goto fail;
}
if (sa) {
(*filter)->src_nd_name =
malloc(strlen(addr_str) + 1);
(void) strcpy((*filter)->src_nd_name,
addr_str);
} else {
(*filter)->dst_nd_name =
malloc(strlen(addr_str) + 1);
(void) strcpy((*filter)->dst_nd_name,
addr_str);
}
}
} else if (strcmp(nvpair_name(nvp), IPQOS_CONF_IP_VERSION) ==
0) {
if (ipv) {
ipqos_msg(MT_ERROR,
gettext("Duplicate parameter line %u.\n"),
lineno);
goto fail;
}
ipv++;
(void) nvpair_value_uint32(nvp,
&(*filter)->ip_versions);
if (v4 && !VERSION_IS_V4(*filter) ||
v6 && !VERSION_IS_V6(*filter)) {
ipqos_msg(MT_ERROR, gettext("Incompatible "
"address version line %u.\n"), lineno);
goto fail;
}
(void) nvlist_remove_all((*filter)->nvlist,
IPQOS_CONF_IP_VERSION);
}
}
if (nm == 0 || cls == 0) {
ipqos_msg(MT_ERROR, gettext("Missing filter/class name "
"before line %u.\n"), lineno);
goto fail;
}
if (in_string_table(perm_filters, num_perm_filters, (*filter)->name)) {
IPQOSCDBG1(L0, "Setting filter %s as permanent.\n",
(*filter)->name);
(*filter)->originator = IPP_CONFIG_PERMANENT;
}
return (IPQOS_CONF_SUCCESS);
fail:
if (*filter)
free_filter(*filter);
if (hp)
freehostent(hp);
if (sl)
free(sl);
return (IPQOS_CONF_ERR);
}
static int
read_curl_begin(FILE *cfp)
{
int res;
char *st;
res = readtoken(cfp, &st);
if (res != IPQOS_CONF_CURL_BEGIN) {
if (res == IPQOS_CONF_EOF) {
ipqos_msg(MT_ERROR, gettext("Unexpected EOF.\n"));
} else if (res != IPQOS_CONF_ERR) {
free(st);
ipqos_msg(MT_ERROR, gettext("\'{\' missing at line "
"%u.\n"), lineno);
}
return (IPQOS_CONF_ERR);
}
free(st);
return (IPQOS_CONF_SUCCESS);
}
static int
ver_str_to_int(
char *version)
{
uint32_t major, minor;
int ver;
if (sscanf(version, "%u.%u", &major, &minor) != 2) {
IPQOSCDBG0(L0, "Failed to process version number string\n");
return (-1);
}
ver = (int)((major * 10000) + minor);
return (ver);
}
static int
read_tfile_ver(
FILE *fp,
char *version_tag,
char *module_name)
{
char lbuf[IPQOS_CONF_LINEBUF_SZ];
char buf[IPQOS_CONF_LINEBUF_SZ+1];
char buf2[IPQOS_CONF_LINEBUF_SZ+1];
int found = 0;
int version;
if (fseek(fp, 0, SEEK_SET) != 0) {
ipqos_msg(MT_ENOSTR, "fseek");
return (-1);
}
while (fgets(lbuf, IPQOS_CONF_LINEBUF_SZ, fp) != NULL) {
if ((sscanf(lbuf,
"%" VAL2STR(IPQOS_CONF_LINEBUF_SZ) "s"
"%" VAL2STR(IPQOS_CONF_LINEBUF_SZ) "s",
buf, buf2) == 2) &&
(strcmp(buf, version_tag) == 0)) {
found++;
break;
}
}
if (found == 0) {
ipqos_msg(MT_ERROR, gettext("Types file for module %s is "
"corrupt.\n"), module_name);
IPQOSCDBG1(L1, "Couldn't find %s in types file\n",
version_tag);
return (-1);
}
if ((version = ver_str_to_int(buf2)) == -1) {
ipqos_msg(MT_ERROR, gettext("Types file for module %s is "
"corrupt.\n"), module_name);
return (-1);
}
return (version);
}
static int
readaction(
FILE *cfp,
ipqos_conf_action_t **action)
{
char *st;
FILE *tfp = NULL;
int nm, md;
int readprms = 0;
int res;
char *strval;
char *name;
nvpair_t *nvp;
ipqos_nvtype_t type;
ipqos_conf_filter_t *filter;
ipqos_conf_class_t *class;
int oe;
char **perm_filters;
int num_perm_filters;
int tf_fmt_ver;
IPQOSCDBG0(L0, "in readaction\n");
res = readtoken(cfp, &st);
if (res == IPQOS_CONF_ERR || res == IPQOS_CONF_EOF) {
return (res);
} else if (strcmp(st, IPQOS_CONF_ACTION_STR) != 0) {
ipqos_msg(MT_ERROR, gettext("Missing %s token line "
"%u.\n"), IPQOS_CONF_ACTION_STR, lineno);
free(st);
return (IPQOS_CONF_ERR);
}
free(st);
*action = alloc_action();
if (*action == NULL) {
return (IPQOS_CONF_ERR);
}
(*action)->params->originator = IPP_CONFIG_IPQOSCONF;
(*action)->lineno = lineno;
res = read_curl_begin(cfp);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
nm = md = 0;
do {
res = readnvpair(cfp, NULL, &(*action)->nvlist, &nvp, &type,
PL_ACTION, NULL);
if (res == IPQOS_CONF_ERR) {
goto fail;
} else if (res == IPQOS_CONF_CURL_END) {
if (nm == 0 || md == 0) {
ipqos_msg(MT_ERROR,
gettext("Missing action name/ module "
"before line %u.\n"), lineno);
goto fail;
}
}
name = nvpair_name(nvp);
if (nm == 0 && strcmp(name, IPQOS_CONF_NAME_STR) == 0) {
(void) nvpair_value_string(nvp, &strval);
if (valid_name(strval) != IPQOS_CONF_SUCCESS ||
valid_aname(strval) != IPQOS_CONF_SUCCESS) {
goto fail;
}
(void) strcpy((*action)->name, strval);
(void) nvlist_remove_all((*action)->nvlist,
IPQOS_CONF_NAME_STR);
nm++;
} else if (md == 0 &&
strcmp(name, IPQOS_CONF_MODULE_STR) == 0) {
(void) nvpair_value_string(nvp, &strval);
if ((tfp = validmod(strval, &oe)) == NULL) {
if (oe) {
if (errno == ENOENT) {
ipqos_msg(MT_ERROR,
gettext("Invalid "
"module name line %u.\n"),
lineno);
} else {
ipqos_msg(MT_ENOSTR, "fopen");
}
}
goto fail;
}
(void) strlcpy((*action)->module, strval,
IPQOS_CONF_NAME_LEN);
(void) nvlist_remove_all((*action)->nvlist,
IPQOS_CONF_MODULE_STR);
md++;
} else {
ipqos_msg(MT_ERROR,
gettext("Unexpected parameter line %u.\n"),
lineno);
goto fail;
}
} while (nm == 0 || md == 0);
if ((strcmp((*action)->module, IPGPC_NAME) == 0) &&
(strcmp((*action)->name, IPGPC_CLASSIFY) != 0)) {
ipqos_msg(MT_ERROR,
gettext("%s action has incorrect name line %u.\n"),
IPGPC_NAME, (*action)->lineno);
goto fail;
}
res = read_perm_items(0, tfp, (*action)->module,
&(*action)->perm_classes, &(*action)->num_perm_classes);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
res = read_perm_items(1, tfp, (*action)->module,
&perm_filters, &num_perm_filters);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
if ((tf_fmt_ver = read_tfile_ver(tfp, IPQOS_FMT_STR,
(*action)->module)) == -1)
goto fail;
if (IPP_MAJOR_MODULE_VER(tf_fmt_ver) > 1 ||
IPP_MINOR_MODULE_VER(tf_fmt_ver) > 0) {
ipqos_msg(MT_ERROR, gettext("Types file for module %s is "
"incompatible.\n"), (*action)->module);
IPQOSCDBG0(L1, "Unsupported fmt major/minor version\n");
goto fail;
}
if (((*action)->module_version = read_tfile_ver(tfp, IPQOS_MOD_STR,
(*action)->module)) == -1)
goto fail;
for (;;) {
res = readtoken(cfp, &st);
if (res == IPQOS_CONF_ERR) {
goto fail;
} else if (res == IPQOS_CONF_EOF) {
ipqos_msg(MT_ERROR, gettext("Unexpected EOF.\n"));
goto fail;
} else if (res == IPQOS_CONF_CURL_END) {
free(st);
break;
}
if (strcmp(st, IPQOS_CONF_FILTER_STR) == 0) {
free(st);
res = readfilter(cfp, tfp, (*action)->module, &filter,
perm_filters, num_perm_filters);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
if (filter->src_nd_name || filter->dst_nd_name) {
res = domultihome(filter, &(*action)->filters,
B_FALSE);
if (res != IPQOS_CONF_SUCCESS) {
if (filter->nlerr == 0) {
free_filter(filter);
goto fail;
} else if (filter->nlerr ==
IPQOS_LOOKUP_RETRY) {
filter->nlerr = 0;
ADD_TO_LIST(
&(*action)->retry_filters,
filter);
} else {
free_filter(filter);
}
} else {
free_filter(filter);
}
} else {
ADD_TO_LIST(&(*action)->filters, filter);
}
} else if (strcmp(st, IPQOS_CONF_CLASS_STR) == 0) {
free(st);
res = readclass(cfp, (*action)->module, &class,
(*action)->perm_classes,
(*action)->num_perm_classes);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
ADD_TO_LIST(&(*action)->classes, class);
} else if (strcmp(st, IPQOS_CONF_PARAMS_STR) == 0) {
free(st);
if (readprms) {
ipqos_msg(MT_ERROR,
gettext("Second parameter clause not "
"supported line %u.\n"), lineno);
goto fail;
}
res = readparams(cfp, tfp, (*action)->module,
(*action)->params);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
readprms++;
} else {
free(st);
ipqos_msg(MT_ERROR,
gettext("Params/filter/class clause expected "
"line %u.\n"), lineno);
goto fail;
}
}
(void) fclose(tfp);
return (IPQOS_CONF_SUCCESS);
fail:
if (tfp)
(void) fclose(tfp);
if (*action) {
free_actions(*action);
*action = NULL;
}
return (IPQOS_CONF_ERR);
}
static int
actions_unique(ipqos_conf_action_t *actions, char **name)
{
IPQOSCDBG0(L1, "In actions_unique.\n");
while (actions) {
if (actionexist(actions->name, actions->next)) {
*name = actions->name;
return (IPQOS_CONF_ERR);
}
actions = actions->next;
}
return (IPQOS_CONF_SUCCESS);
}
static int
in_cycle(
ipqos_conf_action_t *action)
{
ipqos_conf_act_ref_t *aref;
ipqos_conf_class_t *c;
IPQOSCDBG1(L0, "in_cycle: visiting action %s\n", action->name);
if (action->visited == INCYCLE_VISITED) {
action->visited = 0;
return (1);
}
action->visited = INCYCLE_VISITED;
for (aref = action->params->actions; aref != NULL; aref = aref->next) {
if (virtual_action(aref->name)) {
continue;
}
if (in_cycle(aref->action)) {
action->visited = 0;
return (1);
}
}
for (c = action->classes; c != NULL; c = c->next) {
aref = c->alist;
if (virtual_action(aref->name)) {
continue;
}
if (in_cycle(aref->action)) {
action->visited = 0;
return (1);
}
}
IPQOSCDBG0(L0, "in_cycle: return\n");
action->visited = 0;
return (0);
}
static int
validconf(
ipqos_conf_action_t *actions,
int userconf)
{
char *name;
ipqos_conf_action_t *act;
int res;
ipqos_conf_action_t *dact;
ipqos_conf_filter_t *flt;
ipqos_conf_class_t *cls;
ipqos_conf_params_t *params;
ipqos_conf_act_ref_t *aref;
IPQOSCDBG0(L0, "In validconf\n");
if (userconf && actions_unique(actions, &name) != IPQOS_CONF_SUCCESS) {
ipqos_msg(MT_ERROR, gettext("Duplicate named action %s.\n"),
name);
return (IPQOS_CONF_ERR);
}
for (act = actions; act; act = act->next) {
if (userconf) {
for (flt = act->filters; flt; flt = flt->next) {
if (filterexist(flt->name, flt->instance,
flt->next)) {
ipqos_msg(MT_ERROR,
gettext("Duplicate named filter "
"%s in action %s.\n"), flt->name,
act->name);
return (IPQOS_CONF_ERR);
}
if (!classexist(flt->class_name,
act->classes)) {
if (!in_string_table(act->perm_classes,
act->num_perm_classes,
flt->class_name)) {
ipqos_msg(MT_ERROR,
gettext("Undefined "
"class in filter %s, "
"action %s.\n"), flt->name,
act->name);
return (IPQOS_CONF_ERR);
}
}
}
}
for (cls = act->classes; cls; cls = cls->next) {
if (userconf && classexist(cls->name, cls->next)) {
ipqos_msg(MT_ERROR,
gettext("Duplicate named class %s in "
"action %s.\n"), cls->name, act->name);
return (IPQOS_CONF_ERR);
}
if (virtual_action(cls->alist->name)) {
continue;
}
if ((cls->alist->action =
actionexist(cls->alist->name, actions)) == NULL) {
ipqos_msg(MT_ERROR,
gettext("Undefined action in class %s, "
"action %s.\n"), cls->name, act->name);
return (IPQOS_CONF_ERR);
}
dact = cls->alist->action;
res = add_aref(&dact->dependencies, NULL, act->name);
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
dact->dependencies->action = act;
}
params = act->params;
for (aref = params->actions; aref; aref = aref->next) {
if (virtual_action(aref->name)) {
continue;
}
aref->action = actionexist(aref->name, actions);
if (aref->action == NULL) {
ipqos_msg(MT_ERROR,
gettext("Undefined action in parameter "
"%s, action %s.\n"),
SHORT_NAME(aref->field), act->name);
return (IPQOS_CONF_ERR);
}
dact = aref->action;
res = add_aref(&dact->dependencies, NULL,
act->name);
if (res != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
dact->dependencies->action = act;
}
}
if (!userconf) {
return (IPQOS_CONF_SUCCESS);
}
for (act = actions; act; act = act->next) {
if (in_cycle(act)) {
ipqos_msg(MT_ERROR,
gettext("Action %s involved in cycle.\n"),
act->name);
return (IPQOS_CONF_ERR);
}
if (act->dependencies == NULL &&
strcmp(act->name, IPGPC_CLASSIFY) != 0) {
ipqos_msg(MT_ERROR, gettext("Action %s isn't "
"referenced by any other actions.\n"), act->name);
return (IPQOS_CONF_ERR);
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
read_cfile_ver(
FILE *cfp,
char *version_tag)
{
char *sp = NULL;
int res;
int version;
IPQOSCDBG0(L1, "In read_cfile_ver:\n");
res = readtoken(cfp, &sp);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
} else if (strcasecmp(sp, version_tag) != 0) {
goto fail;
}
free(sp);
sp = NULL;
res = readtoken(cfp, &sp);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
if ((version = ver_str_to_int(sp)) == -1) {
goto fail;
}
free(sp);
return (version);
fail:
ipqos_msg(MT_ERROR,
gettext("Missing/Invalid config file %s.\n"), version_tag);
if (sp != NULL)
free(sp);
return (-1);
}
static int
readconf(
FILE *cfp,
ipqos_conf_action_t **conf)
{
int res;
ipqos_conf_action_t *action;
boolean_t ipgpc_action = B_FALSE;
int fmt_ver;
IPQOSCDBG0(L0, "In readconf\n");
*conf = NULL;
fmt_ver = read_cfile_ver(cfp, IPQOS_FMT_VERSION_STR);
if (fmt_ver == -1) {
return (IPQOS_CONF_ERR);
} else {
if ((IPP_MAJOR_MODULE_VER(fmt_ver) > 1) ||
(IPP_MINOR_MODULE_VER(fmt_ver) > 0)) {
ipqos_msg(MT_ERROR, gettext("Unsupported config file "
"format version.\n"));
return (IPQOS_CONF_ERR);
}
}
for (;;) {
action = NULL;
res = readaction(cfp, &action);
if (res == IPQOS_CONF_ERR) {
goto fail;
}
if (res == IPQOS_CONF_EOF) {
break;
}
ADD_TO_LIST(conf, action);
if (strcmp(action->name, IPGPC_CLASSIFY) == 0)
ipgpc_action = B_TRUE;
}
if (ipgpc_action == B_FALSE) {
ipqos_msg(MT_ERROR, gettext("No %s action defined.\n"),
IPGPC_NAME);
goto fail;
}
return (IPQOS_CONF_SUCCESS);
fail:
free_actions(*conf);
*conf = NULL;
return (IPQOS_CONF_ERR);
}
static int
readkconf(ipqos_conf_action_t **conf)
{
int res;
char **modnames = NULL;
int nmods;
char **actnames = NULL;
int nacts;
int x, y;
FILE *tfp;
int openerr;
ipqos_actinfo_prm_t ai_prm;
IPQOSCDBG0(L0, "In readkconf\n");
*conf = NULL;
res = ipp_list_mods(&modnames, &nmods);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "ipp_list_mods");
return (IPQOS_CONF_ERR);
}
for (x = 0; x < nmods; x++) {
if ((tfp = validmod(modnames[x], &openerr)) == NULL) {
if (!openerr) {
goto fail;
} else {
if (errno == ENOENT) {
continue;
} else {
ipqos_msg(MT_ENOSTR, "fopen");
goto fail;
}
}
}
(void) fclose(tfp);
res = ipp_mod_list_actions(modnames[x], &actnames, &nacts);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "ipp_mod_list_actions");
goto fail;
}
for (y = 0; y < nacts; y++) {
ai_prm.action = alloc_action();
if (ai_prm.action == NULL) {
goto fail;
}
(void) strlcpy(ai_prm.action->name, actnames[y],
IPQOS_CONF_NAME_LEN);
(void) strlcpy(ai_prm.action->module, modnames[x],
IPQOS_CONF_NAME_LEN);
res = ipp_action_info(actnames[y],
(int (*)(nvlist_t *, void *))parse_kaction,
(void *)&ai_prm, 0);
if (res != 0) {
if (ai_prm.intl_ret == IPQOS_CONF_SUCCESS) {
ipqos_msg(MT_ENOSTR,
"ipp_action_info");
}
goto fail;
}
ADD_TO_LIST(conf, ai_prm.action);
}
cleanup_string_table(actnames, nacts);
}
cleanup_string_table(modnames, nmods);
return (IPQOS_CONF_SUCCESS);
fail:
free_actions(*conf);
*conf = NULL;
cleanup_string_table(modnames, nmods);
cleanup_string_table(actnames, nacts);
return (IPQOS_CONF_ERR);
}
static int
parse_kaction(
nvlist_t *nvl,
ipqos_actinfo_prm_t *ai_prm)
{
int ret;
uint8_t cfgtype;
ipqos_conf_filter_t *filter = NULL;
ipqos_conf_class_t *class = NULL;
ipqos_conf_action_t *action = ai_prm->action;
IPQOSCDBG1(KRET, "In parse_kaction: action_name: %s\n", action->name);
(void) nvlist_lookup_byte(nvl, IPP_CONFIG_TYPE, &cfgtype);
(void) nvlist_remove_all(nvl, IPP_CONFIG_TYPE);
switch (cfgtype) {
case CLASSIFIER_ADD_FILTER: {
filter = alloc_filter();
if (filter == NULL) {
ai_prm->intl_ret = IPQOS_CONF_ERR;
return (IPQOS_CONF_ERR);
}
ret = parse_kfilter(filter, nvl);
if (ret != IPQOS_CONF_SUCCESS) {
free_filter(filter);
ai_prm->intl_ret = IPQOS_CONF_ERR;
return (ret);
}
ADD_TO_LIST(&action->filters, filter);
break;
}
case CLASSIFIER_ADD_CLASS:
case CLASSIFIER_MODIFY_CLASS: {
class = alloc_class();
if (class == NULL) {
ai_prm->intl_ret = IPQOS_CONF_ERR;
return (IPQOS_CONF_ERR);
}
ret = parse_kclass(class, nvl);
if (ret != IPQOS_CONF_SUCCESS) {
free_class(class);
ai_prm->intl_ret = IPQOS_CONF_ERR;
return (ret);
}
ADD_TO_LIST(&action->classes, class);
break;
}
case IPP_SET: {
ret = parse_kparams(action->module, action->params,
nvl);
if (ret != IPQOS_CONF_SUCCESS) {
ai_prm->intl_ret = IPQOS_CONF_ERR;
return (ret);
}
}
}
ai_prm->intl_ret = IPQOS_CONF_SUCCESS;
return (IPQOS_CONF_SUCCESS);
}
int
parse_kparams(
char *module,
ipqos_conf_params_t *params,
nvlist_t *nvl) {
int ret;
ipqos_nvtype_t type;
str_val_nd_t *tmp;
char *act;
uint32_t u32;
nvpair_t *nvp;
FILE *tfp;
char dfltst[IPQOS_VALST_MAXLEN];
char *param;
nvlist_t *nvlcp;
int openerr;
place_t place;
IPQOSCDBG0(KRET, "In parse_kparams:\n");
tfp = validmod(module, &openerr);
if (tfp == NULL) {
if (openerr) {
ipqos_msg(MT_ENOSTR, "fopen");
}
return (IPQOS_CONF_ERR);
}
ret = nvlist_dup(nvl, &nvlcp, 0);
if (ret != 0) {
return (IPQOS_CONF_ERR);
}
ret = nvlist_lookup_uint32(nvlcp, IPP_CONFIG_ORIGINATOR, &u32);
if (ret == 0) {
params->originator = u32;
(void) nvlist_remove_all(nvlcp, IPP_CONFIG_ORIGINATOR);
} else {
params->originator = IPP_CONFIG_IPQOSCONF;
}
ret = nvlist_lookup_uint32(nvlcp, IPP_ACTION_STATS_ENABLE, &u32);
if (ret == 0) {
params->stats_enable = *(boolean_t *)&u32;
(void) nvlist_remove_all(nvlcp, IPP_ACTION_STATS_ENABLE);
}
nvp = nvlist_next_nvpair(nvlcp, NULL);
while (nvp != NULL) {
param = SHORT_NAME(nvpair_name(nvp));
place = PL_ANY;
ret = readtype(tfp, module, param, &type, &tmp, dfltst,
B_FALSE, &place);
if (ret != IPQOS_CONF_SUCCESS) {
goto fail;
}
if ((place == PL_PARAMS) &&
(type == IPQOS_DATA_TYPE_ACTION)) {
(void) nvpair_value_string(nvp, &act);
ret = add_aref(¶ms->actions, nvpair_name(nvp), act);
if (ret != IPQOS_CONF_SUCCESS) {
goto fail;
}
}
nvp = nvlist_next_nvpair(nvlcp, nvp);
}
params->nvlist = nvlcp;
(void) fclose(tfp);
return (IPQOS_CONF_SUCCESS);
fail:
(void) fclose(tfp);
free_arefs(params->actions);
params->actions = NULL;
nvlist_free(nvlcp);
return (IPQOS_CONF_ERR);
}
static int
parse_kclass(
ipqos_conf_class_t *class,
nvlist_t *nvl)
{
int ret;
uint32_t u32;
char *str;
IPQOSCDBG0(KRET, "In parse_kclass:\n");
ret = nvlist_lookup_uint32(nvl, IPP_CONFIG_ORIGINATOR, &u32);
if (ret == 0) {
class->originator = u32;
} else {
class->originator = IPP_CONFIG_IPQOSCONF;
}
(void) nvlist_lookup_string(nvl, CLASSIFIER_CLASS_NAME, &str);
(void) strlcpy(class->name, str, IPQOS_CONF_NAME_LEN);
IPQOSCDBG1(KRET, "reading class %s\n", class->name);
(void) nvlist_lookup_string(nvl, CLASSIFIER_NEXT_ACTION, &str);
ret = add_aref(&class->alist, NULL, str);
if (ret != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
ret = nvlist_lookup_uint32(nvl, CLASSIFIER_CLASS_STATS_ENABLE, &u32);
if (ret == 0) {
class->stats_enable = *(boolean_t *)&u32;
}
return (IPQOS_CONF_SUCCESS);
}
static int
parse_kfilter(
ipqos_conf_filter_t *filter,
nvlist_t *nvl)
{
int ret;
char *str;
uint32_t u32;
nvlist_t *nvlcp;
char *end;
IPQOSCDBG0(KRET, "In parse_kfilter:\n");
ret = nvlist_dup(nvl, &nvlcp, 0);
if (ret != 0) {
return (IPQOS_CONF_ERR);
}
ret = nvlist_lookup_uint32(nvlcp, IPP_CONFIG_ORIGINATOR, &u32);
if (ret == 0) {
filter->originator = u32;
(void) nvlist_remove_all(nvlcp, IPP_CONFIG_ORIGINATOR);
} else {
filter->originator = IPP_CONFIG_IPQOSCONF;
}
(void) nvlist_lookup_string(nvlcp, CLASSIFIER_FILTER_NAME, &str);
(void) strlcpy(filter->name, str, IPQOS_CONF_NAME_LEN);
(void) nvlist_remove_all(nvlcp, CLASSIFIER_FILTER_NAME);
(void) nvlist_lookup_string(nvlcp, CLASSIFIER_CLASS_NAME, &str);
(void) strlcpy(filter->class_name, str, IPQOS_CONF_NAME_LEN);
(void) nvlist_remove_all(nvlcp, CLASSIFIER_CLASS_NAME);
if (nvlist_lookup_string(nvlcp, IPGPC_SADDR_HOSTNAME, &str) == 0) {
filter->src_nd_name = malloc(strlen(str) + 1);
if (filter->src_nd_name) {
(void) strcpy(filter->src_nd_name, str);
(void) nvlist_remove_all(nvlcp, IPGPC_SADDR_HOSTNAME);
} else {
ipqos_msg(MT_ENOSTR, "malloc");
nvlist_free(nvlcp);
return (IPQOS_CONF_ERR);
}
}
if (nvlist_lookup_string(nvlcp, IPGPC_DADDR_HOSTNAME, &str) == 0) {
filter->dst_nd_name = malloc(strlen(str) + 1);
if (filter->dst_nd_name) {
(void) strcpy(filter->dst_nd_name, str);
(void) nvlist_remove_all(nvlcp, IPGPC_DADDR_HOSTNAME);
} else {
ipqos_msg(MT_ENOSTR, "malloc");
nvlist_free(nvlcp);
return (IPQOS_CONF_ERR);
}
}
if (nvlist_lookup_string(nvlcp, IPGPC_FILTER_PRIVATE, &str) == 0) {
filter->ip_versions = (uint32_t)strtol(str, &end, 0);
if (end != str) {
(void) nvlist_remove_all(nvlcp, IPGPC_FILTER_PRIVATE);
} else {
ipqos_msg(MT_ERROR,
gettext("Corrupted ip_version returned from "
"kernel.\n"));
nvlist_free(nvlcp);
return (IPQOS_CONF_ERR);
}
}
ret = nvlist_lookup_int32(nvlcp, IPGPC_FILTER_INSTANCE,
&filter->instance);
if (ret != 0) {
filter->instance = -1;
} else {
(void) nvlist_remove_all(nvlcp, IPGPC_FILTER_INSTANCE);
}
filter->nvlist = nvlcp;
return (IPQOS_CONF_SUCCESS);
}
static int
virtual_action(char *action_name)
{
if (strcmp(action_name, IPP_ANAME_CONT) == 0 ||
strcmp(action_name, IPP_ANAME_DEFER) == 0 ||
strcmp(action_name, IPP_ANAME_DROP) == 0) {
return (1);
}
return (0);
}
static int
flush(
boolean_t *modified)
{
int res;
char **modnames = NULL;
int nmods;
char **actnames = NULL;
int nacts;
int x, y;
IPQOSCDBG0(L0, "In flush\n");
*modified = B_FALSE;
res = ipp_list_mods(&modnames, &nmods);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "ipp_list_mods");
return (IPQOS_CONF_ERR);
}
for (x = 0; x < nmods; x++) {
IPQOSCDBG1(APPLY, "Getting actions of module %s.\n",
modnames[x]);
res = ipp_mod_list_actions(modnames[x], &actnames, &nacts);
if (res != 0) {
ipqos_msg(MT_ENOSTR, "ipp_mod_list_actions");
cleanup_string_table(modnames, nmods);
return (IPQOS_CONF_ERR);
}
for (y = 0; y < nacts; y++) {
IPQOSCDBG1(APPLY, "deleting action %s\n", actnames[y]);
res = ipp_action_destroy(actnames[y], IPP_DESTROY_REF);
if (res != 0 && errno != ENOENT && errno != EBUSY) {
ipqos_msg(MT_ENOSTR, "ipp_action_destroy");
cleanup_string_table(modnames, nmods);
cleanup_string_table(actnames, nacts);
return (IPQOS_CONF_ERR);
}
if (res == 0)
*modified = B_TRUE;
}
cleanup_string_table(actnames, nacts);
}
cleanup_string_table(modnames, nmods);
return (IPQOS_CONF_SUCCESS);
}
static int
atomic_flush(
boolean_t force_flush)
{
int x = 0;
int res;
boolean_t modified = B_FALSE;
res = flush(&modified);
if ((force_flush == B_FALSE) && (res != IPQOS_CONF_SUCCESS) &&
(modified == B_FALSE)) {
return (IPQOS_CONF_ERR);
} else if (res == IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_SUCCESS);
}
while (res != IPQOS_CONF_SUCCESS) {
if (x == 5) {
ipqos_msg(MT_ERROR,
gettext("Retrying configuration flush.\n"));
x = 0;
}
(void) sleep(2);
x++;
res = flush(&modified);
}
return (IPQOS_CONF_SUCCESS);
}
static int
flushconf()
{
int res;
if ((res = block_all_signals()) == -1)
return (IPQOS_CONF_ERR);
res = atomic_flush(B_FALSE);
(void) restore_all_signals();
if (res == IPQOS_CONF_SUCCESS) {
ipqos_msg(MT_LOG, gettext("Configuration flushed.\n"));
} else {
ipqos_msg(MT_ENOSTR, "atomic_flush");
}
return (res);
}
static int
in_string_table(char *stable[], int size, char *string)
{
IPQOSCDBG1(L1, "In in_string_table: search string %s\n", string);
for (--size; size >= 0; size--) {
if (strcmp(stable[size], string) == 0) {
IPQOSCDBG1(L1, "Found %s in string table\n", string);
return (1);
}
}
return (0);
}
static void
cleanup_string_table(char *ctable[], int size)
{
int x;
if (ctable) {
for (x = 0; x < size; x++) {
free(ctable[x]);
}
free(ctable);
}
}
#if 0
static char **
copy_string_table(char *stable1[], int size)
{
char **st = NULL;
int pos;
st = malloc(size * sizeof (char *));
if (st == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
return (st);
}
for (pos = size - 1; pos >= 0; pos--) {
st[pos] = malloc(strlen(stable1[pos] + 1));
if (st[pos] == NULL) {
for (pos++; pos < size; pos++)
free(st[pos]);
free(st);
ipqos_msg(MT_ENOSTR, "malloc");
return (NULL);
}
(void) strcpy(st[pos], stable1[pos]);
}
return (st);
}
#endif
static int
retry_name_lookups(
ipqos_conf_action_t *actions)
{
ipqos_conf_action_t *act;
ipqos_conf_filter_t **new_filters;
ipqos_conf_filter_t *flt;
IPQOSCDBG0(APPLY, "In retry_name_lookups:\n");
for (act = actions; act != NULL; act = act->next) {
GET_LIST_END(&act->filters, &new_filters);
for (flt = act->retry_filters; flt != NULL; flt = flt->next) {
if (domultihome(flt, new_filters, B_TRUE) !=
IPQOS_CONF_SUCCESS) {
if (flt->nlerr == 0) {
return (IPQOS_CONF_ERR);
}
}
}
for (flt = *new_filters; flt != NULL; flt = flt->next) {
if (add_filter(act->name, flt, act->module_version) !=
IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
}
}
return (IPQOS_CONF_SUCCESS);
}
static int
writeconf(
ipqos_conf_action_t *conf,
char *dstpath)
{
FILE *tmpfp;
char *tmppath;
char *pathend;
ipqos_conf_action_t *act;
int res;
IPQOSCDBG0(L0, "in writeconf\n");
pathend = strrchr(dstpath, '/');
if (pathend == NULL) {
tmppath = malloc(strlen("ipqosconf.tmp") + 1);
if (tmppath == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
return (IPQOS_CONF_ERR);
}
(void) strcpy(tmppath, "ipqosconf.tmp");
} else if (pathend == dstpath) {
tmppath = malloc(strlen("/ipqosconf.tmp") + 1);
if (tmppath == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
return (IPQOS_CONF_ERR);
}
(void) strcpy(tmppath, "/ipqosconf.tmp");
} else {
*pathend = '\0';
tmppath = malloc(strlen(dstpath) + strlen("/ipqosconf.tmp") +
1);
if (tmppath == NULL) {
ipqos_msg(MT_ENOSTR, "malloc");
return (IPQOS_CONF_ERR);
}
(void) strcpy(tmppath, dstpath);
(void) strcat(tmppath, "/ipqosconf.tmp");
*pathend = '/';
}
tmpfp = fopen(tmppath, "w");
if (tmpfp == NULL) {
ipqos_msg(MT_ENOSTR, "fopen");
free(tmppath);
return (IPQOS_CONF_ERR);
}
(void) fprintf(tmpfp, "%s %d.%d\n\n", IPQOS_FMT_VERSION_STR,
IPQOS_CUR_FMT_MAJOR_VER, IPQOS_CUR_FMT_MINOR_VER);
for (act = conf; act != NULL; act = act->next) {
if (act->params->originator == IPP_CONFIG_IPQOSCONF) {
res = printaction(tmpfp, act, 0, 0);
if (res != IPQOS_CONF_SUCCESS) {
free(tmppath);
(void) fclose(tmpfp);
return (res);
}
}
}
(void) fclose(tmpfp);
if (rename(tmppath, dstpath) != 0) {
ipqos_msg(MT_ENOSTR, "rename");
free(tmppath);
return (IPQOS_CONF_ERR);
}
free(tmppath);
return (IPQOS_CONF_SUCCESS);
}
static int
commitconf()
{
int ret;
ipqos_conf_action_t *conf;
IPQOSCDBG0(L0, "In commitconf\n");
ret = readkconf(&conf);
if (ret != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
if (conf == NULL) {
ipqos_msg(MT_ERROR,
gettext("Can't commit a null configuration.\n"));
return (IPQOS_CONF_ERR);
}
(void) umask(S_IXUSR | S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH);
ret = writeconf(conf, IPQOS_CONF_INIT_PATH);
if (ret != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
ipqos_msg(MT_LOG,
gettext("Current configuration saved to init file.\n"));
return (IPQOS_CONF_SUCCESS);
}
static int
rollback_recover(
ipqos_conf_action_t *oconf)
{
int res;
IPQOSCDBG0(RBK, "In rollback_recover\n");
(void) atomic_flush(B_TRUE);
mark_config_new(oconf);
res = applydiff(oconf, NULL);
if (res != IPQOS_CONF_SUCCESS) {
(void) atomic_flush(B_TRUE);
return (IPQOS_CONF_ERR);
}
return (IPQOS_CONF_SUCCESS);
}
static int
applyconf(char *ifile)
{
FILE *ifp;
ipqos_conf_action_t *conf = NULL;
ipqos_conf_action_t *oconf = NULL;
ipqos_conf_action_t *act, *oact;
int res;
IPQOSCDBG0(L0, "In applyconf:\n");
if (strcmp(ifile, "-") == 0) {
ifp = stdin;
} else {
ifp = fopen(ifile, "r");
if (ifp == NULL) {
ipqos_msg(MT_ERROR,
gettext("Opening file %s for read: %s.\n"),
ifile, strerror(errno));
return (IPQOS_CONF_ERR);
}
}
res = readconf(ifp, &conf);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
res = validconf(conf, 1);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
res = readkconf(&oconf);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
for (act = conf; act != NULL; act = act->next) {
for (oact = oconf; oact != NULL; oact = oact->next) {
if (strcmp(act->name, oact->name) == 0) {
if (strcmp(act->module, oact->module) != 0) {
ipqos_msg(MT_ERROR,
gettext("Action at line %u has "
"same name as currently "
"installed action, but is for a "
"different module.\n"),
act->lineno);
goto fail;
} else {
break;
}
}
}
}
res = validconf(oconf, 0);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
res = diffconf(oconf, conf);
if (res != IPQOS_CONF_SUCCESS) {
goto fail;
}
if ((res = block_all_signals()) == -1) {
res = IPQOS_CONF_ERR;
goto fail;
}
res = applydiff(conf, oconf);
#ifdef _IPQOS_CONF_DEBUG
if (force_rback || res != IPQOS_CONF_SUCCESS) {
#else
if (res != IPQOS_CONF_SUCCESS) {
#endif
res = rollback(conf, oconf);
if (res != IPQOS_CONF_SUCCESS) {
res = rollback_recover(oconf);
if (res != IPQOS_CONF_SUCCESS) {
ipqos_msg(MT_ERROR,
gettext("Failed to rollback from failed "
"configuration, configuration flushed.\n"));
res = IPQOS_CONF_RECOVER_ERR;
} else {
ipqos_msg(MT_ERROR,
gettext("Configuration failed, system "
"state unchanged.\n"));
res = IPQOS_CONF_ERR;
}
} else {
ipqos_msg(MT_ERROR,
gettext("Configuration failed, system "
"state unchanged.\n"));
res = IPQOS_CONF_ERR;
}
goto fail;
}
res = retry_name_lookups(conf);
if (res != IPQOS_CONF_SUCCESS) {
res = rollback(conf, oconf);
if (res != IPQOS_CONF_SUCCESS) {
res = rollback_recover(oconf);
if (res != IPQOS_CONF_SUCCESS) {
ipqos_msg(MT_ERROR,
gettext("Failed to rollback from failed "
"configuration, configuration flushed.\n"));
res = IPQOS_CONF_RECOVER_ERR;
} else {
ipqos_msg(MT_ERROR,
gettext("Configuration failed, system "
"state unchanged.\n"));
res = IPQOS_CONF_ERR;
}
} else {
ipqos_msg(MT_ERROR,
gettext("Configuration failed, system "
"state unchanged.\n"));
res = IPQOS_CONF_ERR;
}
goto fail;
}
ipqos_msg(MT_LOG, gettext("IPQoS configuration applied.\n"));
(void) restore_all_signals();
(void) fclose(ifp);
free_actions(conf);
free_actions(oconf);
return (IPQOS_CONF_SUCCESS);
fail:
(void) fclose(ifp);
(void) restore_all_signals();
if (conf)
free_actions(conf);
if (oconf)
free_actions(oconf);
if (res == IPQOS_CONF_RECOVER_ERR)
ipqos_msg(MT_LOG, gettext("Configuration flushed.\n"));
return (res);
}
static sigset_t set, oset;
static int
block_all_signals()
{
if (sigfillset(&set) == -1) {
ipqos_msg(MT_ENOSTR, "sigfillset");
return (-1);
}
if (sigprocmask(SIG_SETMASK, &set, &oset) == -1) {
ipqos_msg(MT_ENOSTR, "sigprocmask");
return (-1);
}
return (0);
}
static int
restore_all_signals()
{
if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
ipqos_msg(MT_ENOSTR, "sigprocmask");
return (-1);
}
return (0);
}
static int
unlock(int fd)
{
if (lockf(fd, F_ULOCK, 0) == -1) {
ipqos_msg(MT_ENOSTR, "lockf");
return (-1);
}
return (0);
}
static int
lock()
{
int fd;
struct stat sbuf1;
struct stat sbuf2;
(void) umask(0077);
if ((fd = open(IPQOS_CONF_LOCK_FILE, O_EXCL|O_CREAT|O_RDWR,
S_IRUSR|S_IWUSR)) == -1) {
if (errno != EEXIST) {
ipqos_msg(MT_ENOSTR,
gettext("Cannot open lock file %s"),
IPQOS_CONF_LOCK_FILE);
return (-1);
}
errno = 0;
if (lstat(IPQOS_CONF_LOCK_FILE, &sbuf1) == -1) {
ipqos_msg(MT_ENOSTR,
gettext("Cannot lstat lock file %s\n"),
IPQOS_CONF_LOCK_FILE);
return (-1);
}
if (!S_ISREG(sbuf1.st_mode) ||
sbuf1.st_nlink != 1 ||
sbuf1.st_uid != 0 ||
sbuf1.st_size != 0) {
ipqos_msg(MT_ERROR, gettext("Bad lock file %s.\n"),
IPQOS_CONF_LOCK_FILE);
return (-1);
}
if ((fd = open(IPQOS_CONF_LOCK_FILE, O_CREAT|O_RDWR,
S_IRUSR|S_IWUSR)) == -1) {
ipqos_msg(MT_ENOSTR,
gettext("Cannot open lock file %s"),
IPQOS_CONF_LOCK_FILE);
return (-1);
}
if (fstat(fd, &sbuf2) == -1) {
ipqos_msg(MT_ENOSTR,
gettext("Cannot fstat lock file %s\n"),
IPQOS_CONF_LOCK_FILE);
return (-1);
}
if (sbuf1.st_dev != sbuf2.st_dev ||
sbuf1.st_ino != sbuf2.st_ino) {
ipqos_msg(MT_ERROR, gettext("Bad lock file %s.\n"),
IPQOS_CONF_LOCK_FILE);
return (-1);
}
}
if (lockf(fd, F_LOCK, 0) == -1) {
ipqos_msg(MT_ENOSTR, "lockf");
return (-1);
}
return (fd);
}
static int
viewconf(int viewall)
{
ipqos_conf_action_t *conf = NULL;
ipqos_conf_action_t *act;
int ret;
IPQOSCDBG0(L0, "In viewconf\n");
ret = readkconf(&conf);
if (ret != IPQOS_CONF_SUCCESS) {
return (IPQOS_CONF_ERR);
}
if (conf != NULL) {
(void) fprintf(stdout, "%s %d.%d\n\n", IPQOS_FMT_VERSION_STR,
IPQOS_CUR_FMT_MAJOR_VER, IPQOS_CUR_FMT_MINOR_VER);
}
for (act = conf; act != NULL; act = act->next) {
ret = printaction(stdout, act, viewall, 0);
if (ret != IPQOS_CONF_SUCCESS) {
free_actions(conf);
return (ret);
}
(void) fprintf(stdout, "\n");
}
free_actions(conf);
return (IPQOS_CONF_SUCCESS);
}
#ifdef _IPQOS_CONF_DEBUG
static int
viewcfile(char *cfile)
{
ipqos_conf_action_t *conf;
ipqos_conf_action_t *act;
int res;
FILE *ifp;
int viewall = 1;
IPQOSCDBG0(L0, "In viewcfile\n");
ifp = fopen(cfile, "r");
if (ifp == NULL) {
ipqos_msg(MT_ERROR, gettext("Opening file %s for read: %s.\n"),
cfile, strerror(errno));
return (IPQOS_CONF_ERR);
}
res = readconf(ifp, &conf);
if (res != IPQOS_CONF_SUCCESS) {
free(ifp);
return (IPQOS_CONF_ERR);
}
for (act = conf; act != NULL; act = act->next) {
res = printaction(stdout, act, viewall, 0);
if (res != IPQOS_CONF_SUCCESS) {
free(ifp);
return (res);
}
(void) fprintf(stdout, "\n");
}
(void) fprintf(stdout, "\n");
return (IPQOS_CONF_SUCCESS);
}
#endif
static void
usage(void)
{
(void) fprintf(stderr, gettext("usage:\n"
"\tipqosconf [-sv] -a file|-\n"
"\tipqosconf -c\n"
"\tipqosconf -l\n"
"\tipqosconf -L\n"
"\tipqosconf -f\n"));
}
int
main(int argc, char *argv[])
{
int c;
char *ifile = NULL;
int args;
int ret;
int cmd;
int viewall = 0;
int lfp;
use_syslog = verbose = 0;
lineno = 0;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
openlog("ipqosconf", 0, LOG_USER);
args = 0;
#ifdef _IPQOS_CONF_DEBUG
#define DBGOPTS "rz:"
#else
#define DBGOPTS
#endif
while ((c = getopt(argc, argv, "sca:vflL" DBGOPTS)) != EOF) {
switch (c) {
#ifdef _IPQOS_CONF_DEBUG
case 'z':
cmd = -1;
ifile = optarg;
if (*ifile == '\0') {
usage();
exit(1);
}
args++;
break;
case 'r':
force_rback++;
break;
#endif
case 'c':
cmd = IPQOS_CONF_COMMIT;
args++;
break;
case 'a':
cmd = IPQOS_CONF_APPLY;
ifile = optarg;
if (*ifile == '\0') {
usage();
exit(1);
}
args++;
break;
case 'f':
cmd = IPQOS_CONF_FLUSH;
args++;
break;
case 'l':
cmd = IPQOS_CONF_VIEW;
args++;
break;
case 'L':
cmd = IPQOS_CONF_VIEW;
viewall++;
args++;
break;
case 'v':
verbose++;
break;
case 's':
use_syslog++;
break;
case '?':
usage();
return (1);
}
}
if (optind != argc || args > 1 ||
use_syslog && cmd != IPQOS_CONF_APPLY ||
verbose && cmd != IPQOS_CONF_APPLY) {
usage();
exit(1);
}
if (args == 0) {
cmd = IPQOS_CONF_VIEW;
}
lfp = lock();
if (lfp == -1) {
exit(1);
}
switch (cmd) {
#ifdef _IPQOS_CONF_DEBUG
case -1:
ret = viewcfile(ifile);
break;
#endif
case IPQOS_CONF_APPLY:
ret = applyconf(ifile);
break;
case IPQOS_CONF_COMMIT:
ret = commitconf();
break;
case IPQOS_CONF_VIEW:
ret = viewconf(viewall);
break;
case IPQOS_CONF_FLUSH:
ret = flushconf();
break;
}
(void) unlock(lfp);
return (ret);
}