Ejemplo n.º 1
0
static int nbyte_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
			    struct bstr *args)
{
	struct bstr *a;
	struct bstr *needle = args;
	unsigned long offset = 0, layer = TCF_LAYER_NETWORK;
	int offset_present = 0;
	struct tcf_em_nbyte nb;

	memset(&nb, 0, sizeof(nb));

#define PARSE_ERR(CARG, FMT, ARGS...) \
	em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT ,##ARGS)

	if (args == NULL)
		return PARSE_ERR(args, "nbyte: missing arguments");

	if (needle->len <= 0)
		return PARSE_ERR(args, "nbyte: needle length is 0");

	for (a = bstr_next(args); a; a = bstr_next(a)) {
		if (!bstrcmp(a, "at")) {
			if (a->next == NULL)
				return PARSE_ERR(a, "nbyte: missing argument");
			a = bstr_next(a);

			offset = bstrtoul(a);
			if (offset == ULONG_MAX)
				return PARSE_ERR(a, "nbyte: invalid offset, " \
				    "must be numeric");

			offset_present = 1;
		} else if (!bstrcmp(a, "layer")) {
			if (a->next == NULL)
				return PARSE_ERR(a, "nbyte: missing argument");
			a = bstr_next(a);

			layer = parse_layer(a);
			if (layer == INT_MAX) {
				layer = bstrtoul(a);
				if (layer == ULONG_MAX)
					return PARSE_ERR(a, "nbyte: invalid " \
					    "layer");
			}

			if (layer > TCF_LAYER_MAX)
				return PARSE_ERR(a, "nbyte: illegal layer, " \
				    "must be in 0..%d", TCF_LAYER_MAX);
		} else
			return PARSE_ERR(a, "nbyte: unknown parameter");
	}

	if (offset_present == 0)
		return PARSE_ERR(a, "nbyte: offset required");

	nb.len = needle->len;
	nb.layer = (__u8) layer;
	nb.off = (__u16) offset;

	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
	addraw_l(n, MAX_MSG, &nb, sizeof(nb));
	addraw_l(n, MAX_MSG, needle->data, needle->len);

#undef PARSE_ERR
	return 0;
}
Ejemplo n.º 2
0
static int cmp_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
                          struct bstr *args)
{
    struct bstr *a;
    int align, opnd = 0;
    unsigned long offset = 0, layer = TCF_LAYER_NETWORK, mask = 0, value = 0;
    int offset_present = 0, value_present = 0;
    struct tcf_em_cmp cmp;

