]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
netlink: handle concat expressions in set data
authorPatrick McHardy <kaber@trash.net>
Sun, 12 Apr 2015 20:10:42 +0000 (21:10 +0100)
committerPatrick McHardy <kaber@trash.net>
Tue, 2 Jun 2015 11:04:00 +0000 (13:04 +0200)
Reconstruct the concat expressions in set data by splicing off the
subtype values based on the keytype of the set.

Signed-off-by: Patrick McHardy
src/datatype.c
src/netlink.c

index a06a58e20abc5d5018541a70ae13691d0415aeb3..ca834263510ca8c7c3b1bda6707865e68cfae167 100644 (file)
@@ -932,7 +932,7 @@ const struct datatype *concat_type_alloc(uint32_t type)
        unsigned int size = 0, subtypes = 0, n;
 
        n = div_round_up(fls(type), TYPE_BITS);
-       while (concat_subtype_id(type, --n)) {
+       while (n > 0 && concat_subtype_id(type, --n)) {
                i = concat_subtype_lookup(type, n);
                if (i == NULL)
                        return NULL;
index 3369d22312b91c7a6d0aa05617e8711adc2b53e0..1167c9516ad19c77775c74cc010bc8789b356349 100644 (file)
@@ -1383,6 +1383,36 @@ static int netlink_del_setelems_compat(struct netlink_ctx *ctx,
        return err;
 }
 
+static struct expr *netlink_parse_concat_elem(const struct datatype *dtype,
+                                             struct expr *data)
+{
+       const struct datatype *subtype;
+       struct expr *concat, *expr;
+       int off = dtype->subtypes;
+
+       concat = concat_expr_alloc(&data->location);
+       while (off > 0) {
+               subtype = concat_subtype_lookup(dtype->type, --off);
+
+               expr            = constant_expr_splice(data, subtype->size);
+               expr->dtype     = subtype;
+               expr->byteorder = subtype->byteorder;
+
+               if (expr->byteorder == BYTEORDER_HOST_ENDIAN)
+                       mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+
+               if (expr->dtype->basetype != NULL &&
+                   expr->dtype->basetype->type == TYPE_BITMASK)
+                       expr = bitmask_expr_to_binops(expr);
+
+               compound_expr_add(concat, expr);
+               data->len -= netlink_padding_len(expr->len);
+       }
+       expr_free(data);
+
+       return concat;
+}
+
 static int netlink_delinearize_setelem(struct nft_set_elem *nlse,
                                       struct set *set)
 {
@@ -1398,6 +1428,8 @@ static int netlink_delinearize_setelem(struct nft_set_elem *nlse,
        key = netlink_alloc_value(&netlink_location, &nld);
        key->dtype      = set->keytype;
        key->byteorder  = set->keytype->byteorder;
+       if (set->keytype->subtypes)
+               key = netlink_parse_concat_elem(set->keytype, key);
 
        if (!(set->flags & SET_F_INTERVAL) &&
            key->byteorder == BYTEORDER_HOST_ENDIAN)