The compare functions had a different interpretation of its return value and
kmalloc can sleep inside batgat because we are running in user context of
kernel.
---
batman/linux/modules/gateway.c | 4 +-
batman/linux/modules/gateway24.c | 4 +-
batman/linux/modules/hash.c | 266 ++++++++++++++++++++------------------
batman/linux/modules/hash.h | 9 +-
4 files changed, 149 insertions(+), 134 deletions(-)
diff --git a/batman/linux/modules/gateway.c b/batman/linux/modules/gateway.c
index 41d75b5..1f2dc24 100644
--- a/batman/linux/modules/gateway.c
+++ b/batman/linux/modules/gateway.c
@@ -713,12 +713,12 @@ static struct gw_client *get_ip_addr(struct sockaddr_in *client_addr)
* the ip address is the first/second field in the struct */
int compare_wip(void *data1, void *data2)
{
- return ( memcmp( data1, data2, 4 ) );
+ return ( !memcmp( data1, data2, 4 ) );
}
int compare_vip(void *data1, void *data2)
{
- return ( memcmp( data1 + 4, data2 + 4, 4 ) );
+ return ( !memcmp( data1 + 4, data2 + 4, 4 ) );
}
/* hashfunction to choose an entry in a hash table of given size */
diff --git a/batman/linux/modules/gateway24.c b/batman/linux/modules/gateway24.c
index dbd1f42..a8d58e6 100644
--- a/batman/linux/modules/gateway24.c
+++ b/batman/linux/modules/gateway24.c
@@ -693,12 +693,12 @@ static int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct iovec
int compare_wip(void *data1, void *data2)
{
- return ( memcmp( data1, data2, 4 ) );
+ return ( !memcmp( data1, data2, 4 ) );
}
int compare_vip(void *data1, void *data2)
{
- return ( memcmp( data1 + 4, data2 + 4, 4 ) );
+ return ( !memcmp( data1 + 4, data2 + 4, 4 ) );
}
int choose_wip(void *data, int32_t size)
diff --git a/batman/linux/modules/hash.c b/batman/linux/modules/hash.c
index ae009be..e88c6e0 100644
--- a/batman/linux/modules/hash.c
+++ b/batman/linux/modules/hash.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2006 B.A.T.M.A.N. contributors:
+/*
+ * Copyright (C) 2006-2008 B.A.T.M.A.N. contributors:
* Simon Wunderlich, Marek Lindner
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
@@ -17,294 +17,304 @@
*
*/
+
+
+
+
#include <linux/string.h> /* strlen, strstr, strncmp ... */
#include <linux/slab.h>
#include "hash.h"
+
/* clears the hash */
-void hash_init(struct hashtable_t *hash) {
+void hash_init(struct hashtable_t *hash)
+{
int i;
- hash->elements=0;
- for (i=0 ; i<hash->size ; i++) {
+
+ hash->elements = 0;
+
+ for (i = 0 ; i < hash->size; i++)
hash->table[i] = NULL;
- }
}
-
/* remove the hash structure. if hashdata_free_cb != NULL,
* this function will be called to remove the elements inside of the hash.
* if you don't remove the elements, memory might be leaked. */
-void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb) {
+void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb)
+{
struct element_t *bucket, *last_bucket;
int i;
- for (i=0; i<hash->size; i++) {
+ for (i = 0; i < hash->size; i++) {
+ bucket = hash->table[i];
- bucket= hash->table[i];
while (bucket != NULL) {
+ if (free_cb != NULL)
+ free_cb(bucket->data);
- if (free_cb!=NULL)
- free_cb( bucket->data );
-
- last_bucket= bucket;
- bucket= bucket->next;
+ last_bucket = bucket;
+ bucket = bucket->next;
kfree(last_bucket);
-
}
}
+
hash_destroy(hash);
}
-
-
/* free only the hashtable and the hash itself. */
-void hash_destroy(struct hashtable_t *hash) {
-
- kfree( hash->table );
- kfree( hash );
-
+void hash_destroy(struct hashtable_t *hash)
+{
+ kfree(hash->table);
+ kfree(hash);
}
-
-
-
/* iterate though the hash. first element is selected with iter_in NULL.
* use the returned iterator to access the elements until hash_it_t returns NULL. */
-struct hash_it_t *hash_iterate(struct hashtable_t *hash, struct hash_it_t *iter_in) {
+struct hash_it_t *hash_iterate(struct hashtable_t *hash, struct hash_it_t *iter_in)
+{
struct hash_it_t *iter;
if (iter_in == NULL) {
- iter= kmalloc(sizeof(struct hash_it_t), GFP_KERNEL);
- iter->index = -1;
+ iter = kmalloc(sizeof(struct hash_it_t), GFP_KERNEL);
+ iter->index = -1;
iter->bucket = NULL;
iter->prev_bucket = NULL;
- } else
+ } else {
iter= iter_in;
+ }
/* sanity checks first (if our bucket got deleted in the last iteration): */
- if (iter->bucket!=NULL) {
+ if (iter->bucket != NULL) {
if (iter->first_bucket != NULL) {
-
/* we're on the first element and it got removed after the last iteration. */
if ((*iter->first_bucket) != iter->bucket) {
-
/* there are still other elements in the list */
- if ( (*iter->first_bucket) != NULL ) {
+ if ((*iter->first_bucket) != NULL) {
iter->prev_bucket = NULL;
- iter->bucket= (*iter->first_bucket);
- iter->first_bucket = &hash->table[ iter->index ];
- return(iter);
+ iter->bucket = (*iter->first_bucket);
+ iter->first_bucket = &hash->table[iter->index];
+ return iter;
} else {
iter->bucket = NULL;
}
-
}
-
- } else if ( iter->prev_bucket != NULL ) {
-
- /* we're not on the first element, and the bucket got removed after the last iteration.
+ } else if (iter->prev_bucket != NULL) {
+ /*
+ * we're not on the first element, and the bucket got removed after the last iteration.
* the last bucket's next pointer is not pointing to our actual bucket anymore.
- * select the next. */
- if ( iter->prev_bucket->next != iter->bucket )
- iter->bucket= iter->prev_bucket;
-
+ * select the next.
+ */
+ if (iter->prev_bucket->next != iter->bucket)
+ iter->bucket = iter->prev_bucket;
}
-
}
/* now as we are sane, select the next one if there is some */
- if (iter->bucket!=NULL) {
- if (iter->bucket->next!=NULL) {
- iter->prev_bucket= iter->bucket;
- iter->bucket= iter->bucket->next;
+ if (iter->bucket != NULL) {
+ if (iter->bucket->next != NULL) {
+ iter->prev_bucket = iter->bucket;
+ iter->bucket = iter->bucket->next;
iter->first_bucket = NULL;
- return(iter);
+ return iter;
}
}
- /* if not returned yet, we've reached the last one on the index and have to search forward */
+ /* if not returned yet, we've reached the last one on the index and have to search forward */
iter->index++;
- while ( iter->index < hash->size ) { /* go through the entries of the hash table */
- if ((hash->table[ iter->index ]) != NULL){
+ /* go through the entries of the hash table */
+ while (iter->index < hash->size) {
+ if ((hash->table[iter->index]) != NULL){
iter->prev_bucket = NULL;
- iter->bucket = hash->table[ iter->index ];
- iter->first_bucket = &hash->table[ iter->index ];
- return(iter); /* if this table entry is not null, return it */
- } else
- iter->index++; /* else, go to the next */
+ iter->bucket = hash->table[iter->index];
+ iter->first_bucket = &hash->table[iter->index];
+ return iter;
+ } else {
+ iter->index++;
+ }
}
+
/* nothing to iterate over anymore */
kfree(iter);
- return(NULL);
+ return NULL;
}
-
/* allocates and clears the hash */
-struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, hashdata_choose_cb choose) {
+struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, hashdata_choose_cb choose)
+{
struct hashtable_t *hash;
- hash= kmalloc( sizeof(struct hashtable_t) , GFP_KERNEL);
- if ( hash == NULL ) /* could not allocate the hash control structure */
- return (NULL);
+ hash = kmalloc(sizeof(struct hashtable_t) , GFP_KERNEL);
+
+ if (hash == NULL)
+ return NULL;
- hash->size= size;
- hash->table= kmalloc( sizeof(struct element_t *) * size, GFP_KERNEL);
- if ( hash->table == NULL ) { /* could not allocate the table */
+ hash->size = size;
+ hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_KERNEL);
+
+ if (hash->table == NULL) {
kfree(hash);
- return(NULL);
+ return NULL;
}
+
hash_init(hash);
- hash->compare= compare;
- hash->choose= choose;
- return(hash);
-}
+ hash->compare = compare;
+ hash->choose = choose;
+
+ return hash;
+}
/* adds data to the hashtable. returns 0 on success, -1 on error */
-int hash_add(struct hashtable_t *hash, void *data) {
+int hash_add(struct hashtable_t *hash, void *data)
+{
int index;
struct element_t *bucket, *prev_bucket = NULL;
- index = hash->choose( data, hash->size );
+ index = hash->choose(data, hash->size);
bucket = hash->table[index];
- while ( bucket!=NULL ) {
- if (0 == hash->compare( bucket->data, data ))
- return(-1);
+ while (bucket != NULL) {
+ if (hash->compare(bucket->data, data))
+ return -1;
prev_bucket = bucket;
- bucket= bucket->next;
+ bucket = bucket->next;
}
/* found the tail of the list, add new element */
- if (NULL == (bucket= kmalloc(sizeof(struct element_t),GFP_KERNEL)))
- return(-1); /* debugMalloc failed */
+ bucket = kmalloc(sizeof(struct element_t),GFP_KERNEL);
+
+ if (bucket == NULL)
+ return -1;
- bucket->data= data; /* init the new bucket */
- bucket->next= NULL;
+ bucket->data = data;
+ bucket->next = NULL;
/* and link it */
- if ( prev_bucket == NULL ) {
+ if (prev_bucket == NULL)
hash->table[index] = bucket;
- } else {
+ else
prev_bucket->next = bucket;
- }
hash->elements++;
- return(0);
-
+ return 0;
}
+
/* finds data, based on the key in keydata. returns the found data on success, or NULL on error */
-void *hash_find(struct hashtable_t *hash, void *keydata) {
+void *hash_find(struct hashtable_t *hash, void *keydata)
+{
int index;
struct element_t *bucket;
- index = hash->choose( keydata , hash->size );
+ index = hash->choose(keydata , hash->size);
bucket = hash->table[index];
- while ( bucket!=NULL ) {
- if (0 == hash->compare( bucket->data, keydata ))
- return( bucket->data );
+ while (bucket != NULL) {
+ if (hash->compare(bucket->data, keydata))
+ return bucket->data;
- bucket= bucket->next;
+ bucket = bucket->next;
}
- return(NULL);
-
+ return NULL;
}
/* remove bucket (this might be used in hash_iterate() if you already found the bucket
* you want to delete and don't need the overhead to find it again with hash_remove().
* But usually, you don't want to use this function, as it fiddles with hash-internals. */
-void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t) {
+void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t)
+{
void *data_save;
- data_save = hash_it_t->bucket->data; /* save the pointer to the data */
+ data_save = hash_it_t->bucket->data;
- if ( hash_it_t->prev_bucket != NULL ) {
+ if (hash_it_t->prev_bucket != NULL)
hash_it_t->prev_bucket->next = hash_it_t->bucket->next;
- } else if ( hash_it_t->first_bucket != NULL ) {
+ else if (hash_it_t->first_bucket != NULL)
(*hash_it_t->first_bucket) = hash_it_t->bucket->next;
- }
kfree(hash_it_t->bucket);
-
hash->elements--;
- return( data_save );
+ return data_save;
}
-
/* removes data from hash, if found. returns pointer do data on success,
* so you can remove the used structure yourself, or NULL on error .
* data could be the structure you use with just the key filled,
* we just need the key for comparing. */
-void *hash_remove(struct hashtable_t *hash, void *data) {
+void *hash_remove(struct hashtable_t *hash, void *data)
+{
struct hash_it_t hash_it_t;
- hash_it_t.index = hash->choose( data, hash->size );
+ hash_it_t.index = hash->choose(data, hash->size);
hash_it_t.bucket = hash->table[hash_it_t.index];
hash_it_t.prev_bucket = NULL;
- while ( hash_it_t.bucket!=NULL ) {
- if (0 == hash->compare( hash_it_t.bucket->data, data )) {
+ while (hash_it_t.bucket != NULL) {
+ if (hash->compare(hash_it_t.bucket->data, data)) {
hash_it_t.first_bucket = (hash_it_t.bucket == hash->table[hash_it_t.index] ? &hash->table[ hash_it_t.index ] : NULL);
- return( hash_remove_bucket(hash, &hash_it_t) );
+ return hash_remove_bucket(hash, &hash_it_t);
}
hash_it_t.prev_bucket = hash_it_t.bucket;
hash_it_t.bucket= hash_it_t.bucket->next;
}
- return(NULL);
-
+ return NULL;
}
-
/* resize the hash, returns the pointer to the new hash or NULL on error. removes the old hash on success. */
-struct hashtable_t *hash_resize(struct hashtable_t *hash, int size) {
+struct hashtable_t *hash_resize(struct hashtable_t *hash, int size)
+{
struct hashtable_t *new_hash;
struct element_t *bucket;
int i;
/* initialize a new hash with the new size */
- if (NULL == (new_hash= hash_new(size, hash->compare, hash->choose)))
- return(NULL);
+ new_hash = hash_new(size, hash->compare, hash->choose);
+
+ if (new_hash == NULL)
+ return NULL;
/* copy the elements */
- for (i=0; i<hash->size; i++) {
- bucket= hash->table[i];
+ for (i = 0; i < hash->size; i++) {
+ bucket = hash->table[i];
+
while (bucket != NULL) {
- hash_add( new_hash, bucket->data );
- bucket= bucket->next;
+ hash_add(new_hash, bucket->data);
+ bucket = bucket->next;
}
}
- hash_delete(hash, NULL); /* remove hash and eventual overflow buckets but not the content itself. */
- return( new_hash);
+ /* remove hash and eventual overflow buckets but not the content itself. */
+ hash_delete(hash, NULL);
+ return new_hash;
}
-/* print the hash table for debugging */
-void hash_debug(struct hashtable_t *hash) {
+/* print the hash table for debugging
+void hash_debug(struct hashtable_t *hash)
+{
int i;
struct element_t *bucket;
for (i=0; i<hash->size;i++) {
- printk("[%d] ",i);
+ printf("[%d] ",i);
bucket= hash->table[i];
while (bucket != NULL) {
- printk("-> [%10p] ", bucket);
+ printf("-> [%10p] ", bucket);
bucket= bucket->next;
}
- printk("\n");
+ printf("\n");
}
- printk("\n");
+ printf("\n");
}
+ */
diff --git a/batman/linux/modules/hash.h b/batman/linux/modules/hash.h
index a87cdcb..a778f04 100644
--- a/batman/linux/modules/hash.h
+++ b/batman/linux/modules/hash.h
@@ -1,6 +1,6 @@
-/* Copyright (C) 2006 B.A.T.M.A.N. contributors:
+/*
+ * Copyright (C) 2006-2008 B.A.T.M.A.N. contributors:
* Simon Wunderlich, Marek Lindner
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
@@ -16,6 +16,11 @@
* 02110-1301, USA
*
*/
+
+
+
+
+
#ifndef _BATMAN_HASH_H
#define _BATMAN_HASH_H
--
1.6.0.1