static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
			   struct bstr *args)
{
	int opnd;
	struct bstr *a;
	struct tcf_meta_hdr meta_hdr;
	unsigned long lvalue = 0, rvalue = 0;

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

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

	if (!bstrcmp(args, "list")) {
		list_meta_ids(stderr);
		return -1;
	}

	a = parse_object(args, args, &meta_hdr.left, &lvalue, NULL);
	if (a == PARSE_FAILURE)
		return -1;
	else if (a == NULL)
		return PARSE_ERR(args, "meta: missing operand");

	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;
	else
		return PARSE_ERR(a, "meta: invalid operand");

	meta_hdr.left.op = (__u8) opnd;

	if (a->next == NULL)
		return PARSE_ERR(args, "meta: missing rvalue");
	a = bstr_next(a);

	a = parse_object(args, a, &meta_hdr.right, &rvalue, &meta_hdr.left);
	if (a == PARSE_FAILURE)
		return -1;
	else if (a != NULL)
		return PARSE_ERR(a, "meta: unexpected trailer");


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

	addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr));

	dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
	dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);

	return 0;
}
Beispiel #2
0
static int ipset_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
			    struct bstr *args)
{
	struct xt_set_info set_info = {};
	int ret;

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

	if (args == NULL)
		return PARSE_ERR(args, "ipset: missing set name");

	if (args->len >= IPSET_MAXNAMELEN)
		return PARSE_ERR(args, "ipset: set name too long (max %u)", IPSET_MAXNAMELEN - 1);
	ret = get_set_byname(args->data, &set_info);
	if (ret < 0)
		return PARSE_ERR(args, "ipset: unknown set name '%s'", args->data);

	if (args->next == NULL)
		return PARSE_ERR(args, "ipset: missing set flags");

	args = bstr_next(args);
	if (parse_dirs(args->data, &set_info))
		return PARSE_ERR(args, "ipset: error parsing set flags");

	if (args->next) {
		args = bstr_next(args);
		return PARSE_ERR(args, "ipset: unknown parameter");
	}

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

#undef PARSE_ERR
	return 0;
}
Beispiel #3
0
static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
{
	int index = 1;
	struct ematch *t;

	for (t = tree; t; t = t->next) {
		struct rtattr *tail = NLMSG_TAIL(n);
		struct tcf_ematch_hdr hdr = {
			.flags = t->relation
		};

		if (t->inverted)
			hdr.flags |= TCF_EM_INVERT;

		addattr_l(n, MAX_MSG, index++, NULL, 0);

		if (t->child) {
			__u32 r = t->child_ref;
			addraw_l(n, MAX_MSG, &hdr, sizeof(hdr));
			addraw_l(n, MAX_MSG, &r, sizeof(r));
		} else {
			int num = 0, err;
			char buf[64];
			struct ematch_util *e;

			if (t->args == NULL)
				return -1;

			strncpy(buf, (char*) t->args->data, sizeof(buf)-1);
			e = get_ematch_kind(buf);
			if (e == NULL) {
				fprintf(stderr, "Unknown ematch \"%s\"\n",
				    buf);
				return -1;
			}

			err = lookup_map_id(buf, &num, EMATCH_MAP);
			if (err < 0) {
				if (err == -ENOENT)
					map_warning(e->kind_num, buf);
				return err;
			}

			hdr.kind = num;
			if (e->parse_eopt(n, &hdr, t->args->next) < 0)
				return -1;
		}

		tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail;
	}

	return 0;
}

