aboutsummaryrefslogtreecommitdiff
path: root/net/netfilter/xt_hashlimit.c
diff options
context:
space:
mode:
authorJan Engelhardt <jengelh@medozas.de>2010-03-19 17:32:59 +0100
committerJan Engelhardt <jengelh@medozas.de>2010-03-25 16:56:09 +0100
commit4a5a5c73b7cfee46a0b1411903cfa0dea532deec (patch)
tree3f7ef0def4adf3a01e15ab3a2a7231967b87bfee /net/netfilter/xt_hashlimit.c
parentd6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddc (diff)
netfilter: xtables: slightly better error reporting
When extended status codes are available, such as ENOMEM on failed allocations, or subsequent functions (e.g. nf_ct_get_l3proto), passing them up to userspace seems like a good idea compared to just always EINVAL. Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
Diffstat (limited to 'net/netfilter/xt_hashlimit.c')
-rw-r--r--net/netfilter/xt_hashlimit.c32
1 files changed, 20 insertions, 12 deletions
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 0c0152902b3..c89fde7d123 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -214,7 +214,7 @@ static int htable_create_v0(struct net *net, struct xt_hashlimit_info *minfo, u_
hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) +
sizeof(struct list_head) * size);
if (!hinfo)
- return -1;
+ return -ENOMEM;
minfo->hinfo = hinfo;
/* copy match config into hashtable config */
@@ -250,7 +250,7 @@ static int htable_create_v0(struct net *net, struct xt_hashlimit_info *minfo, u_
&dl_file_ops, hinfo);
if (!hinfo->pde) {
vfree(hinfo);
- return -1;
+ return -ENOMEM;
}
hinfo->net = net;
@@ -285,7 +285,7 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo,
hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) +
sizeof(struct list_head) * size);
if (hinfo == NULL)
- return -1;
+ return -ENOMEM;
minfo->hinfo = hinfo;
/* copy match config into hashtable config */
@@ -311,7 +311,7 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo,
&dl_file_ops, hinfo);
if (hinfo->pde == NULL) {
vfree(hinfo);
- return -1;
+ return -ENOMEM;
}
hinfo->net = net;
@@ -675,13 +675,14 @@ static int hashlimit_mt_check_v0(const struct xt_mtchk_param *par)
{
struct net *net = par->net;
struct xt_hashlimit_info *r = par->matchinfo;
+ int ret;
/* Check for overflow. */
if (r->cfg.burst == 0 ||
user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) {
pr_info("overflow, try lower: %u/%u\n",
r->cfg.avg, r->cfg.burst);
- return -EINVAL;
+ return -ERANGE;
}
if (r->cfg.mode == 0 ||
r->cfg.mode > (XT_HASHLIMIT_HASH_DPT |
@@ -698,9 +699,12 @@ static int hashlimit_mt_check_v0(const struct xt_mtchk_param *par)
mutex_lock(&hashlimit_mutex);
r->hinfo = htable_find_get(net, r->name, par->family);
- if (!r->hinfo && htable_create_v0(net, r, par->family) != 0) {
- mutex_unlock(&hashlimit_mutex);
- return -EINVAL;
+ if (r->hinfo == NULL) {
+ ret = htable_create_v0(net, r, par->family);
+ if (ret < 0) {
+ mutex_unlock(&hashlimit_mutex);
+ return ret;
+ }
}
mutex_unlock(&hashlimit_mutex);
return 0;
@@ -710,6 +714,7 @@ static int hashlimit_mt_check(const struct xt_mtchk_param *par)
{
struct net *net = par->net;
struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
+ int ret;
/* Check for overflow. */
if (info->cfg.burst == 0 ||
@@ -717,7 +722,7 @@ static int hashlimit_mt_check(const struct xt_mtchk_param *par)
user2credits(info->cfg.avg)) {
pr_info("overflow, try lower: %u/%u\n",
info->cfg.avg, info->cfg.burst);
- return -EINVAL;
+ return -ERANGE;
}
if (info->cfg.gc_interval == 0 || info->cfg.expire == 0)
return -EINVAL;
@@ -733,9 +738,12 @@ static int hashlimit_mt_check(const struct xt_mtchk_param *par)
mutex_lock(&hashlimit_mutex);
info->hinfo = htable_find_get(net, info->name, par->family);
- if (!info->hinfo && htable_create(net, info, par->family) != 0) {
- mutex_unlock(&hashlimit_mutex);
- return -EINVAL;
+ if (info->hinfo == NULL) {
+ ret = htable_create(net, info, par->family);
+ if (ret < 0) {
+ mutex_unlock(&hashlimit_mutex);
+ return ret;
+ }
}
mutex_unlock(&hashlimit_mutex);
return 0;