static int
bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
	struct bitmap_ipmac *map = set->data;
	const struct ipmac *data = value;
	struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);

	switch (elem->match) {
	case MAC_UNSET:
		if (!data->ether)
			/* Already added without ethernet address */
			return -IPSET_ERR_EXIST;
		/* Fill the MAC address */
		memcpy(elem->ether, data->ether, ETH_ALEN);
		elem->match = MAC_FILLED;
		break;
	case MAC_FILLED:
		return -IPSET_ERR_EXIST;
	case MAC_EMPTY:
		if (data->ether) {
			memcpy(elem->ether, data->ether, ETH_ALEN);
			elem->match = MAC_FILLED;
		} else
			elem->match = MAC_UNSET;
	}

	return 0;
}
static inline bool
bitmap_expired(const struct bitmap_ipmac *map, u32 id)
{
	const struct ipmac_telem *elem = bitmap_ipmac_elem(map, id);

	return ip_set_timeout_expired(elem->timeout);
}
Ejemplo n.º 3
0
static int
bitmap_ipmac_tlist(const struct ip_set *set,
		   struct sk_buff *skb, struct netlink_callback *cb)
{
	const struct bitmap_ipmac *map = set->data;
	const struct ipmac_telem *elem;
	struct nlattr *atd, *nested;
	u32 id, first = cb->args[2];
	u32 timeout, last = map->last_ip - map->first_ip;

	atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
	if (!atd)
		return -EMSGSIZE;
	for (; cb->args[2] <= last; cb->args[2]++) {
		id = cb->args[2];
		elem = bitmap_ipmac_elem(map, id);
		if (!bitmap_ipmac_exist(elem))
			continue;
		nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
		if (!nested) {
			if (id == first) {
				nla_nest_cancel(skb, atd);
				return -EMSGSIZE;
			} else
				goto nla_put_failure;
		}
		if (nla_put_ipaddr4(skb, IPSET_ATTR_IP,
				    htonl(map->first_ip + id)) ||
		    (elem->match == MAC_FILLED &&
		     nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN,
			     elem->ether)))
			goto nla_put_failure;
		timeout = elem->match == MAC_UNSET ? elem->timeout
				: ip_set_timeout_get(elem->timeout);
		if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(timeout)))
			goto nla_put_failure;
		ipset_nest_end(skb, nested);
	}
	ipset_nest_end(skb, atd);
	/* Set listing finished */
	cb->args[2] = 0;

	return 0;

nla_put_failure:
	nla_nest_cancel(skb, nested);
	ipset_nest_end(skb, atd);
	if (unlikely(id == first)) {
		cb->args[2] = 0;
		return -EMSGSIZE;
	}
	return 0;
}
static int
bitmap_ipmac_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
	struct bitmap_ipmac *map = set->data;
	const struct ipmac *data = value;
	struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);

	if (elem->match == MAC_EMPTY || bitmap_expired(map, data->id))
		return -IPSET_ERR_EXIST;

	elem->match = MAC_EMPTY;

	return 0;
}
static int
bitmap_ipmac_list(const struct ip_set *set,
		  struct sk_buff *skb, struct netlink_callback *cb)
{
	const struct bitmap_ipmac *map = set->data;
	const struct ipmac_elem *elem;
	struct nlattr *atd, *nested;
	u32 id, first = cb->args[2];
	u32 last = map->last_ip - map->first_ip;

	atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
	if (!atd)
		return -EMSGSIZE;
	for (; cb->args[2] <= last; cb->args[2]++) {
		id = cb->args[2];
		elem = bitmap_ipmac_elem(map, id);
		if (elem->match == MAC_EMPTY)
			continue;
		nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
		if (!nested) {
			if (id == first) {
				nla_nest_cancel(skb, atd);
				return -EMSGSIZE;
			} else
				goto nla_put_failure;
		}
		NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
				htonl(map->first_ip + id));
		if (elem->match == MAC_FILLED)
			NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN,
				elem->ether);
		ipset_nest_end(skb, nested);
	}
	ipset_nest_end(skb, atd);
	/* Set listing finished */
	cb->args[2] = 0;

	return 0;

nla_put_failure:
	nla_nest_cancel(skb, nested);
	ipset_nest_end(skb, atd);
	if (unlikely(id == first)) {
		cb->args[2] = 0;
		return -EMSGSIZE;
	}
	return 0;
}
static int
bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
	const struct bitmap_ipmac *map = set->data;
	const struct ipmac *data = value;
	const struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);

	switch (elem->match) {
	case MAC_UNSET:
		/* Trigger kernel to fill out the ethernet address */
		return -EAGAIN;
	case MAC_FILLED:
		return data->ether == NULL ||
		       ether_addr_equal(data->ether, elem->ether);
	}
	return 0;
}
Ejemplo n.º 7
0
static int
bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout)
{
	const struct bitmap_ipmac *map = set->data;
	const struct ipmac *data = value;
	const struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);

	switch (elem->match) {
	case MAC_UNSET:
		/* Trigger kernel to fill out the ethernet address */
		return -EAGAIN;
	case MAC_FILLED:
		return (data->ether == NULL ||
			compare_ether_addr(data->ether, elem->ether) == 0) &&
		       !bitmap_expired(map, data->id);
	}
	return 0;
}
static int
bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
	struct bitmap_ipmac *map = set->data;
	const struct ipmac *data = value;
	struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
	bool flag_exist = flags & IPSET_FLAG_EXIST;

	switch (elem->match) {
	case MAC_UNSET:
		if (!(data->ether || flag_exist))
			/* Already added without ethernet address */
			return -IPSET_ERR_EXIST;
		/* Fill the MAC address and activate the timer */
		memcpy(elem->ether, data->ether, ETH_ALEN);
		elem->match = MAC_FILLED;
		if (timeout == map->timeout)
			/* Timeout was not specified, get stored one */
			timeout = elem->timeout;
		elem->timeout = ip_set_timeout_set(timeout);
		break;
	case MAC_FILLED:
		if (!(bitmap_expired(map, data->id) || flag_exist))
			return -IPSET_ERR_EXIST;
		/* Fall through */
	case MAC_EMPTY:
		if (data->ether) {
			memcpy(elem->ether, data->ether, ETH_ALEN);
			elem->match = MAC_FILLED;
		} else
			elem->match = MAC_UNSET;
		/* If MAC is unset yet, we store plain timeout value
		 * because the timer is not activated yet
		 * and we can reuse it later when MAC is filled out,
		 * possibly by the kernel */
		elem->timeout = data->ether ? ip_set_timeout_set(timeout)
					    : timeout;
		break;
	}

	return 0;
}
static void
bitmap_ipmac_gc(unsigned long ul_set)
{
	struct ip_set *set = (struct ip_set *) ul_set;
	struct bitmap_ipmac *map = set->data;
	struct ipmac_telem *elem;
	u32 id, last = map->last_ip - map->first_ip;

	/* We run parallel with other readers (test element)
	 * but adding/deleting new entries is locked out */
	read_lock_bh(&set->lock);
	for (id = 0; id <= last; id++) {
		elem = bitmap_ipmac_elem(map, id);
		if (elem->match == MAC_FILLED &&
		    ip_set_timeout_expired(elem->timeout))
			elem->match = MAC_EMPTY;
	}
	read_unlock_bh(&set->lock);

	map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
	add_timer(&map->gc);
}