static int flatten_tree(struct ematch *head, struct ematch *tree)
{
	int i, count = 0;
	struct ematch *t;

	for (;;) {
		count++;

		if (tree->child) {
			for (t = head; t->next; t = t->next);
			t->next = tree->child;
			count += flatten_tree(head, tree->child);
		}

		if (tree->relation == 0)
			break;

		tree = tree->next;
	}

	for (i = 0, t = head; t; t = t->next, i++)
		t->index = i;

	for (t = head; t; t = t->next)
		if (t->child)
			t->child_ref = t->child->index;

	return count;
}
Beispiel #4
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;
}
Beispiel #5
0
/* Add/Delete IP route to/from a specific interface */
static int
netlink_route(ip_route_t *iproute, int cmd)
{
	int status = 1;
	struct {
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[RTM_SIZE];
	} req;
	char buf[RTA_SIZE];
	struct rtattr *rta = (void*)buf;

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

	req.n.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtmsg));
	if (cmd == IPROUTE_DEL) {
		req.n.nlmsg_flags = NLM_F_REQUEST;
		req.n.nlmsg_type  = RTM_DELROUTE;
	}
	else {
		req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
		if (cmd == IPROUTE_REPLACE)
			req.n.nlmsg_flags |= NLM_F_REPLACE;
		req.n.nlmsg_type  = RTM_NEWROUTE;
	}

	rta->rta_type = RTA_METRICS;
	rta->rta_len = RTA_LENGTH(0);

	req.r.rtm_family = iproute->family;
	if (iproute->table < 256)
		req.r.rtm_table = iproute->table;
	else {
		req.r.rtm_table = RT_TABLE_UNSPEC;
		addattr32(&req.n, sizeof(req), RTA_TABLE, iproute->table);
	}

	if (cmd == IPROUTE_DEL) {
		req.r.rtm_scope = RT_SCOPE_NOWHERE;
		if (iproute->mask & IPROUTE_BIT_TYPE)
			req.r.rtm_type = iproute->type;
	}
	else {
		req.r.rtm_protocol = RTPROT_BOOT;
		req.r.rtm_scope = RT_SCOPE_UNIVERSE;
		req.r.rtm_type = iproute->type;
	}

	if (iproute->mask & IPROUTE_BIT_PROTOCOL)
		req.r.rtm_protocol = iproute->protocol;

	if (iproute->mask & IPROUTE_BIT_SCOPE)
		req.r.rtm_scope = iproute->scope;

	if (iproute->dst) {
		req.r.rtm_dst_len = iproute->dst->ifa.ifa_prefixlen;
		add_addr2req(&req.n, sizeof(req), RTA_DST, iproute->dst);
	}

	if (iproute->src) {
		req.r.rtm_src_len = iproute->src->ifa.ifa_prefixlen;
		add_addr2req(&req.n, sizeof(req), RTA_SRC, iproute->src);
	}

	if (iproute->pref_src)
		add_addr2req(&req.n, sizeof(req), RTA_PREFSRC, iproute->pref_src);

//#ifdef _HAVE_RTA_NEWDST_
//	if (iproute->as_to)
//		add_addr2req(&req.n, sizeof(req), RTA_NEWDST, iproute->as_to);
//#endif

	if (iproute->via) {
		if (iproute->via->ifa.ifa_family == iproute->family)
			add_addr2req(&req.n, sizeof(req), RTA_GATEWAY, iproute->via);
#ifdef _HAVE_RTA_VIA_
		else
			add_addr_fam2req(&req.n, sizeof(req), RTA_VIA, iproute->via);
#endif
	}

#ifdef _HAVE_RTA_ENCAP_
	if (iproute->encap.type != LWTUNNEL_ENCAP_NONE) {
		char encap_buf[ENCAP_RTA_SIZE];
		struct rtattr *encap_rta = (void *)encap_buf;

		encap_rta->rta_type = RTA_ENCAP;
		encap_rta->rta_len = RTA_LENGTH(0);
		add_encap(encap_rta, sizeof(encap_buf), &iproute->encap);

		if (encap_rta->rta_len > RTA_LENGTH(0))
			addraw_l(&req.n, sizeof(encap_buf), RTA_DATA(encap_rta), RTA_PAYLOAD(encap_rta));
	}
#endif

	if (iproute->mask & IPROUTE_BIT_DSFIELD)
		req.r.rtm_tos = iproute->tos;
	
	if (iproute->oif)
		addattr32(&req.n, sizeof(req), RTA_OIF, iproute->oif->ifindex);

	if (iproute->mask & IPROUTE_BIT_METRIC)
		addattr32(&req.n, sizeof(req), RTA_PRIORITY, iproute->metric);

	req.r.rtm_flags = iproute->flags;

	if (iproute->realms)
		addattr32(&req.n, sizeof(req), RTA_FLOW, iproute->realms);

#ifdef _HAVE_RTA_EXPIRES_
	if (iproute->mask & IPROUTE_BIT_EXPIRES)
		addattr32(&req.n, sizeof(req), RTA_EXPIRES, iproute->expires);
