#include "missing.h" #define IPFW_INTERNAL #include #include "hashtable.h" #define IPFW_NEWTABLES_MAX 256 struct t_o { /* Object stored in the hash table */ uint32_t addr; uint32_t value; uint8_t mask; }; MALLOC_DEFINE(M_IPFW_HTBL, "ipfw_tbl", "IpFw tables"); int add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, uint8_t mlen, uint32_t value); int new_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr); int del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, uint8_t mlen); int new_flush_table(struct ip_fw_chain *ch, uint16_t tbl); int flush_table(struct ip_fw_chain *ch, uint16_t tbl); int lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, uint32_t *val); int new_count_table_entry(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt); int count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt); int new_dump_table_entry(struct ip_fw_chain *ch, ipfw_table *tbl); int dump_table(struct ip_fw_chain *ch, ipfw_table *tbl); int init_tables(struct ip_fw_chain *ch); /* hash and compare functions for 32-bit entries */ static uint32_t simple_hash32(const void *key, uint32_t size) { uint32_t ret = *(const uint32_t *)key % size; return ret; } static int cmp_func32(const void *key1, const void *key2, int sz) { int k1 = *(const int *)key1; int k2 = *(const int *)key2; int ret; if (k1 < k2) ret = -1; else if (k1 > k2) ret = 1; else ret = 0; return ret; } int add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, uint8_t mlen, uint32_t value) { /* TODO: * - Search the correct hash table (tbl - IPFW_TABLES_MAX) * - Search if the entry already exists * - Insert the new entry in the table * - Possibly reallocate the table if it is too small */ struct t_o obj; int ret; int i = tbl - IPFW_TABLES_MAX; int size = 128; int obj_size = sizeof(struct t_o); if (i < 0 || i > size-1) /* wrong table number */ return 1; if (ch->global_tables[i] == NULL) { ch->global_tables[i] = new_table_init(size, obj_size, simple_hash32, cmp_func32, M_IPFW_HTBL); } obj.addr = addr; obj.value = value; obj.mask = mlen; /* Insert the object in the table */ ret = new_table_insert_obj(ch->global_tables[i], &obj); return ret; } int new_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr) { int ret; int nr = tbl - IPFW_TABLES_MAX; ret = new_table_delete_obj(ch->global_tables[nr], &addr); return ret; } int del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, uint8_t mlen) { if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) { new_del_table_entry(ch, tbl, addr); return 0; } return (EINVAL); } int new_flush_table(struct ip_fw_chain *ch, uint16_t tbl) { new_table_destroy(ch->global_tables[tbl - IPFW_TABLES_MAX]); return 0; } int flush_table(struct ip_fw_chain *ch, uint16_t tbl) { if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) return new_flush_table(ch, tbl); return (EINVAL); } int lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, uint32_t *val) { if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) { struct new_hash_table *h; const struct t_o *obj; h = ch->global_tables[tbl - IPFW_TABLES_MAX]; obj = new_table_extract_obj(h, (void *)&addr); if (obj == NULL) return 0; /* no match */ *val = obj->value; return 1; /* match */ } return 0; } int new_count_table_entry(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt) { *cnt = new_table_get_element(ch->global_tables[tbl - IPFW_TABLES_MAX]); return 0; } int count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt) { if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) { new_count_table_entry(ch, tbl, cnt); return (0); } return (EINVAL); } int new_dump_table_entry(struct ip_fw_chain *ch, ipfw_table *tbl) { /* fill the tbl with all entryes */ ipfw_table_entry *ent; const struct t_o *obj; int i; int n_el; int nr = tbl->tbl - IPFW_TABLES_MAX; struct new_hash_table *t = ch->global_tables[nr]; i = 0; tbl->cnt = 0; /* XXX determine tbl->size */ n_el = new_table_get_element(t); obj = NULL; for (; n_el > 0; n_el--) { obj = table_next(t, obj); if (obj == NULL) break; ent = &tbl->ent[tbl->cnt]; ent->addr = obj->addr; ent->value = obj->value; ent->masklen = obj->mask; tbl->cnt++; } return 0; } int dump_table(struct ip_fw_chain *ch, ipfw_table *tbl) { if (tbl->tbl >= IPFW_TABLES_MAX && tbl->tbl < IPFW_NEWTABLES_MAX) { new_dump_table_entry(ch, tbl); return (0); } return (EINVAL); } int init_tables(struct ip_fw_chain *ch) { int i; /* Initialize new tables XXXMPD */ for (i = 0; i < IPFW_NEWTABLES_MAX - IPFW_TABLES_MAX; i++) { memset(&ch->global_tables[i], sizeof(struct new_hash_table*), 0); } return (0); }