예제 #1
0
파일: htab.c 프로젝트: gilmarion/pennmush
/** Resize a hash table.
 * \param htab pointer to hashtable.
 * \param primesize new size.
 * \param seed_index Index of first hash seed to use
 */
static bool
hash_resize(HASHTAB *htab, int newsize, int hashseed_offset)
{
  struct hash_bucket *oldarr;
  int oldsize, oldoffset, i;

  /* Massive overkill here */
  if (resize_calls > 150) {
    do_rawlog(LT_ERR, "Ooops. Too many attempts to resize a hash table.");
    return false;
  }

  /* If all possible hash function combos have been exhausted,
     grow the array */
  if (hashseed_offset == first_offset) {
    int newersize = next_prime_after(floor(newsize * 1.15));
    first_offset = -1;
    return hash_resize(htab, newersize, hashseed_offset);
  }

  resize_calls += 1;

  /* Save the old data we need */
  oldsize = htab->hashsize;
  oldoffset = htab->hashseed_offset;
  oldarr = htab->buckets;

  htab->buckets =
    mush_calloc(newsize, sizeof(struct hash_bucket), "hash.buckets");
  htab->hashsize = newsize;
  htab->hashseed_offset = hashseed_offset;
  for (i = 0; i < oldsize; i++) {
    if (oldarr[i].key) {
      if (!hash_insert(htab, oldarr[i].key, oldarr[i].keylen, oldarr[i].data)) {
        /* Couldn't fit an element in. Try with different hash functions. */
        mush_free(htab->buckets, "hash.buckets");
        htab->buckets = oldarr;
        htab->hashsize = oldsize;
        htab->hashseed_offset = oldoffset;
        if (first_offset == -1)
          first_offset = hashseed_offset;
        return hash_resize(htab, newsize, (hashseed_offset + 1) % NHASH_MOD);
      }
    }
  }

  mush_free(oldarr, "hash.buckets");
  return true;
}
bool hash_del(atom_p obj, const char* key) {
	assert(obj->type == T_OBJ || obj->type == T_ENV);
	
	uint32_t hash = fnv1a(key);
	size_t index = hash % obj->obj.cap;
	
	while ( !(obj->obj.slots[index].key == OBJ_SLOT_FREE) ) {
		if ( obj->obj.slots[index].hash == hash && strcmp(obj->obj.slots[index].key, key) == 0 ) {
			obj->obj.slots[index].hash = 0;
			obj->obj.slots[index].key = OBJ_SLOT_DELETED;
			obj->obj.slots[index].value = NULL;
			
			obj->obj.len--;
			obj->obj.deleted++;
			
			if (obj->obj.len < obj->obj.cap * 0.2)
				hash_resize(obj, obj->obj.cap / 2);
			
			return true;
		}
		
		index = (index + 1) % obj->obj.cap;
	}
	
	return false;
}
예제 #3
0
int hcfg_deserialize(hcfg_t *cfg, char *buf)
{
    int count, total;
    unsigned int i, kcount, logsize;
    const char *key, *val;

    if (sscanf(buf, " hcfg:%u %u%n", &kcount, &logsize, &count) < 2)
        goto invalid;
    total = count;

    if (hash_resize(cfg, logsize) < 0)
        goto error;

    for (i = 0; i < kcount; ++i) {
        count = scanstr_serial(&key, buf + total);
        if (count < 0) goto invalid;
        total += count;

        count = scanstr_serial(&val, buf + total);
        if (count < 0) goto invalid;
        total += count;

        if (hcfg_set(cfg, key, val) < 0)
            goto error;
    }
    return total;

  invalid:
    errno = EINVAL;
  error:
    return -1;
}
예제 #4
0
/* create a hashtable using the given function and 
   comparator */
