2010-12-13 14:19:28 +03:00
/*
2011-01-27 12:38:15 +03:00
* Copyright ( C ) 2007 - 2011 B . A . T . M . A . N . contributors :
2010-12-13 14:19:28 +03:00
*
* Marek Lindner , Simon Wunderlich
*
* 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
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 , USA
*
*/
# include "main.h"
# include "translation-table.h"
# include "soft-interface.h"
2011-04-20 17:40:58 +04:00
# include "hard-interface.h"
2010-12-13 14:19:28 +03:00
# include "hash.h"
# include "originator.h"
2011-05-05 10:42:45 +04:00
static void tt_local_purge ( struct work_struct * work ) ;
static void _tt_global_del_orig ( struct bat_priv * bat_priv ,
struct tt_global_entry * tt_global_entry ,
2011-05-15 01:14:50 +04:00
const char * message ) ;
2010-12-13 14:19:28 +03:00
2011-02-18 15:28:09 +03:00
/* returns 1 if they are the same mac addr */
2011-05-15 01:14:50 +04:00
static int compare_ltt ( const struct hlist_node * node , const void * data2 )
2011-02-18 15:28:09 +03:00
{
2011-05-15 01:14:50 +04:00
const void * data1 = container_of ( node , struct tt_local_entry ,
hash_entry ) ;
2011-02-18 15:28:09 +03:00
return ( memcmp ( data1 , data2 , ETH_ALEN ) = = 0 ? 1 : 0 ) ;
}
/* returns 1 if they are the same mac addr */
2011-05-15 01:14:50 +04:00
static int compare_gtt ( const struct hlist_node * node , const void * data2 )
2011-02-18 15:28:09 +03:00
{
2011-05-15 01:14:50 +04:00
const void * data1 = container_of ( node , struct tt_global_entry ,
hash_entry ) ;
2011-02-18 15:28:09 +03:00
return ( memcmp ( data1 , data2 , ETH_ALEN ) = = 0 ? 1 : 0 ) ;
}
2011-05-05 10:42:45 +04:00
static void tt_local_start_timer ( struct bat_priv * bat_priv )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
INIT_DELAYED_WORK ( & bat_priv - > tt_work , tt_local_purge ) ;
queue_delayed_work ( bat_event_workqueue , & bat_priv - > tt_work , 10 * HZ ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
static struct tt_local_entry * tt_local_hash_find ( struct bat_priv * bat_priv ,
2011-05-15 01:14:50 +04:00
const void * data )
2011-02-18 15:28:09 +03:00
{
2011-05-05 10:42:45 +04:00
struct hashtable_t * hash = bat_priv - > tt_local_hash ;
2011-02-18 15:28:09 +03:00
struct hlist_head * head ;
struct hlist_node * node ;
2011-05-05 10:42:45 +04:00
struct tt_local_entry * tt_local_entry , * tt_local_entry_tmp = NULL ;
2011-02-18 15:28:09 +03:00
int index ;
if ( ! hash )
return NULL ;
index = choose_orig ( data , hash - > size ) ;
head = & hash - > table [ index ] ;
rcu_read_lock ( ) ;
2011-05-05 10:42:45 +04:00
hlist_for_each_entry_rcu ( tt_local_entry , node , head , hash_entry ) {
if ( ! compare_eth ( tt_local_entry , data ) )
2011-02-18 15:28:09 +03:00
continue ;
2011-05-05 10:42:45 +04:00
tt_local_entry_tmp = tt_local_entry ;
2011-02-18 15:28:09 +03:00
break ;
}
rcu_read_unlock ( ) ;
2011-05-05 10:42:45 +04:00
return tt_local_entry_tmp ;
2011-02-18 15:28:09 +03:00
}
2011-05-05 10:42:45 +04:00
static struct tt_global_entry * tt_global_hash_find ( struct bat_priv * bat_priv ,
2011-05-15 01:14:50 +04:00
const void * data )
2011-02-18 15:28:09 +03:00
{
2011-05-05 10:42:45 +04:00
struct hashtable_t * hash = bat_priv - > tt_global_hash ;
2011-02-18 15:28:09 +03:00
struct hlist_head * head ;
struct hlist_node * node ;
2011-05-05 10:42:45 +04:00
struct tt_global_entry * tt_global_entry ;
struct tt_global_entry * tt_global_entry_tmp = NULL ;
2011-02-18 15:28:09 +03:00
int index ;
if ( ! hash )
return NULL ;
index = choose_orig ( data , hash - > size ) ;
head = & hash - > table [ index ] ;
rcu_read_lock ( ) ;
2011-05-05 10:42:45 +04:00
hlist_for_each_entry_rcu ( tt_global_entry , node , head , hash_entry ) {
if ( ! compare_eth ( tt_global_entry , data ) )
2011-02-18 15:28:09 +03:00
continue ;
2011-05-05 10:42:45 +04:00
tt_global_entry_tmp = tt_global_entry ;
2011-02-18 15:28:09 +03:00
break ;
}
rcu_read_unlock ( ) ;
2011-05-05 10:42:45 +04:00
return tt_global_entry_tmp ;
2011-02-18 15:28:09 +03:00
}
2011-05-05 10:42:45 +04:00
int tt_local_init ( struct bat_priv * bat_priv )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
if ( bat_priv - > tt_local_hash )
2010-12-13 14:19:28 +03:00
return 1 ;
2011-05-05 10:42:45 +04:00
bat_priv - > tt_local_hash = hash_new ( 1024 ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
if ( ! bat_priv - > tt_local_hash )
2010-12-13 14:19:28 +03:00
return 0 ;
2011-05-05 10:42:45 +04:00
atomic_set ( & bat_priv - > tt_local_changed , 0 ) ;
tt_local_start_timer ( bat_priv ) ;
2010-12-13 14:19:28 +03:00
return 1 ;
}
2011-05-15 01:14:50 +04:00
void tt_local_add ( struct net_device * soft_iface , const uint8_t * addr )
2010-12-13 14:19:28 +03:00
{
struct bat_priv * bat_priv = netdev_priv ( soft_iface ) ;
2011-05-05 10:42:45 +04:00
struct tt_local_entry * tt_local_entry ;
struct tt_global_entry * tt_global_entry ;
2010-12-13 14:19:28 +03:00
int required_bytes ;
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_lhash_lock ) ;
tt_local_entry = tt_local_hash_find ( bat_priv , addr ) ;
spin_unlock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
if ( tt_local_entry ) {
tt_local_entry - > last_seen = jiffies ;
2010-12-13 14:19:28 +03:00
return ;
}
/* only announce as many hosts as possible in the batman-packet and
2011-05-05 10:42:45 +04:00
space in batman_packet - > num_tt That also should give a limit to
2010-12-13 14:19:28 +03:00
MAC - flooding . */
2011-05-05 10:42:45 +04:00
required_bytes = ( bat_priv - > num_local_tt + 1 ) * ETH_ALEN ;
2010-12-13 14:19:28 +03:00
required_bytes + = BAT_PACKET_LEN ;
if ( ( required_bytes > ETH_DATA_LEN ) | |
( atomic_read ( & bat_priv - > aggregated_ogms ) & &
required_bytes > MAX_AGGREGATION_BYTES ) | |
2011-05-05 10:42:45 +04:00
( bat_priv - > num_local_tt + 1 > 255 ) ) {
2010-12-13 14:19:28 +03:00
bat_dbg ( DBG_ROUTES , bat_priv ,
2011-05-05 10:42:45 +04:00
" Can't add new local tt entry (%pM): "
" number of local tt entries exceeds packet size \n " ,
2010-12-13 14:19:28 +03:00
addr ) ;
return ;
}
bat_dbg ( DBG_ROUTES , bat_priv ,
2011-05-05 10:42:45 +04:00
" Creating new local tt entry: %pM \n " , addr ) ;
2010-12-13 14:19:28 +03:00
2011-05-15 01:14:54 +04:00
tt_local_entry = kmalloc ( sizeof ( * tt_local_entry ) , GFP_ATOMIC ) ;
2011-05-05 10:42:45 +04:00
if ( ! tt_local_entry )
2010-12-13 14:19:28 +03:00
return ;
2011-05-05 10:42:45 +04:00
memcpy ( tt_local_entry - > addr , addr , ETH_ALEN ) ;
tt_local_entry - > last_seen = jiffies ;
2010-12-13 14:19:28 +03:00
/* the batman interface mac address should never be purged */
2011-02-18 15:28:08 +03:00
if ( compare_eth ( addr , soft_iface - > dev_addr ) )
2011-05-05 10:42:45 +04:00
tt_local_entry - > never_purge = 1 ;
2010-12-13 14:19:28 +03:00
else
2011-05-05 10:42:45 +04:00
tt_local_entry - > never_purge = 0 ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
hash_add ( bat_priv - > tt_local_hash , compare_ltt , choose_orig ,
tt_local_entry , & tt_local_entry - > hash_entry ) ;
bat_priv - > num_local_tt + + ;
atomic_set ( & bat_priv - > tt_local_changed , 1 ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
/* remove address from global hash if present */
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_ghash_lock ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
tt_global_entry = tt_global_hash_find ( bat_priv , addr ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
if ( tt_global_entry )
_tt_global_del_orig ( bat_priv , tt_global_entry ,
" local tt received " ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_ghash_lock ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
int tt_local_fill_buffer ( struct bat_priv * bat_priv ,
2010-12-13 14:19:28 +03:00
unsigned char * buff , int buff_len )
{
2011-05-05 10:42:45 +04:00
struct hashtable_t * hash = bat_priv - > tt_local_hash ;
struct tt_local_entry * tt_local_entry ;
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-02-18 15:28:09 +03:00
int i , count = 0 ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-02-18 15:28:09 +03:00
rcu_read_lock ( ) ;
2011-05-05 10:42:45 +04:00
hlist_for_each_entry_rcu ( tt_local_entry , node ,
2011-02-18 15:28:09 +03:00
head , hash_entry ) {
2010-12-13 14:19:28 +03:00
if ( buff_len < ( count + 1 ) * ETH_ALEN )
break ;
2011-05-05 10:42:45 +04:00
memcpy ( buff + ( count * ETH_ALEN ) , tt_local_entry - > addr ,
2010-12-13 14:19:28 +03:00
ETH_ALEN ) ;
count + + ;
}
2011-02-18 15:28:09 +03:00
rcu_read_unlock ( ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
/* if we did not get all new local tts see you next time ;-) */
if ( count = = bat_priv - > num_local_tt )
atomic_set ( & bat_priv - > tt_local_changed , 0 ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-20 21:32:03 +03:00
return count ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
int tt_local_seq_print_text ( struct seq_file * seq , void * offset )
2010-12-13 14:19:28 +03:00
{
struct net_device * net_dev = ( struct net_device * ) seq - > private ;
struct bat_priv * bat_priv = netdev_priv ( net_dev ) ;
2011-05-05 10:42:45 +04:00
struct hashtable_t * hash = bat_priv - > tt_local_hash ;
struct tt_local_entry * tt_local_entry ;
2011-04-20 17:40:58 +04:00
struct hard_iface * primary_if ;
2011-02-18 15:28:09 +03:00
struct hlist_node * node ;
2010-12-13 14:19:28 +03:00
struct hlist_head * head ;
size_t buf_size , pos ;
char * buff ;
2011-04-20 17:40:58 +04:00
int i , ret = 0 ;
primary_if = primary_if_get_selected ( bat_priv ) ;
if ( ! primary_if ) {
ret = seq_printf ( seq , " BATMAN mesh %s disabled - "
" please specify interfaces to enable it \n " ,
net_dev - > name ) ;
goto out ;
}
2010-12-13 14:19:28 +03:00
2011-04-20 17:40:58 +04:00
if ( primary_if - > if_status ! = IF_ACTIVE ) {
ret = seq_printf ( seq , " BATMAN mesh %s disabled - "
" primary interface not active \n " ,
net_dev - > name ) ;
goto out ;
2010-12-13 14:19:28 +03:00
}
seq_printf ( seq , " Locally retrieved addresses (from %s) "
2011-05-05 10:42:45 +04:00
" announced via TT: \n " ,
2010-12-13 14:19:28 +03:00
net_dev - > name ) ;
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
buf_size = 1 ;
/* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-02-18 15:28:09 +03:00
rcu_read_lock ( ) ;
__hlist_for_each_rcu ( node , head )
2010-12-13 14:19:28 +03:00
buf_size + = 21 ;
2011-02-18 15:28:09 +03:00
rcu_read_unlock ( ) ;
2010-12-13 14:19:28 +03:00
}
buff = kmalloc ( buf_size , GFP_ATOMIC ) ;
if ( ! buff ) {
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_lhash_lock ) ;
2011-04-20 17:40:58 +04:00
ret = - ENOMEM ;
goto out ;
2010-12-13 14:19:28 +03:00
}
2011-02-18 15:28:09 +03:00
2010-12-13 14:19:28 +03:00
buff [ 0 ] = ' \0 ' ;
pos = 0 ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-02-18 15:28:09 +03:00
rcu_read_lock ( ) ;
2011-05-05 10:42:45 +04:00
hlist_for_each_entry_rcu ( tt_local_entry , node ,
2011-02-18 15:28:09 +03:00
head , hash_entry ) {
2010-12-13 14:19:28 +03:00
pos + = snprintf ( buff + pos , 22 , " * %pM \n " ,
2011-05-05 10:42:45 +04:00
tt_local_entry - > addr ) ;
2010-12-13 14:19:28 +03:00
}
2011-02-18 15:28:09 +03:00
rcu_read_unlock ( ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
seq_printf ( seq , " %s " , buff ) ;
kfree ( buff ) ;
2011-04-20 17:40:58 +04:00
out :
if ( primary_if )
hardif_free_ref ( primary_if ) ;
return ret ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
static void _tt_local_del ( struct hlist_node * node , void * arg )
2010-12-13 14:19:28 +03:00
{
2011-05-15 01:14:52 +04:00
struct bat_priv * bat_priv = arg ;
2011-05-05 10:42:45 +04:00
void * data = container_of ( node , struct tt_local_entry , hash_entry ) ;
2010-12-13 14:19:28 +03:00
kfree ( data ) ;
2011-05-05 10:42:45 +04:00
bat_priv - > num_local_tt - - ;
atomic_set ( & bat_priv - > tt_local_changed , 1 ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
static void tt_local_del ( struct bat_priv * bat_priv ,
2011-05-15 01:14:50 +04:00
struct tt_local_entry * tt_local_entry ,
const char * message )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
bat_dbg ( DBG_ROUTES , bat_priv , " Deleting local tt entry (%pM): %s \n " ,
tt_local_entry - > addr , message ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
hash_remove ( bat_priv - > tt_local_hash , compare_ltt , choose_orig ,
tt_local_entry - > addr ) ;
_tt_local_del ( & tt_local_entry - > hash_entry , bat_priv ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
void tt_local_remove ( struct bat_priv * bat_priv ,
2011-05-15 01:14:50 +04:00
const uint8_t * addr , const char * message )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
struct tt_local_entry * tt_local_entry ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
tt_local_entry = tt_local_hash_find ( bat_priv , addr ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
if ( tt_local_entry )
tt_local_del ( bat_priv , tt_local_entry , message ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
static void tt_local_purge ( struct work_struct * work )
2010-12-13 14:19:28 +03:00
{
struct delayed_work * delayed_work =
container_of ( work , struct delayed_work , work ) ;
struct bat_priv * bat_priv =
2011-05-05 10:42:45 +04:00
container_of ( delayed_work , struct bat_priv , tt_work ) ;
struct hashtable_t * hash = bat_priv - > tt_local_hash ;
struct tt_local_entry * tt_local_entry ;
2011-02-18 15:28:09 +03:00
struct hlist_node * node , * node_tmp ;
2010-12-13 14:19:28 +03:00
struct hlist_head * head ;
unsigned long timeout ;
2011-02-18 15:28:09 +03:00
int i ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-05-05 10:42:45 +04:00
hlist_for_each_entry_safe ( tt_local_entry , node , node_tmp ,
2011-02-18 15:28:09 +03:00
head , hash_entry ) {
2011-05-05 10:42:45 +04:00
if ( tt_local_entry - > never_purge )
2011-02-18 15:28:09 +03:00
continue ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
timeout = tt_local_entry - > last_seen ;
timeout + = TT_LOCAL_TIMEOUT * HZ ;
2010-12-13 14:19:28 +03:00
2011-02-18 15:28:09 +03:00
if ( time_before ( jiffies , timeout ) )
continue ;
2011-05-05 10:42:45 +04:00
tt_local_del ( bat_priv , tt_local_entry ,
2011-02-18 15:28:09 +03:00
" address timed out " ) ;
2010-12-13 14:19:28 +03:00
}
}
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_lhash_lock ) ;
tt_local_start_timer ( bat_priv ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
void tt_local_free ( struct bat_priv * bat_priv )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
if ( ! bat_priv - > tt_local_hash )
2010-12-13 14:19:28 +03:00
return ;
2011-05-05 10:42:45 +04:00
cancel_delayed_work_sync ( & bat_priv - > tt_work ) ;
hash_delete ( bat_priv - > tt_local_hash , _tt_local_del , bat_priv ) ;
bat_priv - > tt_local_hash = NULL ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
int tt_global_init ( struct bat_priv * bat_priv )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
if ( bat_priv - > tt_global_hash )
2010-12-13 14:19:28 +03:00
return 1 ;
2011-05-05 10:42:45 +04:00
bat_priv - > tt_global_hash = hash_new ( 1024 ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
if ( ! bat_priv - > tt_global_hash )
2010-12-13 14:19:28 +03:00
return 0 ;
return 1 ;
}
2011-05-05 10:42:45 +04:00
void tt_global_add_orig ( struct bat_priv * bat_priv ,
2010-12-13 14:19:28 +03:00
struct orig_node * orig_node ,
2011-05-15 01:14:50 +04:00
const unsigned char * tt_buff , int tt_buff_len )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
struct tt_global_entry * tt_global_entry ;
struct tt_local_entry * tt_local_entry ;
int tt_buff_count = 0 ;
2011-05-15 01:14:50 +04:00
const unsigned char * tt_ptr ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
while ( ( tt_buff_count + 1 ) * ETH_ALEN < = tt_buff_len ) {
spin_lock_bh ( & bat_priv - > tt_ghash_lock ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
tt_ptr = tt_buff + ( tt_buff_count * ETH_ALEN ) ;
tt_global_entry = tt_global_hash_find ( bat_priv , tt_ptr ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
if ( ! tt_global_entry ) {
spin_unlock_bh ( & bat_priv - > tt_ghash_lock ) ;
2010-12-13 14:19:28 +03:00
2011-05-15 01:14:54 +04:00
tt_global_entry = kmalloc ( sizeof ( * tt_global_entry ) ,
GFP_ATOMIC ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
if ( ! tt_global_entry )
2010-12-13 14:19:28 +03:00
break ;
2011-05-05 10:42:45 +04:00
memcpy ( tt_global_entry - > addr , tt_ptr , ETH_ALEN ) ;
2010-12-13 14:19:28 +03:00
bat_dbg ( DBG_ROUTES , bat_priv ,
2011-05-05 10:42:45 +04:00
" Creating new global tt entry: "
2010-12-13 14:19:28 +03:00
" %pM (via %pM) \n " ,
2011-05-05 10:42:45 +04:00
tt_global_entry - > addr , orig_node - > orig ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_ghash_lock ) ;
hash_add ( bat_priv - > tt_global_hash , compare_gtt ,
choose_orig , tt_global_entry ,
& tt_global_entry - > hash_entry ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
tt_global_entry - > orig_node = orig_node ;
spin_unlock_bh ( & bat_priv - > tt_ghash_lock ) ;
2010-12-13 14:19:28 +03:00
/* remove address from local hash if present */
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
tt_ptr = tt_buff + ( tt_buff_count * ETH_ALEN ) ;
tt_local_entry = tt_local_hash_find ( bat_priv , tt_ptr ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
if ( tt_local_entry )
tt_local_del ( bat_priv , tt_local_entry ,
" global tt received " ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_lhash_lock ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
tt_buff_count + + ;
2010-12-13 14:19:28 +03:00
}
/* initialize, and overwrite if malloc succeeds */
2011-05-05 10:42:45 +04:00
orig_node - > tt_buff = NULL ;
orig_node - > tt_buff_len = 0 ;
if ( tt_buff_len > 0 ) {
orig_node - > tt_buff = kmalloc ( tt_buff_len , GFP_ATOMIC ) ;
if ( orig_node - > tt_buff ) {
memcpy ( orig_node - > tt_buff , tt_buff , tt_buff_len ) ;
orig_node - > tt_buff_len = tt_buff_len ;
2010-12-13 14:19:28 +03:00
}
}
}
2011-05-05 10:42:45 +04:00
int tt_global_seq_print_text ( struct seq_file * seq , void * offset )
2010-12-13 14:19:28 +03:00
{
struct net_device * net_dev = ( struct net_device * ) seq - > private ;
struct bat_priv * bat_priv = netdev_priv ( net_dev ) ;
2011-05-05 10:42:45 +04:00
struct hashtable_t * hash = bat_priv - > tt_global_hash ;
struct tt_global_entry * tt_global_entry ;
2011-04-20 17:40:58 +04:00
struct hard_iface * primary_if ;
2011-02-18 15:28:09 +03:00
struct hlist_node * node ;
2010-12-13 14:19:28 +03:00
struct hlist_head * head ;
size_t buf_size , pos ;
char * buff ;
2011-04-20 17:40:58 +04:00
int i , ret = 0 ;
primary_if = primary_if_get_selected ( bat_priv ) ;
if ( ! primary_if ) {
ret = seq_printf ( seq , " BATMAN mesh %s disabled - please "
" specify interfaces to enable it \n " ,
net_dev - > name ) ;
goto out ;
}
2010-12-13 14:19:28 +03:00
2011-04-20 17:40:58 +04:00
if ( primary_if - > if_status ! = IF_ACTIVE ) {
ret = seq_printf ( seq , " BATMAN mesh %s disabled - "
" primary interface not active \n " ,
net_dev - > name ) ;
goto out ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
seq_printf ( seq ,
" Globally announced TT entries received via the mesh %s \n " ,
2010-12-13 14:19:28 +03:00
net_dev - > name ) ;
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_ghash_lock ) ;
2010-12-13 14:19:28 +03:00
buf_size = 1 ;
/* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-02-18 15:28:09 +03:00
rcu_read_lock ( ) ;
__hlist_for_each_rcu ( node , head )
2010-12-13 14:19:28 +03:00
buf_size + = 43 ;
2011-02-18 15:28:09 +03:00
rcu_read_unlock ( ) ;
2010-12-13 14:19:28 +03:00
}
buff = kmalloc ( buf_size , GFP_ATOMIC ) ;
if ( ! buff ) {
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_ghash_lock ) ;
2011-04-20 17:40:58 +04:00
ret = - ENOMEM ;
goto out ;
2010-12-13 14:19:28 +03:00
}
buff [ 0 ] = ' \0 ' ;
pos = 0 ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-02-18 15:28:09 +03:00
rcu_read_lock ( ) ;
2011-05-05 10:42:45 +04:00
hlist_for_each_entry_rcu ( tt_global_entry , node ,
2011-02-18 15:28:09 +03:00
head , hash_entry ) {
2010-12-13 14:19:28 +03:00
pos + = snprintf ( buff + pos , 44 ,
" * %pM via %pM \n " ,
2011-05-05 10:42:45 +04:00
tt_global_entry - > addr ,
tt_global_entry - > orig_node - > orig ) ;
2010-12-13 14:19:28 +03:00
}
2011-02-18 15:28:09 +03:00
rcu_read_unlock ( ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_ghash_lock ) ;
2010-12-13 14:19:28 +03:00
seq_printf ( seq , " %s " , buff ) ;
kfree ( buff ) ;
2011-04-20 17:40:58 +04:00
out :
if ( primary_if )
hardif_free_ref ( primary_if ) ;
return ret ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
static void _tt_global_del_orig ( struct bat_priv * bat_priv ,
struct tt_global_entry * tt_global_entry ,
2011-05-15 01:14:50 +04:00
const char * message )
2010-12-13 14:19:28 +03:00
{
bat_dbg ( DBG_ROUTES , bat_priv ,
2011-05-05 10:42:45 +04:00
" Deleting global tt entry %pM (via %pM): %s \n " ,
tt_global_entry - > addr , tt_global_entry - > orig_node - > orig ,
2010-12-13 14:19:28 +03:00
message ) ;
2011-05-05 10:42:45 +04:00
hash_remove ( bat_priv - > tt_global_hash , compare_gtt , choose_orig ,
tt_global_entry - > addr ) ;
kfree ( tt_global_entry ) ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
void tt_global_del_orig ( struct bat_priv * bat_priv ,
2011-05-15 01:14:50 +04:00
struct orig_node * orig_node , const char * message )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
struct tt_global_entry * tt_global_entry ;
int tt_buff_count = 0 ;
unsigned char * tt_ptr ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
if ( orig_node - > tt_buff_len = = 0 )
2010-12-13 14:19:28 +03:00
return ;
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_ghash_lock ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
while ( ( tt_buff_count + 1 ) * ETH_ALEN < = orig_node - > tt_buff_len ) {
tt_ptr = orig_node - > tt_buff + ( tt_buff_count * ETH_ALEN ) ;
tt_global_entry = tt_global_hash_find ( bat_priv , tt_ptr ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
if ( ( tt_global_entry ) & &
( tt_global_entry - > orig_node = = orig_node ) )
_tt_global_del_orig ( bat_priv , tt_global_entry ,
2010-12-13 14:19:28 +03:00
message ) ;
2011-05-05 10:42:45 +04:00
tt_buff_count + + ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_ghash_lock ) ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
orig_node - > tt_buff_len = 0 ;
kfree ( orig_node - > tt_buff ) ;
orig_node - > tt_buff = NULL ;
2010-12-13 14:19:28 +03:00
}
2011-05-05 10:42:45 +04:00
static void tt_global_del ( struct hlist_node * node , void * arg )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
void * data = container_of ( node , struct tt_global_entry , hash_entry ) ;
2011-02-18 15:28:09 +03:00
2010-12-13 14:19:28 +03:00
kfree ( data ) ;
}
2011-05-05 10:42:45 +04:00
void tt_global_free ( struct bat_priv * bat_priv )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
if ( ! bat_priv - > tt_global_hash )
2010-12-13 14:19:28 +03:00
return ;
2011-05-05 10:42:45 +04:00
hash_delete ( bat_priv - > tt_global_hash , tt_global_del , NULL ) ;
bat_priv - > tt_global_hash = NULL ;
2010-12-13 14:19:28 +03:00
}
2011-05-15 01:14:50 +04:00
struct orig_node * transtable_search ( struct bat_priv * bat_priv ,
const uint8_t * addr )
2010-12-13 14:19:28 +03:00
{
2011-05-05 10:42:45 +04:00
struct tt_global_entry * tt_global_entry ;
2011-02-18 15:28:10 +03:00
struct orig_node * orig_node = NULL ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
spin_lock_bh ( & bat_priv - > tt_ghash_lock ) ;
tt_global_entry = tt_global_hash_find ( bat_priv , addr ) ;
2011-02-18 15:28:09 +03:00
2011-05-05 10:42:45 +04:00
if ( ! tt_global_entry )
2011-02-18 15:28:10 +03:00
goto out ;
2011-02-18 15:28:09 +03:00
2011-05-05 10:42:45 +04:00
if ( ! atomic_inc_not_zero ( & tt_global_entry - > orig_node - > refcount ) )
2011-02-18 15:28:10 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2011-05-05 10:42:45 +04:00
orig_node = tt_global_entry - > orig_node ;
2010-12-13 14:19:28 +03:00
2011-02-18 15:28:10 +03:00
out :
2011-05-05 10:42:45 +04:00
spin_unlock_bh ( & bat_priv - > tt_ghash_lock ) ;
2011-02-18 15:28:10 +03:00
return orig_node ;
2010-12-13 14:19:28 +03:00
}