/*- * Copyright (c) 2005 Andrey Simonenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #ifndef lint static const char rcsid[] ATTR_UNUSED = "@(#)$Id: ipastat_limits.c,v 1.1.4.2 2007/05/11 16:29:59 simon Exp $"; #endif /* !lint */ #include #include #include #include #include "ipa_mod.h" #include "dlapi.h" #include "confcommon.h" #include "memfunc.h" #include "ipastat_log.h" #include "ipastat_main.h" #include "ipastat_rules.h" #include "ipastat_st.h" int has_opt_limits = 0; /* 1, if -q ... -l ... */ #ifdef WITH_LIMITS int dynamic_limits = -1; /* dynamic_limits parameter. */ ipa_mzone *limit_mzone; /* Mzone for struct limit{}. */ struct limit * alloc_limit(void) { struct limit *limit; if ( (limit = mzone_alloc(limit_mzone)) == NULL) { xlogmsgx(IPA_LOG_ERR, "alloc_limit: mzone_alloc failed"); return NULL; } limit->limit_info = NULL; limit->st_list = NULL; limit->inited = 0; return limit; } /* * Return pointer to limit with the given name. */ struct limit * limit_by_name(const struct rule *rule, const char *name) { struct limit *limit; STAILQ_FOREACH(limit, &rule->limits, link) if (strcmp(name, limit->limit_name) == 0) return limit; return NULL; } static void get_min_max_no( const struct opt_limits *opt_limits, u_int *minno, u_int *maxno) { const struct limit *limit; const struct opt_limit *opt_limit; *minno = *maxno = STAILQ_FIRST(opt_limits)->limit->limitno; STAILQ_FOREACH(opt_limit, opt_limits, link) { limit = opt_limit->limit; if (*minno > limit->limitno) *minno = limit->limitno; if (*maxno < limit->limitno) *maxno = limit->limitno; } } /* * Init all limits from one rule in modules. */ int init_limits(const struct opt_rule *opt_rule) { u_int minno, maxno, no; struct limit *limit; const struct rule *rule; const struct opt_limit *opt_limit; const struct opt_limits *opt_limits; rule = opt_rule->rule; opt_limits = &opt_rule->opt_limits; get_min_max_no(opt_limits, &minno, &maxno); for (no = minno; no <= maxno; ++no) STAILQ_FOREACH(opt_limit, &opt_rule->opt_limits, link) { limit = opt_limit->limit; if (limit->limitno == no) { if (!limit->inited) { limit->inited = 1; /* Init in modules. */ if (st_init_limit(rule, limit) < 0) { logmsgx(IPA_LOG_ERR, "rule %s, limit %s: init_limits: st_init_limit failed", rule->rule_name, limit->limit_name); return -1; } } break; } } return 0; } int deinit_limits(const struct opt_rule *opt_rule) { int error = 0; u_int minno, maxno, no; struct limit *limit; const struct rule *rule; const struct opt_limit *opt_limit; const struct opt_limits *opt_limits; rule = opt_rule->rule; opt_limits = &opt_rule->opt_limits; get_min_max_no(opt_limits, &minno, &maxno); for (no = minno; no <= maxno; ++no) STAILQ_FOREACH(opt_limit, &opt_rule->opt_limits, link) { limit = opt_limit->limit; if (limit->limitno == no) { if (limit->inited) { limit->inited = 0; /* Deinit in modules. */ if (st_deinit_limit(rule, limit) < 0) { logmsgx(IPA_LOG_ERR, "rule %s, limit %s: deinit_limits: st_deinit_limit failed", rule->rule_name, limit->limit_name); error = -1; } } break; } } return error; } /* * Copy all limits from list_src to rule. */ int copy_limits(struct rule *rule, const struct limits_list *list_src) { struct limit *limit_dst; const struct limit *limit_src; STAILQ_FOREACH(limit_src, list_src, link) { if ( (limit_dst = mzone_alloc(limit_mzone)) == NULL) { xlogmsgx(IPA_LOG_ERR, "copy_limits: mzone_alloc failed"); return -1; } /* Copy settings from source limit. */ *limit_dst = *limit_src; limit_dst->free_mask = 0; /* Link just allocated limit to rule. */ STAILQ_INSERT_TAIL(&rule->limits, limit_dst, link); } return 0; } /* * Release memory used by a list of limits. */ void free_limits(struct limits_list *limits) { struct limit *limit, *limit_next; for (limit = STAILQ_FIRST(limits); limit != NULL; limit = limit_next) { limit_next = STAILQ_NEXT(limit, link); if (limit->free_mask & LIMIT_FREE_NAME) mem_free(limit->limit_name, m_anon); mem_free(limit->limit_info, m_result); mzone_free(limit_mzone, limit); } } /* * Add one optional limit given in the -q -r option. */ int add_opt_limit(const char *limit_name) { struct opt_limit *opt_limit; if ( (opt_limit = mem_malloc(sizeof *opt_limit, m_anon)) == NULL) { logmsgx(IPA_LOG_ERR, "add_opt_limit: mem_malloc failed"); return -1; } opt_limit->limit_name = limit_name; opt_limit->opt_st = cur_opt_st; opt_limit->data = NULL; cur_opt_rule->type = OPT_RULE_LIMIT; STAILQ_INSERT_TAIL(&cur_opt_rule->opt_limits, opt_limit, link); has_opt_limits = 1; return 0; } int parse_opt_limits(const struct opt_rule *opt_rule) { u_int limitno; struct rule *rule; struct limit *limit; struct opt_limit *opt_limit; if (!STAILQ_EMPTY(&opt_rule->opt_limits)) { rule = opt_rule->rule; if (STAILQ_EMPTY(&rule->limits)) limitno = 0; else { limit = STAILQ_LAST(&rule->limits, limit, link); limitno = limit->limitno + 1; } STAILQ_FOREACH(opt_limit, &opt_rule->opt_limits, link) { if ( (limit = limit_by_name(rule, opt_limit->limit_name)) == NULL) { /* This limit is not given in the configuration file. */ if (!dynamic_limits) { logmsgx(IPA_LOG_ERR, "parse_opt_limits: unknown rule %s, limit %s", rule->rule_name, opt_limit->limit_name); return -1; } if ( (limit = alloc_limit()) == NULL) { logmsgx(IPA_LOG_ERR, "parse_opt_limits: alloc_limit failed"); return -1; } STAILQ_INSERT_TAIL(&rule->limits, limit, link); limit->limitno = limitno++; limit->limit_name = (char *)opt_limit->limit_name; limit->free_mask = 0; } opt_limit->limit = limit; if (opt_limit->opt_st != NULL) limit->st_list = opt_limit->opt_st->st_list; if (limit->st_list == NULL) limit->st_list = rule->st_list; } } return 0; } void free_opt_limits(const struct opt_limits *opt_limits) { struct opt_limit *opt_limit, *opt_limit_next; for (opt_limit = STAILQ_FIRST(opt_limits); opt_limit != NULL; opt_limit = opt_limit_next) { opt_limit_next = STAILQ_NEXT(opt_limit, link); mem_free(opt_limit, m_anon); } } #endif /* WITH_LIMITS */