void hash_create(gc_type *gc, hash_fn fn,
                 hash_cmp cmp, hashtable_type **ret) {
    
    hash_internal_type *table = 0;
    
    /* register the hashtable type with the gc */
    if(!hashtable_type_def) {
        hashtable_type_def = register_hashtable(gc);
        key_value_type_def = register_key_value(gc);
    }
    
    gc_register_root(gc, (void**)&table);

    gc_alloc_type(gc, 0, hashtable_type_def, (void **)&table);

    table->gc = gc;
    table->calc_hash = fn;
    table->compare = cmp;
    table->copy_on_write = false;
    
    /* resize the hashtable */
    hash_resize(table, HASH_SIZE);

    table->key_value = key_value_type_def;

    *ret = (hashtable_type *)table;

    gc_unregister_root(gc, (void**)&table);
}
예제 #5
0
파일: hash.c 프로젝트: wangxinghu/script
// if the elem_num is almost as large as the capacity of the hashtable
// we need to resize the hashtable to contain enough elements
static void resize_hash_table_if_needed(HashTable *ht)
{
    if(ht->size - ht->elem_num < 1)
    {
        hash_resize(ht);    
    }
}
예제 #6
0
/* Resize the hash table if needed, after list->count was incremented.  */
static void
hash_resize_after_add (gl_list_t list)
{
  size_t count = list->count;
  size_t estimate = xsum (count, count / 2); /* 1.5 * count */
  if (estimate > list->table_size)
    hash_resize (list, estimate);
}
예제 #7
0
파일: hashtable.c 프로젝트: GunioRobot/tipi
// if the elem_num is almost as large as the capacity of the hashtable
// we need to resize the hashtable to contain enough elements
static void resize_hash_table_if_needed(HashTable *ht)
{
	if(ht->size - ht->elem_num <= 1)
	{
		LOG_MSG("HashTable need resize, size: %i, elem_num: %i\n", ht->size, ht->elem_num);
		hash_resize(ht);	
	}
}
예제 #8
0
파일: abhash.c 프로젝트: abrady/abscope
BOOL hash_insert(HashTable *ht, char *key, void *p)
{
    U32 off;
    int i;
    U32 hash;
    HashNode *n;
    
    if(!ht || !key)
        return FALSE;
    
    VALID_HASHTABLE_CHECK(ht);
    
    if(!ht->elts)
    {
        ht->n_elts = 16;
        ht->elts = calloc(sizeof(*ht->elts),ht->n_elts);
        ht->n_used = 0;
    }
    
    if(!ht->cmpfp)
        ht->cmpfp = strcmp;
    if(!ht->hashfp)
        ht->hashfp = str_hashfunc;
    
    // check for need to rehash
#define PT75(N) (((N)>>2) + ((N)>>1)) // 75% = 1/2 + 1/4
    if(ht->n_used > PT75(ht->n_elts))
        hash_resize(ht,ht->n_elts*2);
#undef PT75
    
    hash = ht->hashfp(key, ht->ctxt);
    if(!hash)
    {
        fprintf(stderr,"key didn't make a hash value\n");
        return FALSE;
    }
    
    // linear probe
    for(i = 0; i<ht->n_elts; ++i)
    {
        off = ((hash + i) & (ht->n_elts - 1));
        n = ht->elts + off;
        
        if(!n->hash)
        {
            n->hash = hash;
            n->p = p;
            n->key = key;
            ht->n_used++;
            return TRUE;
        }
        if(n->hash == hash && 0==ht->cmpfp(key,n->key))
            return FALSE; // match existing
    }
    abassert(0&&"shouldn't get here");
    return FALSE;
}
예제 #9
0
파일: htab.c 프로젝트: gilmarion/pennmush
/** Add an entry to a hash table.
 * \param htab pointer to hash table.
 * \param key key string to store data under.
 * \param hashdata void pointer to data to be stored.
 * \retval false failure.
 * \retval true success.
 */
