2010-12-13 19:19:28 +08:00
/*
2012-01-01 07:41:38 +08:00
* Copyright ( C ) 2007 - 2012 B . A . T . M . A . N . contributors :
2010-12-13 19:19:28 +08: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 "hard-interface.h"
# include "soft-interface.h"
# include "send.h"
# include "translation-table.h"
# include "routing.h"
# include "bat_sysfs.h"
# include "originator.h"
# include "hash.h"
# include <linux/if_arp.h>
2011-01-27 20:16:08 +08:00
static int batman_skb_recv ( struct sk_buff * skb ,
struct net_device * dev ,
struct packet_type * ptype ,
struct net_device * orig_dev ) ;
2011-02-10 22:33:51 +08:00
void hardif_free_rcu ( struct rcu_head * rcu )
2010-12-13 19:19:28 +08:00
{
2011-02-18 20:33:20 +08:00
struct hard_iface * hard_iface ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
hard_iface = container_of ( rcu , struct hard_iface , rcu ) ;
dev_put ( hard_iface - > net_dev ) ;
kfree ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
}
2011-05-15 05:14:50 +08:00
struct hard_iface * hardif_get_by_netdev ( const struct net_device * net_dev )
2010-12-13 19:19:28 +08:00
{
2011-02-18 20:33:20 +08:00
struct hard_iface * hard_iface ;
2010-12-13 19:19:28 +08:00
rcu_read_lock ( ) ;
2011-02-18 20:33:20 +08:00
list_for_each_entry_rcu ( hard_iface , & hardif_list , list ) {
if ( hard_iface - > net_dev = = net_dev & &
atomic_inc_not_zero ( & hard_iface - > refcount ) )
2010-12-13 19:19:28 +08:00
goto out ;
}
2011-02-18 20:33:20 +08:00
hard_iface = NULL ;
2010-12-13 19:19:28 +08:00
out :
rcu_read_unlock ( ) ;
2011-02-18 20:33:20 +08:00
return hard_iface ;
2010-12-13 19:19:28 +08:00
}
2011-05-15 05:14:50 +08:00
static int is_valid_iface ( const struct net_device * net_dev )
2010-12-13 19:19:28 +08:00
{
if ( net_dev - > flags & IFF_LOOPBACK )
return 0 ;
if ( net_dev - > type ! = ARPHRD_ETHER )
return 0 ;
if ( net_dev - > addr_len ! = ETH_ALEN )
return 0 ;
/* no batman over batman */
2011-03-05 05:36:41 +08:00
if ( softif_is_valid ( net_dev ) )
2010-12-13 19:19:28 +08:00
return 0 ;
/* Device is being bridged */
/* if (net_dev->priv_flags & IFF_BRIDGE_PORT)
return 0 ; */
return 1 ;
}
2011-05-15 05:14:50 +08:00
static struct hard_iface * hardif_get_active ( const struct net_device * soft_iface )
2010-12-13 19:19:28 +08:00
{
2011-02-18 20:33:20 +08:00
struct hard_iface * hard_iface ;
2010-12-13 19:19:28 +08:00
rcu_read_lock ( ) ;
2011-02-18 20:33:20 +08:00
list_for_each_entry_rcu ( hard_iface , & hardif_list , list ) {
if ( hard_iface - > soft_iface ! = soft_iface )
2010-12-13 19:19:28 +08:00
continue ;
2011-02-18 20:33:20 +08:00
if ( hard_iface - > if_status = = IF_ACTIVE & &
atomic_inc_not_zero ( & hard_iface - > refcount ) )
2010-12-13 19:19:28 +08:00
goto out ;
}
2011-02-18 20:33:20 +08:00
hard_iface = NULL ;
2010-12-13 19:19:28 +08:00
out :
rcu_read_unlock ( ) ;
2011-02-18 20:33:20 +08:00
return hard_iface ;
2010-12-13 19:19:28 +08:00
}
2011-04-20 21:40:58 +08:00
static void primary_if_update_addr ( struct bat_priv * bat_priv )
2010-12-13 19:19:28 +08:00
{
struct vis_packet * vis_packet ;
2011-04-20 21:40:58 +08:00
struct hard_iface * primary_if ;
primary_if = primary_if_get_selected ( bat_priv ) ;
if ( ! primary_if )
goto out ;
2010-12-13 19:19:28 +08:00
vis_packet = ( struct vis_packet * )
bat_priv - > my_vis_info - > skb_packet - > data ;
2011-04-20 21:40:58 +08:00
memcpy ( vis_packet - > vis_orig , primary_if - > net_dev - > dev_addr , ETH_ALEN ) ;
2010-12-13 19:19:28 +08:00
memcpy ( vis_packet - > sender_orig ,
2011-04-20 21:40:58 +08:00
primary_if - > net_dev - > dev_addr , ETH_ALEN ) ;
out :
if ( primary_if )
hardif_free_ref ( primary_if ) ;
2010-12-13 19:19:28 +08:00
}
2011-04-20 21:40:58 +08:00
static void primary_if_select ( struct bat_priv * bat_priv ,
struct hard_iface * new_hard_iface )
2010-12-13 19:19:28 +08:00
{
2011-04-20 21:40:58 +08:00
struct hard_iface * curr_hard_iface ;
2010-12-13 19:19:28 +08:00
2011-05-03 17:51:38 +08:00
ASSERT_RTNL ( ) ;
2010-12-13 19:19:28 +08:00
2011-04-20 21:40:58 +08:00
if ( new_hard_iface & & ! atomic_inc_not_zero ( & new_hard_iface - > refcount ) )
new_hard_iface = NULL ;
2010-12-13 19:19:28 +08:00
2011-05-15 06:50:21 +08:00
curr_hard_iface = rcu_dereference_protected ( bat_priv - > primary_if , 1 ) ;
2011-04-20 21:40:58 +08:00
rcu_assign_pointer ( bat_priv - > primary_if , new_hard_iface ) ;
2010-12-13 19:19:28 +08:00
2011-04-20 21:40:58 +08:00
if ( curr_hard_iface )
hardif_free_ref ( curr_hard_iface ) ;
2010-12-13 19:19:28 +08:00
2011-04-20 21:40:58 +08:00
if ( ! new_hard_iface )
2011-05-03 17:51:38 +08:00
return ;
2011-04-20 21:40:58 +08:00
2011-11-28 21:31:55 +08:00
bat_priv - > bat_algo_ops - > bat_ogm_init_primary ( new_hard_iface ) ;
2011-04-20 21:40:58 +08:00
primary_if_update_addr ( bat_priv ) ;
2010-12-13 19:19:28 +08:00
}
2011-05-15 05:14:50 +08:00
static bool hardif_is_iface_up ( const struct hard_iface * hard_iface )
2010-12-13 19:19:28 +08:00
{
2011-02-18 20:33:20 +08:00
if ( hard_iface - > net_dev - > flags & IFF_UP )
2010-12-13 19:19:28 +08:00
return true ;
return false ;
}
2011-05-15 05:14:50 +08:00
static void check_known_mac_addr ( const struct net_device * net_dev )
2010-12-13 19:19:28 +08:00
{
2011-05-15 05:14:50 +08:00
const struct hard_iface * hard_iface ;
2010-12-13 19:19:28 +08:00
rcu_read_lock ( ) ;
2011-02-18 20:33:20 +08:00
list_for_each_entry_rcu ( hard_iface , & hardif_list , list ) {
if ( ( hard_iface - > if_status ! = IF_ACTIVE ) & &
( hard_iface - > if_status ! = IF_TO_BE_ACTIVATED ) )
2010-12-13 19:19:28 +08:00
continue ;
2011-02-18 20:33:20 +08:00
if ( hard_iface - > net_dev = = net_dev )
2010-12-13 19:19:28 +08:00
continue ;
2011-02-18 20:33:20 +08:00
if ( ! compare_eth ( hard_iface - > net_dev - > dev_addr ,
net_dev - > dev_addr ) )
2010-12-13 19:19:28 +08:00
continue ;
2012-03-07 16:07:45 +08:00
pr_warning ( " The newly added mac address (%pM) already exists on: %s \n " ,
net_dev - > dev_addr , hard_iface - > net_dev - > name ) ;
pr_warning ( " It is strongly recommended to keep mac addresses unique to avoid problems! \n " ) ;
2010-12-13 19:19:28 +08:00
}
rcu_read_unlock ( ) ;
}
int hardif_min_mtu ( struct net_device * soft_iface )
{
2011-05-15 05:14:50 +08:00
const struct bat_priv * bat_priv = netdev_priv ( soft_iface ) ;
const struct hard_iface * hard_iface ;
2010-12-13 19:19:28 +08:00
/* allow big frames if all devices are capable to do so
* ( have MTU > 1500 + BAT_HEADER_LEN ) */
int min_mtu = ETH_DATA_LEN ;
if ( atomic_read ( & bat_priv - > fragmentation ) )
goto out ;
rcu_read_lock ( ) ;
2011-02-18 20:33:20 +08:00
list_for_each_entry_rcu ( hard_iface , & hardif_list , list ) {
if ( ( hard_iface - > if_status ! = IF_ACTIVE ) & &
( hard_iface - > if_status ! = IF_TO_BE_ACTIVATED ) )
2010-12-13 19:19:28 +08:00
continue ;
2011-02-18 20:33:20 +08:00
if ( hard_iface - > soft_iface ! = soft_iface )
2010-12-13 19:19:28 +08:00
continue ;
2011-02-18 20:33:20 +08:00
min_mtu = min_t ( int , hard_iface - > net_dev - > mtu - BAT_HEADER_LEN ,
2010-12-13 19:19:28 +08:00
min_mtu ) ;
}
rcu_read_unlock ( ) ;
out :
return min_mtu ;
}
/* adjusts the MTU if a new interface with a smaller MTU appeared. */
void update_min_mtu ( struct net_device * soft_iface )
{
int min_mtu ;
min_mtu = hardif_min_mtu ( soft_iface ) ;
if ( soft_iface - > mtu ! = min_mtu )
soft_iface - > mtu = min_mtu ;
}
2011-02-18 20:33:20 +08:00
static void hardif_activate_interface ( struct hard_iface * hard_iface )
2010-12-13 19:19:28 +08:00
{
struct bat_priv * bat_priv ;
2011-04-20 21:40:58 +08:00
struct hard_iface * primary_if = NULL ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
if ( hard_iface - > if_status ! = IF_INACTIVE )
2011-04-20 21:40:58 +08:00
goto out ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
2010-12-13 19:19:28 +08:00
2011-11-28 21:31:55 +08:00
bat_priv - > bat_algo_ops - > bat_ogm_update_mac ( hard_iface ) ;
2011-02-18 20:33:20 +08:00
hard_iface - > if_status = IF_TO_BE_ACTIVATED ;
2010-12-13 19:19:28 +08:00
/**
* the first active interface becomes our primary interface or
2011-07-09 23:52:13 +08:00
* the next active interface after the old primary interface was removed
2010-12-13 19:19:28 +08:00
*/
2011-04-20 21:40:58 +08:00
primary_if = primary_if_get_selected ( bat_priv ) ;
if ( ! primary_if )
primary_if_select ( bat_priv , hard_iface ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
bat_info ( hard_iface - > soft_iface , " Interface activated: %s \n " ,
hard_iface - > net_dev - > name ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
update_min_mtu ( hard_iface - > soft_iface ) ;
2011-04-20 21:40:58 +08:00
out :
if ( primary_if )
hardif_free_ref ( primary_if ) ;
2010-12-13 19:19:28 +08:00
}
2011-02-18 20:33:20 +08:00
static void hardif_deactivate_interface ( struct hard_iface * hard_iface )
2010-12-13 19:19:28 +08:00
{
2011-02-18 20:33:20 +08:00
if ( ( hard_iface - > if_status ! = IF_ACTIVE ) & &
( hard_iface - > if_status ! = IF_TO_BE_ACTIVATED ) )
2010-12-13 19:19:28 +08:00
return ;
2011-02-18 20:33:20 +08:00
hard_iface - > if_status = IF_INACTIVE ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
bat_info ( hard_iface - > soft_iface , " Interface deactivated: %s \n " ,
hard_iface - > net_dev - > name ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
update_min_mtu ( hard_iface - > soft_iface ) ;
2010-12-13 19:19:28 +08:00
}
2011-05-15 05:14:50 +08:00
int hardif_enable_interface ( struct hard_iface * hard_iface ,
const char * iface_name )
2010-12-13 19:19:28 +08:00
{
struct bat_priv * bat_priv ;
2011-03-05 05:36:41 +08:00
struct net_device * soft_iface ;
int ret ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
if ( hard_iface - > if_status ! = IF_NOT_IN_USE )
2010-12-13 19:19:28 +08:00
goto out ;
2011-02-18 20:33:20 +08:00
if ( ! atomic_inc_not_zero ( & hard_iface - > refcount ) )
2011-02-10 22:33:51 +08:00
goto out ;
2011-12-07 18:02:50 +08:00
/* hard-interface is part of a bridge */
if ( hard_iface - > net_dev - > priv_flags & IFF_BRIDGE_PORT )
2012-03-07 16:07:45 +08:00
pr_err ( " You are about to enable batman-adv on '%s' which already is part of a bridge. Unless you know exactly what you are doing this is probably wrong and won't work the way you think it would. \n " ,
2011-12-07 18:02:50 +08:00
hard_iface - > net_dev - > name ) ;
2011-03-05 05:36:41 +08:00
soft_iface = dev_get_by_name ( & init_net , iface_name ) ;
2010-12-13 19:19:28 +08:00
2011-03-05 05:36:41 +08:00
if ( ! soft_iface ) {
soft_iface = softif_create ( iface_name ) ;
2010-12-13 19:19:28 +08:00
2011-03-05 05:36:41 +08:00
if ( ! soft_iface ) {
ret = - ENOMEM ;
2010-12-13 19:19:28 +08:00
goto err ;
2011-03-05 05:36:41 +08:00
}
2010-12-13 19:19:28 +08:00
/* dev_get_by_name() increases the reference counter for us */
2011-03-05 05:36:41 +08:00
dev_hold ( soft_iface ) ;
}
if ( ! softif_is_valid ( soft_iface ) ) {
2012-03-07 16:07:45 +08:00
pr_err ( " Can't create batman mesh interface %s: already exists as regular interface \n " ,
2011-03-05 05:36:41 +08:00
soft_iface - > name ) ;
dev_put ( soft_iface ) ;
ret = - EINVAL ;
goto err ;
2010-12-13 19:19:28 +08:00
}
2011-03-05 05:36:41 +08:00
hard_iface - > soft_iface = soft_iface ;
2011-02-18 20:33:20 +08:00
bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
2011-07-30 18:33:33 +08:00
2011-11-28 21:31:55 +08:00
bat_priv - > bat_algo_ops - > bat_ogm_init ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
if ( ! hard_iface - > packet_buff ) {
2012-03-07 16:07:45 +08:00
bat_err ( hard_iface - > soft_iface ,
" Can't add interface packet (%s): out of memory \n " ,
hard_iface - > net_dev - > name ) ;
2011-03-05 05:36:41 +08:00
ret = - ENOMEM ;
2010-12-13 19:19:28 +08:00
goto err ;
}
2011-02-18 20:33:20 +08:00
hard_iface - > if_num = bat_priv - > num_ifaces ;
2010-12-13 19:19:28 +08:00
bat_priv - > num_ifaces + + ;
2011-02-18 20:33:20 +08:00
hard_iface - > if_status = IF_INACTIVE ;
orig_hash_add_if ( hard_iface , bat_priv - > num_ifaces ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
hard_iface - > batman_adv_ptype . type = __constant_htons ( ETH_P_BATMAN ) ;
hard_iface - > batman_adv_ptype . func = batman_skb_recv ;
hard_iface - > batman_adv_ptype . dev = hard_iface - > net_dev ;
dev_add_pack ( & hard_iface - > batman_adv_ptype ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
atomic_set ( & hard_iface - > seqno , 1 ) ;
atomic_set ( & hard_iface - > frag_seqno , 1 ) ;
bat_info ( hard_iface - > soft_iface , " Adding interface: %s \n " ,
hard_iface - > net_dev - > name ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
if ( atomic_read ( & bat_priv - > fragmentation ) & & hard_iface - > net_dev - > mtu <
2010-12-13 19:19:28 +08:00
ETH_DATA_LEN + BAT_HEADER_LEN )
2011-02-18 20:33:20 +08:00
bat_info ( hard_iface - > soft_iface ,
2012-03-07 16:07:45 +08:00
" The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %zi would solve the problem. \n " ,
2012-02-28 17:55:36 +08:00
hard_iface - > net_dev - > name , hard_iface - > net_dev - > mtu ,
ETH_DATA_LEN + BAT_HEADER_LEN ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
if ( ! atomic_read ( & bat_priv - > fragmentation ) & & hard_iface - > net_dev - > mtu <
2010-12-13 19:19:28 +08:00
ETH_DATA_LEN + BAT_HEADER_LEN )
2011-02-18 20:33:20 +08:00
bat_info ( hard_iface - > soft_iface ,
2012-03-07 16:07:45 +08:00
" The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %zi. \n " ,
2012-02-28 17:55:36 +08:00
hard_iface - > net_dev - > name , hard_iface - > net_dev - > mtu ,
ETH_DATA_LEN + BAT_HEADER_LEN ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
if ( hardif_is_iface_up ( hard_iface ) )
hardif_activate_interface ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
else
2012-03-07 16:07:45 +08:00
bat_err ( hard_iface - > soft_iface ,
" Not using interface %s (retrying later): interface not active \n " ,
2011-02-18 20:33:20 +08:00
hard_iface - > net_dev - > name ) ;
2010-12-13 19:19:28 +08:00
/* begin scheduling originator messages on that interface */
2011-08-03 15:09:30 +08:00
schedule_bat_ogm ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
out :
return 0 ;
err :
2011-02-18 20:33:20 +08:00
hardif_free_ref ( hard_iface ) ;
2011-03-05 05:36:41 +08:00
return ret ;
2010-12-13 19:19:28 +08:00
}
2011-02-18 20:33:20 +08:00
void hardif_disable_interface ( struct hard_iface * hard_iface )
2010-12-13 19:19:28 +08:00
{
2011-02-18 20:33:20 +08:00
struct bat_priv * bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
2011-04-20 21:40:58 +08:00
struct hard_iface * primary_if = NULL ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
if ( hard_iface - > if_status = = IF_ACTIVE )
hardif_deactivate_interface ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
if ( hard_iface - > if_status ! = IF_INACTIVE )
2011-04-20 21:40:58 +08:00
goto out ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
bat_info ( hard_iface - > soft_iface , " Removing interface: %s \n " ,
hard_iface - > net_dev - > name ) ;
dev_remove_pack ( & hard_iface - > batman_adv_ptype ) ;
2010-12-13 19:19:28 +08:00
bat_priv - > num_ifaces - - ;
2011-02-18 20:33:20 +08:00
orig_hash_del_if ( hard_iface , bat_priv - > num_ifaces ) ;
2010-12-13 19:19:28 +08:00
2011-04-20 21:40:58 +08:00
primary_if = primary_if_get_selected ( bat_priv ) ;
if ( hard_iface = = primary_if ) {
2011-02-18 20:33:20 +08:00
struct hard_iface * new_if ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
new_if = hardif_get_active ( hard_iface - > soft_iface ) ;
2011-04-20 21:40:58 +08:00
primary_if_select ( bat_priv , new_if ) ;
2010-12-13 19:19:28 +08:00
if ( new_if )
2011-02-10 22:33:51 +08:00
hardif_free_ref ( new_if ) ;
2010-12-13 19:19:28 +08:00
}
2011-02-18 20:33:20 +08:00
kfree ( hard_iface - > packet_buff ) ;
hard_iface - > packet_buff = NULL ;
hard_iface - > if_status = IF_NOT_IN_USE ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
/* delete all references to this hard_iface */
2010-12-13 19:19:28 +08:00
purge_orig_ref ( bat_priv ) ;
2011-02-18 20:33:20 +08:00
purge_outstanding_packets ( bat_priv , hard_iface ) ;
dev_put ( hard_iface - > soft_iface ) ;
2010-12-13 19:19:28 +08:00
/* nobody uses this interface anymore */
if ( ! bat_priv - > num_ifaces )
2011-02-18 20:33:20 +08:00
softif_destroy ( hard_iface - > soft_iface ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
hard_iface - > soft_iface = NULL ;
hardif_free_ref ( hard_iface ) ;
2011-04-20 21:40:58 +08:00
out :
if ( primary_if )
hardif_free_ref ( primary_if ) ;
2010-12-13 19:19:28 +08:00
}
2011-02-18 20:33:20 +08:00
static struct hard_iface * hardif_add_interface ( struct net_device * net_dev )
2010-12-13 19:19:28 +08:00
{
2011-02-18 20:33:20 +08:00
struct hard_iface * hard_iface ;
2010-12-13 19:19:28 +08:00
int ret ;
2011-05-03 17:51:38 +08:00
ASSERT_RTNL ( ) ;
2010-12-13 19:19:28 +08:00
ret = is_valid_iface ( net_dev ) ;
if ( ret ! = 1 )
goto out ;
dev_hold ( net_dev ) ;
2011-05-15 05:14:54 +08:00
hard_iface = kmalloc ( sizeof ( * hard_iface ) , GFP_ATOMIC ) ;
2011-08-30 05:17:24 +08:00
if ( ! hard_iface )
2010-12-13 19:19:28 +08:00
goto release_dev ;
2011-02-18 20:33:20 +08:00
ret = sysfs_add_hardif ( & hard_iface - > hardif_obj , net_dev ) ;
2010-12-13 19:19:28 +08:00
if ( ret )
goto free_if ;
2011-02-18 20:33:20 +08:00
hard_iface - > if_num = - 1 ;
hard_iface - > net_dev = net_dev ;
hard_iface - > soft_iface = NULL ;
hard_iface - > if_status = IF_NOT_IN_USE ;
INIT_LIST_HEAD ( & hard_iface - > list ) ;
2011-02-10 22:33:51 +08:00
/* extra reference for return */
2011-02-18 20:33:20 +08:00
atomic_set ( & hard_iface - > refcount , 2 ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
check_known_mac_addr ( hard_iface - > net_dev ) ;
list_add_tail_rcu ( & hard_iface - > list , & hardif_list ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
return hard_iface ;
2010-12-13 19:19:28 +08:00
free_if :
2011-02-18 20:33:20 +08:00
kfree ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
release_dev :
dev_put ( net_dev ) ;
out :
return NULL ;
}
2011-02-18 20:33:20 +08:00
static void hardif_remove_interface ( struct hard_iface * hard_iface )
2010-12-13 19:19:28 +08:00
{
2011-05-03 17:51:38 +08:00
ASSERT_RTNL ( ) ;
2010-12-13 19:19:28 +08:00
/* first deactivate interface */
2011-02-18 20:33:20 +08:00
if ( hard_iface - > if_status ! = IF_NOT_IN_USE )
hardif_disable_interface ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
if ( hard_iface - > if_status ! = IF_NOT_IN_USE )
2010-12-13 19:19:28 +08:00
return ;
2011-02-18 20:33:20 +08:00
hard_iface - > if_status = IF_TO_BE_REMOVED ;
sysfs_del_hardif ( & hard_iface - > hardif_obj ) ;
hardif_free_ref ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
}
void hardif_remove_interfaces ( void )
{
2011-02-18 20:33:20 +08:00
struct hard_iface * hard_iface , * hard_iface_tmp ;
2010-12-13 19:19:28 +08:00
2011-05-03 17:51:38 +08:00
rtnl_lock ( ) ;
2011-02-18 20:33:20 +08:00
list_for_each_entry_safe ( hard_iface , hard_iface_tmp ,
& hardif_list , list ) {
list_del_rcu ( & hard_iface - > list ) ;
hardif_remove_interface ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
}
rtnl_unlock ( ) ;
}
static int hard_if_event ( struct notifier_block * this ,
unsigned long event , void * ptr )
{
2011-05-15 05:14:52 +08:00
struct net_device * net_dev = ptr ;
2011-02-18 20:33:20 +08:00
struct hard_iface * hard_iface = hardif_get_by_netdev ( net_dev ) ;
2011-04-20 21:40:58 +08:00
struct hard_iface * primary_if = NULL ;
2010-12-13 19:19:28 +08:00
struct bat_priv * bat_priv ;
2011-02-18 20:33:20 +08:00
if ( ! hard_iface & & event = = NETDEV_REGISTER )
hard_iface = hardif_add_interface ( net_dev ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
if ( ! hard_iface )
2010-12-13 19:19:28 +08:00
goto out ;
switch ( event ) {
case NETDEV_UP :
2011-02-18 20:33:20 +08:00
hardif_activate_interface ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
break ;
case NETDEV_GOING_DOWN :
case NETDEV_DOWN :
2011-02-18 20:33:20 +08:00
hardif_deactivate_interface ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
break ;
case NETDEV_UNREGISTER :
2011-02-18 20:33:20 +08:00
list_del_rcu ( & hard_iface - > list ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
hardif_remove_interface ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
break ;
case NETDEV_CHANGEMTU :
2011-02-18 20:33:20 +08:00
if ( hard_iface - > soft_iface )
update_min_mtu ( hard_iface - > soft_iface ) ;
2010-12-13 19:19:28 +08:00
break ;
case NETDEV_CHANGEADDR :
2011-02-18 20:33:20 +08:00
if ( hard_iface - > if_status = = IF_NOT_IN_USE )
2010-12-13 19:19:28 +08:00
goto hardif_put ;
2011-02-18 20:33:20 +08:00
check_known_mac_addr ( hard_iface - > net_dev ) ;
2010-12-13 19:19:28 +08:00
2011-02-18 20:33:20 +08:00
bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
2011-11-28 21:31:55 +08:00
bat_priv - > bat_algo_ops - > bat_ogm_update_mac ( hard_iface ) ;
2011-04-20 21:40:58 +08:00
primary_if = primary_if_get_selected ( bat_priv ) ;
if ( ! primary_if )
goto hardif_put ;
if ( hard_iface = = primary_if )
primary_if_update_addr ( bat_priv ) ;
2010-12-13 19:19:28 +08:00
break ;
default :
break ;
2011-06-03 19:51:19 +08:00
}
2010-12-13 19:19:28 +08:00
hardif_put :
2011-02-18 20:33:20 +08:00
hardif_free_ref ( hard_iface ) ;
2010-12-13 19:19:28 +08:00
out :
2011-04-20 21:40:58 +08:00
if ( primary_if )
hardif_free_ref ( primary_if ) ;
2010-12-13 19:19:28 +08:00
return NOTIFY_DONE ;
}
2011-07-09 23:52:13 +08:00
/* incoming packets with the batman ethertype received on any active hard
2010-12-13 19:19:28 +08:00
* interface */
2011-01-27 20:16:08 +08:00
static int batman_skb_recv ( struct sk_buff * skb , struct net_device * dev ,
struct packet_type * ptype ,
struct net_device * orig_dev )
2010-12-13 19:19:28 +08:00
{
struct bat_priv * bat_priv ;
2011-07-29 23:31:50 +08:00
struct batman_ogm_packet * batman_ogm_packet ;
2011-02-18 20:33:20 +08:00
struct hard_iface * hard_iface ;
2010-12-13 19:19:28 +08:00
int ret ;
2011-02-18 20:33:20 +08:00
hard_iface = container_of ( ptype , struct hard_iface , batman_adv_ptype ) ;
2010-12-13 19:19:28 +08:00
skb = skb_share_check ( skb , GFP_ATOMIC ) ;
/* skb was released by skb_share_check() */
if ( ! skb )
goto err_out ;
/* packet should hold at least type and version */
if ( unlikely ( ! pskb_may_pull ( skb , 2 ) ) )
goto err_free ;
/* expect a valid ethernet header here. */
2012-02-28 17:55:36 +08:00
if ( unlikely ( skb - > mac_len ! = sizeof ( struct ethhdr ) | |
! skb_mac_header ( skb ) ) )
2010-12-13 19:19:28 +08:00
goto err_free ;
2011-02-18 20:33:20 +08:00
if ( ! hard_iface - > soft_iface )
2010-12-13 19:19:28 +08:00
goto err_free ;
2011-02-18 20:33:20 +08:00
bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
2010-12-13 19:19:28 +08:00
if ( atomic_read ( & bat_priv - > mesh_state ) ! = MESH_ACTIVE )
goto err_free ;
/* discard frames on not active interfaces */
2011-02-18 20:33:20 +08:00
if ( hard_iface - > if_status ! = IF_ACTIVE )
2010-12-13 19:19:28 +08:00
goto err_free ;
2011-07-29 23:31:50 +08:00
batman_ogm_packet = ( struct batman_ogm_packet * ) skb - > data ;
2010-12-13 19:19:28 +08:00
2011-11-20 22:47:38 +08:00
if ( batman_ogm_packet - > header . version ! = COMPAT_VERSION ) {
2010-12-13 19:19:28 +08:00
bat_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: incompatible batman version (%i) \n " ,
2011-11-20 22:47:38 +08:00
batman_ogm_packet - > header . version ) ;
2010-12-13 19:19:28 +08:00
goto err_free ;
}
/* all receive handlers return whether they received or reused
* the supplied skb . if not , we have to free the skb . */
2011-11-20 22:47:38 +08:00
switch ( batman_ogm_packet - > header . packet_type ) {
2010-12-13 19:19:28 +08:00
/* batman originator packet */
2011-07-29 23:31:50 +08:00
case BAT_OGM :
2011-07-30 18:04:12 +08:00
ret = recv_bat_ogm_packet ( skb , hard_iface ) ;
2010-12-13 19:19:28 +08:00
break ;
/* batman icmp packet */
case BAT_ICMP :
2011-02-18 20:33:20 +08:00
ret = recv_icmp_packet ( skb , hard_iface ) ;
2010-12-13 19:19:28 +08:00
break ;
/* unicast packet */
case BAT_UNICAST :
2011-02-18 20:33:20 +08:00
ret = recv_unicast_packet ( skb , hard_iface ) ;
2010-12-13 19:19:28 +08:00
break ;
/* fragmented unicast packet */
case BAT_UNICAST_FRAG :
2011-02-18 20:33:20 +08:00
ret = recv_ucast_frag_packet ( skb , hard_iface ) ;
2010-12-13 19:19:28 +08:00
break ;
/* broadcast packet */
case BAT_BCAST :
2011-02-18 20:33:20 +08:00
ret = recv_bcast_packet ( skb , hard_iface ) ;
2010-12-13 19:19:28 +08:00
break ;
/* vis packet */
case BAT_VIS :
2011-02-18 20:33:20 +08:00
ret = recv_vis_packet ( skb , hard_iface ) ;
2010-12-13 19:19:28 +08:00
break ;
2011-04-27 20:27:44 +08:00
/* Translation table query (request or response) */
case BAT_TT_QUERY :
ret = recv_tt_query ( skb , hard_iface ) ;
break ;
2011-04-27 20:27:57 +08:00
/* Roaming advertisement */
case BAT_ROAM_ADV :
ret = recv_roam_adv ( skb , hard_iface ) ;
break ;
2010-12-13 19:19:28 +08:00
default :
ret = NET_RX_DROP ;
}
if ( ret = = NET_RX_DROP )
kfree_skb ( skb ) ;
/* return NET_RX_SUCCESS in any case as we
* most probably dropped the packet for
* routing - logical reasons . */
return NET_RX_SUCCESS ;
err_free :
kfree_skb ( skb ) ;
err_out :
return NET_RX_DROP ;
}
2011-07-07 21:35:35 +08:00
/* This function returns true if the interface represented by ifindex is a
* 802.11 wireless device */
bool is_wifi_iface ( int ifindex )
{
struct net_device * net_device = NULL ;
bool ret = false ;
if ( ifindex = = NULL_IFINDEX )
goto out ;
net_device = dev_get_by_index ( & init_net , ifindex ) ;
if ( ! net_device )
goto out ;
# ifdef CONFIG_WIRELESS_EXT
/* pre-cfg80211 drivers have to implement WEXT, so it is possible to
* check for wireless_handlers ! = NULL */
if ( net_device - > wireless_handlers )
ret = true ;
else
# endif
/* cfg80211 drivers have to set ieee80211_ptr */
if ( net_device - > ieee80211_ptr )
ret = true ;
out :
if ( net_device )
dev_put ( net_device ) ;
return ret ;
}
2010-12-13 19:19:28 +08:00
struct notifier_block hard_if_notifier = {
. notifier_call = hard_if_event ,
} ;