    memset(&cmp, 0, sizeof(cmp));

#define PARSE_ERR(CARG, FMT, ARGS...) \
	em_parse_error(EINVAL, args, CARG, &cmp_ematch_util, FMT ,##ARGS)

    if (args == NULL)
        return PARSE_ERR(args, "cmp: missing arguments");

    if (!bstrcmp(args, "u8"))
        align = TCF_EM_ALIGN_U8;
    else if (!bstrcmp(args, "u16"))
        align = TCF_EM_ALIGN_U16;
    else if (!bstrcmp(args, "u32"))
        align = TCF_EM_ALIGN_U32;
    else
        return PARSE_ERR(args, "cmp: invalid alignment");

    for (a = bstr_next(args); a; a = bstr_next(a)) {
        if (!bstrcmp(a, "at")) {
            if (a->next == NULL)
                return PARSE_ERR(a, "cmp: missing argument");
            a = bstr_next(a);

            offset = bstrtoul(a);
            if (offset == ULONG_MAX)
                return PARSE_ERR(a, "cmp: invalid offset, " \
                                 "must be numeric");

            offset_present = 1;
        } else if (!bstrcmp(a, "layer")) {
            if (a->next == NULL)
                return PARSE_ERR(a, "cmp: missing argument");
            a = bstr_next(a);

            layer = parse_layer(a);
            if (layer == INT_MAX) {
                layer = bstrtoul(a);
                if (layer == ULONG_MAX)
                    return PARSE_ERR(a, "cmp: invalid " \
                                     "layer");
            }

            if (layer > TCF_LAYER_MAX)
                return PARSE_ERR(a, "cmp: illegal layer, " \
                                 "must be in 0..%d", TCF_LAYER_MAX);
        } else if (!bstrcmp(a, "mask")) {
            if (a->next == NULL)
                return PARSE_ERR(a, "cmp: missing argument");
            a = bstr_next(a);

            mask = bstrtoul(a);
            if (mask == ULONG_MAX)
                return PARSE_ERR(a, "cmp: invalid mask");
        } else if (!bstrcmp(a, "trans")) {
            cmp.flags |= TCF_EM_CMP_TRANS;
        } else if (!bstrcmp(a, "eq") || !bstrcmp(a, "gt") ||
                   !bstrcmp(a, "lt")) {

            if (!bstrcmp(a, "eq"))
                opnd = TCF_EM_OPND_EQ;
            else if (!bstrcmp(a, "gt"))
                opnd = TCF_EM_OPND_GT;
            else if (!bstrcmp(a, "lt"))
                opnd = TCF_EM_OPND_LT;

            if (a->next == NULL)
                return PARSE_ERR(a, "cmp: missing argument");
            a = bstr_next(a);

            value = bstrtoul(a);
            if (value == ULONG_MAX)
                return PARSE_ERR(a, "cmp: invalid value");

            value_present = 1;
        } else
            return PARSE_ERR(a, "nbyte: unknown parameter");
    }

    if (offset_present == 0 || value_present == 0)
        return PARSE_ERR(a, "cmp: offset and value required");

    cmp.val = (__u32) value;
    cmp.mask = (__u32) mask;
    cmp.off = (__u16) offset;
    cmp.align = (__u8) align;
    cmp.layer = (__u8) layer;
    cmp.opnd = (__u8) opnd;

    addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
    addraw_l(n, MAX_MSG, &cmp, sizeof(cmp));

#undef PARSE_ERR
    return 0;
}
static inline struct bstr *
parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
	     unsigned long *dst, struct tcf_meta_val *left)
{
	struct meta_entry *entry;
	unsigned long num;
	struct bstr *a;

	if (arg->quoted) {
		obj->kind = TCF_META_TYPE_VAR << 12;
		obj->kind |= TCF_META_ID_VALUE;
		*dst = (unsigned long) arg;
		return bstr_next(arg);
	}

	num = bstrtoul(arg);
	if (num != ULONG_MAX) {
		obj->kind = TCF_META_TYPE_INT << 12;
		obj->kind |= TCF_META_ID_VALUE;
		*dst = (unsigned long) num;
		return bstr_next(arg);
	}

	entry = lookup_meta_entry(arg);

	if (entry == NULL) {
		PARSE_ERR(arg, "meta: unknown meta id\n");
		return PARSE_FAILURE;
	}

	obj->kind = entry->id | (map_type(entry->mask[0]) << 12);

	if (left) {
		struct tcf_meta_val *right = obj;

		if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind))
			goto compatible;

		if (can_adopt(left) && !can_adopt(right)) {
			if (is_compatible(left, right))
				left->kind = overwrite_type(left, right);
			else
				goto not_compatible;
		} else if (can_adopt(right) && !can_adopt(left)) {
			if (is_compatible(right, left))
				right->kind = overwrite_type(right, left);
			else
				goto not_compatible;
		} else if (can_adopt(left) && can_adopt(right)) {
			if (is_compatible(left, right))
				left->kind = overwrite_type(left, right);
			else if (is_compatible(right, left))
				right->kind = overwrite_type(right, left);
			else
				goto not_compatible;
		} else
			goto not_compatible;
	}

compatible:

	a = bstr_next(arg);

	while(a) {
		if (!bstrcmp(a, "shift")) {
			unsigned long shift;

			if (a->next == NULL) {
				PARSE_ERR(a, "meta: missing argument");
				return PARSE_FAILURE;
			}
			a = bstr_next(a);

			shift = bstrtoul(a);
			if (shift == ULONG_MAX) {
				PARSE_ERR(a, "meta: invalid shift, must " \
				    "be numeric");
				return PARSE_FAILURE;
			}

			obj->shift = (__u8) shift;
			a = bstr_next(a);
		} else if (!bstrcmp(a, "mask")) {
			unsigned long mask;

			if (a->next == NULL) {
				PARSE_ERR(a, "meta: missing argument");
				return PARSE_FAILURE;
			}
			a = bstr_next(a);

			mask = bstrtoul(a);
			if (mask == ULONG_MAX) {
				PARSE_ERR(a, "meta: invalid mask, must be " \
				    "numeric");
				return PARSE_FAILURE;
			}
			*dst = (unsigned long) mask;
			a = bstr_next(a);
		} else
			break;
	}

	return a;

