===================================================================
@@ -214,6 +214,18 @@ dsthash_free(struct xt_hashlimit_htable
}
static void htable_gc(unsigned long htlong);
+static void
+htable_update_cfg(struct xt_hashlimit_htable *hinfo,
+ const struct xt_hashlimit_mtinfo1 *minfo)
+{
+ /* copy match config into hashtable config */
+ memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
+ if (hinfo->cfg.max == 0)
+ hinfo->cfg.max = 8 * hinfo->cfg.size;
+ else if (hinfo->cfg.max < hinfo->cfg.size)
+ hinfo->cfg.max = hinfo->cfg.size;
+}
+
static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo,
u_int8_t family)
{
@@ -239,13 +251,8 @@ static int htable_create(struct net *net
return -ENOMEM;
minfo->hinfo = hinfo;
- /* copy match config into hashtable config */
- memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
hinfo->cfg.size = size;
- if (hinfo->cfg.max == 0)
- hinfo->cfg.max = 8 * hinfo->cfg.size;
- else if (hinfo->cfg.max < hinfo->cfg.size)
- hinfo->cfg.max = hinfo->cfg.size;
+ htable_update_cfg(hinfo, minfo);
for (i = 0; i < hinfo->cfg.size; i++)
INIT_HLIST_HEAD(&hinfo->hash[i]);
@@ -318,6 +325,27 @@ static void htable_gc(unsigned long htlo
add_timer(&ht->timer);
}
+static int
+htable_update(struct xt_hashlimit_mtinfo1 *minfo,
+ u_int8_t family)
+{
+ struct xt_hashlimit_htable *hinfo = minfo->hinfo;
+
+ if (hinfo == NULL)
+ return -ENOENT;
+
+ if (minfo->cfg.size && hinfo->cfg.size != minfo->cfg.size)
+ return -EBUSY;
+ if (hinfo->family != family)
+ return -EBUSY;
+
+ hinfo->use++;
+ htable_update_cfg(hinfo, minfo);
+ htable_selective_cleanup(hinfo, select_all);
+
+ return 0;
+}
+
static void htable_destroy(struct xt_hashlimit_htable *hinfo)
{
struct hashlimit_net *hashlimit_net = hashlimit_pernet(hinfo->net);
@@ -691,20 +719,28 @@ static int hashlimit_mt_check(const stru
info->hinfo = htable_find_get(net, info->name, par->family);
if (info->hinfo == NULL) {
ret = htable_create(net, info, par->family);
- if (ret < 0) {
- mutex_unlock(&hashlimit_mutex);
- return ret;
- }
+ if (ret < 0)
+ goto err_unlock;
+ } else {
+ ret = htable_update(info, par->family);
+ if (ret < 0)
+ goto err_unlock;
}
+
mutex_unlock(&hashlimit_mutex);
return 0;
+
+err_unlock:
+ mutex_unlock(&hashlimit_mutex);
+ return ret;
}
static void hashlimit_mt_destroy(const struct xt_mtdtor_param *par)
{
- const struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
+ struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
htable_put(info->hinfo);
+ info->hinfo = NULL;
}
static struct xt_match hashlimit_mt_reg[] __read_mostly = {