2016-01-01 06:01:03 +07:00
/* Copyright (C) 2007-2016 B.A.T.M.A.N. contributors:
2010-12-13 18:19:28 +07: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
2013-11-04 02:40:48 +07:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2010-12-13 18:19:28 +07:00
*/
# include "hard-interface.h"
2015-04-18 00:40:28 +07:00
# include "main.h"
2010-12-13 18:19:28 +07:00
2016-01-16 16:29:54 +07:00
# include <linux/atomic.h>
2015-04-18 00:40:28 +07:00
# include <linux/bug.h>
# include <linux/byteorder/generic.h>
# include <linux/errno.h>
# include <linux/fs.h>
2010-12-13 18:19:28 +07:00
# include <linux/if_arp.h>
2012-11-26 06:38:50 +07:00
# include <linux/if_ether.h>
2015-04-18 00:40:28 +07:00
# include <linux/if.h>
# include <linux/kernel.h>
2016-01-16 16:29:54 +07:00
# include <linux/kref.h>
2015-04-18 00:40:28 +07:00
# include <linux/list.h>
# include <linux/netdevice.h>
# include <linux/printk.h>
# include <linux/rculist.h>
# include <linux/rtnetlink.h>
# include <linux/slab.h>
2015-08-04 20:09:55 +07:00
# include <linux/spinlock.h>
2015-04-18 00:40:28 +07:00
# include <linux/workqueue.h>
# include "bridge_loop_avoidance.h"
# include "debugfs.h"
# include "distributed-arp-table.h"
# include "gateway_client.h"
# include "originator.h"
# include "packet.h"
# include "send.h"
# include "soft-interface.h"
# include "sysfs.h"
# include "translation-table.h"
2010-12-13 18:19:28 +07:00
2016-01-05 18:06:26 +07:00
/**
* batadv_hardif_release - release hard interface from lists and queue for
* free after rcu grace period
2016-01-16 16:29:54 +07:00
* @ ref : kref pointer of the hard interface
2016-01-05 18:06:26 +07:00
*/
2016-01-16 16:29:54 +07:00
void batadv_hardif_release ( struct kref * ref )
2010-12-13 18:19:28 +07:00
{
2016-01-16 16:29:54 +07:00
struct batadv_hard_iface * hard_iface ;
hard_iface = container_of ( ref , struct batadv_hard_iface , refcount ) ;
2011-02-18 19:33:20 +07:00
dev_put ( hard_iface - > net_dev ) ;
2016-01-05 18:06:26 +07:00
kfree_rcu ( hard_iface , rcu ) ;
2010-12-13 18:19:28 +07:00
}
2012-06-06 03:31:31 +07:00
struct batadv_hard_iface *
batadv_hardif_get_by_netdev ( const struct net_device * net_dev )
2010-12-13 18:19:28 +07:00
{
2012-06-06 03:31:31 +07:00
struct batadv_hard_iface * hard_iface ;
2010-12-13 18:19:28 +07:00
rcu_read_lock ( ) ;
2012-05-12 07:09:42 +07:00
list_for_each_entry_rcu ( hard_iface , & batadv_hardif_list , list ) {
2011-02-18 19:33:20 +07:00
if ( hard_iface - > net_dev = = net_dev & &
2016-01-16 16:29:54 +07:00
kref_get_unless_zero ( & hard_iface - > refcount ) )
2010-12-13 18:19:28 +07:00
goto out ;
}
2011-02-18 19:33:20 +07:00
hard_iface = NULL ;
2010-12-13 18:19:28 +07:00
out :
rcu_read_unlock ( ) ;
2011-02-18 19:33:20 +07:00
return hard_iface ;
2010-12-13 18:19:28 +07:00
}
2016-02-12 04:15:57 +07:00
/**
* batadv_mutual_parents - check if two devices are each others parent
* @ dev1 : 1 st net_device
* @ dev2 : 2 nd net_device
*
* veth devices come in pairs and each is the parent of the other !
*
* Return : true if the devices are each others parent , otherwise false
*/
static bool batadv_mutual_parents ( const struct net_device * dev1 ,
const struct net_device * dev2 )
{
int dev1_parent_iflink = dev_get_iflink ( dev1 ) ;
int dev2_parent_iflink = dev_get_iflink ( dev2 ) ;
if ( ! dev1_parent_iflink | | ! dev2_parent_iflink )
return false ;
return ( dev1_parent_iflink = = dev2 - > ifindex ) & &
( dev2_parent_iflink = = dev1 - > ifindex ) ;
}
2012-09-09 15:46:46 +07:00
/**
* batadv_is_on_batman_iface - check if a device is a batman iface descendant
* @ net_dev : the device to check
*
* If the user creates any virtual device on top of a batman - adv interface , it
* is important to prevent this new interface to be used to create a new mesh
* network ( this behaviour would lead to a batman - over - batman configuration ) .
* This function recursively checks all the fathers of the device passed as
* argument looking for a batman - adv soft interface .
*
2015-09-16 00:00:48 +07:00
* Return : true if the device is descendant of a batman - adv mesh interface ( or
2012-09-09 15:46:46 +07:00
* if it is a batman - adv interface itself ) , false otherwise
*/
static bool batadv_is_on_batman_iface ( const struct net_device * net_dev )
{
struct net_device * parent_dev ;
2016-04-21 17:57:27 +07:00
struct net * net = dev_net ( net_dev ) ;
2012-09-09 15:46:46 +07:00
bool ret ;
/* check if this is a batman-adv mesh interface */
if ( batadv_softif_is_valid ( net_dev ) )
return true ;
/* no more parents..stop recursion */
2015-04-02 22:07:00 +07:00
if ( dev_get_iflink ( net_dev ) = = 0 | |
dev_get_iflink ( net_dev ) = = net_dev - > ifindex )
2012-09-09 15:46:46 +07:00
return false ;
/* recurse over the parent device */
2016-04-21 17:57:27 +07:00
parent_dev = __dev_get_by_index ( net , dev_get_iflink ( net_dev ) ) ;
2012-09-09 15:46:46 +07:00
/* if we got a NULL parent_dev there is something broken.. */
if ( WARN ( ! parent_dev , " Cannot find parent device " ) )
return false ;
2016-02-12 04:15:57 +07:00
if ( batadv_mutual_parents ( net_dev , parent_dev ) )
return false ;
2012-09-09 15:46:46 +07:00
ret = batadv_is_on_batman_iface ( parent_dev ) ;
return ret ;
}
2016-02-23 03:02:39 +07:00
static bool batadv_is_valid_iface ( const struct net_device * net_dev )
2010-12-13 18:19:28 +07:00
{
if ( net_dev - > flags & IFF_LOOPBACK )
2016-02-23 03:02:39 +07:00
return false ;
2010-12-13 18:19:28 +07:00
if ( net_dev - > type ! = ARPHRD_ETHER )
2016-02-23 03:02:39 +07:00
return false ;
2010-12-13 18:19:28 +07:00
if ( net_dev - > addr_len ! = ETH_ALEN )
2016-02-23 03:02:39 +07:00
return false ;
2010-12-13 18:19:28 +07:00
/* no batman over batman */
2012-09-09 15:46:46 +07:00
if ( batadv_is_on_batman_iface ( net_dev ) )
2016-02-23 03:02:39 +07:00
return false ;
2010-12-13 18:19:28 +07:00
2016-02-23 03:02:39 +07:00
return true ;
2010-12-13 18:19:28 +07:00
}
2013-03-10 05:14:22 +07:00
/**
* batadv_is_wifi_netdev - check if the given net_device struct is a wifi
* interface
* @ net_device : the device to check
*
2015-09-16 00:00:48 +07:00
* Return : true if the net device is a 802.11 wireless device , false otherwise .
2013-03-10 05:14:22 +07:00
*/
2013-10-13 07:50:18 +07:00
bool batadv_is_wifi_netdev ( struct net_device * net_device )
2013-03-10 05:14:22 +07:00
{
2013-10-13 07:50:18 +07:00
if ( ! net_device )
return false ;
2013-03-10 05:14:22 +07:00
# 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 )
return true ;
# endif
/* cfg80211 drivers have to set ieee80211_ptr */
if ( net_device - > ieee80211_ptr )
return true ;
return false ;
}
2012-06-06 03:31:31 +07:00
static struct batadv_hard_iface *
2012-05-12 23:33:57 +07:00
batadv_hardif_get_active ( const struct net_device * soft_iface )
2010-12-13 18:19:28 +07:00
{
2012-06-06 03:31:31 +07:00
struct batadv_hard_iface * hard_iface ;
2010-12-13 18:19:28 +07:00
rcu_read_lock ( ) ;
2012-05-12 07:09:42 +07:00
list_for_each_entry_rcu ( hard_iface , & batadv_hardif_list , list ) {
2011-02-18 19:33:20 +07:00
if ( hard_iface - > soft_iface ! = soft_iface )
2010-12-13 18:19:28 +07:00
continue ;
2012-06-04 03:19:19 +07:00
if ( hard_iface - > if_status = = BATADV_IF_ACTIVE & &
2016-01-16 16:29:54 +07:00
kref_get_unless_zero ( & hard_iface - > refcount ) )
2010-12-13 18:19:28 +07:00
goto out ;
}
2011-02-18 19:33:20 +07:00
hard_iface = NULL ;
2010-12-13 18:19:28 +07:00
out :
rcu_read_unlock ( ) ;
2011-02-18 19:33:20 +07:00
return hard_iface ;
2010-12-13 18:19:28 +07:00
}
2012-06-06 03:31:31 +07:00
static void batadv_primary_if_update_addr ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * oldif )
2010-12-13 18:19:28 +07:00
{
2012-06-06 03:31:31 +07:00
struct batadv_hard_iface * primary_if ;
2011-04-20 20:40:58 +07:00
2012-05-12 18:48:54 +07:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-04-20 20:40:58 +07:00
if ( ! primary_if )
goto out ;
2010-12-13 18:19:28 +07:00
2011-11-23 17:35:44 +07:00
batadv_dat_init_own_addr ( bat_priv , primary_if ) ;
2012-05-12 18:38:47 +07:00
batadv_bla_update_orig_address ( bat_priv , primary_if , oldif ) ;
2011-04-20 20:40:58 +07:00
out :
if ( primary_if )
2016-01-17 17:01:10 +07:00
batadv_hardif_put ( primary_if ) ;
2010-12-13 18:19:28 +07:00
}
2012-06-06 03:31:31 +07:00
static void batadv_primary_if_select ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * new_hard_iface )
2010-12-13 18:19:28 +07:00
{
2012-06-06 03:31:31 +07:00
struct batadv_hard_iface * curr_hard_iface ;
2010-12-13 18:19:28 +07:00
2011-05-03 16:51:38 +07:00
ASSERT_RTNL ( ) ;
2010-12-13 18:19:28 +07:00
2016-04-11 18:06:40 +07:00
if ( new_hard_iface )
kref_get ( & new_hard_iface - > refcount ) ;
2010-12-13 18:19:28 +07:00
2011-05-15 05:50:21 +07:00
curr_hard_iface = rcu_dereference_protected ( bat_priv - > primary_if , 1 ) ;
2011-04-20 20:40:58 +07:00
rcu_assign_pointer ( bat_priv - > primary_if , new_hard_iface ) ;
2010-12-13 18:19:28 +07:00
2011-04-20 20:40:58 +07:00
if ( ! new_hard_iface )
2012-01-23 02:00:19 +07:00
goto out ;
2011-04-20 20:40:58 +07:00
2012-02-07 16:20:49 +07:00
bat_priv - > bat_algo_ops - > bat_primary_iface_set ( new_hard_iface ) ;
2012-05-12 23:33:57 +07:00
batadv_primary_if_update_addr ( bat_priv , curr_hard_iface ) ;
2012-01-23 02:00:19 +07:00
out :
if ( curr_hard_iface )
2016-01-17 17:01:10 +07:00
batadv_hardif_put ( curr_hard_iface ) ;
2010-12-13 18:19:28 +07:00
}
2012-06-06 03:31:31 +07:00
static bool
batadv_hardif_is_iface_up ( const struct batadv_hard_iface * hard_iface )
2010-12-13 18:19:28 +07:00
{
2011-02-18 19:33:20 +07:00
if ( hard_iface - > net_dev - > flags & IFF_UP )
2010-12-13 18:19:28 +07:00
return true ;
return false ;
}
2012-05-12 23:33:57 +07:00
static void batadv_check_known_mac_addr ( const struct net_device * net_dev )
2010-12-13 18:19:28 +07:00
{
2012-06-06 03:31:31 +07:00
const struct batadv_hard_iface * hard_iface ;
2010-12-13 18:19:28 +07:00
rcu_read_lock ( ) ;
2012-05-12 07:09:42 +07:00
list_for_each_entry_rcu ( hard_iface , & batadv_hardif_list , list ) {
2012-06-04 03:19:19 +07:00
if ( ( hard_iface - > if_status ! = BATADV_IF_ACTIVE ) & &
( hard_iface - > if_status ! = BATADV_IF_TO_BE_ACTIVATED ) )
2010-12-13 18:19:28 +07:00
continue ;
2011-02-18 19:33:20 +07:00
if ( hard_iface - > net_dev = = net_dev )
2010-12-13 18:19:28 +07:00
continue ;
2012-05-12 18:48:58 +07:00
if ( ! batadv_compare_eth ( hard_iface - > net_dev - > dev_addr ,
net_dev - > dev_addr ) )
2010-12-13 18:19:28 +07:00
continue ;
2012-03-26 21:22:45 +07:00
pr_warn ( " The newly added mac address (%pM) already exists on: %s \n " ,
net_dev - > dev_addr , hard_iface - > net_dev - > name ) ;
pr_warn ( " It is strongly recommended to keep mac addresses unique to avoid problems! \n " ) ;
2010-12-13 18:19:28 +07:00
}
rcu_read_unlock ( ) ;
}
2015-08-08 00:28:42 +07:00
/**
* batadv_hardif_recalc_extra_skbroom ( ) - Recalculate skbuff extra head / tailroom
* @ soft_iface : netdev struct of the mesh interface
*/
static void batadv_hardif_recalc_extra_skbroom ( struct net_device * soft_iface )
{
const struct batadv_hard_iface * hard_iface ;
unsigned short lower_header_len = ETH_HLEN ;
unsigned short lower_headroom = 0 ;
unsigned short lower_tailroom = 0 ;
unsigned short needed_headroom ;
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( hard_iface , & batadv_hardif_list , list ) {
if ( hard_iface - > if_status = = BATADV_IF_NOT_IN_USE )
continue ;
if ( hard_iface - > soft_iface ! = soft_iface )
continue ;
lower_header_len = max_t ( unsigned short , lower_header_len ,
hard_iface - > net_dev - > hard_header_len ) ;
lower_headroom = max_t ( unsigned short , lower_headroom ,
hard_iface - > net_dev - > needed_headroom ) ;
lower_tailroom = max_t ( unsigned short , lower_tailroom ,
hard_iface - > net_dev - > needed_tailroom ) ;
}
rcu_read_unlock ( ) ;
needed_headroom = lower_headroom + ( lower_header_len - ETH_HLEN ) ;
needed_headroom + = batadv_max_header_len ( ) ;
soft_iface - > needed_headroom = needed_headroom ;
soft_iface - > needed_tailroom = lower_tailroom ;
}
2012-05-12 07:09:31 +07:00
int batadv_hardif_min_mtu ( struct net_device * soft_iface )
2010-12-13 18:19:28 +07:00
{
2013-05-27 14:33:25 +07:00
struct batadv_priv * bat_priv = netdev_priv ( soft_iface ) ;
2012-06-06 03:31:31 +07:00
const struct batadv_hard_iface * hard_iface ;
2014-01-21 17:22:05 +07:00
int min_mtu = INT_MAX ;
2010-12-13 18:19:28 +07:00
rcu_read_lock ( ) ;
2012-05-12 07:09:42 +07:00
list_for_each_entry_rcu ( hard_iface , & batadv_hardif_list , list ) {
2012-06-04 03:19:19 +07:00
if ( ( hard_iface - > if_status ! = BATADV_IF_ACTIVE ) & &
( hard_iface - > if_status ! = BATADV_IF_TO_BE_ACTIVATED ) )
2010-12-13 18:19:28 +07:00
continue ;
2011-02-18 19:33:20 +07:00
if ( hard_iface - > soft_iface ! = soft_iface )
2010-12-13 18:19:28 +07:00
continue ;
2013-05-27 14:33:25 +07:00
min_mtu = min_t ( int , hard_iface - > net_dev - > mtu , min_mtu ) ;
2010-12-13 18:19:28 +07:00
}
rcu_read_unlock ( ) ;
2013-05-27 14:33:25 +07:00
if ( atomic_read ( & bat_priv - > fragmentation ) = = 0 )
goto out ;
/* with fragmentation enabled the maximum size of internally generated
* packets such as translation table exchanges or tvlv containers , etc
* has to be calculated
*/
min_mtu = min_t ( int , min_mtu , BATADV_FRAG_MAX_FRAG_SIZE ) ;
min_mtu - = sizeof ( struct batadv_frag_packet ) ;
min_mtu * = BATADV_FRAG_MAX_FRAGMENTS ;
2010-12-13 18:19:28 +07:00
out :
2014-01-21 17:22:05 +07:00
/* report to the other components the maximum amount of bytes that
* batman - adv can send over the wire ( without considering the payload
* overhead ) . For example , this value is used by TT to compute the
* maximum local table table size
*/
atomic_set ( & bat_priv - > packet_size_max , min_mtu ) ;
/* the real soft-interface MTU is computed by removing the payload
* overhead from the maximum amount of bytes that was just computed .
*
* However batman - adv does not support MTUs bigger than ETH_DATA_LEN
*/
return min_t ( int , min_mtu - batadv_max_header_len ( ) , ETH_DATA_LEN ) ;
2010-12-13 18:19:28 +07:00
}
/* adjusts the MTU if a new interface with a smaller MTU appeared. */
2012-05-12 07:09:31 +07:00
void batadv_update_min_mtu ( struct net_device * soft_iface )
2010-12-13 18:19:28 +07:00
{
2013-05-27 14:33:25 +07:00
soft_iface - > mtu = batadv_hardif_min_mtu ( soft_iface ) ;
2010-12-13 18:19:28 +07:00
2013-05-27 14:33:25 +07:00
/* Check if the local translate table should be cleaned up to match a
* new ( and smaller ) MTU .
*/
batadv_tt_local_resize_to_mtu ( soft_iface ) ;
2010-12-13 18:19:28 +07:00
}
2012-06-06 03:31:31 +07:00
static void
batadv_hardif_activate_interface ( struct batadv_hard_iface * hard_iface )
2010-12-13 18:19:28 +07:00
{
2012-06-06 03:31:31 +07:00
struct batadv_priv * bat_priv ;
struct batadv_hard_iface * primary_if = NULL ;
2010-12-13 18:19:28 +07:00
2012-06-04 03:19:19 +07:00
if ( hard_iface - > if_status ! = BATADV_IF_INACTIVE )
2011-04-20 20:40:58 +07:00
goto out ;
2010-12-13 18:19:28 +07:00
2011-02-18 19:33:20 +07:00
bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
2010-12-13 18:19:28 +07:00
2012-03-11 05:17:50 +07:00
bat_priv - > bat_algo_ops - > bat_iface_update_mac ( hard_iface ) ;
2012-06-04 03:19:19 +07:00
hard_iface - > if_status = BATADV_IF_TO_BE_ACTIVATED ;
2010-12-13 18:19:28 +07:00
2012-05-12 07:09:43 +07:00
/* the first active interface becomes our primary interface or
2011-07-09 22:52:13 +07:00
* the next active interface after the old primary interface was removed
2010-12-13 18:19:28 +07:00
*/
2012-05-12 18:48:54 +07:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-04-20 20:40:58 +07:00
if ( ! primary_if )
2012-05-12 23:33:57 +07:00
batadv_primary_if_select ( bat_priv , hard_iface ) ;
2010-12-13 18:19:28 +07:00
2012-05-17 01:23:22 +07:00
batadv_info ( hard_iface - > soft_iface , " Interface activated: %s \n " ,
hard_iface - > net_dev - > name ) ;
2010-12-13 18:19:28 +07:00
2012-05-12 07:09:31 +07:00
batadv_update_min_mtu ( hard_iface - > soft_iface ) ;
2011-04-20 20:40:58 +07:00
2016-04-14 08:37:05 +07:00
if ( bat_priv - > bat_algo_ops - > bat_iface_activate )
bat_priv - > bat_algo_ops - > bat_iface_activate ( hard_iface ) ;
2011-04-20 20:40:58 +07:00
out :
if ( primary_if )
2016-01-17 17:01:10 +07:00
batadv_hardif_put ( primary_if ) ;
2010-12-13 18:19:28 +07:00
}
2012-06-06 03:31:31 +07:00
static void
batadv_hardif_deactivate_interface ( struct batadv_hard_iface * hard_iface )
2010-12-13 18:19:28 +07:00
{
2012-06-04 03:19:19 +07:00
if ( ( hard_iface - > if_status ! = BATADV_IF_ACTIVE ) & &
( hard_iface - > if_status ! = BATADV_IF_TO_BE_ACTIVATED ) )
2010-12-13 18:19:28 +07:00
return ;
2012-06-04 03:19:19 +07:00
hard_iface - > if_status = BATADV_IF_INACTIVE ;
2010-12-13 18:19:28 +07:00
2012-05-17 01:23:22 +07:00
batadv_info ( hard_iface - > soft_iface , " Interface deactivated: %s \n " ,
hard_iface - > net_dev - > name ) ;
2010-12-13 18:19:28 +07:00
2012-05-12 07:09:31 +07:00
batadv_update_min_mtu ( hard_iface - > soft_iface ) ;
2010-12-13 18:19:28 +07:00
}
2013-02-16 20:42:39 +07:00
/**
* batadv_master_del_slave - remove hard_iface from the current master interface
* @ slave : the interface enslaved in another master
* @ master : the master from which slave has to be removed
*
* Invoke ndo_del_slave on master passing slave as argument . In this way slave
* is free ' d and master can correctly change its internal state .
2015-09-16 00:00:48 +07:00
*
* Return : 0 on success , a negative value representing the error otherwise
2013-02-16 20:42:39 +07:00
*/
static int batadv_master_del_slave ( struct batadv_hard_iface * slave ,
struct net_device * master )
{
int ret ;
if ( ! master )
return 0 ;
ret = - EBUSY ;
if ( master - > netdev_ops - > ndo_del_slave )
ret = master - > netdev_ops - > ndo_del_slave ( master , slave - > net_dev ) ;
return ret ;
}
2012-06-06 03:31:31 +07:00
int batadv_hardif_enable_interface ( struct batadv_hard_iface * hard_iface ,
2016-04-21 17:57:27 +07:00
struct net * net , const char * iface_name )
2010-12-13 18:19:28 +07:00
{
2012-06-06 03:31:31 +07:00
struct batadv_priv * bat_priv ;
2013-02-16 20:42:39 +07:00
struct net_device * soft_iface , * master ;
2013-05-19 17:55:16 +07:00
__be16 ethertype = htons ( ETH_P_BATMAN ) ;
2013-05-08 12:31:59 +07:00
int max_header_len = batadv_max_header_len ( ) ;
2011-03-05 04:36:41 +07:00
int ret ;
2010-12-13 18:19:28 +07:00
2012-06-04 03:19:19 +07:00
if ( hard_iface - > if_status ! = BATADV_IF_NOT_IN_USE )
2010-12-13 18:19:28 +07:00
goto out ;
2016-04-11 18:06:40 +07:00
kref_get ( & hard_iface - > refcount ) ;
2011-02-10 21:33:51 +07:00
2016-04-21 17:57:27 +07:00
soft_iface = dev_get_by_name ( net , iface_name ) ;
2010-12-13 18:19:28 +07:00
2011-03-05 04:36:41 +07:00
if ( ! soft_iface ) {
2016-04-21 17:57:27 +07:00
soft_iface = batadv_softif_create ( net , iface_name ) ;
2010-12-13 18:19:28 +07:00
2011-03-05 04:36:41 +07:00
if ( ! soft_iface ) {
ret = - ENOMEM ;
2010-12-13 18:19:28 +07:00
goto err ;
2011-03-05 04:36:41 +07:00
}
2010-12-13 18:19:28 +07:00
/* dev_get_by_name() increases the reference counter for us */
2011-03-05 04:36:41 +07:00
dev_hold ( soft_iface ) ;
}
2012-05-12 07:09:38 +07:00
if ( ! batadv_softif_is_valid ( soft_iface ) ) {
2012-03-07 15:07:45 +07:00
pr_err ( " Can't create batman mesh interface %s: already exists as regular interface \n " ,
2011-03-05 04:36:41 +07:00
soft_iface - > name ) ;
ret = - EINVAL ;
2012-02-07 16:20:48 +07:00
goto err_dev ;
2010-12-13 18:19:28 +07:00
}
2013-02-16 20:42:39 +07:00
/* check if the interface is enslaved in another virtual one and
* in that case unlink it first
*/
master = netdev_master_upper_dev_get ( hard_iface - > net_dev ) ;
ret = batadv_master_del_slave ( hard_iface , master ) ;
if ( ret )
goto err_dev ;
2011-03-05 04:36:41 +07:00
hard_iface - > soft_iface = soft_iface ;
2011-02-18 19:33:20 +07:00
bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
2011-07-30 17:33:33 +07:00
2015-12-03 18:12:10 +07:00
ret = netdev_master_upper_dev_link ( hard_iface - > net_dev ,
2015-12-03 18:12:11 +07:00
soft_iface , NULL , NULL ) ;
2013-02-11 16:10:27 +07:00
if ( ret )
goto err_dev ;
2012-02-07 16:20:48 +07:00
ret = bat_priv - > bat_algo_ops - > bat_iface_enable ( hard_iface ) ;
2012-05-05 18:27:28 +07:00
if ( ret < 0 )
2013-02-11 16:10:27 +07:00
goto err_upper ;
2010-12-13 18:19:28 +07:00
2011-02-18 19:33:20 +07:00
hard_iface - > if_num = bat_priv - > num_ifaces ;
2010-12-13 18:19:28 +07:00
bat_priv - > num_ifaces + + ;
2012-06-04 03:19:19 +07:00
hard_iface - > if_status = BATADV_IF_INACTIVE ;
2012-07-02 03:51:55 +07:00
ret = batadv_orig_hash_add_if ( hard_iface , bat_priv - > num_ifaces ) ;
if ( ret < 0 ) {
bat_priv - > bat_algo_ops - > bat_iface_disable ( hard_iface ) ;
bat_priv - > num_ifaces - - ;
hard_iface - > if_status = BATADV_IF_NOT_IN_USE ;
2013-02-11 16:10:27 +07:00
goto err_upper ;
2012-07-02 03:51:55 +07:00
}
2010-12-13 18:19:28 +07:00
2016-03-05 22:09:18 +07:00
kref_get ( & hard_iface - > refcount ) ;
2012-06-04 03:19:13 +07:00
hard_iface - > batman_adv_ptype . type = ethertype ;
2012-05-12 07:09:42 +07:00
hard_iface - > batman_adv_ptype . func = batadv_batman_skb_recv ;
2011-02-18 19:33:20 +07:00
hard_iface - > batman_adv_ptype . dev = hard_iface - > net_dev ;
dev_add_pack ( & hard_iface - > batman_adv_ptype ) ;
2010-12-13 18:19:28 +07:00
2012-05-17 01:23:22 +07:00
batadv_info ( hard_iface - > soft_iface , " Adding interface: %s \n " ,
hard_iface - > net_dev - > name ) ;
2010-12-13 18:19:28 +07:00
2012-06-20 01:26:30 +07:00
if ( atomic_read ( & bat_priv - > fragmentation ) & &
2013-05-08 12:31:59 +07:00
hard_iface - > net_dev - > mtu < ETH_DATA_LEN + max_header_len )
2012-05-17 01:23:22 +07:00
batadv_info ( hard_iface - > soft_iface ,
2013-05-08 12:31:59 +07: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 %i would solve the problem. \n " ,
2012-05-17 01:23:22 +07:00
hard_iface - > net_dev - > name , hard_iface - > net_dev - > mtu ,
2013-05-08 12:31:59 +07:00
ETH_DATA_LEN + max_header_len ) ;
2010-12-13 18:19:28 +07:00
2012-06-20 01:26:30 +07:00
if ( ! atomic_read ( & bat_priv - > fragmentation ) & &
2013-05-08 12:31:59 +07:00
hard_iface - > net_dev - > mtu < ETH_DATA_LEN + max_header_len )
2012-05-17 01:23:22 +07:00
batadv_info ( hard_iface - > soft_iface ,
2013-05-08 12:31:59 +07: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 %i. \n " ,
2012-05-17 01:23:22 +07:00
hard_iface - > net_dev - > name , hard_iface - > net_dev - > mtu ,
2013-05-08 12:31:59 +07:00
ETH_DATA_LEN + max_header_len ) ;
2010-12-13 18:19:28 +07:00
2012-05-12 23:33:57 +07:00
if ( batadv_hardif_is_iface_up ( hard_iface ) )
batadv_hardif_activate_interface ( hard_iface ) ;
2010-12-13 18:19:28 +07:00
else
2012-05-17 01:23:22 +07:00
batadv_err ( hard_iface - > soft_iface ,
" Not using interface %s (retrying later): interface not active \n " ,
hard_iface - > net_dev - > name ) ;
2010-12-13 18:19:28 +07:00
2015-08-08 00:28:42 +07:00
batadv_hardif_recalc_extra_skbroom ( soft_iface ) ;
2010-12-13 18:19:28 +07:00
out :
return 0 ;
2013-02-11 16:10:27 +07:00
err_upper :
netdev_upper_dev_unlink ( hard_iface - > net_dev , soft_iface ) ;
2012-02-07 16:20:48 +07:00
err_dev :
2013-02-11 16:10:27 +07:00
hard_iface - > soft_iface = NULL ;
2012-02-07 16:20:48 +07:00
dev_put ( soft_iface ) ;
2010-12-13 18:19:28 +07:00
err :
2016-01-17 17:01:10 +07:00
batadv_hardif_put ( hard_iface ) ;
2011-03-05 04:36:41 +07:00
return ret ;
2010-12-13 18:19:28 +07:00
}
2013-02-11 16:10:24 +07:00
void batadv_hardif_disable_interface ( struct batadv_hard_iface * hard_iface ,
enum batadv_hard_if_cleanup autodel )
2010-12-13 18:19:28 +07:00
{
2012-06-06 03:31:31 +07:00
struct batadv_priv * bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
struct batadv_hard_iface * primary_if = NULL ;
2010-12-13 18:19:28 +07:00
2016-03-19 19:55:21 +07:00
batadv_hardif_deactivate_interface ( hard_iface ) ;
2010-12-13 18:19:28 +07:00
2012-06-04 03:19:19 +07:00
if ( hard_iface - > if_status ! = BATADV_IF_INACTIVE )
2011-04-20 20:40:58 +07:00
goto out ;
2010-12-13 18:19:28 +07:00
2012-05-17 01:23:22 +07:00
batadv_info ( hard_iface - > soft_iface , " Removing interface: %s \n " ,
hard_iface - > net_dev - > name ) ;
2011-02-18 19:33:20 +07:00
dev_remove_pack ( & hard_iface - > batman_adv_ptype ) ;
2016-03-05 22:09:18 +07:00
batadv_hardif_put ( hard_iface ) ;
2010-12-13 18:19:28 +07:00
bat_priv - > num_ifaces - - ;
2012-05-12 07:09:34 +07:00
batadv_orig_hash_del_if ( hard_iface , bat_priv - > num_ifaces ) ;
2010-12-13 18:19:28 +07:00
2012-05-12 18:48:54 +07:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-04-20 20:40:58 +07:00
if ( hard_iface = = primary_if ) {
2012-06-06 03:31:31 +07:00
struct batadv_hard_iface * new_if ;
2010-12-13 18:19:28 +07:00
2012-05-12 23:33:57 +07:00
new_if = batadv_hardif_get_active ( hard_iface - > soft_iface ) ;
batadv_primary_if_select ( bat_priv , new_if ) ;
2010-12-13 18:19:28 +07:00
if ( new_if )
2016-01-17 17:01:10 +07:00
batadv_hardif_put ( new_if ) ;
2010-12-13 18:19:28 +07:00
}
2012-02-07 16:20:47 +07:00
bat_priv - > bat_algo_ops - > bat_iface_disable ( hard_iface ) ;
2012-06-04 03:19:19 +07:00
hard_iface - > if_status = BATADV_IF_NOT_IN_USE ;
2010-12-13 18:19:28 +07:00
2011-02-18 19:33:20 +07:00
/* delete all references to this hard_iface */
2012-05-12 07:09:34 +07:00
batadv_purge_orig_ref ( bat_priv ) ;
2012-05-12 07:09:37 +07:00
batadv_purge_outstanding_packets ( bat_priv , hard_iface ) ;
2011-02-18 19:33:20 +07:00
dev_put ( hard_iface - > soft_iface ) ;
2010-12-13 18:19:28 +07:00
2015-08-05 03:26:19 +07:00
netdev_upper_dev_unlink ( hard_iface - > net_dev , hard_iface - > soft_iface ) ;
2015-08-08 00:28:42 +07:00
batadv_hardif_recalc_extra_skbroom ( hard_iface - > soft_iface ) ;
2015-08-05 03:26:19 +07:00
2010-12-13 18:19:28 +07:00
/* nobody uses this interface anymore */
2013-08-19 23:39:59 +07:00
if ( ! bat_priv - > num_ifaces ) {
batadv_gw_check_client_stop ( bat_priv ) ;
if ( autodel = = BATADV_IF_CLEANUP_AUTO )
batadv_softif_destroy_sysfs ( hard_iface - > soft_iface ) ;
}
2010-12-13 18:19:28 +07:00
2011-02-18 19:33:20 +07:00
hard_iface - > soft_iface = NULL ;
2016-01-17 17:01:10 +07:00
batadv_hardif_put ( hard_iface ) ;
2011-04-20 20:40:58 +07:00
out :
if ( primary_if )
2016-01-17 17:01:10 +07:00
batadv_hardif_put ( primary_if ) ;
2010-12-13 18:19:28 +07:00
}
2013-01-11 16:19:51 +07:00
/**
* batadv_hardif_remove_interface_finish - cleans up the remains of a hardif
* @ work : work queue item
*
* Free the parts of the hard interface which can not be removed under
* rtnl lock ( to prevent deadlock situations ) .
*/
static void batadv_hardif_remove_interface_finish ( struct work_struct * work )
{
struct batadv_hard_iface * hard_iface ;
hard_iface = container_of ( work , struct batadv_hard_iface ,
cleanup_work ) ;
2013-11-21 20:16:12 +07:00
batadv_debugfs_del_hardif ( hard_iface ) ;
2013-01-11 16:19:51 +07:00
batadv_sysfs_del_hardif ( & hard_iface - > hardif_obj ) ;
2016-01-17 17:01:10 +07:00
batadv_hardif_put ( hard_iface ) ;
2013-01-11 16:19:51 +07:00
}
2012-06-06 03:31:31 +07:00
static struct batadv_hard_iface *
2012-05-12 23:33:57 +07:00
batadv_hardif_add_interface ( struct net_device * net_dev )
2010-12-13 18:19:28 +07:00
{
2012-06-06 03:31:31 +07:00
struct batadv_hard_iface * hard_iface ;
2010-12-13 18:19:28 +07:00
int ret ;
2011-05-03 16:51:38 +07:00
ASSERT_RTNL ( ) ;
2016-02-23 03:02:39 +07:00
if ( ! batadv_is_valid_iface ( net_dev ) )
2010-12-13 18:19:28 +07:00
goto out ;
dev_hold ( net_dev ) ;
2013-04-02 17:16:53 +07:00
hard_iface = kzalloc ( sizeof ( * hard_iface ) , GFP_ATOMIC ) ;
2011-08-30 04:17:24 +07:00
if ( ! hard_iface )
2010-12-13 18:19:28 +07:00
goto release_dev ;
2012-05-12 07:09:24 +07:00
ret = batadv_sysfs_add_hardif ( & hard_iface - > hardif_obj , net_dev ) ;
2010-12-13 18:19:28 +07:00
if ( ret )
goto free_if ;
2011-02-18 19:33:20 +07:00
hard_iface - > if_num = - 1 ;
hard_iface - > net_dev = net_dev ;
hard_iface - > soft_iface = NULL ;
2012-06-04 03:19:19 +07:00
hard_iface - > if_status = BATADV_IF_NOT_IN_USE ;
2013-11-21 20:16:12 +07:00
ret = batadv_debugfs_add_hardif ( hard_iface ) ;
if ( ret )
goto free_sysfs ;
2011-02-18 19:33:20 +07:00
INIT_LIST_HEAD ( & hard_iface - > list ) ;
2015-08-04 20:09:55 +07:00
INIT_HLIST_HEAD ( & hard_iface - > neigh_list ) ;
2013-01-11 16:19:51 +07:00
INIT_WORK ( & hard_iface - > cleanup_work ,
batadv_hardif_remove_interface_finish ) ;
2015-08-04 20:09:55 +07:00
spin_lock_init ( & hard_iface - > neigh_list_lock ) ;
2013-03-10 05:14:23 +07:00
hard_iface - > num_bcasts = BATADV_NUM_BCASTS_DEFAULT ;
if ( batadv_is_wifi_netdev ( net_dev ) )
hard_iface - > num_bcasts = BATADV_NUM_BCASTS_WIRELESS ;
2011-02-10 21:33:51 +07:00
/* extra reference for return */
2016-01-16 16:29:54 +07:00
kref_init ( & hard_iface - > refcount ) ;
kref_get ( & hard_iface - > refcount ) ;
2010-12-13 18:19:28 +07:00
2012-05-12 23:33:57 +07:00
batadv_check_known_mac_addr ( hard_iface - > net_dev ) ;
2012-05-12 07:09:42 +07:00
list_add_tail_rcu ( & hard_iface - > list , & batadv_hardif_list ) ;
2010-12-13 18:19:28 +07:00
2011-02-18 19:33:20 +07:00
return hard_iface ;
2010-12-13 18:19:28 +07:00
2013-11-21 20:16:12 +07:00
free_sysfs :
batadv_sysfs_del_hardif ( & hard_iface - > hardif_obj ) ;
2010-12-13 18:19:28 +07:00
free_if :
2011-02-18 19:33:20 +07:00
kfree ( hard_iface ) ;
2010-12-13 18:19:28 +07:00
release_dev :
dev_put ( net_dev ) ;
out :
return NULL ;
}
2012-06-06 03:31:31 +07:00
static void batadv_hardif_remove_interface ( struct batadv_hard_iface * hard_iface )
2010-12-13 18:19:28 +07:00
{
2011-05-03 16:51:38 +07:00
ASSERT_RTNL ( ) ;
2010-12-13 18:19:28 +07:00
/* first deactivate interface */
2012-06-04 03:19:19 +07:00
if ( hard_iface - > if_status ! = BATADV_IF_NOT_IN_USE )
2013-02-11 16:10:24 +07:00
batadv_hardif_disable_interface ( hard_iface ,
BATADV_IF_CLEANUP_AUTO ) ;
2010-12-13 18:19:28 +07:00
2012-06-04 03:19:19 +07:00
if ( hard_iface - > if_status ! = BATADV_IF_NOT_IN_USE )
2010-12-13 18:19:28 +07:00
return ;
2012-06-04 03:19:19 +07:00
hard_iface - > if_status = BATADV_IF_TO_BE_REMOVED ;
2013-01-11 16:19:51 +07:00
queue_work ( batadv_event_workqueue , & hard_iface - > cleanup_work ) ;
2010-12-13 18:19:28 +07:00
}
2012-05-12 07:09:31 +07:00
void batadv_hardif_remove_interfaces ( void )
2010-12-13 18:19:28 +07:00
{
2012-06-06 03:31:31 +07:00
struct batadv_hard_iface * hard_iface , * hard_iface_tmp ;
2010-12-13 18:19:28 +07:00
2011-05-03 16:51:38 +07:00
rtnl_lock ( ) ;
2011-02-18 19:33:20 +07:00
list_for_each_entry_safe ( hard_iface , hard_iface_tmp ,
2012-05-12 07:09:42 +07:00
& batadv_hardif_list , list ) {
2011-02-18 19:33:20 +07:00
list_del_rcu ( & hard_iface - > list ) ;
2012-05-12 23:33:57 +07:00
batadv_hardif_remove_interface ( hard_iface ) ;
2010-12-13 18:19:28 +07:00
}
rtnl_unlock ( ) ;
}
2012-05-12 23:33:57 +07:00
static int batadv_hard_if_event ( struct notifier_block * this ,
unsigned long event , void * ptr )
2010-12-13 18:19:28 +07:00
{
2013-05-28 08:30:21 +07:00
struct net_device * net_dev = netdev_notifier_info_to_dev ( ptr ) ;
2012-06-06 03:31:31 +07:00
struct batadv_hard_iface * hard_iface ;
struct batadv_hard_iface * primary_if = NULL ;
struct batadv_priv * bat_priv ;
2010-12-13 18:19:28 +07:00
2013-02-11 16:10:22 +07:00
if ( batadv_softif_is_valid ( net_dev ) & & event = = NETDEV_REGISTER ) {
batadv_sysfs_add_meshif ( net_dev ) ;
2013-07-02 16:04:34 +07:00
bat_priv = netdev_priv ( net_dev ) ;
batadv_softif_create_vlan ( bat_priv , BATADV_NO_FLAGS ) ;
2013-02-11 16:10:22 +07:00
return NOTIFY_DONE ;
}
2012-06-06 03:31:31 +07:00
hard_iface = batadv_hardif_get_by_netdev ( net_dev ) ;
2015-12-04 03:12:33 +07:00
if ( ! hard_iface & & ( event = = NETDEV_REGISTER | |
event = = NETDEV_POST_TYPE_CHANGE ) )
2012-05-12 23:33:57 +07:00
hard_iface = batadv_hardif_add_interface ( net_dev ) ;
2010-12-13 18:19:28 +07:00
2011-02-18 19:33:20 +07:00
if ( ! hard_iface )
2010-12-13 18:19:28 +07:00
goto out ;
switch ( event ) {
case NETDEV_UP :
2012-05-12 23:33:57 +07:00
batadv_hardif_activate_interface ( hard_iface ) ;
2010-12-13 18:19:28 +07:00
break ;
case NETDEV_GOING_DOWN :
case NETDEV_DOWN :
2012-05-12 23:33:57 +07:00
batadv_hardif_deactivate_interface ( hard_iface ) ;
2010-12-13 18:19:28 +07:00
break ;
case NETDEV_UNREGISTER :
2015-12-04 03:12:33 +07:00
case NETDEV_PRE_TYPE_CHANGE :
2011-02-18 19:33:20 +07:00
list_del_rcu ( & hard_iface - > list ) ;
2010-12-13 18:19:28 +07:00
2012-05-12 23:33:57 +07:00
batadv_hardif_remove_interface ( hard_iface ) ;
2010-12-13 18:19:28 +07:00
break ;
case NETDEV_CHANGEMTU :
2011-02-18 19:33:20 +07:00
if ( hard_iface - > soft_iface )
2012-05-12 07:09:31 +07:00
batadv_update_min_mtu ( hard_iface - > soft_iface ) ;
2010-12-13 18:19:28 +07:00
break ;
case NETDEV_CHANGEADDR :
2012-06-04 03:19:19 +07:00
if ( hard_iface - > if_status = = BATADV_IF_NOT_IN_USE )
2010-12-13 18:19:28 +07:00
goto hardif_put ;
2012-05-12 23:33:57 +07:00
batadv_check_known_mac_addr ( hard_iface - > net_dev ) ;
2010-12-13 18:19:28 +07:00
2011-02-18 19:33:20 +07:00
bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
2012-03-11 05:17:50 +07:00
bat_priv - > bat_algo_ops - > bat_iface_update_mac ( hard_iface ) ;
2011-11-28 20:31:55 +07:00
2012-05-12 18:48:54 +07:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-04-20 20:40:58 +07:00
if ( ! primary_if )
goto hardif_put ;
if ( hard_iface = = primary_if )
2012-05-12 23:33:57 +07:00
batadv_primary_if_update_addr ( bat_priv , NULL ) ;
2010-12-13 18:19:28 +07:00
break ;
default :
break ;
2011-06-03 18:51:19 +07:00
}
2010-12-13 18:19:28 +07:00
hardif_put :
2016-01-17 17:01:10 +07:00
batadv_hardif_put ( hard_iface ) ;
2010-12-13 18:19:28 +07:00
out :
2011-04-20 20:40:58 +07:00
if ( primary_if )
2016-01-17 17:01:10 +07:00
batadv_hardif_put ( primary_if ) ;
2010-12-13 18:19:28 +07:00
return NOTIFY_DONE ;
}
2012-05-12 07:09:31 +07:00
struct notifier_block batadv_hard_if_notifier = {
2012-05-12 23:33:57 +07:00
. notifier_call = batadv_hard_if_event ,
2010-12-13 18:19:28 +07:00
} ;