bool
hash_add(HASHTAB *htab, const char *key, void *hashdata)
{
  char *keycopy;
  int keylen;

  if (hash_find(htab, key) != NULL)
    return false;

  keycopy = mush_strdup(key, "hash.key");
  keylen = strlen(keycopy);

  if (htab->entries == htab->hashsize)
    hash_resize(htab, next_prime_after(floor(htab->hashsize * 1.15)),
                htab->hashseed_offset);

  htab->entries += 1;
  if (!hash_insert(htab, keycopy, keylen, hashdata)) {
    first_offset = -1;
    resize_calls = 0;
    hash_resize(htab, htab->hashsize, (htab->hashseed_offset + 1) % NHASH_MOD);
  }
  return true;
}
예제 #10
0
/* add a value to the hash */
void hash_set(hashtable_type *void_table, void *key, void * value) {
    key_value_type *kv = 0;

    hash_internal_type *table=(hash_internal_type *)void_table;
    size_t new_size = 0;

    kv = hash_find(table, key, CREATE);
    kv->value = value;

    /* check to see if we need to resize hash */
    if(hash_load(table) > MAX_LOAD) {
        /* calculate new size */
        new_size = floor(table->entries / TARGET_LOAD) + 1;
        hash_resize(table, new_size);
    }
}
예제 #11
0
파일: hashtable.c 프로젝트: daviga404/army
bool hash_insert(struct hashtable *table, const char *key, const void *value)
{
    // Find relevant bucket and keep index (used to find reference to bucket in buckets array)
    int index            = bucket_index(key, table->num_buckets);
    struct entry *bucket = table->buckets[index];

    // Check the table for an existing entry (bucket is first entry, as it
    // represents the head of the linked list)
    for (struct entry *entry = bucket; entry != NULL; entry = entry->next)
    {
        if (!strcmp(entry->key, key))
        {
            entry->value = value;
            return true;
        }
    }

    // Ensure that the table will not exceed the maximum load factor
    // with the new number of entries; if it will, resize it to double the
    // number of buckets, and set the new index/bucket.
    if ( (float)(table->num_entries + 1) / table->num_buckets > MAX_LOAD_FACTOR )
    {
        hash_resize(table, table->num_buckets * 2);

        index = bucket_index(key, table->num_buckets);
        bucket = table->buckets[index];
    }

    // Create the new entry to add to the table
    struct entry *new_entry;

    if ((new_entry = (struct entry *)malloc( sizeof(struct entry) )) == NULL)
        return false;

    new_entry->key = key;
    new_entry->value = value;
    new_entry->next = NULL;

    add_entry(&(table->buckets[index]), new_entry);

    // Increment the number of table entries
    ++table->num_entries;
    return true;
}
예제 #12
0
int hash_insert(hcfg_t *cfg, const char *key, const char *val)
{
    keyval_t *entry;
    char *new_val;

    entry = hash_find(cfg, key);
    if (entry == NULL)
        return -1;

    if (entry->key == NULL)
    {
        /* New entry case. */
        entry->key = malloc(strlen(key) + 1);
        entry->val = malloc(strlen(val) + 1);

        if (entry->key == NULL || entry->val == NULL) {
            free(entry->key);
            free(entry->val);
            entry->key = NULL;
            entry->val = NULL;
            return -1;
        }

        strcpy(entry->key, key);
        strcpy(entry->val, val);

        if (((++cfg->count * 100) / (1 << cfg->logsize)) > HASH_GROWTH_THRESH)
            hash_resize(cfg, cfg->logsize + 1); /* Failing to grow the
                                                   hash is not an error. */
    }
    else {
        /* Value replacement case. */
        new_val = malloc(strlen(val) + 1);
        if (new_val == NULL)
            return -1;
        strcpy(new_val, val);
        free(entry->val);
        entry->val = new_val;
    }
    return 0;
}
void hash_set(atom_p obj, const char* key, atom_p value) {
	assert(obj->type == T_OBJ || obj->type == T_ENV);
	
	if (obj->obj.len + obj->obj.deleted + 1 > obj->obj.cap * 0.7)
		hash_resize(obj, (obj->obj.cap == 0) ? 2 : obj->obj.cap * 2);
	
	uint32_t hash = fnv1a(key);
	size_t index = hash % obj->obj.cap;
	
	while ( !(obj->obj.slots[index].key == OBJ_SLOT_FREE || obj->obj.slots[index].key == OBJ_SLOT_DELETED) ) {
		if ( obj->obj.slots[index].hash == hash && strcmp(obj->obj.slots[index].key, key) == 0 )
			break;
		index = (index + 1) % obj->obj.cap;
	}
	
	if (obj->obj.slots[index].key == OBJ_SLOT_DELETED)
		obj->obj.deleted--;
	obj->obj.len++;
	obj->obj.slots[index].hash = hash;
	obj->obj.slots[index].key = key;
	obj->obj.slots[index].value = value;
}
예제 #14
0
파일: hash.c 프로젝트: flygoast/tasque
/* Insert a key/value pair into the hash table. */
int hash_insert(hash_t *ht, const void *key, const void *val) {
    hash_entry_t *he;
    unsigned long hash, i;

    if ((ht->count /  ht->slots) >= HASH_RESIZE_RATIO) {
        if (hash_resize(ht) != 0) {
            return -1;
        }
    }

    hash = hash_func(ht, key);
    i = hash % ht->slots;

    if ((he = ht->data[i])) {
        while (he) {
            if (HASH_CMP_KEYS(ht, key, he->key)) {
                /* replace the value */
                HASH_FREE_VAL(ht, he);
                HASH_SET_VAL(ht, he, (void *)val);
                return 0;
            }
            he = he->next;
        }
    }

    he = calloc(1, sizeof(*he));
    if (!he) {
        return -1;
    }

    HASH_SET_KEY(ht, he, (void *)key);
    HASH_SET_VAL(ht, he, (void *)val);

    he->next = ht->data[i];
    ht->data[i] = he;
    ++ht->count;
    return 0;
}
예제 #15
0
static void __hash_insert_node(hash_type *hash , hash_node_type *node) {
  __hash_wrlock( hash );
  {
    uint32_t table_index = hash_node_get_table_index(node);
    {
      /*
        If a node with the same key already exists in the table
        it is removed.
      */
      hash_node_type *existing_node = __hash_get_node_unlocked(hash , hash_node_get_key(node) , false);
      if (existing_node != NULL) {
        hash_sll_del_node(hash->table[table_index] , existing_node);
        hash->elements--;
      }
    }

    hash_sll_add_node(hash->table[table_index] , node);
    hash->elements++;
    if ((1.0 * hash->elements / hash->size) > hash->resize_fill)
      hash_resize(hash , hash->size * 2);
  }
  __hash_unlock( hash );
}
예제 #16
0
/* locate or create a key_value_object the given key */
key_value_type *hash_find(hash_internal_type *table,
                          void *key, hash_action_type action) {
    hash_type hash = (*table->calc_hash)(key);
    hash_type index = hash % table->size; /* calculate the search table index */
    key_value_type *kv = 0;
    key_value_type *prev_kv = 0;
   
    /* Check for "write" operations and a COW hash */
    if (table->copy_on_write && (action == CREATE || action == DELETE)) {
        /* resize implicitly copies everything */
        hash_resize(table, table->size);

        table->copy_on_write = false;
    }

    /* is there anything at the given index? */
    if((kv = table->table[index])) {
        /* search through the list of key value pairs */
        while(kv) {
            if((*table->compare)(key, kv->key) == EQ) {

                /* do the delete if needed */
                if(action == DELETE) {
                    
                    /* Do we have a chain? */
                    if(prev_kv) {
                        /* Remove node from chain */
                        prev_kv->next = kv->next;
                    } else {
                        /* This node is either the head of a chain
                           or there is no chain.  */
                        table->table[index] = kv->next;
                    }
                }
                return kv;
            }
            prev_kv = kv;
            kv = kv->next;
        }
    }
    
    /* we did not find the key, should we create it? */
    if(action == CREATE) {
        gc_register_root(table->gc, (void**)&kv);

        gc_alloc_type(table->gc, 0, table->key_value, (void **)&kv);

        kv->key = key;

        /* attach kv to table */
        kv->next = table->table[index];
        table->table[index] = kv;

        table->entries++;

        gc_unregister_root(table->gc, (void**)&kv);

        return kv;
    }

    
    return 0;
}
예제 #17
0
static void parse_hosts_file(struct hashtable_t **hash, const char path[], int read_opt)
{
	FILE *fd;
	char *line_ptr = NULL;
	char name[HOST_NAME_MAX_LEN], mac_str[18];
	struct ether_addr *mac_addr;
	struct bat_host *bat_host;
	struct hashtable_t *swaphash;
	size_t len = 0;

	name[0] = mac_str[0] = '\0';

	fd = fopen(path, "r");
	if (!fd)
		return;

	while (getline(&line_ptr, &len, fd) != -1) {
		/* ignore empty lines and comments */
		if ((line_ptr[0] == '\n') || (line_ptr[0] == '#'))
			continue;

		if (sscanf(line_ptr, "%17[^ \t]%49s\n", mac_str, name) != 2) {
			if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Warning - unrecognized bat-host definition: %s", line_ptr);
			continue;
		}

		mac_addr = ether_aton(mac_str);
		if (!mac_addr) {
			if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Warning - invalid mac address in '%s' detected: %s\n", path, mac_str);
			continue;
		}

		bat_host = bat_hosts_find_by_mac((char *)mac_addr);

		/* mac entry already exists - we found a new name for it */
		if (bat_host) {
			/* if the mac addresses and the names are the same we can safely ignore the entry */
			if (strcmp(bat_host->name, name) == 0)
				continue;

			if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Warning - mac already known (changing name from '%s' to '%s'): %s\n",
					bat_host->name, name, mac_str);
			strncpy(bat_host->name, name, HOST_NAME_MAX_LEN - 1);
			continue;
		}

		bat_host = bat_hosts_find_by_name(name);

		/* name entry already exists - we found a new mac address for it */
		if (bat_host) {
			if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Warning - name already known (changing mac from '%s' to '%s'): %s\n",
					ether_ntoa(&bat_host->mac_addr), mac_str, name);
			hash_remove(*hash, bat_host);
			free(bat_host);
		}

		bat_host = malloc(sizeof(struct bat_host));

		if (!bat_host) {
			if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Error - could not allocate memory: %s\n", strerror(errno));
			goto out;
		}

		memcpy(&bat_host->mac_addr, mac_addr, sizeof(struct ether_addr));
		strncpy(bat_host->name, name, HOST_NAME_MAX_LEN - 1);

		hash_add(*hash, bat_host);

		if ((*hash)->elements * 4 > (*hash)->size) {
			swaphash = hash_resize((*hash), (*hash)->size * 2);

			if (swaphash)
				*hash = swaphash;
			else if (read_opt & USE_BAT_HOSTS)
				fprintf(stderr, "Warning - couldn't resize bat hosts hash table\n");
		}
	}

