2010-12-13 14:19:28 +03:00
/*
2011-01-27 12:38:15 +03:00
* Copyright ( C ) 2009 - 2011 B . A . T . M . A . N . contributors :
2010-12-13 14:19:28 +03: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"
# include "gateway_client.h"
# include "gateway_common.h"
# include "hard-interface.h"
2011-03-15 01:43:33 +03:00
# include "originator.h"
2010-12-13 14:19:28 +03:00
# include <linux/ip.h>
# include <linux/ipv6.h>
# include <linux/udp.h>
# include <linux/if_vlan.h>
2011-02-10 17:33:49 +03:00
static void gw_node_free_rcu ( struct rcu_head * rcu )
2010-12-13 14:19:28 +03:00
{
struct gw_node * gw_node ;
2011-02-10 17:33:49 +03:00
gw_node = container_of ( rcu , struct gw_node , rcu ) ;
2010-12-13 14:19:28 +03:00
kfree ( gw_node ) ;
}
2011-02-10 17:33:49 +03:00
static void gw_node_free_ref ( struct gw_node * gw_node )
2010-12-13 14:19:28 +03:00
{
2011-02-10 17:33:49 +03:00
if ( atomic_dec_and_test ( & gw_node - > refcount ) )
call_rcu ( & gw_node - > rcu , gw_node_free_rcu ) ;
2010-12-13 14:19:28 +03:00
}
2011-03-23 13:24:34 +03:00
static struct gw_node * gw_get_selected_gw_node ( struct bat_priv * bat_priv )
2010-12-13 14:19:28 +03:00
{
2011-03-23 13:24:34 +03:00
struct gw_node * gw_node ;
2010-12-13 14:19:28 +03:00
2011-02-14 00:13:02 +03:00
rcu_read_lock ( ) ;
2011-03-23 13:24:34 +03:00
gw_node = rcu_dereference ( bat_priv - > curr_gw ) ;
if ( ! gw_node )
2011-02-18 15:28:10 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2011-03-23 13:24:34 +03:00
if ( ! atomic_inc_not_zero ( & gw_node - > refcount ) )
gw_node = NULL ;
2011-02-14 00:13:04 +03:00
2011-02-14 00:13:02 +03:00
out :
rcu_read_unlock ( ) ;
2011-03-23 13:24:34 +03:00
return gw_node ;
2010-12-13 14:19:28 +03:00
}
2011-03-23 13:24:34 +03:00
struct orig_node * gw_get_selected_orig ( struct bat_priv * bat_priv )
2010-12-13 14:19:28 +03:00
{
2011-02-14 00:13:02 +03:00
struct gw_node * gw_node ;
2011-03-23 13:24:34 +03:00
struct orig_node * orig_node = NULL ;
2010-12-13 14:19:28 +03:00
2011-03-23 13:24:34 +03: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 14:19:28 +03:00
2011-03-23 13:24:34 +03:00
unlock :
rcu_read_unlock ( ) ;
out :
2010-12-13 14:19:28 +03:00
if ( gw_node )
2011-02-10 17:33:49 +03:00
gw_node_free_ref ( gw_node ) ;
2011-03-23 13:24:34 +03:00
return orig_node ;
2010-12-13 14:19:28 +03:00
}
2011-02-10 17:33:49 +03:00
static void gw_select ( struct bat_priv * bat_priv , struct gw_node * new_gw_node )
2010-12-13 14:19:28 +03:00
{
2011-02-14 00:13:02 +03:00
struct gw_node * curr_gw_node ;
2010-12-13 14:19:28 +03:00
2011-03-23 13:24:34 +03:00
spin_lock_bh ( & bat_priv - > gw_list_lock ) ;
2011-02-10 17:33:49 +03:00
if ( new_gw_node & & ! atomic_inc_not_zero ( & new_gw_node - > refcount ) )
new_gw_node = NULL ;
2010-12-13 14:19:28 +03:00
2011-03-23 13:24:34 +03:00
curr_gw_node = bat_priv - > curr_gw ;
2011-02-14 00:13:02 +03:00
rcu_assign_pointer ( bat_priv - > curr_gw , new_gw_node ) ;
2011-02-10 17:33:49 +03:00
if ( curr_gw_node )
gw_node_free_ref ( curr_gw_node ) ;
2011-03-23 13:24:34 +03:00
spin_unlock_bh ( & bat_priv - > gw_list_lock ) ;
}
void gw_deselect ( struct bat_priv * bat_priv )
{
gw_select ( bat_priv , NULL ) ;
2010-12-13 14:19:28 +03:00
}
void gw_election ( struct bat_priv * bat_priv )
{
struct hlist_node * node ;
2011-03-23 13:24:34 +03:00
struct gw_node * gw_node , * curr_gw = NULL , * curr_gw_tmp = NULL ;
2011-03-15 01:43:37 +03:00
struct neigh_node * router ;
2010-12-13 14:19:28 +03:00
uint8_t max_tq = 0 ;
uint32_t max_gw_factor = 0 , tmp_gw_factor = 0 ;
int down , up ;
/**
* 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 )
return ;
2011-03-23 13:24:34 +03:00
curr_gw = gw_get_selected_gw_node ( bat_priv ) ;
2011-04-26 00:44:32 +04:00
if ( curr_gw )
2011-03-23 13:24:34 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2011-03-23 13:24:34 +03:00
rcu_read_lock ( ) ;
2010-12-13 14:19:28 +03:00
if ( hlist_empty ( & bat_priv - > gw_list ) ) {
2011-03-23 13:24:34 +03:00
bat_dbg ( DBG_BATMAN , bat_priv ,
" Removing selected gateway - "
" no gateway in range \n " ) ;
gw_deselect ( bat_priv ) ;
goto unlock ;
2010-12-13 14:19:28 +03:00
}
hlist_for_each_entry_rcu ( gw_node , node , & bat_priv - > gw_list , list ) {
2011-03-15 01:43:37 +03:00
if ( gw_node - > deleted )
2010-12-13 14:19:28 +03:00
continue ;
2011-03-15 01:43:37 +03:00
router = orig_node_get_router ( gw_node - > orig_node ) ;
if ( ! router )
2010-12-13 14:19:28 +03:00
continue ;
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-15 01:43:37 +03:00
tmp_gw_factor = ( router - > tq_avg * router - > tq_avg *
2010-12-13 14:19:28 +03: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-03-15 01:43:37 +03:00
( router - > tq_avg > max_tq ) ) )
2010-12-13 14:19:28 +03:00
curr_gw_tmp = gw_node ;
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-03-15 01:43:37 +03:00
if ( router - > tq_avg > max_tq )
2010-12-13 14:19:28 +03:00
curr_gw_tmp = gw_node ;
break ;
}
2011-03-15 01:43:37 +03:00
if ( router - > tq_avg > max_tq )
max_tq = router - > tq_avg ;
2010-12-13 14:19:28 +03:00
if ( tmp_gw_factor > max_gw_factor )
max_gw_factor = tmp_gw_factor ;
2011-03-15 01:43:37 +03:00
neigh_node_free_ref ( router ) ;
2010-12-13 14:19:28 +03:00
}
2011-02-14 00:13:02 +03:00
if ( curr_gw ! = curr_gw_tmp ) {
2011-03-15 01:43:37 +03:00
router = orig_node_get_router ( curr_gw_tmp - > orig_node ) ;
if ( ! router )
2011-03-23 13:24:34 +03:00
goto unlock ;
2011-03-15 01:43:37 +03:00
2011-02-14 00:13:02 +03:00
if ( ( curr_gw ) & & ( ! curr_gw_tmp ) )
2010-12-13 14:19:28 +03:00
bat_dbg ( DBG_BATMAN , bat_priv ,
" Removing selected gateway - "
" no gateway in range \n " ) ;
2011-02-14 00:13:02 +03:00
else if ( ( ! curr_gw ) & & ( curr_gw_tmp ) )
2010-12-13 14:19:28 +03:00
bat_dbg ( DBG_BATMAN , bat_priv ,
" Adding route to gateway %pM "
" (gw_flags: %i, tq: %i) \n " ,
curr_gw_tmp - > orig_node - > orig ,
curr_gw_tmp - > orig_node - > gw_flags ,
2011-03-15 01:43:37 +03:00
router - > tq_avg ) ;
2010-12-13 14:19:28 +03:00
else
bat_dbg ( DBG_BATMAN , bat_priv ,
" Changing route to gateway %pM "
" (gw_flags: %i, tq: %i) \n " ,
curr_gw_tmp - > orig_node - > orig ,
curr_gw_tmp - > orig_node - > gw_flags ,
2011-03-15 01:43:37 +03:00
router - > tq_avg ) ;
2010-12-13 14:19:28 +03:00
2011-03-15 01:43:37 +03:00
neigh_node_free_ref ( router ) ;
2011-02-10 17:33:49 +03:00
gw_select ( bat_priv , curr_gw_tmp ) ;
2010-12-13 14:19:28 +03:00
}
2011-03-23 13:24:34 +03:00
unlock :
2010-12-13 14:19:28 +03:00
rcu_read_unlock ( ) ;
2011-03-23 13:24:34 +03:00
out :
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
2010-12-13 14:19:28 +03:00
}
void gw_check_election ( struct bat_priv * bat_priv , struct orig_node * orig_node )
{
2011-03-15 01:43:33 +03:00
struct orig_node * curr_gw_orig ;
2011-03-15 01:43:37 +03:00
struct neigh_node * router_gw = NULL , * router_orig = NULL ;
2010-12-13 14:19:28 +03:00
uint8_t gw_tq_avg , orig_tq_avg ;
2011-03-23 13:24:34 +03:00
curr_gw_orig = gw_get_selected_orig ( bat_priv ) ;
2011-03-15 01:43:33 +03:00
if ( ! curr_gw_orig )
goto deselect ;
2010-12-13 14:19:28 +03:00
2011-03-15 01:43:37 +03:00
router_gw = orig_node_get_router ( curr_gw_orig ) ;
if ( ! router_gw )
goto deselect ;
2010-12-13 14:19:28 +03:00
/* this node already is the gateway */
2011-03-15 01:43:33 +03:00
if ( curr_gw_orig = = orig_node )
2011-03-15 01:43:37 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2011-03-15 01:43:37 +03:00
router_orig = orig_node_get_router ( orig_node ) ;
if ( ! router_orig )
goto out ;
2011-02-14 00:13:02 +03:00
2011-03-15 01:43:37 +03:00
gw_tq_avg = router_gw - > tq_avg ;
orig_tq_avg = router_orig - > tq_avg ;
2010-12-13 14:19:28 +03:00
/* the TQ value has to be better */
if ( orig_tq_avg < gw_tq_avg )
2011-02-14 00:13:02 +03:00
goto out ;
2010-12-13 14:19:28 +03: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-14 00:13:02 +03:00
goto out ;
2010-12-13 14:19:28 +03: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-14 00:13:02 +03:00
out :
2011-03-15 01:43:33 +03:00
if ( curr_gw_orig )
orig_node_free_ref ( curr_gw_orig ) ;
2011-03-15 01:43:37 +03:00
if ( router_gw )
neigh_node_free_ref ( router_gw ) ;
if ( router_orig )
neigh_node_free_ref ( router_orig ) ;
2011-03-15 01:43:33 +03:00
2011-02-14 00:13:02 +03:00
return ;
2010-12-13 14:19:28 +03: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 ;
gw_node = kmalloc ( sizeof ( struct gw_node ) , GFP_ATOMIC ) ;
if ( ! gw_node )
return ;
memset ( gw_node , 0 , sizeof ( struct gw_node ) ) ;
INIT_HLIST_NODE ( & gw_node - > list ) ;
gw_node - > orig_node = orig_node ;
2011-02-10 17:33:49 +03:00
atomic_set ( & gw_node - > refcount , 1 ) ;
2010-12-13 14:19:28 +03: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 13:24:34 +03:00
struct gw_node * gw_node , * curr_gw ;
2011-04-26 00:44:32 +04: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 13:24:34 +03:00
curr_gw = gw_get_selected_gw_node ( bat_priv ) ;
2010-12-13 14:19:28 +03: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 ;
if ( new_gwflags = = 0 ) {
gw_node - > deleted = jiffies ;
bat_dbg ( DBG_BATMAN , bat_priv ,
" Gateway %pM removed from gateway list \n " ,
orig_node - > orig ) ;
2011-03-23 13:24:34 +03:00
if ( gw_node = = curr_gw )
goto deselect ;
2010-12-13 14:19:28 +03:00
}
2011-03-23 13:24:34 +03:00
goto unlock ;
2010-12-13 14:19:28 +03:00
}
if ( new_gwflags = = 0 )
2011-03-23 13:24:34 +03:00
goto unlock ;
2010-12-13 14:19:28 +03:00
gw_node_add ( bat_priv , orig_node , new_gwflags ) ;
2011-03-23 13:24:34 +03:00
goto unlock ;
deselect :
gw_deselect ( bat_priv ) ;
unlock :
rcu_read_unlock ( ) ;
2011-04-26 00:44:32 +04:00
2011-03-23 13:24:34 +03:00
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
2010-12-13 14:19:28 +03:00
}
void gw_node_delete ( struct bat_priv * bat_priv , struct orig_node * orig_node )
{
return gw_node_update ( bat_priv , orig_node , 0 ) ;
}
void gw_node_purge ( struct bat_priv * bat_priv )
{
2011-03-23 13:24:34 +03:00
struct gw_node * gw_node , * curr_gw ;
2010-12-13 14:19:28 +03:00
struct hlist_node * node , * node_tmp ;
unsigned long timeout = 2 * PURGE_TIMEOUT * HZ ;
2011-03-23 13:24:34 +03:00
char do_deselect = 0 ;
curr_gw = gw_get_selected_gw_node ( bat_priv ) ;
2010-12-13 14:19:28 +03: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 13:24:34 +03:00
if ( curr_gw = = gw_node )
do_deselect = 1 ;
2010-12-13 14:19:28 +03:00
hlist_del_rcu ( & gw_node - > list ) ;
2011-02-10 17:33:49 +03:00
gw_node_free_ref ( gw_node ) ;
2010-12-13 14:19:28 +03:00
}
spin_unlock_bh ( & bat_priv - > gw_list_lock ) ;
2011-03-23 13:24:34 +03: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 14:19:28 +03:00
}
2011-03-15 01:43:37 +03:00
/**
* fails if orig_node has no router
*/
2010-12-13 14:19:28 +03:00
static int _write_buffer_text ( struct bat_priv * bat_priv ,
struct seq_file * seq , struct gw_node * gw_node )
{
2011-02-14 00:13:02 +03:00
struct gw_node * curr_gw ;
2011-03-15 01:43:37 +03:00
struct neigh_node * router ;
int down , up , ret = - 1 ;
2010-12-13 14:19:28 +03:00
gw_bandwidth_to_kbit ( gw_node - > orig_node - > gw_flags , & down , & up ) ;
2011-03-15 01:43:37 +03:00
router = orig_node_get_router ( gw_node - > orig_node ) ;
if ( ! router )
goto out ;
2011-03-23 13:24:34 +03:00
curr_gw = gw_get_selected_gw_node ( bat_priv ) ;
2011-02-14 00:13:02 +03:00
ret = seq_printf ( seq , " %s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s \n " ,
2011-03-23 13:24:34 +03: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-14 00:13:02 +03:00
2011-03-15 01:43:37 +03:00
neigh_node_free_ref ( router ) ;
2011-03-23 13:24:34 +03:00
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
2011-03-15 01:43:37 +03:00
out :
2011-02-14 00:13:02 +03:00
return ret ;
2010-12-13 14:19:28 +03: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 ) ;
struct gw_node * gw_node ;
struct hlist_node * node ;
int gw_count = 0 ;
if ( ! bat_priv - > primary_if ) {
return seq_printf ( seq , " BATMAN mesh %s disabled - please "
" specify interfaces to enable it \n " ,
net_dev - > name ) ;
}
if ( bat_priv - > primary_if - > if_status ! = IF_ACTIVE ) {
return seq_printf ( seq , " BATMAN mesh %s disabled - "
" primary interface not active \n " ,
net_dev - > name ) ;
}
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 ,
bat_priv - > primary_if - > net_dev - > name ,
bat_priv - > primary_if - > net_dev - > dev_addr , net_dev - > name ) ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( gw_node , node , & bat_priv - > gw_list , list ) {
if ( gw_node - > deleted )
continue ;
2011-03-15 01:43:37 +03:00
/* fails if orig_node has no router */
if ( _write_buffer_text ( bat_priv , seq , gw_node ) < 0 )
2010-12-13 14:19:28 +03:00
continue ;
gw_count + + ;
}
rcu_read_unlock ( ) ;
if ( gw_count = = 0 )
seq_printf ( seq , " No gateways in range ... \n " ) ;
return 0 ;
}
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 13:24:34 +03:00
struct gw_node * curr_gw ;
2010-12-13 14:19:28 +03: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 :
if ( ! pskb_may_pull ( skb , header_len + sizeof ( struct iphdr ) ) )
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 :
if ( ! pskb_may_pull ( skb , header_len + sizeof ( struct ipv6hdr ) ) )
return 0 ;
ipv6hdr = ( struct ipv6hdr * ) ( skb - > data + header_len ) ;
header_len + = sizeof ( struct ipv6hdr ) ;
/* check for udp header */
if ( ipv6hdr - > nexthdr ! = IPPROTO_UDP )
return 0 ;
break ;
default :
return 0 ;
}
if ( ! pskb_may_pull ( skb , header_len + sizeof ( struct udphdr ) ) )
return 0 ;
udphdr = ( struct udphdr * ) ( skb - > data + header_len ) ;
header_len + = sizeof ( struct udphdr ) ;
/* 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 13:24:34 +03:00
curr_gw = gw_get_selected_gw_node ( bat_priv ) ;
if ( ! curr_gw )
2010-12-13 14:19:28 +03:00
return 0 ;
2011-03-23 13:24:34 +03:00
if ( curr_gw )
gw_node_free_ref ( curr_gw ) ;
2010-12-13 14:19:28 +03:00
return 1 ;
}