/** 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; }
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; }
/* 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); }
// 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); } }
/* 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); }
// 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); } }
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; }
/** 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; }
/* 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); } }
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; }
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; }
/* 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; }
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 ); }
/* 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; }
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; }
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); }
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); }