not_compatible:
	PARSE_ERR(arg, "lvalue and rvalue are not compatible.");
	return PARSE_FAILURE;
}
Ejemplo n.º 4
0
static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
			  struct bstr *args)
{
	struct bstr *a;
	int align, nh_len;
	unsigned long key, mask, offmask = 0, offset;
	struct tc_u32_key u_key;

	memset(&u_key, 0, sizeof(u_key));

#define PARSE_ERR(CARG, FMT, ARGS...) \
	em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT ,##ARGS)

	if (args == NULL)
		return PARSE_ERR(args, "u32: missing arguments");

	if (!bstrcmp(args, "u8"))
		align = 1;
	else if (!bstrcmp(args, "u16"))
		align = 2;
	else if (!bstrcmp(args, "u32"))
		align = 4;
	else
		return PARSE_ERR(args, "u32: invalid alignment");

	a = bstr_next(args);
	if (a == NULL)
		return PARSE_ERR(a, "u32: missing key");

	key = bstrtoul(a);
	if (key == ULONG_MAX)
		return PARSE_ERR(a, "u32: invalid key, must be numeric");

	a = bstr_next(a);
	if (a == NULL)
		return PARSE_ERR(a, "u32: missing mask");

	mask = bstrtoul(a);
	if (mask == ULONG_MAX)
		return PARSE_ERR(a, "u32: invalid mask, must be numeric");

	a = bstr_next(a);
	if (a == NULL || bstrcmp(a, "at") != 0)
		return PARSE_ERR(a, "u32: missing \"at\"");

	a = bstr_next(a);
	if (a == NULL)
		return PARSE_ERR(a, "u32: missing offset");

	nh_len = strlen("nexthdr+");
	if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) {
		char buf[a->len - nh_len + 1];
		offmask = -1;
		memcpy(buf, a->data + nh_len, a->len - nh_len);
		offset = strtoul(buf, NULL, 0);
	} else if (!bstrcmp(a, "nexthdr+")) {
		a = bstr_next(a);
		if (a == NULL)
			return PARSE_ERR(a, "u32: missing offset");
		offset = bstrtoul(a);
	} else
		offset = bstrtoul(a);

	if (offset == ULONG_MAX)
		return PARSE_ERR(a, "u32: invalid offset");

	if (a->next)
		return PARSE_ERR(a->next, "u32: unexpected trailer");

	switch (align) {
		case 1:
			if (key > 0xFF)
				return PARSE_ERR(a, "Illegal key (>0xFF)");
			if (mask > 0xFF)
				return PARSE_ERR(a, "Illegal mask (>0xFF)");

			key <<= 24 - ((offset & 3) * 8);
			mask <<= 24 - ((offset & 3) * 8);
			offset &= ~3;
			break;

		case 2:
			if (key > 0xFFFF)
				return PARSE_ERR(a, "Illegal key (>0xFFFF)");
			if (mask > 0xFFFF)
				return PARSE_ERR(a, "Illegal mask (>0xFFFF)");

			if ((offset & 3) == 0) {
				key <<= 16;
				mask <<= 16;
			}
			offset &= ~3;
			break;
	}

	key = htonl(key);
	mask = htonl(mask);

	if (offset % 4)
		return PARSE_ERR(a, "u32: invalid offset alignment, " \
		    "must be aligned to 4.");

	key &= mask;

	u_key.mask = mask;
	u_key.val = key;
	u_key.off = offset;
	u_key.offmask = offmask;

	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
	addraw_l(n, MAX_MSG, &u_key, sizeof(u_key));

#undef PARSE_ERR
	return 0;
}