2012-05-12 02:09:43 +02:00
/* Copyright (C) 2008-2012 B.A.T.M.A.N. contributors:
2010-12-13 11:19:28 +00:00
*
* 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 "send.h"
# include "translation-table.h"
# include "vis.h"
# include "soft-interface.h"
# include "hard-interface.h"
# include "hash.h"
# include "originator.h"
2012-06-03 22:19:07 +02:00
# define BATADV_MAX_VIS_PACKET_SIZE 1000
2010-12-13 11:19:28 +00:00
2012-05-16 20:23:18 +02:00
static void batadv_start_vis_timer ( struct bat_priv * bat_priv ) ;
2010-12-13 11:19:28 +00:00
/* free the info */
2012-05-16 20:23:18 +02:00
static void batadv_free_info ( struct kref * ref )
2010-12-13 11:19:28 +00:00
{
struct vis_info * info = container_of ( ref , struct vis_info , refcount ) ;
struct bat_priv * bat_priv = info - > bat_priv ;
struct recvlist_node * entry , * tmp ;
list_del_init ( & info - > send_list ) ;
spin_lock_bh ( & bat_priv - > vis_list_lock ) ;
list_for_each_entry_safe ( entry , tmp , & info - > recv_list , list ) {
list_del ( & entry - > list ) ;
kfree ( entry ) ;
}
spin_unlock_bh ( & bat_priv - > vis_list_lock ) ;
kfree_skb ( info - > skb_packet ) ;
2011-01-28 18:34:06 +01:00
kfree ( info ) ;
2010-12-13 11:19:28 +00:00
}
/* Compare two vis packets, used by the hashing algorithm */
2012-05-16 20:23:18 +02:00
static int batadv_vis_info_cmp ( const struct hlist_node * node , const void * data2 )
2010-12-13 11:19:28 +00:00
{
2011-05-14 23:14:50 +02:00
const struct vis_info * d1 , * d2 ;
const struct vis_packet * p1 , * p2 ;
2011-02-18 12:28:09 +00:00
d1 = container_of ( node , struct vis_info , hash_entry ) ;
2010-12-13 11:19:28 +00:00
d2 = data2 ;
p1 = ( struct vis_packet * ) d1 - > skb_packet - > data ;
p2 = ( struct vis_packet * ) d2 - > skb_packet - > data ;
2012-05-12 13:48:58 +02:00
return batadv_compare_eth ( p1 - > vis_orig , p2 - > vis_orig ) ;
2010-12-13 11:19:28 +00:00
}
2012-05-12 02:09:43 +02:00
/* hash function to choose an entry in a hash table of given size
* hash algorithm from http : //en.wikipedia.org/wiki/Hash_table
*/
2012-05-16 20:23:18 +02:00
static uint32_t batadv_vis_info_choose ( const void * data , uint32_t size )
2010-12-13 11:19:28 +00:00
{
2011-05-14 23:14:50 +02:00
const struct vis_info * vis_info = data ;
const struct vis_packet * packet ;
const unsigned char * key ;
2010-12-13 11:19:28 +00:00
uint32_t hash = 0 ;
size_t i ;
packet = ( struct vis_packet * ) vis_info - > skb_packet - > data ;
key = packet - > vis_orig ;
for ( i = 0 ; i < ETH_ALEN ; i + + ) {
hash + = key [ i ] ;
hash + = ( hash < < 10 ) ;
hash ^ = ( hash > > 6 ) ;
}
hash + = ( hash < < 3 ) ;
hash ^ = ( hash > > 11 ) ;
hash + = ( hash < < 15 ) ;
return hash % size ;
}
2012-05-16 20:23:18 +02:00
static struct vis_info * batadv_vis_hash_find ( struct bat_priv * bat_priv ,
const void * data )
2011-02-18 12:28:09 +00:00
{
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash = bat_priv - > vis_hash ;
2011-02-18 12:28:09 +00:00
struct hlist_head * head ;
struct hlist_node * node ;
struct vis_info * vis_info , * vis_info_tmp = NULL ;
2011-10-05 17:05:25 +02:00
uint32_t index ;
2011-02-18 12:28:09 +00:00
if ( ! hash )
return NULL ;
2012-05-16 20:23:18 +02:00
index = batadv_vis_info_choose ( data , hash - > size ) ;
2011-02-18 12:28:09 +00:00
head = & hash - > table [ index ] ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( vis_info , node , head , hash_entry ) {
2012-05-16 20:23:18 +02:00
if ( ! batadv_vis_info_cmp ( node , data ) )
2011-02-18 12:28:09 +00:00
continue ;
vis_info_tmp = vis_info ;
break ;
}
rcu_read_unlock ( ) ;
return vis_info_tmp ;
}
2010-12-13 11:19:28 +00:00
/* insert interface to the list of interfaces of one originator, if it
2012-05-12 02:09:43 +02:00
* does not already exist in the list
*/
2012-05-16 20:23:18 +02:00
static void batadv_vis_data_insert_interface ( const uint8_t * interface ,
struct hlist_head * if_list ,
bool primary )
2010-12-13 11:19:28 +00:00
{
struct if_list_entry * entry ;
struct hlist_node * pos ;
hlist_for_each_entry ( entry , pos , if_list , list ) {
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( entry - > addr , interface ) )
2010-12-13 11:19:28 +00:00
return ;
}
2011-07-09 17:52:13 +02:00
/* it's a new address, add it to the list */
2010-12-13 11:19:28 +00:00
entry = kmalloc ( sizeof ( * entry ) , GFP_ATOMIC ) ;
if ( ! entry )
return ;
memcpy ( entry - > addr , interface , ETH_ALEN ) ;
entry - > primary = primary ;
hlist_add_head ( & entry - > list , if_list ) ;
}
2012-05-16 20:23:23 +02:00
static void batadv_vis_data_read_prim_sec ( struct seq_file * seq ,
const struct hlist_head * if_list )
2010-12-13 11:19:28 +00:00
{
struct if_list_entry * entry ;
struct hlist_node * pos ;
hlist_for_each_entry ( entry , pos , if_list , list ) {
if ( entry - > primary )
2012-05-16 20:23:23 +02:00
seq_printf ( seq , " PRIMARY, " ) ;
2010-12-13 11:19:28 +00:00
else
2012-05-16 20:23:23 +02:00
seq_printf ( seq , " SEC %pM, " , entry - > addr ) ;
2010-12-13 11:19:28 +00:00
}
2012-05-16 20:23:23 +02:00
}
/* read an entry */
static ssize_t batadv_vis_data_read_entry ( struct seq_file * seq ,
const struct vis_info_entry * entry ,
const uint8_t * src , bool primary )
{
if ( primary & & entry - > quality = = 0 )
return seq_printf ( seq , " TT %pM, " , entry - > dest ) ;
else if ( batadv_compare_eth ( entry - > src , src ) )
return seq_printf ( seq , " TQ %pM %d, " , entry - > dest ,
entry - > quality ) ;
2010-12-13 11:19:28 +00:00
2012-05-16 20:23:23 +02:00
return 0 ;
2010-12-13 11:19:28 +00:00
}
2012-05-16 20:23:23 +02:00
static void batadv_vis_data_insert_interfaces ( struct hlist_head * list ,
struct vis_packet * packet ,
struct vis_info_entry * entries )
2010-12-13 11:19:28 +00:00
{
2012-05-16 20:23:23 +02:00
int i ;
for ( i = 0 ; i < packet - > entries ; i + + ) {
if ( entries [ i ] . quality = = 0 )
continue ;
if ( batadv_compare_eth ( entries [ i ] . src , packet - > vis_orig ) )
continue ;
batadv_vis_data_insert_interface ( entries [ i ] . src , list , false ) ;
}
}
static void batadv_vis_data_read_entries ( struct seq_file * seq ,
struct hlist_head * list ,
struct vis_packet * packet ,
struct vis_info_entry * entries )
{
int i ;
2010-12-13 11:19:28 +00:00
struct if_list_entry * entry ;
struct hlist_node * pos ;
2012-05-16 20:23:23 +02:00
hlist_for_each_entry ( entry , pos , list , list ) {
seq_printf ( seq , " %pM, " , entry - > addr ) ;
for ( i = 0 ; i < packet - > entries ; i + + )
batadv_vis_data_read_entry ( seq , & entries [ i ] ,
entry - > addr , entry - > primary ) ;
/* add primary/secondary records */
if ( batadv_compare_eth ( entry - > addr , packet - > vis_orig ) )
batadv_vis_data_read_prim_sec ( seq , list ) ;
2010-12-13 11:19:28 +00:00
2012-05-16 20:23:23 +02:00
seq_printf ( seq , " \n " ) ;
}
2010-12-13 11:19:28 +00:00
}
2012-05-16 20:23:23 +02:00
static void batadv_vis_seq_print_text_bucket ( struct seq_file * seq ,
const struct hlist_head * head )
2010-12-13 11:19:28 +00:00
{
2012-05-16 20:23:23 +02:00
struct hlist_node * node ;
struct vis_info * info ;
struct vis_packet * packet ;
uint8_t * entries_pos ;
struct vis_info_entry * entries ;
struct if_list_entry * entry ;
struct hlist_node * pos , * n ;
2010-12-13 11:19:28 +00:00
2012-05-16 20:23:23 +02:00
HLIST_HEAD ( vis_if_list ) ;
hlist_for_each_entry_rcu ( info , node , head , hash_entry ) {
packet = ( struct vis_packet * ) info - > skb_packet - > data ;
entries_pos = ( uint8_t * ) packet + sizeof ( * packet ) ;
entries = ( struct vis_info_entry * ) entries_pos ;
batadv_vis_data_insert_interface ( packet - > vis_orig , & vis_if_list ,
true ) ;
batadv_vis_data_insert_interfaces ( & vis_if_list , packet ,
entries ) ;
batadv_vis_data_read_entries ( seq , & vis_if_list , packet ,
entries ) ;
hlist_for_each_entry_safe ( entry , pos , n , & vis_if_list , list ) {
hlist_del ( & entry - > list ) ;
kfree ( entry ) ;
}
}
2010-12-13 11:19:28 +00:00
}
2012-05-12 02:09:41 +02:00
int batadv_vis_seq_print_text ( struct seq_file * seq , void * offset )
2010-12-13 11:19:28 +00:00
{
2011-04-20 15:40:58 +02:00
struct hard_iface * primary_if ;
2010-12-13 11:19:28 +00:00
struct hlist_head * head ;
struct net_device * net_dev = ( struct net_device * ) seq - > private ;
struct bat_priv * bat_priv = netdev_priv ( net_dev ) ;
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash = bat_priv - > vis_hash ;
2011-10-05 17:05:25 +02:00
uint32_t i ;
2012-05-16 20:23:23 +02:00
int ret = 0 ;
2010-12-13 11:19:28 +00:00
int vis_server = atomic_read ( & bat_priv - > vis_mode ) ;
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-04-20 15:40:58 +02:00
if ( ! primary_if )
goto out ;
2012-06-03 22:19:21 +02:00
if ( vis_server = = BATADV_VIS_TYPE_CLIENT_UPDATE )
2011-04-20 15:40:58 +02:00
goto out ;
2010-12-13 11:19:28 +00:00
spin_lock_bh ( & bat_priv - > vis_hash_lock ) ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2012-05-16 20:23:23 +02:00
batadv_vis_seq_print_text_bucket ( seq , head ) ;
2010-12-13 11:19:28 +00:00
}
spin_unlock_bh ( & bat_priv - > vis_hash_lock ) ;
2011-04-20 15:40:58 +02:00
out :
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2011-04-20 15:40:58 +02:00
return ret ;
2010-12-13 11:19:28 +00:00
}
/* add the info packet to the send list, if it was not
2012-05-12 02:09:43 +02:00
* already linked in .
*/
2012-05-16 20:23:18 +02:00
static void batadv_send_list_add ( struct bat_priv * bat_priv ,
struct vis_info * info )
2010-12-13 11:19:28 +00:00
{
if ( list_empty ( & info - > send_list ) ) {
kref_get ( & info - > refcount ) ;
list_add_tail ( & info - > send_list , & bat_priv - > vis_send_list ) ;
}
}
/* delete the info packet from the send list, if it was
2012-05-12 02:09:43 +02:00
* linked in .
*/
2012-05-16 20:23:18 +02:00
static void batadv_send_list_del ( struct vis_info * info )
2010-12-13 11:19:28 +00:00
{
if ( ! list_empty ( & info - > send_list ) ) {
list_del_init ( & info - > send_list ) ;
2012-05-16 20:23:18 +02:00
kref_put ( & info - > refcount , batadv_free_info ) ;
2010-12-13 11:19:28 +00:00
}
}
/* tries to add one entry to the receive list. */
2012-05-16 20:23:18 +02:00
static void batadv_recv_list_add ( struct bat_priv * bat_priv ,
struct list_head * recv_list , const char * mac )
2010-12-13 11:19:28 +00:00
{
struct recvlist_node * entry ;
2011-05-14 23:14:54 +02:00
entry = kmalloc ( sizeof ( * entry ) , GFP_ATOMIC ) ;
2010-12-13 11:19:28 +00:00
if ( ! entry )
return ;
memcpy ( entry - > mac , mac , ETH_ALEN ) ;
spin_lock_bh ( & bat_priv - > vis_list_lock ) ;
list_add_tail ( & entry - > list , recv_list ) ;
spin_unlock_bh ( & bat_priv - > vis_list_lock ) ;
}
/* returns 1 if this mac is in the recv_list */
2012-05-16 20:23:18 +02:00
static int batadv_recv_list_is_in ( struct bat_priv * bat_priv ,
const struct list_head * recv_list ,
const char * mac )
2010-12-13 11:19:28 +00:00
{
2011-05-14 23:14:50 +02:00
const struct recvlist_node * entry ;
2010-12-13 11:19:28 +00:00
spin_lock_bh ( & bat_priv - > vis_list_lock ) ;
list_for_each_entry ( entry , recv_list , list ) {
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( entry - > mac , mac ) ) {
2010-12-13 11:19:28 +00:00
spin_unlock_bh ( & bat_priv - > vis_list_lock ) ;
return 1 ;
}
}
spin_unlock_bh ( & bat_priv - > vis_list_lock ) ;
return 0 ;
}
/* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old,
* broken . . ) . vis hash must be locked outside . is_new is set when the packet
2012-05-12 02:09:43 +02:00
* is newer than old entries in the hash .
*/
2012-05-16 20:23:18 +02:00
static struct vis_info * batadv_add_packet ( struct bat_priv * bat_priv ,
struct vis_packet * vis_packet ,
int vis_info_len , int * is_new ,
int make_broadcast )
2010-12-13 11:19:28 +00:00
{
struct vis_info * info , * old_info ;
struct vis_packet * search_packet , * old_packet ;
struct vis_info search_elem ;
struct vis_packet * packet ;
int hash_added ;
* is_new = 0 ;
/* sanity check */
if ( ! bat_priv - > vis_hash )
return NULL ;
/* see if the packet is already in vis_hash */
2011-05-14 23:14:54 +02:00
search_elem . skb_packet = dev_alloc_skb ( sizeof ( * search_packet ) ) ;
2010-12-13 11:19:28 +00:00
if ( ! search_elem . skb_packet )
return NULL ;
search_packet = ( struct vis_packet * ) skb_put ( search_elem . skb_packet ,
2011-05-14 23:14:54 +02:00
sizeof ( * search_packet ) ) ;
2010-12-13 11:19:28 +00:00
memcpy ( search_packet - > vis_orig , vis_packet - > vis_orig , ETH_ALEN ) ;
2012-05-16 20:23:18 +02:00
old_info = batadv_vis_hash_find ( bat_priv , & search_elem ) ;
2010-12-13 11:19:28 +00:00
kfree_skb ( search_elem . skb_packet ) ;
if ( old_info ) {
old_packet = ( struct vis_packet * ) old_info - > skb_packet - > data ;
2012-05-16 20:23:22 +02:00
if ( ! batadv_seq_after ( ntohl ( vis_packet - > seqno ) ,
ntohl ( old_packet - > seqno ) ) ) {
2010-12-13 11:19:28 +00:00
if ( old_packet - > seqno = = vis_packet - > seqno ) {
2012-05-16 20:23:18 +02:00
batadv_recv_list_add ( bat_priv ,
& old_info - > recv_list ,
vis_packet - > sender_orig ) ;
2010-12-13 11:19:28 +00:00
return old_info ;
} else {
/* newer packet is already in hash. */
return NULL ;
}
}
/* remove old entry */
2012-05-16 20:23:18 +02:00
batadv_hash_remove ( bat_priv - > vis_hash , batadv_vis_info_cmp ,
batadv_vis_info_choose , old_info ) ;
batadv_send_list_del ( old_info ) ;
kref_put ( & old_info - > refcount , batadv_free_info ) ;
2010-12-13 11:19:28 +00:00
}
2011-05-14 23:14:54 +02:00
info = kmalloc ( sizeof ( * info ) , GFP_ATOMIC ) ;
2010-12-13 11:19:28 +00:00
if ( ! info )
return NULL ;
2011-05-14 23:14:54 +02:00
info - > skb_packet = dev_alloc_skb ( sizeof ( * packet ) + vis_info_len +
2012-02-18 11:27:34 +01:00
ETH_HLEN ) ;
2010-12-13 11:19:28 +00:00
if ( ! info - > skb_packet ) {
kfree ( info ) ;
return NULL ;
}
2012-02-18 11:27:34 +01:00
skb_reserve ( info - > skb_packet , ETH_HLEN ) ;
2011-05-14 23:14:54 +02:00
packet = ( struct vis_packet * ) skb_put ( info - > skb_packet , sizeof ( * packet )
+ vis_info_len ) ;
2010-12-13 11:19:28 +00:00
kref_init ( & info - > refcount ) ;
INIT_LIST_HEAD ( & info - > send_list ) ;
INIT_LIST_HEAD ( & info - > recv_list ) ;
info - > first_seen = jiffies ;
info - > bat_priv = bat_priv ;
2011-05-14 23:14:54 +02:00
memcpy ( packet , vis_packet , sizeof ( * packet ) + vis_info_len ) ;
2010-12-13 11:19:28 +00:00
/* initialize and add new packet. */
* is_new = 1 ;
/* Make it a broadcast packet, if required */
if ( make_broadcast )
2012-05-12 02:09:42 +02:00
memcpy ( packet - > target_orig , batadv_broadcast_addr , ETH_ALEN ) ;
2010-12-13 11:19:28 +00:00
/* repair if entries is longer than packet. */
if ( packet - > entries * sizeof ( struct vis_info_entry ) > vis_info_len )
packet - > entries = vis_info_len / sizeof ( struct vis_info_entry ) ;
2012-05-16 20:23:18 +02:00
batadv_recv_list_add ( bat_priv , & info - > recv_list , packet - > sender_orig ) ;
2010-12-13 11:19:28 +00:00
/* try to add it */
2012-05-16 20:23:18 +02:00
hash_added = batadv_hash_add ( bat_priv - > vis_hash , batadv_vis_info_cmp ,
batadv_vis_info_choose , info ,
& info - > hash_entry ) ;
2011-07-10 00:36:36 +02:00
if ( hash_added ! = 0 ) {
2010-12-13 11:19:28 +00:00
/* did not work (for some reason) */
2012-05-16 20:23:18 +02:00
kref_put ( & info - > refcount , batadv_free_info ) ;
2010-12-13 11:19:28 +00:00
info = NULL ;
}
return info ;
}
/* handle the server sync packet, forward if needed. */
2012-05-12 02:09:41 +02:00
void batadv_receive_server_sync_packet ( struct bat_priv * bat_priv ,
struct vis_packet * vis_packet ,
int vis_info_len )
2010-12-13 11:19:28 +00:00
{
struct vis_info * info ;
int is_new , make_broadcast ;
int vis_server = atomic_read ( & bat_priv - > vis_mode ) ;
2012-06-03 22:19:21 +02:00
make_broadcast = ( vis_server = = BATADV_VIS_TYPE_SERVER_SYNC ) ;
2010-12-13 11:19:28 +00:00
spin_lock_bh ( & bat_priv - > vis_hash_lock ) ;
2012-05-16 20:23:18 +02:00
info = batadv_add_packet ( bat_priv , vis_packet , vis_info_len ,
& is_new , make_broadcast ) ;
2010-12-13 11:19:28 +00:00
if ( ! info )
goto end ;
/* only if we are server ourselves and packet is newer than the one in
2012-05-12 02:09:43 +02:00
* hash .
*/
2012-06-03 22:19:21 +02:00
if ( vis_server = = BATADV_VIS_TYPE_SERVER_SYNC & & is_new )
2012-05-16 20:23:18 +02:00
batadv_send_list_add ( bat_priv , info ) ;
2010-12-13 11:19:28 +00:00
end :
spin_unlock_bh ( & bat_priv - > vis_hash_lock ) ;
}
/* handle an incoming client update packet and schedule forward if needed. */
2012-05-12 02:09:41 +02:00
void batadv_receive_client_update_packet ( struct bat_priv * bat_priv ,
struct vis_packet * vis_packet ,
int vis_info_len )
2010-12-13 11:19:28 +00:00
{
struct vis_info * info ;
struct vis_packet * packet ;
int is_new ;
int vis_server = atomic_read ( & bat_priv - > vis_mode ) ;
int are_target = 0 ;
/* clients shall not broadcast. */
if ( is_broadcast_ether_addr ( vis_packet - > target_orig ) )
return ;
/* Are we the target for this VIS packet? */
2012-06-03 22:19:21 +02:00
if ( vis_server = = BATADV_VIS_TYPE_SERVER_SYNC & &
2012-05-12 02:09:42 +02:00
batadv_is_my_mac ( vis_packet - > target_orig ) )
2010-12-13 11:19:28 +00:00
are_target = 1 ;
spin_lock_bh ( & bat_priv - > vis_hash_lock ) ;
2012-05-16 20:23:18 +02:00
info = batadv_add_packet ( bat_priv , vis_packet , vis_info_len ,
& is_new , are_target ) ;
2010-12-13 11:19:28 +00:00
if ( ! info )
goto end ;
/* note that outdated packets will be dropped at this point. */
packet = ( struct vis_packet * ) info - > skb_packet - > data ;
/* send only if we're the target server or ... */
if ( are_target & & is_new ) {
2012-06-03 22:19:21 +02:00
packet - > vis_type = BATADV_VIS_TYPE_SERVER_SYNC ; /* upgrade! */
2012-05-16 20:23:18 +02:00
batadv_send_list_add ( bat_priv , info ) ;
2010-12-13 11:19:28 +00:00
/* ... we're not the recipient (and thus need to forward). */
2012-05-12 02:09:42 +02:00
} else if ( ! batadv_is_my_mac ( packet - > target_orig ) ) {
2012-05-16 20:23:18 +02:00
batadv_send_list_add ( bat_priv , info ) ;
2010-12-13 11:19:28 +00:00
}
end :
spin_unlock_bh ( & bat_priv - > vis_hash_lock ) ;
}
/* Walk the originators and find the VIS server with the best tq. Set the packet
* address to its address and return the best_tq .
*
2012-05-12 02:09:43 +02:00
* Must be called with the originator hash locked
*/
2012-05-16 20:23:18 +02:00
static int batadv_find_best_vis_server ( struct bat_priv * bat_priv ,
struct vis_info * info )
2010-12-13 11:19:28 +00:00
{
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash = bat_priv - > orig_hash ;
2011-03-14 22:43:37 +00:00
struct neigh_node * router ;
2011-02-18 12:28:09 +00:00
struct hlist_node * node ;
2010-12-13 11:19:28 +00:00
struct hlist_head * head ;
struct orig_node * orig_node ;
struct vis_packet * packet ;
2011-10-05 17:05:25 +02:00
int best_tq = - 1 ;
uint32_t i ;
2010-12-13 11:19:28 +00:00
packet = ( struct vis_packet * ) info - > skb_packet - > data ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-01-19 20:01:40 +00:00
rcu_read_lock ( ) ;
2011-02-18 12:28:09 +00:00
hlist_for_each_entry_rcu ( orig_node , node , head , hash_entry ) {
2012-05-12 02:09:34 +02:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-03-14 22:43:37 +00:00
if ( ! router )
continue ;
2012-06-03 22:19:21 +02:00
if ( ( orig_node - > flags & BATADV_VIS_SERVER ) & &
2011-03-14 22:43:37 +00:00
( router - > tq_avg > best_tq ) ) {
best_tq = router - > tq_avg ;
2010-12-13 11:19:28 +00:00
memcpy ( packet - > target_orig , orig_node - > orig ,
ETH_ALEN ) ;
}
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( router ) ;
2010-12-13 11:19:28 +00:00
}
2011-01-19 20:01:40 +00:00
rcu_read_unlock ( ) ;
2010-12-13 11:19:28 +00:00
}
return best_tq ;
}
/* Return true if the vis packet is full. */
2012-05-16 20:23:18 +02:00
static bool batadv_vis_packet_full ( const struct vis_info * info )
2010-12-13 11:19:28 +00:00
{
2011-05-14 23:14:50 +02:00
const struct vis_packet * packet ;
2012-06-03 22:19:07 +02:00
size_t num_items ;
2010-12-13 11:19:28 +00:00
packet = ( struct vis_packet * ) info - > skb_packet - > data ;
2012-06-03 22:19:07 +02:00
num_items = BATADV_MAX_VIS_PACKET_SIZE / sizeof ( struct vis_info_entry ) ;
2010-12-13 11:19:28 +00:00
2012-06-03 22:19:07 +02:00
if ( num_items < packet - > entries + 1 )
2010-12-13 11:19:28 +00:00
return true ;
return false ;
}
/* generates a packet of own vis data,
2012-05-12 02:09:43 +02:00
* returns 0 on success , - 1 if no packet could be generated
*/
2012-05-16 20:23:18 +02:00
static int batadv_generate_vis_packet ( struct bat_priv * bat_priv )
2010-12-13 11:19:28 +00:00
{
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash = bat_priv - > orig_hash ;
2011-02-18 12:28:09 +00:00
struct hlist_node * node ;
2010-12-13 11:19:28 +00:00
struct hlist_head * head ;
struct orig_node * orig_node ;
2011-03-14 22:43:37 +00:00
struct neigh_node * router ;
2011-05-14 23:14:53 +02:00
struct vis_info * info = bat_priv - > my_vis_info ;
2010-12-13 11:19:28 +00:00
struct vis_packet * packet = ( struct vis_packet * ) info - > skb_packet - > data ;
struct vis_info_entry * entry ;
2011-10-30 12:17:33 +01:00
struct tt_common_entry * tt_common_entry ;
2011-10-05 17:05:25 +02:00
int best_tq = - 1 ;
uint32_t i ;
2010-12-13 11:19:28 +00:00
info - > first_seen = jiffies ;
packet - > vis_type = atomic_read ( & bat_priv - > vis_mode ) ;
2012-05-12 02:09:42 +02:00
memcpy ( packet - > target_orig , batadv_broadcast_addr , ETH_ALEN ) ;
2012-06-03 22:19:17 +02:00
packet - > header . ttl = BATADV_TTL ;
2010-12-13 11:19:28 +00:00
packet - > seqno = htonl ( ntohl ( packet - > seqno ) + 1 ) ;
packet - > entries = 0 ;
2011-05-14 23:14:54 +02:00
skb_trim ( info - > skb_packet , sizeof ( * packet ) ) ;
2010-12-13 11:19:28 +00:00
2012-06-03 22:19:21 +02:00
if ( packet - > vis_type = = BATADV_VIS_TYPE_CLIENT_UPDATE ) {
2012-05-16 20:23:18 +02:00
best_tq = batadv_find_best_vis_server ( bat_priv , info ) ;
2010-12-13 11:19:28 +00:00
2011-01-19 20:01:44 +00:00
if ( best_tq < 0 )
2012-05-05 13:27:28 +02:00
return best_tq ;
2010-12-13 11:19:28 +00:00
}
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-01-19 20:01:40 +00:00
rcu_read_lock ( ) ;
2011-02-18 12:28:09 +00:00
hlist_for_each_entry_rcu ( orig_node , node , head , hash_entry ) {
2012-05-12 02:09:34 +02:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-03-14 22:43:37 +00:00
if ( ! router )
2010-12-13 11:19:28 +00:00
continue ;
2012-05-12 13:48:58 +02:00
if ( ! batadv_compare_eth ( router - > addr , orig_node - > orig ) )
2011-03-14 22:43:37 +00:00
goto next ;
2010-12-13 11:19:28 +00:00
2012-06-03 22:19:19 +02:00
if ( router - > if_incoming - > if_status ! = BATADV_IF_ACTIVE )
2011-03-14 22:43:37 +00:00
goto next ;
2010-12-13 11:19:28 +00:00
2011-03-14 22:43:37 +00:00
if ( router - > tq_avg < 1 )
goto next ;
2010-12-13 11:19:28 +00:00
/* fill one entry into buffer. */
entry = ( struct vis_info_entry * )
skb_put ( info - > skb_packet , sizeof ( * entry ) ) ;
memcpy ( entry - > src ,
2011-03-14 22:43:37 +00:00
router - > if_incoming - > net_dev - > dev_addr ,
2010-12-13 11:19:28 +00:00
ETH_ALEN ) ;
memcpy ( entry - > dest , orig_node - > orig , ETH_ALEN ) ;
2011-03-14 22:43:37 +00:00
entry - > quality = router - > tq_avg ;
2010-12-13 11:19:28 +00:00
packet - > entries + + ;
2011-03-14 22:43:37 +00:00
next :
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( router ) ;
2011-03-14 22:43:37 +00:00
2012-05-16 20:23:18 +02:00
if ( batadv_vis_packet_full ( info ) )
2011-01-19 20:01:44 +00:00
goto unlock ;
2010-12-13 11:19:28 +00:00
}
2011-01-19 20:01:40 +00:00
rcu_read_unlock ( ) ;
2010-12-13 11:19:28 +00:00
}
2011-05-05 08:42:45 +02:00
hash = bat_priv - > tt_local_hash ;
2010-12-13 11:19:28 +00:00
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-04-27 14:28:07 +02:00
rcu_read_lock ( ) ;
2011-10-30 12:17:33 +01:00
hlist_for_each_entry_rcu ( tt_common_entry , node , head ,
2011-04-27 14:28:07 +02:00
hash_entry ) {
2010-12-13 11:19:28 +00:00
entry = ( struct vis_info_entry * )
skb_put ( info - > skb_packet ,
sizeof ( * entry ) ) ;
memset ( entry - > src , 0 , ETH_ALEN ) ;
2011-10-30 12:17:33 +01:00
memcpy ( entry - > dest , tt_common_entry - > addr , ETH_ALEN ) ;
2011-05-05 08:42:45 +02:00
entry - > quality = 0 ; /* 0 means TT */
2010-12-13 11:19:28 +00:00
packet - > entries + + ;
2012-05-16 20:23:18 +02:00
if ( batadv_vis_packet_full ( info ) )
2011-04-27 14:28:07 +02:00
goto unlock ;
2010-12-13 11:19:28 +00:00
}
2011-04-27 14:28:07 +02:00
rcu_read_unlock ( ) ;
2010-12-13 11:19:28 +00:00
}
return 0 ;
2011-01-19 20:01:44 +00:00
unlock :
rcu_read_unlock ( ) ;
return 0 ;
2010-12-13 11:19:28 +00:00
}
/* free old vis packets. Must be called with this vis_hash_lock
2012-05-12 02:09:43 +02:00
* held
*/
2012-05-16 20:23:18 +02:00
static void batadv_purge_vis_packets ( struct bat_priv * bat_priv )
2010-12-13 11:19:28 +00:00
{
2011-10-05 17:05:25 +02:00
uint32_t i ;
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash = bat_priv - > vis_hash ;
2011-02-18 12:28:09 +00:00
struct hlist_node * node , * node_tmp ;
2010-12-13 11:19:28 +00:00
struct hlist_head * head ;
struct vis_info * info ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-02-18 12:28:09 +00:00
hlist_for_each_entry_safe ( info , node , node_tmp ,
head , hash_entry ) {
2010-12-13 11:19:28 +00:00
/* never purge own data. */
if ( info = = bat_priv - > my_vis_info )
continue ;
2012-05-12 13:48:58 +02:00
if ( batadv_has_timed_out ( info - > first_seen ,
2012-06-03 22:19:16 +02:00
BATADV_VIS_TIMEOUT ) ) {
2011-02-18 12:28:09 +00:00
hlist_del ( node ) ;
2012-05-16 20:23:18 +02:00
batadv_send_list_del ( info ) ;
kref_put ( & info - > refcount , batadv_free_info ) ;
2010-12-13 11:19:28 +00:00
}
}
}
}
2012-05-16 20:23:18 +02:00
static void batadv_broadcast_vis_packet ( struct bat_priv * bat_priv ,
struct vis_info * info )
2010-12-13 11:19:28 +00:00
{
2011-03-14 22:43:37 +00:00
struct neigh_node * router ;
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash = bat_priv - > orig_hash ;
2011-02-18 12:28:09 +00:00
struct hlist_node * node ;
2010-12-13 11:19:28 +00:00
struct hlist_head * head ;
struct orig_node * orig_node ;
struct vis_packet * packet ;
struct sk_buff * skb ;
2011-02-18 12:33:20 +00:00
struct hard_iface * hard_iface ;
2010-12-13 11:19:28 +00:00
uint8_t dstaddr [ ETH_ALEN ] ;
2011-10-05 17:05:25 +02:00
uint32_t i ;
2010-12-13 11:19:28 +00:00
packet = ( struct vis_packet * ) info - > skb_packet - > data ;
/* send to all routers in range. */
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-01-19 20:01:40 +00:00
rcu_read_lock ( ) ;
2011-02-18 12:28:09 +00:00
hlist_for_each_entry_rcu ( orig_node , node , head , hash_entry ) {
2010-12-13 11:19:28 +00:00
/* if it's a vis server and reachable, send it. */
2012-06-03 22:19:21 +02:00
if ( ! ( orig_node - > flags & BATADV_VIS_SERVER ) )
2010-12-13 11:19:28 +00:00
continue ;
2011-03-14 22:43:37 +00:00
2012-05-12 02:09:34 +02:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-03-14 22:43:37 +00:00
if ( ! router )
continue ;
2010-12-13 11:19:28 +00:00
/* don't send it if we already received the packet from
2012-05-12 02:09:43 +02:00
* this node .
*/
2012-05-16 20:23:18 +02:00
if ( batadv_recv_list_is_in ( bat_priv , & info - > recv_list ,
orig_node - > orig ) ) {
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( router ) ;
2010-12-13 11:19:28 +00:00
continue ;
2011-03-14 22:43:37 +00:00
}
2010-12-13 11:19:28 +00:00
memcpy ( packet - > target_orig , orig_node - > orig , ETH_ALEN ) ;
2011-03-14 22:43:37 +00:00
hard_iface = router - > if_incoming ;
memcpy ( dstaddr , router - > addr , ETH_ALEN ) ;
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( router ) ;
2010-12-13 11:19:28 +00:00
skb = skb_clone ( info - > skb_packet , GFP_ATOMIC ) ;
if ( skb )
2012-05-12 02:09:37 +02:00
batadv_send_skb_packet ( skb , hard_iface ,
dstaddr ) ;
2010-12-13 11:19:28 +00:00
}
2011-01-19 20:01:40 +00:00
rcu_read_unlock ( ) ;
2010-12-13 11:19:28 +00:00
}
}
2012-05-16 20:23:18 +02:00
static void batadv_unicast_vis_packet ( struct bat_priv * bat_priv ,
struct vis_info * info )
2010-12-13 11:19:28 +00:00
{
struct orig_node * orig_node ;
2011-03-14 22:43:37 +00:00
struct neigh_node * router = NULL ;
2010-12-13 11:19:28 +00:00
struct sk_buff * skb ;
struct vis_packet * packet ;
packet = ( struct vis_packet * ) info - > skb_packet - > data ;
2012-05-12 13:48:56 +02:00
orig_node = batadv_orig_hash_find ( bat_priv , packet - > target_orig ) ;
2011-02-10 14:33:53 +00:00
if ( ! orig_node )
2011-03-14 22:43:37 +00:00
goto out ;
2011-02-10 14:33:53 +00:00
2012-05-12 02:09:34 +02:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-03-14 22:43:37 +00:00
if ( ! router )
goto out ;
2010-12-13 11:19:28 +00:00
skb = skb_clone ( info - > skb_packet , GFP_ATOMIC ) ;
if ( skb )
2012-05-12 02:09:37 +02:00
batadv_send_skb_packet ( skb , router - > if_incoming , router - > addr ) ;
2010-12-13 11:19:28 +00:00
out :
2011-03-14 22:43:37 +00:00
if ( router )
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( router ) ;
2011-02-10 14:33:53 +00:00
if ( orig_node )
2012-05-12 02:09:34 +02:00
batadv_orig_node_free_ref ( orig_node ) ;
2010-12-13 11:19:28 +00:00
}
2012-05-16 20:23:18 +02:00
/* only send one vis packet. called from batadv_send_vis_packets() */
static void batadv_send_vis_packet ( struct bat_priv * bat_priv ,
struct vis_info * info )
2010-12-13 11:19:28 +00:00
{
2011-04-20 15:40:58 +02:00
struct hard_iface * primary_if ;
2010-12-13 11:19:28 +00:00
struct vis_packet * packet ;
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-04-20 15:40:58 +02:00
if ( ! primary_if )
goto out ;
2010-12-13 11:19:28 +00:00
packet = ( struct vis_packet * ) info - > skb_packet - > data ;
2011-11-20 15:47:38 +01:00
if ( packet - > header . ttl < 2 ) {
2010-12-13 11:19:28 +00:00
pr_debug ( " Error - can't send vis packet: ttl exceeded \n " ) ;
2011-04-20 15:40:58 +02:00
goto out ;
2010-12-13 11:19:28 +00:00
}
2011-04-20 15:40:58 +02:00
memcpy ( packet - > sender_orig , primary_if - > net_dev - > dev_addr , ETH_ALEN ) ;
2011-11-20 15:47:38 +01:00
packet - > header . ttl - - ;
2010-12-13 11:19:28 +00:00
if ( is_broadcast_ether_addr ( packet - > target_orig ) )
2012-05-16 20:23:18 +02:00
batadv_broadcast_vis_packet ( bat_priv , info ) ;
2010-12-13 11:19:28 +00:00
else
2012-05-16 20:23:18 +02:00
batadv_unicast_vis_packet ( bat_priv , info ) ;
2011-11-20 15:47:38 +01:00
packet - > header . ttl + + ; /* restore TTL */
2011-04-20 15:40:58 +02:00
out :
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2010-12-13 11:19:28 +00:00
}
/* called from timer; send (and maybe generate) vis packet. */
2012-05-16 20:23:18 +02:00
static void batadv_send_vis_packets ( struct work_struct * work )
2010-12-13 11:19:28 +00:00
{
struct delayed_work * delayed_work =
container_of ( work , struct delayed_work , work ) ;
struct bat_priv * bat_priv =
container_of ( delayed_work , struct bat_priv , vis_work ) ;
2011-01-28 18:34:07 +01:00
struct vis_info * info ;
2010-12-13 11:19:28 +00:00
spin_lock_bh ( & bat_priv - > vis_hash_lock ) ;
2012-05-16 20:23:18 +02:00
batadv_purge_vis_packets ( bat_priv ) ;
2010-12-13 11:19:28 +00:00
2012-05-16 20:23:18 +02:00
if ( batadv_generate_vis_packet ( bat_priv ) = = 0 ) {
2010-12-13 11:19:28 +00:00
/* schedule if generation was successful */
2012-05-16 20:23:18 +02:00
batadv_send_list_add ( bat_priv , bat_priv - > my_vis_info ) ;
2010-12-13 11:19:28 +00:00
}
2011-01-28 18:34:07 +01:00
while ( ! list_empty ( & bat_priv - > vis_send_list ) ) {
info = list_first_entry ( & bat_priv - > vis_send_list ,
typeof ( * info ) , send_list ) ;
2010-12-13 11:19:28 +00:00
kref_get ( & info - > refcount ) ;
spin_unlock_bh ( & bat_priv - > vis_hash_lock ) ;
2012-05-16 20:23:18 +02:00
batadv_send_vis_packet ( bat_priv , info ) ;
2010-12-13 11:19:28 +00:00
spin_lock_bh ( & bat_priv - > vis_hash_lock ) ;
2012-05-16 20:23:18 +02:00
batadv_send_list_del ( info ) ;
kref_put ( & info - > refcount , batadv_free_info ) ;
2010-12-13 11:19:28 +00:00
}
spin_unlock_bh ( & bat_priv - > vis_hash_lock ) ;
2012-05-16 20:23:18 +02:00
batadv_start_vis_timer ( bat_priv ) ;
2010-12-13 11:19:28 +00:00
}
/* init the vis server. this may only be called when if_list is already
2012-05-12 02:09:43 +02:00
* initialized ( e . g . bat0 is initialized , interfaces have been added )
*/
2012-05-12 02:09:41 +02:00
int batadv_vis_init ( struct bat_priv * bat_priv )
2010-12-13 11:19:28 +00:00
{
struct vis_packet * packet ;
int hash_added ;
2012-06-03 22:19:07 +02:00
unsigned int len ;
2012-06-03 22:19:17 +02:00
unsigned long first_seen ;
2010-12-13 11:19:28 +00:00
if ( bat_priv - > vis_hash )
2012-05-05 13:27:28 +02:00
return 0 ;
2010-12-13 11:19:28 +00:00
spin_lock_bh ( & bat_priv - > vis_hash_lock ) ;
2012-05-12 02:09:32 +02:00
bat_priv - > vis_hash = batadv_hash_new ( 256 ) ;
2010-12-13 11:19:28 +00:00
if ( ! bat_priv - > vis_hash ) {
pr_err ( " Can't initialize vis_hash \n " ) ;
goto err ;
}
2012-06-03 22:19:07 +02:00
bat_priv - > my_vis_info = kmalloc ( BATADV_MAX_VIS_PACKET_SIZE , GFP_ATOMIC ) ;
2011-08-29 14:17:24 -07:00
if ( ! bat_priv - > my_vis_info )
2010-12-13 11:19:28 +00:00
goto err ;
2012-06-03 22:19:07 +02:00
len = sizeof ( * packet ) + BATADV_MAX_VIS_PACKET_SIZE + ETH_HLEN ;
bat_priv - > my_vis_info - > skb_packet = dev_alloc_skb ( len ) ;
2010-12-13 11:19:28 +00:00
if ( ! bat_priv - > my_vis_info - > skb_packet )
goto free_info ;
2012-02-18 11:27:34 +01:00
skb_reserve ( bat_priv - > my_vis_info - > skb_packet , ETH_HLEN ) ;
2011-05-14 23:14:54 +02:00
packet = ( struct vis_packet * ) skb_put ( bat_priv - > my_vis_info - > skb_packet ,
sizeof ( * packet ) ) ;
2010-12-13 11:19:28 +00:00
/* prefill the vis info */
2012-06-03 22:19:17 +02:00
first_seen = jiffies - msecs_to_jiffies ( BATADV_VIS_INTERVAL ) ;
bat_priv - > my_vis_info - > first_seen = first_seen ;
2010-12-13 11:19:28 +00:00
INIT_LIST_HEAD ( & bat_priv - > my_vis_info - > recv_list ) ;
INIT_LIST_HEAD ( & bat_priv - > my_vis_info - > send_list ) ;
kref_init ( & bat_priv - > my_vis_info - > refcount ) ;
bat_priv - > my_vis_info - > bat_priv = bat_priv ;
2012-06-03 22:19:13 +02:00
packet - > header . version = BATADV_COMPAT_VERSION ;
2012-06-03 22:19:21 +02:00
packet - > header . packet_type = BATADV_VIS ;
2012-06-03 22:19:17 +02:00
packet - > header . ttl = BATADV_TTL ;
2010-12-13 11:19:28 +00:00
packet - > seqno = 0 ;
packet - > entries = 0 ;
INIT_LIST_HEAD ( & bat_priv - > vis_send_list ) ;
2012-05-16 20:23:18 +02:00
hash_added = batadv_hash_add ( bat_priv - > vis_hash , batadv_vis_info_cmp ,
batadv_vis_info_choose ,
bat_priv - > my_vis_info ,
2012-05-12 13:48:55 +02:00
& bat_priv - > my_vis_info - > hash_entry ) ;
2011-07-10 00:36:36 +02:00
if ( hash_added ! = 0 ) {
2010-12-13 11:19:28 +00:00
pr_err ( " Can't add own vis packet into hash \n " ) ;
/* not in hash, need to remove it manually. */
2012-05-16 20:23:18 +02:00
kref_put ( & bat_priv - > my_vis_info - > refcount , batadv_free_info ) ;
2010-12-13 11:19:28 +00:00
goto err ;
}
spin_unlock_bh ( & bat_priv - > vis_hash_lock ) ;
2012-05-16 20:23:18 +02:00
batadv_start_vis_timer ( bat_priv ) ;
2012-05-05 13:27:28 +02:00
return 0 ;
2010-12-13 11:19:28 +00:00
free_info :
kfree ( bat_priv - > my_vis_info ) ;
bat_priv - > my_vis_info = NULL ;
err :
spin_unlock_bh ( & bat_priv - > vis_hash_lock ) ;
2012-05-12 02:09:41 +02:00
batadv_vis_quit ( bat_priv ) ;
2012-05-05 13:27:28 +02:00
return - ENOMEM ;
2010-12-13 11:19:28 +00:00
}
/* Decrease the reference count on a hash item info */
2012-05-16 20:23:18 +02:00
static void batadv_free_info_ref ( struct hlist_node * node , void * arg )
2010-12-13 11:19:28 +00:00
{
2011-02-18 12:28:09 +00:00
struct vis_info * info ;
2010-12-13 11:19:28 +00:00
2011-02-18 12:28:09 +00:00
info = container_of ( node , struct vis_info , hash_entry ) ;
2012-05-16 20:23:18 +02:00
batadv_send_list_del ( info ) ;
kref_put ( & info - > refcount , batadv_free_info ) ;
2010-12-13 11:19:28 +00:00
}
/* shutdown vis-server */
2012-05-12 02:09:41 +02:00
void batadv_vis_quit ( struct bat_priv * bat_priv )
2010-12-13 11:19:28 +00:00
{
if ( ! bat_priv - > vis_hash )
return ;
cancel_delayed_work_sync ( & bat_priv - > vis_work ) ;
spin_lock_bh ( & bat_priv - > vis_hash_lock ) ;
/* properly remove, kill timers ... */
2012-05-16 20:23:18 +02:00
batadv_hash_delete ( bat_priv - > vis_hash , batadv_free_info_ref , NULL ) ;
2010-12-13 11:19:28 +00:00
bat_priv - > vis_hash = NULL ;
bat_priv - > my_vis_info = NULL ;
spin_unlock_bh ( & bat_priv - > vis_hash_lock ) ;
}
/* schedule packets for (re)transmission */
2012-05-16 20:23:18 +02:00
static void batadv_start_vis_timer ( struct bat_priv * bat_priv )
2010-12-13 11:19:28 +00:00
{
2012-05-16 20:23:18 +02:00
INIT_DELAYED_WORK ( & bat_priv - > vis_work , batadv_send_vis_packets ) ;
2012-05-12 02:09:42 +02:00
queue_delayed_work ( batadv_event_workqueue , & bat_priv - > vis_work ,
2012-06-03 22:19:17 +02:00
msecs_to_jiffies ( BATADV_VIS_INTERVAL ) ) ;
2010-12-13 11:19:28 +00:00
}