2010-12-13 11:19:28 +00:00
/*
2011-01-27 10:38:15 +01:00
* Copyright ( C ) 2009 - 2011 B . A . T . M . A . N . contributors :
2010-12-13 11:19:28 +00:00
*
* 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
* 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"
2011-04-27 00:22:00 +02:00
# include "bat_sysfs.h"
2010-12-13 11:19:28 +00:00
# include "gateway_client.h"
# include "gateway_common.h"
# include "hard-interface.h"
2011-03-14 22:43:33 +00:00
# include "originator.h"
2010-12-13 11:19:28 +00:00
# include <linux/ip.h>
# include <linux/ipv6.h>
# include <linux/udp.h>
# include <linux/if_vlan.h>
2011-02-10 14:33:49 +00:00
static void gw_node_free_ref ( struct gw_node * gw_node )
2010-12-13 11:19:28 +00:00
{
2011-02-10 14:33:49 +00:00
if ( atomic_dec_and_test ( & gw_node - > refcount ) )
2011-05-01 23:25:02 -07:00
kfree_rcu ( gw_node , rcu ) ;
2010-12-13 11:19:28 +00:00
}
2011-03-23 11:24:34 +01:00
static struct gw_node * gw_get_selected_gw_node ( struct bat_priv * bat_priv )
2010-12-13 11:19:28 +00:00
{
2011-03-23 11:24:34 +01:00
struct gw_node * gw_node ;
2010-12-13 11:19:28 +00:00
2011-02-13 21:13:02 +00:00
rcu_read_lock ( ) ;
2011-03-23 11:24:34 +01:00
gw_node = rcu_dereference ( bat_priv - > curr_gw ) ;
if ( ! gw_node )
2011-02-18 12:28:10 +00:00
goto out ;
2010-12-13 11:19:28 +00:00
2011-03-23 11:24:34 +01:00
if ( ! atomic_inc_not_zero ( & gw_node - > refcount ) )
gw_node = NULL ;
2011-02-13 21:13:04 +00:00
2011-02-13 21:13:02 +00:00
out :
rcu_read_unlock ( ) ;
2011-03-23 11:24:34 +01:00
return gw_node ;
2010-12-13 11:19:28 +00:00
}
2011-03-23 11:24:34 +01:00
struct orig_node * gw_get_selected_orig ( struct bat_priv * bat_priv )
2010-12-13 11:19:28 +00:00
{
2011-02-13 21:13:02 +00:00
struct gw_node * gw_node ;
2011-03-23 11:24:34 +01:00
struct orig_node * orig_node = NULL ;
2010-12-13 11:19:28 +00:00
2011-03-23 11:24:34 +01:00
gw_node = gw_get_selected_gw_node ( bat_priv ) ;
if ( ! gw_node )
goto out ;
rcu_read_lock ( ) ;
orig_node = gw_node - > orig_node ;
if ( ! orig_node )
goto unlock ;
if ( ! atomic_inc_not_zero ( & orig_node - > refcount ) )
orig_node = NULL ;
2010-12-13 11:19:28 +00:00
2011-03-23 11:24:34 +01:00
unlock :
rcu_read_unlock ( ) ;
out :
2010-12-13 11:19:28 +00:00
if ( gw_node )
2011-02-10 14:33:49 +00:00
gw_node_free_ref ( gw_node ) ;
2011-03-23 11:24:34 +01:00
return orig_node ;
2010-12-13 11:19:28 +00:00
}
2011-02-10 14:33:49 +00:00
static void gw_select ( struct bat_priv * bat_priv , struct gw_node * new_gw_node )
2010-12-13 11:19:28 +00:00
{
2011-02-13 21:13:02 +00:00
struct gw_node * curr_gw_node ;
2010-12-13 11:19:28 +00:00
2011-03-23 11:24:34 +01:00
spin_lock_bh ( & bat_priv - > gw_list_lock ) ;
2011-02-10 14:33:49 +00:00
if ( new_gw_node & & ! atomic_inc_not_zero ( & new_gw_node - > refcount ) )
new_gw_node = NULL ;
2010-12-13 11:19:28 +00:00
2011-05-15 00:50:21 +02:00
curr_gw_node = rcu_dereference_protected ( bat_priv - > curr_gw , 1 ) ;
2011-02-13 21:13:02 +00:00
rcu_assign_pointer ( bat_priv - > curr_gw , new_gw_node ) ;
2011-02-10 14:33:49 +00:00
if ( curr_gw_node )
gw_node_free_ref ( curr_gw_node ) ;
2011-03-23 11:24:34 +01:00
spin_unlock_bh ( & bat_priv - > gw_list_lock ) ;
}
void gw_deselect ( struct bat_priv * bat_priv )
{
2011-04-27 00:22:00 +02:00
atomic_set ( & bat_priv - > gw_reselect , 1 ) ;
2010-12-13 11:19:28 +00:00
}
2011-04-27 00:22:00 +02:00
static struct gw_node * gw_get_best_gw_node ( struct bat_priv * bat_priv )
2010-12-13 11:19:28 +00:00
{
2011-03-14 22:43:37 +00:00
struct neigh_node * router ;
2011-04-27 00:22:00 +02:00
struct hlist_node * node ;
struct gw_node * gw_node , * curr_gw = NULL ;
2010-12-13 11:19:28 +00:00
uint32_t max_gw_factor = 0 , tmp_gw_factor = 0 ;
2011-04-27 00:22:00 +02:00
uint8_t max_tq = 0 ;
2010-12-13 11:19:28 +00:00
int down , up ;
2011-03-23 11:24:34 +01:00
rcu_read_lock ( ) ;
2010-12-13 11:19:28 +00:00
hlist_for_each_entry_rcu ( gw_node , node , & bat_priv - > gw_list , list ) {
2011-03-14 22:43:37 +00:00
if ( gw_node - > deleted )
2010-12-13 11:19:28 +00:00
continue ;
2011-03-14 22:43:37 +00:00
router = orig_node_get_router ( gw_node - > orig_node ) ;
if ( ! router )
2010-12-13 11:19:28 +00:00
continue ;
2011-04-27 00:22:00 +02:00
if ( ! atomic_inc_not_zero ( & gw_node - > refcount ) )
goto next ;
2010-12-13 11:19:28 +00:00
switch ( atomic_read ( & bat_priv - > gw_sel_class ) ) {
case 1 : /* fast connection */
gw_bandwidth_to_kbit ( gw_node - > orig_node - > gw_flags ,
& down , & up ) ;
2011-03-14 22:43:37 +00:00
tmp_gw_factor = ( router - > tq_avg * router - > tq_avg *
2010-12-13 11:19:28 +00:00
down * 100 * 100 ) /
( TQ_LOCAL_WINDOW_SIZE *
TQ_LOCAL_WINDOW_SIZE * 64 ) ;
if ( ( tmp_gw_factor > max_gw_factor ) | |
( ( tmp_gw_factor = = max_gw_factor ) & &
2011-04-27 00:22:00 +02:00
( router - > tq_avg > max_tq ) ) ) {
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
curr_gw = gw_node ;
atomic_inc ( & curr_gw - > refcount ) ;
}
2010-12-13 11:19:28 +00:00
break ;
default : /**
* 2 : stable connection ( use best statistic )
* 3 : fast - switch ( use best statistic but change as
* soon as a better gateway appears )
* XX : late - switch ( use best statistic but change as
* soon as a better gateway appears which has
* $ routing_class more tq points )
* */
2011-04-27 00:22:00 +02:00
if ( router - > tq_avg > max_tq ) {
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
curr_gw = gw_node ;
atomic_inc ( & curr_gw - > refcount ) ;
}
2010-12-13 11:19:28 +00:00
break ;
}
2011-03-14 22:43:37 +00:00
if ( router - > tq_avg > max_tq )
max_tq = router - > tq_avg ;
2010-12-13 11:19:28 +00:00
if ( tmp_gw_factor > max_gw_factor )
max_gw_factor = tmp_gw_factor ;
2011-03-14 22:43:37 +00:00
2011-04-27 00:22:00 +02:00
gw_node_free_ref ( gw_node ) ;
next :
2011-03-14 22:43:37 +00:00
neigh_node_free_ref ( router ) ;
2010-12-13 11:19:28 +00:00
}
2011-04-27 00:22:00 +02:00
rcu_read_unlock ( ) ;
2010-12-13 11:19:28 +00:00
2011-04-27 00:22:00 +02:00
return curr_gw ;
}
2010-12-13 11:19:28 +00:00
2011-04-27 00:22:00 +02:00
void gw_election ( struct bat_priv * bat_priv )
{
struct gw_node * curr_gw = NULL , * next_gw = NULL ;
struct neigh_node * router = NULL ;
2011-06-12 11:58:58 +02:00
char gw_addr [ 18 ] = { ' \0 ' } ;
2011-04-27 00:22:00 +02:00
/**
* The batman daemon checks here if we already passed a full originator
* cycle in order to make sure we don ' t choose the first gateway we
* hear about . This check is based on the daemon ' s uptime which we
* don ' t have .
* */
if ( atomic_read ( & bat_priv - > gw_mode ) ! = GW_MODE_CLIENT )
goto out ;
if ( ! atomic_dec_not_zero ( & bat_priv - > gw_reselect ) )
goto out ;
curr_gw = gw_get_selected_gw_node ( bat_priv ) ;
next_gw = gw_get_best_gw_node ( bat_priv ) ;
if ( curr_gw = = next_gw )
goto out ;
if ( next_gw ) {
2011-06-12 11:58:58 +02:00
sprintf ( gw_addr , " %pM " , next_gw - > orig_node - > orig ) ;
2011-04-27 00:22:00 +02:00
router = orig_node_get_router ( next_gw - > orig_node ) ;
if ( ! router ) {
gw_deselect ( bat_priv ) ;
goto out ;
}
2010-12-13 11:19:28 +00:00
}
2011-04-27 00:22:00 +02:00
if ( ( curr_gw ) & & ( ! next_gw ) ) {
bat_dbg ( DBG_BATMAN , bat_priv ,
" Removing selected gateway - no gateway in range \n " ) ;
2011-06-12 11:58:58 +02:00
throw_uevent ( bat_priv , UEV_GW , UEV_DEL , NULL ) ;
2011-04-27 00:22:00 +02:00
} else if ( ( ! curr_gw ) & & ( next_gw ) ) {
bat_dbg ( DBG_BATMAN , bat_priv ,
" Adding route to gateway %pM (gw_flags: %i, tq: %i) \n " ,
next_gw - > orig_node - > orig ,
next_gw - > orig_node - > gw_flags ,
router - > tq_avg ) ;
2011-06-12 11:58:58 +02:00
throw_uevent ( bat_priv , UEV_GW , UEV_ADD , gw_addr ) ;
2011-04-27 00:22:00 +02:00
} else {
bat_dbg ( DBG_BATMAN , bat_priv ,
" Changing route to gateway %pM "
" (gw_flags: %i, tq: %i) \n " ,
next_gw - > orig_node - > orig ,
next_gw - > orig_node - > gw_flags ,
router - > tq_avg ) ;
2011-06-12 11:58:58 +02:00
throw_uevent ( bat_priv , UEV_GW , UEV_CHANGE , gw_addr ) ;
2011-04-27 00:22:00 +02:00
}
gw_select ( bat_priv , next_gw ) ;
2011-03-23 11:24:34 +01:00
out :
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
2011-04-27 00:22:00 +02:00
if ( next_gw )
gw_node_free_ref ( next_gw ) ;
if ( router )
neigh_node_free_ref ( router ) ;
2010-12-13 11:19:28 +00:00
}
void gw_check_election ( struct bat_priv * bat_priv , struct orig_node * orig_node )
{
2011-03-14 22:43:33 +00:00
struct orig_node * curr_gw_orig ;
2011-03-14 22:43:37 +00:00
struct neigh_node * router_gw = NULL , * router_orig = NULL ;
2010-12-13 11:19:28 +00:00
uint8_t gw_tq_avg , orig_tq_avg ;
2011-03-23 11:24:34 +01:00
curr_gw_orig = gw_get_selected_orig ( bat_priv ) ;
2011-03-14 22:43:33 +00:00
if ( ! curr_gw_orig )
goto deselect ;
2010-12-13 11:19:28 +00:00
2011-03-14 22:43:37 +00:00
router_gw = orig_node_get_router ( curr_gw_orig ) ;
if ( ! router_gw )
goto deselect ;
2010-12-13 11:19:28 +00:00
/* this node already is the gateway */
2011-03-14 22:43:33 +00:00
if ( curr_gw_orig = = orig_node )
2011-03-14 22:43:37 +00:00
goto out ;
2010-12-13 11:19:28 +00:00
2011-03-14 22:43:37 +00:00
router_orig = orig_node_get_router ( orig_node ) ;
if ( ! router_orig )
goto out ;
2011-02-13 21:13:02 +00:00
2011-03-14 22:43:37 +00:00
gw_tq_avg = router_gw - > tq_avg ;
orig_tq_avg = router_orig - > tq_avg ;
2010-12-13 11:19:28 +00:00
/* the TQ value has to be better */
if ( orig_tq_avg < gw_tq_avg )
2011-02-13 21:13:02 +00:00
goto out ;
2010-12-13 11:19:28 +00:00
/**
* if the routing class is greater than 3 the value tells us how much
* greater the TQ value of the new gateway must be
* */
if ( ( atomic_read ( & bat_priv - > gw_sel_class ) > 3 ) & &
( orig_tq_avg - gw_tq_avg < atomic_read ( & bat_priv - > gw_sel_class ) ) )
2011-02-13 21:13:02 +00:00
goto out ;
2010-12-13 11:19:28 +00:00
bat_dbg ( DBG_BATMAN , bat_priv ,
" Restarting gateway selection: better gateway found (tq curr: "
" %i, tq new: %i) \n " ,
gw_tq_avg , orig_tq_avg ) ;
deselect :
gw_deselect ( bat_priv ) ;
2011-02-13 21:13:02 +00:00
out :
2011-03-14 22:43:33 +00:00
if ( curr_gw_orig )
orig_node_free_ref ( curr_gw_orig ) ;
2011-03-14 22:43:37 +00:00
if ( router_gw )
neigh_node_free_ref ( router_gw ) ;
if ( router_orig )
neigh_node_free_ref ( router_orig ) ;
2011-03-14 22:43:33 +00:00
2011-02-13 21:13:02 +00:00
return ;
2010-12-13 11:19:28 +00:00
}
static void gw_node_add ( struct bat_priv * bat_priv ,
struct orig_node * orig_node , uint8_t new_gwflags )
{
struct gw_node * gw_node ;
int down , up ;
2011-05-14 23:14:54 +02:00
gw_node = kzalloc ( sizeof ( * gw_node ) , GFP_ATOMIC ) ;
2010-12-13 11:19:28 +00:00
if ( ! gw_node )
return ;
INIT_HLIST_NODE ( & gw_node - > list ) ;
gw_node - > orig_node = orig_node ;
2011-02-10 14:33:49 +00:00
atomic_set ( & gw_node - > refcount , 1 ) ;
2010-12-13 11:19:28 +00:00
spin_lock_bh ( & bat_priv - > gw_list_lock ) ;
hlist_add_head_rcu ( & gw_node - > list , & bat_priv - > gw_list ) ;
spin_unlock_bh ( & bat_priv - > gw_list_lock ) ;
gw_bandwidth_to_kbit ( new_gwflags , & down , & up ) ;
bat_dbg ( DBG_BATMAN , bat_priv ,
" Found new gateway %pM -> gw_class: %i - %i%s/%i%s \n " ,
orig_node - > orig , new_gwflags ,
( down > 2048 ? down / 1024 : down ) ,
( down > 2048 ? " MBit " : " KBit " ) ,
( up > 2048 ? up / 1024 : up ) ,
( up > 2048 ? " MBit " : " KBit " ) ) ;
}
void gw_node_update ( struct bat_priv * bat_priv ,
struct orig_node * orig_node , uint8_t new_gwflags )
{
struct hlist_node * node ;
2011-03-23 11:24:34 +01:00
struct gw_node * gw_node , * curr_gw ;
2011-04-25 22:44:32 +02:00
/**
* Note : We don ' t need a NULL check here , since curr_gw never gets
* dereferenced . If curr_gw is NULL we also should not exit as we may
* have this gateway in our list ( duplication check ! ) even though we
* have no currently selected gateway .
*/
2011-03-23 11:24:34 +01:00
curr_gw = gw_get_selected_gw_node ( bat_priv ) ;
2010-12-13 11:19:28 +00:00
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( gw_node , node , & bat_priv - > gw_list , list ) {
if ( gw_node - > orig_node ! = orig_node )
continue ;
bat_dbg ( DBG_BATMAN , bat_priv ,
" Gateway class of originator %pM changed from "
" %i to %i \n " ,
orig_node - > orig , gw_node - > orig_node - > gw_flags ,
new_gwflags ) ;
gw_node - > deleted = 0 ;
2011-06-09 17:13:09 +02:00
if ( new_gwflags = = NO_FLAGS ) {
2010-12-13 11:19:28 +00:00
gw_node - > deleted = jiffies ;
bat_dbg ( DBG_BATMAN , bat_priv ,
" Gateway %pM removed from gateway list \n " ,
orig_node - > orig ) ;
2011-03-23 11:24:34 +01:00
if ( gw_node = = curr_gw )
goto deselect ;
2010-12-13 11:19:28 +00:00
}
2011-03-23 11:24:34 +01:00
goto unlock ;
2010-12-13 11:19:28 +00:00
}
2011-06-09 17:13:09 +02:00
if ( new_gwflags = = NO_FLAGS )
2011-03-23 11:24:34 +01:00
goto unlock ;
2010-12-13 11:19:28 +00:00
gw_node_add ( bat_priv , orig_node , new_gwflags ) ;
2011-03-23 11:24:34 +01:00
goto unlock ;
deselect :
gw_deselect ( bat_priv ) ;
unlock :
rcu_read_unlock ( ) ;
2011-04-25 22:44:32 +02:00
2011-03-23 11:24:34 +01:00
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
2010-12-13 11:19:28 +00:00
}
void gw_node_delete ( struct bat_priv * bat_priv , struct orig_node * orig_node )
{
2011-06-04 12:40:37 +02:00
gw_node_update ( bat_priv , orig_node , 0 ) ;
2010-12-13 11:19:28 +00:00
}
void gw_node_purge ( struct bat_priv * bat_priv )
{
2011-03-23 11:24:34 +01:00
struct gw_node * gw_node , * curr_gw ;
2010-12-13 11:19:28 +00:00
struct hlist_node * node , * node_tmp ;
unsigned long timeout = 2 * PURGE_TIMEOUT * HZ ;
2011-06-15 09:41:37 +02:00
int do_deselect = 0 ;
2011-03-23 11:24:34 +01:00
curr_gw = gw_get_selected_gw_node ( bat_priv ) ;
2010-12-13 11:19:28 +00:00
spin_lock_bh ( & bat_priv - > gw_list_lock ) ;
hlist_for_each_entry_safe ( gw_node , node , node_tmp ,
& bat_priv - > gw_list , list ) {
if ( ( ( ! gw_node - > deleted ) | |
( time_before ( jiffies , gw_node - > deleted + timeout ) ) ) & &
atomic_read ( & bat_priv - > mesh_state ) = = MESH_ACTIVE )
continue ;
2011-03-23 11:24:34 +01:00
if ( curr_gw = = gw_node )
do_deselect = 1 ;
2010-12-13 11:19:28 +00:00
hlist_del_rcu ( & gw_node - > list ) ;
2011-02-10 14:33:49 +00:00
gw_node_free_ref ( gw_node ) ;
2010-12-13 11:19:28 +00:00
}
spin_unlock_bh ( & bat_priv - > gw_list_lock ) ;
2011-03-23 11:24:34 +01:00
/* gw_deselect() needs to acquire the gw_list_lock */
if ( do_deselect )
gw_deselect ( bat_priv ) ;
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
2010-12-13 11:19:28 +00:00
}
2011-03-14 22:43:37 +00:00
/**
* fails if orig_node has no router
*/
2011-05-14 23:14:50 +02:00
static int _write_buffer_text ( struct bat_priv * bat_priv , struct seq_file * seq ,
const struct gw_node * gw_node )
2010-12-13 11:19:28 +00:00
{
2011-02-13 21:13:02 +00:00
struct gw_node * curr_gw ;
2011-03-14 22:43:37 +00:00
struct neigh_node * router ;
int down , up , ret = - 1 ;
2010-12-13 11:19:28 +00:00
gw_bandwidth_to_kbit ( gw_node - > orig_node - > gw_flags , & down , & up ) ;
2011-03-14 22:43:37 +00:00
router = orig_node_get_router ( gw_node - > orig_node ) ;
if ( ! router )
goto out ;
2011-02-13 21:13:02 +00:00
2011-03-23 11:24:34 +01:00
curr_gw = gw_get_selected_gw_node ( bat_priv ) ;
2011-02-13 21:13:02 +00:00
ret = seq_printf ( seq , " %s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s \n " ,
2011-03-23 11:24:34 +01:00
( curr_gw = = gw_node ? " => " : " " ) ,
gw_node - > orig_node - > orig ,
router - > tq_avg , router - > addr ,
router - > if_incoming - > net_dev - > name ,
gw_node - > orig_node - > gw_flags ,
( down > 2048 ? down / 1024 : down ) ,
( down > 2048 ? " MBit " : " KBit " ) ,
( up > 2048 ? up / 1024 : up ) ,
( up > 2048 ? " MBit " : " KBit " ) ) ;
2011-02-13 21:13:02 +00:00
2011-03-14 22:43:37 +00:00
neigh_node_free_ref ( router ) ;
2011-03-23 11:24:34 +01:00
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
2011-03-14 22:43:37 +00:00
out :
2011-02-13 21:13:02 +00:00
return ret ;
2010-12-13 11:19:28 +00:00
}
int gw_client_seq_print_text ( struct seq_file * seq , void * offset )
{
struct net_device * net_dev = ( struct net_device * ) seq - > private ;
struct bat_priv * bat_priv = netdev_priv ( net_dev ) ;
2011-04-20 15:40:58 +02:00
struct hard_iface * primary_if ;
2010-12-13 11:19:28 +00:00
struct gw_node * gw_node ;
struct hlist_node * node ;
2011-04-20 15:40:58 +02:00
int gw_count = 0 , ret = 0 ;
2010-12-13 11:19:28 +00:00
2011-04-20 15:40:58 +02:00
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 11:19:28 +00:00
}
2011-04-20 15:40:58 +02: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 11:19:28 +00:00
}
seq_printf ( seq , " %-12s (%s/%i) %17s [%10s]: gw_class ... "
" [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)] \n " ,
" Gateway " , " # " , TQ_MAX_VALUE , " Nexthop " ,
" outgoingIF " , SOURCE_VERSION , REVISION_VERSION_STR ,
2011-04-20 15:40:58 +02:00
primary_if - > net_dev - > name ,
primary_if - > net_dev - > dev_addr , net_dev - > name ) ;
2010-12-13 11:19:28 +00:00
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( gw_node , node , & bat_priv - > gw_list , list ) {
if ( gw_node - > deleted )
continue ;
2011-03-14 22:43:37 +00:00
/* fails if orig_node has no router */
if ( _write_buffer_text ( bat_priv , seq , gw_node ) < 0 )
2010-12-13 11:19:28 +00:00
continue ;
gw_count + + ;
}
rcu_read_unlock ( ) ;
if ( gw_count = = 0 )
seq_printf ( seq , " No gateways in range ... \n " ) ;
2011-04-20 15:40:58 +02:00
out :
if ( primary_if )
hardif_free_ref ( primary_if ) ;
return ret ;
2010-12-13 11:19:28 +00:00
}
int gw_is_target ( struct bat_priv * bat_priv , struct sk_buff * skb )
{
struct ethhdr * ethhdr ;
struct iphdr * iphdr ;
struct ipv6hdr * ipv6hdr ;
struct udphdr * udphdr ;
2011-03-23 11:24:34 +01:00
struct gw_node * curr_gw ;
2010-12-13 11:19:28 +00:00
unsigned int header_len = 0 ;
if ( atomic_read ( & bat_priv - > gw_mode ) = = GW_MODE_OFF )
return 0 ;
/* check for ethernet header */
if ( ! pskb_may_pull ( skb , header_len + ETH_HLEN ) )
return 0 ;
ethhdr = ( struct ethhdr * ) skb - > data ;
header_len + = ETH_HLEN ;
/* check for initial vlan header */
if ( ntohs ( ethhdr - > h_proto ) = = ETH_P_8021Q ) {
if ( ! pskb_may_pull ( skb , header_len + VLAN_HLEN ) )
return 0 ;
ethhdr = ( struct ethhdr * ) ( skb - > data + VLAN_HLEN ) ;
header_len + = VLAN_HLEN ;
}
/* check for ip header */
switch ( ntohs ( ethhdr - > h_proto ) ) {
case ETH_P_IP :
2011-05-14 23:14:54 +02:00
if ( ! pskb_may_pull ( skb , header_len + sizeof ( * iphdr ) ) )
2010-12-13 11:19:28 +00:00
return 0 ;
iphdr = ( struct iphdr * ) ( skb - > data + header_len ) ;
header_len + = iphdr - > ihl * 4 ;
/* check for udp header */
if ( iphdr - > protocol ! = IPPROTO_UDP )
return 0 ;
break ;
case ETH_P_IPV6 :
2011-05-14 23:14:54 +02:00
if ( ! pskb_may_pull ( skb , header_len + sizeof ( * ipv6hdr ) ) )
2010-12-13 11:19:28 +00:00
return 0 ;
ipv6hdr = ( struct ipv6hdr * ) ( skb - > data + header_len ) ;
2011-05-14 23:14:54 +02:00
header_len + = sizeof ( * ipv6hdr ) ;
2010-12-13 11:19:28 +00:00
/* check for udp header */
if ( ipv6hdr - > nexthdr ! = IPPROTO_UDP )
return 0 ;
break ;
default :
return 0 ;
}
2011-05-14 23:14:54 +02:00
if ( ! pskb_may_pull ( skb , header_len + sizeof ( * udphdr ) ) )
2010-12-13 11:19:28 +00:00
return 0 ;
udphdr = ( struct udphdr * ) ( skb - > data + header_len ) ;
2011-05-14 23:14:54 +02:00
header_len + = sizeof ( * udphdr ) ;
2010-12-13 11:19:28 +00:00
/* check for bootp port */
if ( ( ntohs ( ethhdr - > h_proto ) = = ETH_P_IP ) & &
( ntohs ( udphdr - > dest ) ! = 67 ) )
return 0 ;
if ( ( ntohs ( ethhdr - > h_proto ) = = ETH_P_IPV6 ) & &
( ntohs ( udphdr - > dest ) ! = 547 ) )
return 0 ;
if ( atomic_read ( & bat_priv - > gw_mode ) = = GW_MODE_SERVER )
return - 1 ;
2011-03-23 11:24:34 +01:00
curr_gw = gw_get_selected_gw_node ( bat_priv ) ;
if ( ! curr_gw )
2010-12-13 11:19:28 +00:00
return 0 ;
2011-03-23 11:24:34 +01:00
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
2010-12-13 11:19:28 +00:00
return 1 ;
}