#endif

#ifdef RTAX_CC_ALGO
	if (iproute->congctl)
		rta_addattr_l(rta, sizeof(buf), RTAX_CC_ALGO, iproute->congctl, strlen(iproute->congctl));
#endif

	if (iproute->mask & IPROUTE_BIT_RTT)
		rta_addattr32(rta, sizeof(buf), RTAX_RTT, iproute->rtt);

	if (iproute->mask & IPROUTE_BIT_RTTVAR)
		rta_addattr32(rta, sizeof(buf), RTAX_RTTVAR, iproute->rttvar);

	if (iproute->mask & IPROUTE_BIT_RTO_MIN)
		rta_addattr32(rta, sizeof(buf), RTAX_RTO_MIN, iproute->rto_min);

#ifdef RTAX_FEATURES
	if (iproute->features)
		rta_addattr32(rta, sizeof(buf), RTAX_FEATURES, iproute->features);
#endif

	if (iproute->mask & IPROUTE_BIT_MTU)
		rta_addattr32(rta, sizeof(buf), RTAX_MTU, iproute->mtu);

	if (iproute->mask & IPROUTE_BIT_WINDOW)
		rta_addattr32(rta, sizeof(buf), RTAX_WINDOW, iproute->window);

	if (iproute->mask & IPROUTE_BIT_SSTHRESH)
		rta_addattr32(rta, sizeof(buf), RTAX_SSTHRESH, iproute->ssthresh);

	if (iproute->mask & IPROUTE_BIT_CWND)
		rta_addattr32(rta, sizeof(buf), RTAX_CWND, iproute->cwnd);

	if (iproute->mask & IPROUTE_BIT_ADVMSS)
		rta_addattr32(rta, sizeof(buf), RTAX_ADVMSS, iproute->advmss);

	if (iproute->mask & IPROUTE_BIT_REORDERING)
		rta_addattr32(rta, sizeof(buf), RTAX_REORDERING, iproute->reordering);

	if (iproute->mask & IPROUTE_BIT_HOPLIMIT)
		rta_addattr32(rta, sizeof(buf), RTAX_HOPLIMIT, iproute->hoplimit);

	if (iproute->mask & IPROUTE_BIT_INITCWND)
		rta_addattr32(rta, sizeof(buf), RTAX_INITCWND, iproute->initcwnd);

#ifdef RTAX_INITRWND
	if (iproute->mask & IPROUTE_BIT_INITRWND)
		rta_addattr32(rta, sizeof(buf), RTAX_INITRWND, iproute->initrwnd);
#endif

#ifdef RTAX_QUICKACK
	if (iproute->mask & IPROUTE_BIT_QUICKACK)
		rta_addattr32(rta, sizeof(buf), RTAX_QUICKACK, iproute->quickack);
#endif

#ifdef _HAVE_RTA_PREF_
	if (iproute->mask & IPROUTE_BIT_PREF)
		addattr8(&req.n, sizeof(req), RTA_PREF, iproute->pref);
#endif

	if (rta->rta_len > RTA_LENGTH(0)) {
		if (iproute->lock)
			rta_addattr32(rta, sizeof(buf), RTAX_LOCK, iproute->lock);
		addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(rta), RTA_PAYLOAD(rta));
	}

	if (!LIST_ISEMPTY(iproute->nhs))
		add_nexthops(iproute, &req.n, &req.r);

#ifdef DEBUG_NETLINK_MSG
	size_t i, j;
	uint8_t *p;
	char lbuf[3072];
	char *op = lbuf;

	log_message(LOG_INFO, "rtmsg buffer used %lu, rtattr buffer used %d", req.n.nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)), rta->rta_len);

	op += snprintf(op, sizeof(lbuf) - (op - lbuf), "nlmsghdr %p(%u):", &req.n, req.n.nlmsg_len);
	for (i = 0, p = (uint8_t*)&req.n; i < sizeof(struct nlmsghdr); i++)
		op += snprintf(op, sizeof(lbuf) - (op - lbuf), " %2.2hhx", *(p++));
	log_message(LOG_INFO, "%s\n", lbuf);

	op = lbuf;
	op += snprintf(op, sizeof(lbuf) - (op - lbuf), "rtmsg %p(%lu):", &req.r, req.n.nlmsg_len - sizeof(struct nlmsghdr));
	for (i = 0, p = (uint8_t*)&req.r; i < + req.n.nlmsg_len - sizeof(struct nlmsghdr); i++)
		op += snprintf(op, sizeof(lbuf) - (op - lbuf), " %2.2hhx", *(p++));

	for (j = 0; lbuf + j < op; j+= MAX_LOG_MSG)
		log_message(LOG_INFO, "%.*\n", MAX_LOG_MSG, lbuf+j);