out:
	if (fd)
		fclose(fd);
	if (line_ptr)
		free(line_ptr);
	return;
}
예제 #18
0
void hna_global_add_orig(struct bat_priv *bat_priv,
			 struct orig_node *orig_node,
			 unsigned char *hna_buff, int hna_buff_len)
{
	struct hna_global_entry *hna_global_entry;
	struct hna_local_entry *hna_local_entry;
	struct hashtable_t *swaphash;
	int hna_buff_count = 0;
	unsigned long flags;
	unsigned char *hna_ptr;

	while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
		spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);

		hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
		hna_global_entry = (struct hna_global_entry *)
			hash_find(bat_priv->hna_global_hash, hna_ptr);

		if (!hna_global_entry) {
			spin_unlock_irqrestore(&bat_priv->hna_ghash_lock,
					       flags);

			hna_global_entry =
				kmalloc(sizeof(struct hna_global_entry),
					GFP_ATOMIC);

			if (!hna_global_entry)
				break;

			memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);

			bat_dbg(DBG_ROUTES, bat_priv,
				"Creating new global hna entry: "
				"%pM (via %pM)\n",
				hna_global_entry->addr, orig_node->orig);

			spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);
			hash_add(bat_priv->hna_global_hash, hna_global_entry);

		}

		hna_global_entry->orig_node = orig_node;
		spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags);

		/* remove address from local hash if present */
		spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);

		hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
		hna_local_entry = (struct hna_local_entry *)
			hash_find(bat_priv->hna_local_hash, hna_ptr);

		if (hna_local_entry)
			hna_local_del(bat_priv, hna_local_entry,
				      "global hna received");

		spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);

		hna_buff_count++;
	}

	/* initialize, and overwrite if malloc succeeds */
	orig_node->hna_buff = NULL;
	orig_node->hna_buff_len = 0;

	if (hna_buff_len > 0) {
		orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC);
		if (orig_node->hna_buff) {
			memcpy(orig_node->hna_buff, hna_buff, hna_buff_len);
			orig_node->hna_buff_len = hna_buff_len;
		}
	}

	spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);

	if (bat_priv->hna_global_hash->elements * 4 >
					bat_priv->hna_global_hash->size) {
		swaphash = hash_resize(bat_priv->hna_global_hash,
				       bat_priv->hna_global_hash->size * 2);

		if (!swaphash)
			pr_err("Couldn't resize global hna hash table\n");
		else
			bat_priv->hna_global_hash = swaphash;
	}

	spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags);
}
예제 #19
0
void hna_local_add(struct net_device *soft_iface, uint8_t *addr)
{
	struct bat_priv *bat_priv = netdev_priv(soft_iface);
	struct hna_local_entry *hna_local_entry;
	struct hna_global_entry *hna_global_entry;
	struct hashtable_t *swaphash;
	unsigned long flags;
	int required_bytes;

	spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
	hna_local_entry =
		((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash,
						     addr));
	spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);

	if (hna_local_entry) {
		hna_local_entry->last_seen = jiffies;
		return;
	}

	/* only announce as many hosts as possible in the batman-packet and
	   space in batman_packet->num_hna That also should give a limit to
	   MAC-flooding. */
	required_bytes = (bat_priv->num_local_hna + 1) * ETH_ALEN;
	required_bytes += BAT_PACKET_LEN;

	if ((required_bytes > ETH_DATA_LEN) ||
	    (atomic_read(&bat_priv->aggregation_enabled) &&
	     required_bytes > MAX_AGGREGATION_BYTES) ||
	    (bat_priv->num_local_hna + 1 > 255)) {
		bat_dbg(DBG_ROUTES, bat_priv,
			"Can't add new local hna entry (%pM): "
			"number of local hna entries exceeds packet size\n",
			addr);
		return;
	}

	bat_dbg(DBG_ROUTES, bat_priv,
		"Creating new local hna entry: %pM\n", addr);

	hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
	if (!hna_local_entry)
		return;

	memcpy(hna_local_entry->addr, addr, ETH_ALEN);
	hna_local_entry->last_seen = jiffies;

	/* the batman interface mac address should never be purged */
	if (compare_orig(addr, soft_iface->dev_addr))
		hna_local_entry->never_purge = 1;
	else
		hna_local_entry->never_purge = 0;

	spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);

	hash_add(bat_priv->hna_local_hash, hna_local_entry);
	bat_priv->num_local_hna++;
	atomic_set(&bat_priv->hna_local_changed, 1);

	if (bat_priv->hna_local_hash->elements * 4 >
					bat_priv->hna_local_hash->size) {
		swaphash = hash_resize(bat_priv->hna_local_hash,
				       bat_priv->hna_local_hash->size * 2);

		if (!swaphash)
			pr_err("Couldn't resize local hna hash table\n");
		else
			bat_priv->hna_local_hash = swaphash;
	}

	spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);

	/* remove address from global hash if present */
	spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);

	hna_global_entry = ((struct hna_global_entry *)
				hash_find(bat_priv->hna_global_hash, addr));

	if (hna_global_entry)
		_hna_global_del_orig(bat_priv, hna_global_entry,
				     "local hna received");

	spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags);
}
void hna_global_add_orig(struct orig_node *orig_node,
			 unsigned char *hna_buff, int hna_buff_len)
{
	struct hna_global_entry *hna_global_entry;
	struct hna_local_entry *hna_local_entry;
	struct hashtable_t *swaphash;
	char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN];
	int hna_buff_count = 0;
	unsigned long flags;
	unsigned char *hna_ptr;

	addr_to_string(orig_str, orig_node->orig);

	while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
		spin_lock_irqsave(&hna_global_hash_lock, flags);

		hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
		hna_global_entry = (struct hna_global_entry *)
			hash_find(hna_global_hash, hna_ptr);

		if (hna_global_entry == NULL) {
			spin_unlock_irqrestore(&hna_global_hash_lock, flags);

			hna_global_entry =
				kmalloc(sizeof(struct hna_global_entry),
					GFP_ATOMIC);

			if (!hna_global_entry)
				break;

			memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);

			addr_to_string(hna_str, hna_global_entry->addr);
			debug_log(LOG_TYPE_ROUTES, "Creating new global hna entry: %s (via %s)\n", hna_str, orig_str);

			spin_lock_irqsave(&hna_global_hash_lock, flags);
			hash_add(hna_global_hash, hna_global_entry);

		}

		hna_global_entry->orig_node = orig_node;
		spin_unlock_irqrestore(&hna_global_hash_lock, flags);

		/* remove address from local hash if present */
		spin_lock_irqsave(&hna_local_hash_lock, flags);

		hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
		hna_local_entry = (struct hna_local_entry *)
			hash_find(hna_local_hash, hna_ptr);

		if (hna_local_entry != NULL)
			hna_local_del(hna_local_entry, "global hna received");

		spin_unlock_irqrestore(&hna_local_hash_lock, flags);

		hna_buff_count++;
	}

	orig_node->hna_buff_len = hna_buff_len;

	if (orig_node->hna_buff_len > 0) {
		orig_node->hna_buff = kmalloc(orig_node->hna_buff_len,
					      GFP_ATOMIC);
		memcpy(orig_node->hna_buff, hna_buff, orig_node->hna_buff_len);
	} else {
		orig_node->hna_buff = NULL;
	}

	spin_lock_irqsave(&hna_global_hash_lock, flags);

	if (hna_global_hash->elements * 4 > hna_global_hash->size) {
		swaphash = hash_resize(hna_global_hash,
				       hna_global_hash->size * 2);

		if (swaphash == NULL)
			debug_log(LOG_TYPE_CRIT, "Couldn't resize global hna hash table \n");
		else
			hna_global_hash = swaphash;
	}

	spin_unlock_irqrestore(&hna_global_hash_lock, flags);
}
void hna_local_add(uint8_t *addr)
{
	struct hna_local_entry *hna_local_entry;
	struct hna_global_entry *hna_global_entry;
	struct hashtable_t *swaphash;
	char hna_str[ETH_STR_LEN];
	unsigned long flags;

	spin_lock_irqsave(&hna_local_hash_lock, flags);
	hna_local_entry =
		((struct hna_local_entry *)hash_find(hna_local_hash, addr));
	spin_unlock_irqrestore(&hna_local_hash_lock, flags);

	if (hna_local_entry != NULL) {
		hna_local_entry->last_seen = jiffies;
		return;
	}

	addr_to_string(hna_str, addr);

	/* only announce as many hosts as possible in the batman-packet and
	   space in batman_packet->num_hna That also should give a limit to
	   MAC-flooding. */
	if ((num_hna + 1 > (ETH_DATA_LEN - BAT_PACKET_LEN) / ETH_ALEN) ||
	    (num_hna + 1 > 255)) {
		debug_log(LOG_TYPE_ROUTES, "Can't add new local hna entry (%s): number of local hna entries exceeds packet size \n", hna_str);
		return;
	}

	debug_log(LOG_TYPE_ROUTES, "Creating new local hna entry: %s \n",
		  hna_str);

	hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
	if (!hna_local_entry)
		return;

	memcpy(hna_local_entry->addr, addr, ETH_ALEN);
	hna_local_entry->last_seen = jiffies;

	/* the batman interface mac address should never be purged */
	if (compare_orig(addr, soft_device->dev_addr))
		hna_local_entry->never_purge = 1;
	else
		hna_local_entry->never_purge = 0;

	spin_lock_irqsave(&hna_local_hash_lock, flags);

	hash_add(hna_local_hash, hna_local_entry);
	num_hna++;
	atomic_set(&hna_local_changed, 1);

	if (hna_local_hash->elements * 4 > hna_local_hash->size) {
		swaphash = hash_resize(hna_local_hash,
				       hna_local_hash->size * 2);

		if (swaphash == NULL)
			debug_log(LOG_TYPE_CRIT, "Couldn't resize local hna hash table \n");
		else
			hna_local_hash = swaphash;
	}

	spin_unlock_irqrestore(&hna_local_hash_lock, flags);

	/* remove address from global hash if present */
	spin_lock_irqsave(&hna_global_hash_lock, flags);

	hna_global_entry =
		((struct hna_global_entry *)hash_find(hna_global_hash, addr));

	if (hna_global_entry != NULL)
		_hna_global_del_orig(hna_global_entry, "local hna received");

	spin_unlock_irqrestore(&hna_global_hash_lock, flags);
}