static int list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext, struct ip_set_ext *mext, u32 flags) { struct list_set *map = set->data; struct set_adt_elem *d = value; struct set_elem *e; u32 i; for (i = 0; i < map->size; i++) { e = list_set_elem(set, map, i); if (e->id == IPSET_INVALID_ID) return d->before != 0 ? -IPSET_ERR_REF_EXIST : -IPSET_ERR_EXIST; else if (SET_WITH_TIMEOUT(set) && ip_set_timeout_expired(ext_timeout(e, set))) continue; else if (e->id != d->id) continue; if (d->before == 0) return list_set_del(set, i); else if (d->before > 0) { if (!id_eq(set, i + 1, d->refid)) return -IPSET_ERR_REF_EXIST; return list_set_del(set, i); } else if (i == 0 || !id_eq(set, i - 1, d->refid)) return -IPSET_ERR_REF_EXIST; else return list_set_del(set, i); } return -IPSET_ERR_EXIST; }
static void cleanup_entries(struct list_set *map) { struct set_telem *e; u32 i; for (i = 0; i < map->size; i++) { e = list_set_telem(map, i); if (e->id != IPSET_INVALID_ID && list_set_expired(map, i)) list_set_del(map, i); } }
static void set_cleanup_entries(struct ip_set *set) { struct list_set *map = set->data; struct set_elem *e; u32 i = 0; while (i < map->size) { e = list_set_elem(set, map, i); if (e->id != IPSET_INVALID_ID && ip_set_timeout_expired(ext_timeout(e, set))) list_set_del(set, i); /* Check element moved to position i in next loop */ else i++; } }
static int list_set_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { struct list_set *map = set->data; bool with_timeout = with_timeout(map->timeout); bool flag_exist = flags & IPSET_FLAG_EXIST; int before = 0; u32 timeout = map->timeout; ip_set_id_t id, refid = IPSET_INVALID_ID; const struct set_elem *elem; struct ip_set *s; u32 i; int ret = 0; if (unlikely(!tb[IPSET_ATTR_NAME] || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s); if (id == IPSET_INVALID_ID) return -IPSET_ERR_NAME; /* "Loop detection" */ if (s->type->features & IPSET_TYPE_NAME) { ret = -IPSET_ERR_LOOP; goto finish; } if (tb[IPSET_ATTR_CADT_FLAGS]) { u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); before = f & IPSET_FLAG_BEFORE; } if (before && !tb[IPSET_ATTR_NAMEREF]) { ret = -IPSET_ERR_BEFORE; goto finish; } if (tb[IPSET_ATTR_NAMEREF]) { refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]), &s); if (refid == IPSET_INVALID_ID) { ret = -IPSET_ERR_NAMEREF; goto finish; } if (!before) before = -1; } if (tb[IPSET_ATTR_TIMEOUT]) { if (!with_timeout) { ret = -IPSET_ERR_TIMEOUT; goto finish; } timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } if (with_timeout && adt != IPSET_TEST) cleanup_entries(map); switch (adt) { case IPSET_TEST: for (i = 0; i < map->size && !ret; i++) { elem = list_set_elem(map, i); if (elem->id == IPSET_INVALID_ID || (before != 0 && i + 1 >= map->size)) break; else if (with_timeout && list_set_expired(map, i)) continue; else if (before > 0 && elem->id == id) ret = id_eq_timeout(map, i + 1, refid); else if (before < 0 && elem->id == refid) ret = id_eq_timeout(map, i + 1, id); else if (before == 0 && elem->id == id) ret = 1; } break; case IPSET_ADD: for (i = 0; i < map->size; i++) { elem = list_set_elem(map, i); if (elem->id != id) continue; if (!(with_timeout && flag_exist)) { ret = -IPSET_ERR_EXIST; goto finish; } else { struct set_telem *e = list_set_telem(map, i); if ((before > 1 && !id_eq(map, i + 1, refid)) || (before < 0 && (i == 0 || !id_eq(map, i - 1, refid)))) { ret = -IPSET_ERR_EXIST; goto finish; } e->timeout = ip_set_timeout_set(timeout); ip_set_put_byindex(id); ret = 0; goto finish; } } ret = -IPSET_ERR_LIST_FULL; for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) { elem = list_set_elem(map, i); if (elem->id == IPSET_INVALID_ID) ret = before != 0 ? -IPSET_ERR_REF_EXIST : list_set_add(map, i, id, timeout); else if (elem->id != refid) continue; else if (before > 0) ret = list_set_add(map, i, id, timeout); else if (i + 1 < map->size) ret = list_set_add(map, i + 1, id, timeout); } break; case IPSET_DEL: ret = -IPSET_ERR_EXIST; for (i = 0; i < map->size && ret == -IPSET_ERR_EXIST; i++) { elem = list_set_elem(map, i); if (elem->id == IPSET_INVALID_ID) { ret = before != 0 ? -IPSET_ERR_REF_EXIST : -IPSET_ERR_EXIST; break; } else if (elem->id == id && (before == 0 || (before > 0 && id_eq(map, i + 1, refid)))) ret = list_set_del(map, i); else if (elem->id == refid && before < 0 && id_eq(map, i + 1, id)) ret = list_set_del(map, i + 1); } break; default: break; } finish: if (refid != IPSET_INVALID_ID) ip_set_put_byindex(refid); if (adt != IPSET_ADD || ret) ip_set_put_byindex(id); return ip_set_eexist(ret, flags) ? 0 : ret; }