#endif

	/* This returns ESRCH if the address of via address doesn't exist */
	/* ENETDOWN if dev p33p1.40 for example is down */
	if (netlink_talk(&nl_cmd, &req.n) < 0) {
#ifdef _HAVE_RTA_EXPIRES_
		/* If an expiry was set on the route, it may have disappeared already */
		if (cmd != IPADDRESS_DEL || !(iproute->mask & IPROUTE_BIT_EXPIRES))
#endif
			status = -1;
	}

	return status;
}
Beispiel #6
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 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;
}
Beispiel #8
0
static int canid_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
			  struct bstr *args)
{
	int iseff = 0;
	int ret = 0;
	struct rules rules = {
		.rules_capacity = 25, /* Denominator of EM_CANID_RULES_MAX
			Will be multiplied by 2 to calculate the size for realloc() */
		.rules_cnt = 0
	};

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

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

	rules.rules_raw = malloc(sizeof(struct can_filter) * rules.rules_capacity);
	memset(rules.rules_raw, 0, sizeof(struct can_filter) * rules.rules_capacity);

	do {
		if (!bstrcmp(args, "sff")) {
			iseff = 0;
		} else if (!bstrcmp(args, "eff")) {
			iseff = 1;
		} else {
			ret = PARSE_ERR(args, "canid: invalid key");
			goto exit;
		}

		args = bstr_next(args);
		if (args == NULL) {
			ret = PARSE_ERR(args, "canid: missing argument");
			goto exit;
		}

		ret = canid_parse_rule(&rules, args, iseff);
		if (ret == -1) {
			ret = PARSE_ERR(args, "canid: Improperly formed CAN ID & mask\n");
			goto exit;
		} else if (ret == -2) {
			ret = PARSE_ERR(args, "canid: Too many arguments on input\n");
			goto exit;
		}
	} while ((args = bstr_next(args)) != NULL);

	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
	addraw_l(n, MAX_MSG, rules.rules_raw,
		sizeof(struct can_filter) * rules.rules_cnt);

#undef PARSE_ERR
exit:
	free(rules.rules_raw);
	return ret;
}

static int canid_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
			  int data_len)
{
	struct can_filter *conf = data; /* Array with rules */
	int rules_count;
	int i;

	rules_count = data_len / sizeof(struct can_filter);

	for (i = 0; i < rules_count; i++) {
		struct can_filter *pcfltr = &conf[i];

		if (pcfltr->can_id & CAN_EFF_FLAG) {
			if (pcfltr->can_mask == (CAN_EFF_FLAG | CAN_EFF_MASK))
				fprintf(fd, "eff 0x%"PRIX32,
						pcfltr->can_id & CAN_EFF_MASK);
			else
				fprintf(fd, "eff 0x%"PRIX32":0x%"PRIX32,
						pcfltr->can_id & CAN_EFF_MASK,
						pcfltr->can_mask & CAN_EFF_MASK);
		} else {
			if (pcfltr->can_mask == (CAN_EFF_FLAG | CAN_SFF_MASK))
				fprintf(fd, "sff 0x%"PRIX32,
						pcfltr->can_id & CAN_SFF_MASK);
			else
				fprintf(fd, "sff 0x%"PRIX32":0x%"PRIX32,
						pcfltr->can_id & CAN_SFF_MASK,
						pcfltr->can_mask & CAN_SFF_MASK);
		}

		if ((i + 1) < rules_count)
			fprintf(fd, " ");
	}

	return 0;
}

struct ematch_util canid_ematch_util = {
	.kind = "canid",
	.kind_num = TCF_EM_CANID,
	.parse_eopt = canid_parse_eopt,
	.print_eopt = canid_print_eopt,
	.print_usage = canid_print_usage
};