2014-01-04 21:04:25 +04:00
/* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors:
2010-12-13 14:19:28 +03:00
*
* 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 .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2013-11-03 23:40:48 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2010-12-13 14:19:28 +03:00
*/
# ifndef _NET_BATMAN_ADV_HASH_H_
# define _NET_BATMAN_ADV_HASH_H_
# include <linux/list.h>
2012-05-12 04:09:43 +04:00
/* callback to a compare function. should compare 2 element datas for their
* keys , return 0 if same and not 0 if not same
*/
2012-06-06 00:31:28 +04:00
typedef int ( * batadv_hashdata_compare_cb ) ( const struct hlist_node * ,
const void * ) ;
2010-12-13 14:19:28 +03:00
/* the hashfunction, should return an index
* based on the key in the data of the first
2012-05-12 04:09:43 +04:00
* argument and the size the second
*/
2012-06-06 00:31:28 +04:00
typedef uint32_t ( * batadv_hashdata_choose_cb ) ( const void * , uint32_t ) ;
typedef void ( * batadv_hashdata_free_cb ) ( struct hlist_node * , void * ) ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:28 +04:00
struct batadv_hashtable {
2011-01-19 23:01:40 +03:00
struct hlist_head * table ; /* the hashtable itself with the buckets */
spinlock_t * list_locks ; /* spinlock for each hash list entry */
2011-10-05 19:05:25 +04:00
uint32_t size ; /* size of hashtable */
2010-12-13 14:19:28 +03:00
} ;
/* allocates and clears the hash */
2012-06-06 00:31:28 +04:00
struct batadv_hashtable * batadv_hash_new ( uint32_t size ) ;
2010-12-13 14:19:28 +03:00
2012-03-29 14:38:20 +04:00
/* set class key for all locks */
2012-06-06 00:31:28 +04:00
void batadv_hash_set_lock_class ( struct batadv_hashtable * hash ,
2012-03-29 14:38:20 +04:00
struct lock_class_key * key ) ;
2010-12-13 14:19:28 +03:00
/* free only the hashtable and the hash itself. */
2012-06-06 00:31:28 +04:00
void batadv_hash_destroy ( struct batadv_hashtable * hash ) ;
2010-12-13 14:19:28 +03:00
/* 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
2012-05-12 04:09:43 +04:00
* elements , memory might be leaked .
*/
2012-06-06 00:31:28 +04:00
static inline void batadv_hash_delete ( struct batadv_hashtable * hash ,
batadv_hashdata_free_cb free_cb ,
void * arg )
2010-12-13 14:19:28 +03:00
{
struct hlist_head * head ;
2011-02-18 15:28:09 +03:00
struct hlist_node * node , * node_tmp ;
2011-01-19 23:01:40 +03:00
spinlock_t * list_lock ; /* spinlock to protect write access */
2011-10-05 19:05:25 +04:00
uint32_t i ;
2010-12-13 14:19:28 +03:00
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-01-19 23:01:40 +03:00
list_lock = & hash - > list_locks [ i ] ;
2010-12-13 14:19:28 +03:00
2011-01-19 23:01:40 +03:00
spin_lock_bh ( list_lock ) ;
2011-02-18 15:28:09 +03:00
hlist_for_each_safe ( node , node_tmp , head ) {
hlist_del_rcu ( node ) ;
2010-12-13 14:19:28 +03:00
2011-02-18 15:28:09 +03:00
if ( free_cb )
free_cb ( node , arg ) ;
2010-12-13 14:19:28 +03:00
}
2011-01-19 23:01:40 +03:00
spin_unlock_bh ( list_lock ) ;
2010-12-13 14:19:28 +03:00
}
2012-05-12 04:09:32 +04:00
batadv_hash_destroy ( hash ) ;
2010-12-13 14:19:28 +03:00
}
2012-08-30 20:22:27 +04:00
/**
* batadv_hash_bytes - hash some bytes and add them to the previous hash
* @ hash : previous hash value
* @ data : data to be hashed
* @ size : number of bytes to be hashed
*
* Returns the new hash value .
*/
2012-12-07 17:35:36 +04:00
static inline uint32_t batadv_hash_bytes ( uint32_t hash , const void * data ,
2012-08-30 20:22:27 +04:00
uint32_t size )
{
const unsigned char * key = data ;
int i ;
for ( i = 0 ; i < size ; i + + ) {
hash + = key [ i ] ;
hash + = ( hash < < 10 ) ;
hash ^ = ( hash > > 6 ) ;
}
return hash ;
}
2012-07-10 14:55:09 +04:00
/**
* batadv_hash_add - adds data to the hashtable
2011-07-10 02:36:36 +04:00
* @ hash : storage hash table
* @ compare : callback to determine if 2 hash elements are identical
* @ choose : callback calculating the hash index
* @ data : data passed to the aforementioned callbacks as argument
* @ data_node : to be added element
*
* Returns 0 on success , 1 if the element already is in the hash
* and - 1 on error .
*/
2012-06-06 00:31:28 +04:00
static inline int batadv_hash_add ( struct batadv_hashtable * hash ,
batadv_hashdata_compare_cb compare ,
batadv_hashdata_choose_cb choose ,
2012-05-12 15:48:55 +04:00
const void * data ,
struct hlist_node * data_node )
2010-12-13 14:19:28 +03:00
{
2011-10-05 19:05:25 +04:00
uint32_t index ;
int ret = - 1 ;
2010-12-13 14:19:28 +03:00
struct hlist_head * head ;
2011-02-18 15:28:09 +03:00
struct hlist_node * node ;
2011-01-19 23:01:40 +03:00
spinlock_t * list_lock ; /* spinlock to protect write access */
2010-12-13 14:19:28 +03:00
if ( ! hash )
2011-07-10 02:36:36 +04:00
goto out ;
2010-12-13 14:19:28 +03:00
index = choose ( data , hash - > size ) ;
head = & hash - > table [ index ] ;
2011-01-19 23:01:40 +03:00
list_lock = & hash - > list_locks [ index ] ;
2010-12-13 14:19:28 +03:00
2012-05-09 00:31:57 +04:00
spin_lock_bh ( list_lock ) ;
hlist_for_each ( node , head ) {
2011-02-18 15:28:09 +03:00
if ( ! compare ( node , data ) )
continue ;
2011-07-10 02:36:36 +04:00
ret = 1 ;
2012-05-09 00:31:57 +04:00
goto unlock ;
2010-12-13 14:19:28 +03:00
}
/* no duplicate found in list, add new element */
2011-02-18 15:28:09 +03:00
hlist_add_head_rcu ( data_node , head ) ;
2010-12-13 14:19:28 +03:00
2011-07-10 02:36:36 +04:00
ret = 0 ;
2011-01-19 23:01:40 +03:00
2012-05-09 00:31:57 +04:00
unlock :
spin_unlock_bh ( list_lock ) ;
2011-07-10 02:36:36 +04:00
out :
return ret ;
2010-12-13 14:19:28 +03:00
}
/* 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
2012-05-12 04:09:43 +04:00
* comparing .
*/
2012-06-06 00:31:28 +04:00
static inline void * batadv_hash_remove ( struct batadv_hashtable * hash ,
batadv_hashdata_compare_cb compare ,
batadv_hashdata_choose_cb choose ,
void * data )
2010-12-13 14:19:28 +03:00
{
2011-10-05 19:05:25 +04:00
uint32_t index ;
2011-02-18 15:28:09 +03:00
struct hlist_node * node ;
2010-12-13 14:19:28 +03:00
struct hlist_head * head ;
2011-01-19 23:01:40 +03:00
void * data_save = NULL ;
2010-12-13 14:19:28 +03:00
index = choose ( data , hash - > size ) ;
head = & hash - > table [ index ] ;
2011-01-19 23:01:40 +03:00
spin_lock_bh ( & hash - > list_locks [ index ] ) ;
2011-02-18 15:28:09 +03:00
hlist_for_each ( node , head ) {
if ( ! compare ( node , data ) )
continue ;
data_save = node ;
hlist_del_rcu ( node ) ;
break ;
2010-12-13 14:19:28 +03:00
}
2011-01-19 23:01:40 +03:00
spin_unlock_bh ( & hash - > list_locks [ index ] ) ;
2010-12-13 14:19:28 +03:00
2011-01-19 23:01:40 +03:00
return data_save ;
2010-12-13 14:19:28 +03:00
}
# endif /* _NET_BATMAN_ADV_HASH_H_ */