2017-11-19 17:05:11 +03:00
// SPDX-License-Identifier: GPL-2.0
2017-01-01 02:00:00 +03:00
/* Copyright (C) 2010-2017 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
2013-11-03 23:40:48 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2010-12-13 14:19:28 +03:00
*/
2012-06-11 01:58:51 +04:00
# include "sysfs.h"
2015-04-17 20:40:28 +03:00
# include "main.h"
# include <linux/atomic.h>
# include <linux/compiler.h>
# include <linux/device.h>
# include <linux/errno.h>
2017-11-19 19:12:02 +03:00
# include <linux/gfp.h>
2015-04-17 20:40:28 +03:00
# include <linux/if.h>
# include <linux/if_vlan.h>
# include <linux/kernel.h>
2017-11-19 19:12:05 +03:00
# include <linux/kobject.h>
2016-05-15 12:07:42 +03:00
# include <linux/kref.h>
2015-04-17 20:40:28 +03:00
# include <linux/netdevice.h>
# include <linux/printk.h>
# include <linux/rculist.h>
# include <linux/rcupdate.h>
# include <linux/rtnetlink.h>
# include <linux/slab.h>
# include <linux/stddef.h>
# include <linux/string.h>
# include <linux/stringify.h>
2016-06-13 08:41:30 +03:00
# include <linux/workqueue.h>
2017-12-21 12:17:41 +03:00
# include <uapi/linux/batadv_packet.h>
2015-04-17 20:40:28 +03:00
2016-05-15 12:07:42 +03:00
# include "bridge_loop_avoidance.h"
2012-08-08 20:50:57 +04:00
# include "distributed-arp-table.h"
2015-04-17 20:40:28 +03:00
# include "gateway_client.h"
# include "gateway_common.h"
2010-12-13 14:19:28 +03:00
# include "hard-interface.h"
2016-05-16 00:48:31 +03:00
# include "log.h"
2015-04-17 20:40:28 +03:00
# include "network-coding.h"
2013-07-02 13:04:35 +04:00
# include "soft-interface.h"
2010-12-13 14:19:28 +03:00
2012-05-12 20:33:52 +04:00
static struct net_device * batadv_kobj_to_netdev ( struct kobject * obj )
2011-06-05 12:20:19 +04:00
{
struct device * dev = container_of ( obj - > parent , struct device , kobj ) ;
2014-05-10 20:56:37 +04:00
2011-06-05 12:20:19 +04:00
return to_net_dev ( dev ) ;
}
2012-06-06 00:31:31 +04:00
static struct batadv_priv * batadv_kobj_to_batpriv ( struct kobject * obj )
2011-06-05 12:20:19 +04:00
{
2012-05-12 20:33:52 +04:00
struct net_device * net_dev = batadv_kobj_to_netdev ( obj ) ;
2014-05-10 20:56:37 +04:00
2011-06-05 12:20:19 +04:00
return netdev_priv ( net_dev ) ;
}
2010-12-13 14:19:28 +03:00
2013-07-02 13:04:35 +04:00
/**
2017-12-02 21:51:47 +03:00
* batadv_vlan_kobj_to_batpriv ( ) - convert a vlan kobj in the associated batpriv
2013-07-02 13:04:35 +04:00
* @ obj : kobject to covert
*
2015-09-15 20:00:48 +03:00
* Return : the associated batadv_priv struct .
2013-07-02 13:04:35 +04:00
*/
static struct batadv_priv * batadv_vlan_kobj_to_batpriv ( struct kobject * obj )
{
/* VLAN specific attributes are located in the root sysfs folder if they
* refer to the untagged VLAN . .
*/
if ( ! strcmp ( BATADV_SYSFS_IF_MESH_SUBDIR , obj - > name ) )
return batadv_kobj_to_batpriv ( obj ) ;
/* ..while the attributes for the tagged vlans are located in
* the in the corresponding " vlan%VID " subfolder
*/
return batadv_kobj_to_batpriv ( obj - > parent ) ;
}
/**
2017-12-02 21:51:47 +03:00
* batadv_kobj_to_vlan ( ) - convert a kobj in the associated softif_vlan struct
2015-10-31 14:29:29 +03:00
* @ bat_priv : the bat priv with all the soft interface information
2013-07-02 13:04:35 +04:00
* @ obj : kobject to covert
*
2015-09-15 20:00:48 +03:00
* Return : the associated softif_vlan struct if found , NULL otherwise .
2013-07-02 13:04:35 +04:00
*/
static struct batadv_softif_vlan *
batadv_kobj_to_vlan ( struct batadv_priv * bat_priv , struct kobject * obj )
{
struct batadv_softif_vlan * vlan_tmp , * vlan = NULL ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( vlan_tmp , & bat_priv - > softif_vlan_list , list ) {
if ( vlan_tmp - > kobj ! = obj )
continue ;
2016-01-16 12:29:42 +03:00
if ( ! kref_get_unless_zero ( & vlan_tmp - > refcount ) )
2013-07-02 13:04:35 +04:00
continue ;
vlan = vlan_tmp ;
break ;
}
rcu_read_unlock ( ) ;
return vlan ;
}
2012-06-04 00:19:07 +04:00
# define BATADV_UEV_TYPE_VAR "BATTYPE="
# define BATADV_UEV_ACTION_VAR "BATACTION="
# define BATADV_UEV_DATA_VAR "BATDATA="
2011-04-26 20:26:01 +04:00
2012-05-12 20:33:52 +04:00
static char * batadv_uev_action_str [ ] = {
2011-04-26 20:26:01 +04:00
" add " ,
" del " ,
2016-03-12 12:49:33 +03:00
" change " ,
" loopdetect " ,
2011-04-26 20:26:01 +04:00
} ;
2012-05-12 20:33:52 +04:00
static char * batadv_uev_type_str [ ] = {
2016-03-12 12:49:33 +03:00
" gw " ,
" bla " ,
2011-04-26 20:26:01 +04:00
} ;
2013-07-02 13:04:35 +04:00
/* Use this, if you have customized show and store functions for vlan attrs */
# define BATADV_ATTR_VLAN(_name, _mode, _show, _store) \
struct batadv_attribute batadv_attr_vlan_ # # _name = { \
. attr = { . name = __stringify ( _name ) , \
. mode = _mode } , \
. show = _show , \
. store = _store , \
2014-05-15 13:24:26 +04:00
}
2013-07-02 13:04:35 +04:00
2010-12-13 14:19:28 +03:00
/* Use this, if you have customized show and store functions */
2012-06-04 00:19:07 +04:00
# define BATADV_ATTR(_name, _mode, _show, _store) \
2012-06-06 00:31:29 +04:00
struct batadv_attribute batadv_attr_ # # _name = { \
2012-06-04 00:19:07 +04:00
. attr = { . name = __stringify ( _name ) , \
. mode = _mode } , \
. show = _show , \
. store = _store , \
2014-05-15 13:24:26 +04:00
}
2010-12-13 14:19:28 +03:00
2012-06-04 00:19:07 +04:00
# define BATADV_ATTR_SIF_STORE_BOOL(_name, _post_func) \
2012-05-12 20:33:52 +04:00
ssize_t batadv_store_ # # _name ( struct kobject * kobj , \
struct attribute * attr , char * buff , \
size_t count ) \
2010-12-13 14:19:28 +03:00
{ \
2012-05-12 20:33:52 +04:00
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ; \
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( net_dev ) ; \
2014-05-10 20:56:37 +04:00
\
2012-05-12 20:33:52 +04:00
return __batadv_store_bool_attr ( buff , count , _post_func , attr , \
& bat_priv - > _name , net_dev ) ; \
2010-12-13 14:19:28 +03:00
}
2012-06-04 00:19:07 +04:00
# define BATADV_ATTR_SIF_SHOW_BOOL(_name) \
2012-05-12 20:33:52 +04:00
ssize_t batadv_show_ # # _name ( struct kobject * kobj , \
struct attribute * attr , char * buff ) \
2010-12-13 14:19:28 +03:00
{ \
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = batadv_kobj_to_batpriv ( kobj ) ; \
2014-05-10 20:56:37 +04:00
\
2010-12-13 14:19:28 +03:00
return sprintf ( buff , " %s \n " , \
atomic_read ( & bat_priv - > _name ) = = 0 ? \
" disabled " : " enabled " ) ; \
} \
2012-03-11 02:17:51 +04:00
/* Use this, if you are going to turn a [name] in the soft-interface
2012-05-12 04:09:43 +04:00
* ( bat_priv ) on or off
*/
2012-06-04 00:19:07 +04:00
# define BATADV_ATTR_SIF_BOOL(_name, _mode, _post_func) \
static BATADV_ATTR_SIF_STORE_BOOL ( _name , _post_func ) \
static BATADV_ATTR_SIF_SHOW_BOOL ( _name ) \
static BATADV_ATTR ( _name , _mode , batadv_show_ # # _name , \
batadv_store_ # # _name )
2010-12-13 14:19:28 +03:00
2015-02-28 19:50:16 +03:00
# define BATADV_ATTR_SIF_STORE_UINT(_name, _var, _min, _max, _post_func) \
2012-05-12 20:33:52 +04:00
ssize_t batadv_store_ # # _name ( struct kobject * kobj , \
struct attribute * attr , char * buff , \
size_t count ) \
2010-12-13 14:19:28 +03:00
{ \
2012-05-12 20:33:52 +04:00
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ; \
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( net_dev ) ; \
2014-05-10 20:56:37 +04:00
\
2012-05-12 20:33:52 +04:00
return __batadv_store_uint_attr ( buff , count , _min , _max , \
_post_func , attr , \
2015-02-28 19:50:16 +03:00
& bat_priv - > _var , net_dev ) ; \
2010-12-13 14:19:28 +03:00
}
2015-02-28 19:50:16 +03:00
# define BATADV_ATTR_SIF_SHOW_UINT(_name, _var) \
2012-05-12 20:33:52 +04:00
ssize_t batadv_show_ # # _name ( struct kobject * kobj , \
struct attribute * attr , char * buff ) \
2010-12-13 14:19:28 +03:00
{ \
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = batadv_kobj_to_batpriv ( kobj ) ; \
2014-05-10 20:56:37 +04:00
\
2015-02-28 19:50:16 +03:00
return sprintf ( buff , " %i \n " , atomic_read ( & bat_priv - > _var ) ) ; \
2010-12-13 14:19:28 +03:00
} \
2012-03-11 02:17:51 +04:00
/* Use this, if you are going to set [name] in the soft-interface
2012-05-12 04:09:43 +04:00
* ( bat_priv ) to an unsigned integer value
*/
2015-02-28 19:50:16 +03:00
# define BATADV_ATTR_SIF_UINT(_name, _var, _mode, _min, _max, _post_func)\
static BATADV_ATTR_SIF_STORE_UINT ( _name , _var , _min , _max , _post_func ) \
static BATADV_ATTR_SIF_SHOW_UINT ( _name , _var ) \
2012-06-04 00:19:07 +04:00
static BATADV_ATTR ( _name , _mode , batadv_show_ # # _name , \
batadv_store_ # # _name )
2010-12-13 14:19:28 +03:00
2013-07-02 13:04:35 +04:00
# define BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \
ssize_t batadv_store_vlan_ # # _name ( struct kobject * kobj , \
struct attribute * attr , char * buff , \
size_t count ) \
{ \
struct batadv_priv * bat_priv = batadv_vlan_kobj_to_batpriv ( kobj ) ; \
struct batadv_softif_vlan * vlan = batadv_kobj_to_vlan ( bat_priv , \
kobj ) ; \
size_t res = __batadv_store_bool_attr ( buff , count , _post_func , \
attr , & vlan - > _name , \
bat_priv - > soft_iface ) ; \
2014-05-10 20:56:37 +04:00
\
2016-01-17 13:01:21 +03:00
batadv_softif_vlan_put ( vlan ) ; \
2013-07-02 13:04:35 +04:00
return res ; \
}
# define BATADV_ATTR_VLAN_SHOW_BOOL(_name) \
ssize_t batadv_show_vlan_ # # _name ( struct kobject * kobj , \
struct attribute * attr , char * buff ) \
{ \
struct batadv_priv * bat_priv = batadv_vlan_kobj_to_batpriv ( kobj ) ; \
struct batadv_softif_vlan * vlan = batadv_kobj_to_vlan ( bat_priv , \
kobj ) ; \
size_t res = sprintf ( buff , " %s \n " , \
atomic_read ( & vlan - > _name ) = = 0 ? \
" disabled " : " enabled " ) ; \
2014-05-10 20:56:37 +04:00
\
2016-01-17 13:01:21 +03:00
batadv_softif_vlan_put ( vlan ) ; \
2013-07-02 13:04:35 +04:00
return res ; \
}
/* Use this, if you are going to turn a [name] in the vlan struct on or off */
# define BATADV_ATTR_VLAN_BOOL(_name, _mode, _post_func) \
static BATADV_ATTR_VLAN_STORE_BOOL ( _name , _post_func ) \
static BATADV_ATTR_VLAN_SHOW_BOOL ( _name ) \
static BATADV_ATTR_VLAN ( _name , _mode , batadv_show_vlan_ # # _name , \
batadv_store_vlan_ # # _name )
2016-01-16 11:40:08 +03:00
# define BATADV_ATTR_HIF_STORE_UINT(_name, _var, _min, _max, _post_func) \
ssize_t batadv_store_ # # _name ( struct kobject * kobj , \
struct attribute * attr , char * buff , \
size_t count ) \
{ \
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ; \
struct batadv_hard_iface * hard_iface ; \
ssize_t length ; \
\
hard_iface = batadv_hardif_get_by_netdev ( net_dev ) ; \
if ( ! hard_iface ) \
return 0 ; \
\
length = __batadv_store_uint_attr ( buff , count , _min , _max , \
_post_func , attr , \
& hard_iface - > _var , net_dev ) ; \
\
batadv_hardif_put ( hard_iface ) ; \
return length ; \
}
# define BATADV_ATTR_HIF_SHOW_UINT(_name, _var) \
ssize_t batadv_show_ # # _name ( struct kobject * kobj , \
struct attribute * attr , char * buff ) \
{ \
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ; \
struct batadv_hard_iface * hard_iface ; \
ssize_t length ; \
\
hard_iface = batadv_hardif_get_by_netdev ( net_dev ) ; \
if ( ! hard_iface ) \
return 0 ; \
\
length = sprintf ( buff , " %i \n " , atomic_read ( & hard_iface - > _var ) ) ; \
\
batadv_hardif_put ( hard_iface ) ; \
return length ; \
}
/* Use this, if you are going to set [name] in hard_iface to an
* unsigned integer value
*/
# define BATADV_ATTR_HIF_UINT(_name, _var, _mode, _min, _max, _post_func)\
static BATADV_ATTR_HIF_STORE_UINT ( _name , _var , _min , \
_max , _post_func ) \
static BATADV_ATTR_HIF_SHOW_UINT ( _name , _var ) \
static BATADV_ATTR ( _name , _mode , batadv_show_ # # _name , \
batadv_store_ # # _name )
2010-12-13 14:19:28 +03:00
2012-05-12 20:33:52 +04:00
static int batadv_store_bool_attr ( char * buff , size_t count ,
struct net_device * net_dev ,
2015-11-17 16:11:26 +03:00
const char * attr_name , atomic_t * attr ,
bool * changed )
2010-12-13 14:19:28 +03:00
{
int enabled = - 1 ;
2015-11-17 16:11:26 +03:00
* changed = false ;
2010-12-13 14:19:28 +03:00
if ( buff [ count - 1 ] = = ' \n ' )
buff [ count - 1 ] = ' \0 ' ;
if ( ( strncmp ( buff , " 1 " , 2 ) = = 0 ) | |
( strncmp ( buff , " enable " , 7 ) = = 0 ) | |
( strncmp ( buff , " enabled " , 8 ) = = 0 ) )
enabled = 1 ;
if ( ( strncmp ( buff , " 0 " , 2 ) = = 0 ) | |
( strncmp ( buff , " disable " , 8 ) = = 0 ) | |
( strncmp ( buff , " disabled " , 9 ) = = 0 ) )
enabled = 0 ;
if ( enabled < 0 ) {
2012-05-16 22:23:22 +04:00
batadv_info ( net_dev , " %s: Invalid parameter received: %s \n " ,
attr_name , buff ) ;
2010-12-13 14:19:28 +03:00
return - EINVAL ;
}
if ( atomic_read ( attr ) = = enabled )
return count ;
2012-05-16 22:23:22 +04:00
batadv_info ( net_dev , " %s: Changing from: %s to: %s \n " , attr_name ,
atomic_read ( attr ) = = 1 ? " enabled " : " disabled " ,
enabled = = 1 ? " enabled " : " disabled " ) ;
2010-12-13 14:19:28 +03:00
2015-11-17 16:11:26 +03:00
* changed = true ;
2012-04-15 09:58:06 +04:00
atomic_set ( attr , ( unsigned int ) enabled ) ;
2010-12-13 14:19:28 +03:00
return count ;
}
2012-05-12 20:33:52 +04:00
static inline ssize_t
__batadv_store_bool_attr ( char * buff , size_t count ,
void ( * post_func ) ( struct net_device * ) ,
struct attribute * attr ,
atomic_t * attr_store , struct net_device * net_dev )
2010-12-13 14:19:28 +03:00
{
2015-11-17 16:11:26 +03:00
bool changed ;
2010-12-13 14:19:28 +03:00
int ret ;
2012-05-12 20:33:52 +04:00
ret = batadv_store_bool_attr ( buff , count , net_dev , attr - > name ,
2015-11-17 16:11:26 +03:00
attr_store , & changed ) ;
if ( post_func & & changed )
2010-12-13 14:19:28 +03:00
post_func ( net_dev ) ;
return ret ;
}
2012-05-12 20:33:52 +04:00
static int batadv_store_uint_attr ( const char * buff , size_t count ,
struct net_device * net_dev ,
const char * attr_name ,
unsigned int min , unsigned int max ,
atomic_t * attr )
2010-12-13 14:19:28 +03:00
{
unsigned long uint_val ;
int ret ;
2011-09-30 15:32:01 +04:00
ret = kstrtoul ( buff , 10 , & uint_val ) ;
2010-12-13 14:19:28 +03:00
if ( ret ) {
2012-05-16 22:23:22 +04:00
batadv_info ( net_dev , " %s: Invalid parameter received: %s \n " ,
attr_name , buff ) ;
2010-12-13 14:19:28 +03:00
return - EINVAL ;
}
if ( uint_val < min ) {
2012-05-16 22:23:22 +04:00
batadv_info ( net_dev , " %s: Value is too small: %lu min: %u \n " ,
attr_name , uint_val , min ) ;
2010-12-13 14:19:28 +03:00
return - EINVAL ;
}
if ( uint_val > max ) {
2012-05-16 22:23:22 +04:00
batadv_info ( net_dev , " %s: Value is too big: %lu max: %u \n " ,
attr_name , uint_val , max ) ;
2010-12-13 14:19:28 +03:00
return - EINVAL ;
}
if ( atomic_read ( attr ) = = uint_val )
return count ;
2012-05-16 22:23:22 +04:00
batadv_info ( net_dev , " %s: Changing from: %i to: %lu \n " ,
attr_name , atomic_read ( attr ) , uint_val ) ;
2010-12-13 14:19:28 +03:00
atomic_set ( attr , uint_val ) ;
return count ;
}
2016-05-05 21:46:37 +03:00
static ssize_t __batadv_store_uint_attr ( const char * buff , size_t count ,
int min , int max ,
void ( * post_func ) ( struct net_device * ) ,
const struct attribute * attr ,
atomic_t * attr_store ,
struct net_device * net_dev )
2010-12-13 14:19:28 +03:00
{
int ret ;
2012-05-12 20:33:52 +04:00
ret = batadv_store_uint_attr ( buff , count , net_dev , attr - > name , min , max ,
attr_store ) ;
2010-12-13 14:19:28 +03:00
if ( post_func & & ret )
post_func ( net_dev ) ;
return ret ;
}
2012-05-12 20:33:52 +04:00
static ssize_t batadv_show_bat_algo ( struct kobject * kobj ,
struct attribute * attr , char * buff )
2011-11-28 20:15:37 +04:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = batadv_kobj_to_batpriv ( kobj ) ;
2014-05-10 20:56:37 +04:00
2016-05-25 18:27:31 +03:00
return sprintf ( buff , " %s \n " , bat_priv - > algo_ops - > name ) ;
2011-11-28 20:15:37 +04:00
}
2013-11-04 23:59:41 +04:00
static void batadv_post_gw_reselect ( struct net_device * net_dev )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( net_dev ) ;
2014-05-10 20:56:37 +04:00
2013-11-04 23:59:41 +04:00
batadv_gw_reselect ( bat_priv ) ;
2010-12-13 14:19:28 +03:00
}
2012-05-12 20:33:52 +04:00
static ssize_t batadv_show_gw_mode ( struct kobject * kobj , struct attribute * attr ,
char * buff )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = batadv_kobj_to_batpriv ( kobj ) ;
2010-12-13 14:19:28 +03:00
int bytes_written ;
2016-07-03 13:46:35 +03:00
/* GW mode is not available if the routing algorithm in use does not
* implement the GW API
*/
if ( ! bat_priv - > algo_ops - > gw . get_best_gw_node | |
! bat_priv - > algo_ops - > gw . is_eligible )
return - ENOENT ;
2016-05-05 21:46:38 +03:00
switch ( atomic_read ( & bat_priv - > gw . mode ) ) {
2012-06-04 00:19:18 +04:00
case BATADV_GW_MODE_CLIENT :
2012-06-04 00:19:11 +04:00
bytes_written = sprintf ( buff , " %s \n " ,
BATADV_GW_MODE_CLIENT_NAME ) ;
2010-12-13 14:19:28 +03:00
break ;
2012-06-04 00:19:18 +04:00
case BATADV_GW_MODE_SERVER :
2012-06-04 00:19:11 +04:00
bytes_written = sprintf ( buff , " %s \n " ,
BATADV_GW_MODE_SERVER_NAME ) ;
2010-12-13 14:19:28 +03:00
break ;
default :
2012-06-04 00:19:11 +04:00
bytes_written = sprintf ( buff , " %s \n " ,
BATADV_GW_MODE_OFF_NAME ) ;
2010-12-13 14:19:28 +03:00
break ;
}
return bytes_written ;
}
2012-05-12 20:33:52 +04:00
static ssize_t batadv_store_gw_mode ( struct kobject * kobj ,
struct attribute * attr , char * buff ,
size_t count )
2010-12-13 14:19:28 +03:00
{
2012-05-12 20:33:52 +04:00
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ;
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( net_dev ) ;
2010-12-13 14:19:28 +03:00
char * curr_gw_mode_str ;
int gw_mode_tmp = - 1 ;
2016-07-03 13:46:35 +03:00
/* toggling GW mode is allowed only if the routing algorithm in use
* provides the GW API
*/
if ( ! bat_priv - > algo_ops - > gw . get_best_gw_node | |
! bat_priv - > algo_ops - > gw . is_eligible )
return - EINVAL ;
2010-12-13 14:19:28 +03:00
if ( buff [ count - 1 ] = = ' \n ' )
buff [ count - 1 ] = ' \0 ' ;
2012-06-04 00:19:11 +04:00
if ( strncmp ( buff , BATADV_GW_MODE_OFF_NAME ,
strlen ( BATADV_GW_MODE_OFF_NAME ) ) = = 0 )
2012-06-04 00:19:18 +04:00
gw_mode_tmp = BATADV_GW_MODE_OFF ;
2010-12-13 14:19:28 +03:00
2012-06-04 00:19:11 +04:00
if ( strncmp ( buff , BATADV_GW_MODE_CLIENT_NAME ,
strlen ( BATADV_GW_MODE_CLIENT_NAME ) ) = = 0 )
2012-06-04 00:19:18 +04:00
gw_mode_tmp = BATADV_GW_MODE_CLIENT ;
2010-12-13 14:19:28 +03:00
2012-06-04 00:19:11 +04:00
if ( strncmp ( buff , BATADV_GW_MODE_SERVER_NAME ,
strlen ( BATADV_GW_MODE_SERVER_NAME ) ) = = 0 )
2012-06-04 00:19:18 +04:00
gw_mode_tmp = BATADV_GW_MODE_SERVER ;
2010-12-13 14:19:28 +03:00
if ( gw_mode_tmp < 0 ) {
2012-05-16 22:23:22 +04:00
batadv_info ( net_dev ,
" Invalid parameter for 'gw mode' setting received: %s \n " ,
buff ) ;
2010-12-13 14:19:28 +03:00
return - EINVAL ;
}
2016-05-05 21:46:38 +03:00
if ( atomic_read ( & bat_priv - > gw . mode ) = = gw_mode_tmp )
2010-12-13 14:19:28 +03:00
return count ;
2016-05-05 21:46:38 +03:00
switch ( atomic_read ( & bat_priv - > gw . mode ) ) {
2012-06-04 00:19:18 +04:00
case BATADV_GW_MODE_CLIENT :
2012-06-04 00:19:11 +04:00
curr_gw_mode_str = BATADV_GW_MODE_CLIENT_NAME ;
2010-12-13 14:19:28 +03:00
break ;
2012-06-04 00:19:18 +04:00
case BATADV_GW_MODE_SERVER :
2012-06-04 00:19:11 +04:00
curr_gw_mode_str = BATADV_GW_MODE_SERVER_NAME ;
2010-12-13 14:19:28 +03:00
break ;
default :
2012-06-04 00:19:11 +04:00
curr_gw_mode_str = BATADV_GW_MODE_OFF_NAME ;
2010-12-13 14:19:28 +03:00
break ;
}
2012-05-16 22:23:22 +04:00
batadv_info ( net_dev , " Changing gw mode from: %s to: %s \n " ,
curr_gw_mode_str , buff ) ;
2010-12-13 14:19:28 +03:00
2013-11-04 23:59:40 +04:00
/* Invoking batadv_gw_reselect() is not enough to really de-select the
* current GW . It will only instruct the gateway client code to perform
* a re - election the next time that this is needed .
*
* When gw client mode is being switched off the current GW must be
* de - selected explicitly otherwise no GW_ADD uevent is thrown on
* client mode re - activation . This is operation is performed in
* batadv_gw_check_client_stop ( ) .
*/
2013-11-04 23:59:41 +04:00
batadv_gw_reselect ( bat_priv ) ;
2013-07-13 02:06:00 +04:00
/* always call batadv_gw_check_client_stop() before changing the gateway
* state
*/
batadv_gw_check_client_stop ( bat_priv ) ;
2016-05-05 21:46:38 +03:00
atomic_set ( & bat_priv - > gw . mode , ( unsigned int ) gw_mode_tmp ) ;
2013-04-23 17:39:58 +04:00
batadv_gw_tvlv_container_update ( bat_priv ) ;
2010-12-13 14:19:28 +03:00
return count ;
}
2016-07-03 13:46:32 +03:00
static ssize_t batadv_show_gw_sel_class ( struct kobject * kobj ,
struct attribute * attr , char * buff )
{
struct batadv_priv * bat_priv = batadv_kobj_to_batpriv ( kobj ) ;
2016-07-03 13:46:35 +03:00
/* GW selection class is not available if the routing algorithm in use
* does not implement the GW API
*/
if ( ! bat_priv - > algo_ops - > gw . get_best_gw_node | |
! bat_priv - > algo_ops - > gw . is_eligible )
return - ENOENT ;
2016-07-03 13:46:32 +03:00
if ( bat_priv - > algo_ops - > gw . show_sel_class )
return bat_priv - > algo_ops - > gw . show_sel_class ( bat_priv , buff ) ;
return sprintf ( buff , " %i \n " , atomic_read ( & bat_priv - > gw . sel_class ) ) ;
}
static ssize_t batadv_store_gw_sel_class ( struct kobject * kobj ,
struct attribute * attr , char * buff ,
size_t count )
{
struct batadv_priv * bat_priv = batadv_kobj_to_batpriv ( kobj ) ;
2016-07-03 13:46:35 +03:00
/* setting the GW selection class is allowed only if the routing
* algorithm in use implements the GW API
*/
if ( ! bat_priv - > algo_ops - > gw . get_best_gw_node | |
! bat_priv - > algo_ops - > gw . is_eligible )
return - EINVAL ;
2016-07-03 13:46:32 +03:00
if ( buff [ count - 1 ] = = ' \n ' )
buff [ count - 1 ] = ' \0 ' ;
if ( bat_priv - > algo_ops - > gw . store_sel_class )
return bat_priv - > algo_ops - > gw . store_sel_class ( bat_priv , buff ,
count ) ;
return __batadv_store_uint_attr ( buff , count , 1 , BATADV_TQ_MAX_VALUE ,
batadv_post_gw_reselect , attr ,
& bat_priv - > gw . sel_class ,
bat_priv - > soft_iface ) ;
}
2012-05-12 20:33:52 +04:00
static ssize_t batadv_show_gw_bwidth ( struct kobject * kobj ,
struct attribute * attr , char * buff )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = batadv_kobj_to_batpriv ( kobj ) ;
2015-05-26 19:34:26 +03:00
u32 down , up ;
2013-04-23 17:39:58 +04:00
down = atomic_read ( & bat_priv - > gw . bandwidth_down ) ;
up = atomic_read ( & bat_priv - > gw . bandwidth_up ) ;
return sprintf ( buff , " %u.%u/%u.%u MBit \n " , down / 10 ,
down % 10 , up / 10 , up % 10 ) ;
2010-12-13 14:19:28 +03:00
}
2012-05-12 20:33:52 +04:00
static ssize_t batadv_store_gw_bwidth ( struct kobject * kobj ,
struct attribute * attr , char * buff ,
size_t count )
2010-12-13 14:19:28 +03:00
{
2012-05-12 20:33:52 +04:00
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ;
2010-12-13 14:19:28 +03:00
if ( buff [ count - 1 ] = = ' \n ' )
buff [ count - 1 ] = ' \0 ' ;
2012-05-12 04:09:30 +04:00
return batadv_gw_bandwidth_set ( net_dev , buff , count ) ;
2010-12-13 14:19:28 +03:00
}
2013-11-16 15:03:47 +04:00
/**
2017-12-02 21:51:47 +03:00
* batadv_show_isolation_mark ( ) - print the current isolation mark / mask
2013-11-16 15:03:47 +04:00
* @ kobj : kobject representing the private mesh sysfs directory
* @ attr : the batman - adv attribute the user is interacting with
* @ buff : the buffer that will contain the data to send back to the user
*
2015-09-15 20:00:48 +03:00
* Return : the number of bytes written into ' buff ' on success or a negative
2013-11-16 15:03:47 +04:00
* error code in case of failure
*/
static ssize_t batadv_show_isolation_mark ( struct kobject * kobj ,
struct attribute * attr , char * buff )
{
struct batadv_priv * bat_priv = batadv_kobj_to_batpriv ( kobj ) ;
return sprintf ( buff , " %#.8x/%#.8x \n " , bat_priv - > isolation_mark ,
bat_priv - > isolation_mark_mask ) ;
}
/**
2017-12-02 21:51:47 +03:00
* batadv_store_isolation_mark ( ) - parse and store the isolation mark / mask
* entered by the user
2013-11-16 15:03:47 +04:00
* @ kobj : kobject representing the private mesh sysfs directory
* @ attr : the batman - adv attribute the user is interacting with
* @ buff : the buffer containing the user data
* @ count : number of bytes in the buffer
*
2015-09-15 20:00:48 +03:00
* Return : ' count ' on success or a negative error code in case of failure
2013-11-16 15:03:47 +04:00
*/
static ssize_t batadv_store_isolation_mark ( struct kobject * kobj ,
struct attribute * attr , char * buff ,
size_t count )
{
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ;
struct batadv_priv * bat_priv = netdev_priv ( net_dev ) ;
2015-05-26 19:34:26 +03:00
u32 mark , mask ;
2013-11-16 15:03:47 +04:00
char * mask_ptr ;
/* parse the mask if it has been specified, otherwise assume the mask is
* the biggest possible
*/
mask = 0xFFFFFFFF ;
mask_ptr = strchr ( buff , ' / ' ) ;
if ( mask_ptr ) {
* mask_ptr = ' \0 ' ;
mask_ptr + + ;
/* the mask must be entered in hex base as it is going to be a
* bitmask and not a prefix length
*/
if ( kstrtou32 ( mask_ptr , 16 , & mask ) < 0 )
return - EINVAL ;
}
/* the mark can be entered in any base */
if ( kstrtou32 ( buff , 0 , & mark ) < 0 )
return - EINVAL ;
bat_priv - > isolation_mark_mask = mask ;
/* erase bits not covered by the mask */
bat_priv - > isolation_mark = mark & bat_priv - > isolation_mark_mask ;
batadv_info ( net_dev ,
" New skb mark for extended isolation: %#.8x/%#.8x \n " ,
bat_priv - > isolation_mark , bat_priv - > isolation_mark_mask ) ;
return count ;
}
2016-09-01 11:25:12 +03:00
BATADV_ATTR_SIF_BOOL ( aggregated_ogms , 0644 , NULL ) ;
BATADV_ATTR_SIF_BOOL ( bonding , 0644 , NULL ) ;
2012-01-22 23:00:27 +04:00
# ifdef CONFIG_BATMAN_ADV_BLA
2016-09-01 11:25:12 +03:00
BATADV_ATTR_SIF_BOOL ( bridge_loop_avoidance , 0644 , batadv_bla_status_update ) ;
2012-01-22 23:00:27 +04:00
# endif
2012-08-08 20:50:57 +04:00
# ifdef CONFIG_BATMAN_ADV_DAT
2016-09-01 11:25:12 +03:00
BATADV_ATTR_SIF_BOOL ( distributed_arp_table , 0644 , batadv_dat_status_update ) ;
2012-08-08 20:50:57 +04:00
# endif
2016-09-01 11:25:12 +03:00
BATADV_ATTR_SIF_BOOL ( fragmentation , 0644 , batadv_update_min_mtu ) ;
static BATADV_ATTR ( routing_algo , 0444 , batadv_show_bat_algo , NULL ) ;
static BATADV_ATTR ( gw_mode , 0644 , batadv_show_gw_mode , batadv_store_gw_mode ) ;
BATADV_ATTR_SIF_UINT ( orig_interval , orig_interval , 0644 , 2 * BATADV_JITTER ,
INT_MAX , NULL ) ;
BATADV_ATTR_SIF_UINT ( hop_penalty , hop_penalty , 0644 , 0 , BATADV_TQ_MAX_VALUE ,
NULL ) ;
static BATADV_ATTR ( gw_sel_class , 0644 , batadv_show_gw_sel_class ,
2016-07-03 13:46:32 +03:00
batadv_store_gw_sel_class ) ;
2016-09-01 11:25:12 +03:00
static BATADV_ATTR ( gw_bandwidth , 0644 , batadv_show_gw_bwidth ,
2012-06-04 00:19:07 +04:00
batadv_store_gw_bwidth ) ;
2014-02-15 20:47:52 +04:00
# ifdef CONFIG_BATMAN_ADV_MCAST
2016-09-01 11:25:12 +03:00
BATADV_ATTR_SIF_BOOL ( multicast_mode , 0644 , NULL ) ;
2014-02-15 20:47:52 +04:00
# endif
2010-12-13 14:19:28 +03:00
# ifdef CONFIG_BATMAN_ADV_DEBUG
2016-09-01 11:25:12 +03:00
BATADV_ATTR_SIF_UINT ( log_level , log_level , 0644 , 0 , BATADV_DBG_ALL , NULL ) ;
2010-12-13 14:19:28 +03:00
# endif
2013-01-25 14:12:38 +04:00
# ifdef CONFIG_BATMAN_ADV_NC
2016-09-01 11:25:12 +03:00
BATADV_ATTR_SIF_BOOL ( network_coding , 0644 , batadv_nc_status_update ) ;
2013-01-25 14:12:38 +04:00
# endif
2016-09-01 11:25:12 +03:00
static BATADV_ATTR ( isolation_mark , 0644 , batadv_show_isolation_mark ,
batadv_store_isolation_mark ) ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:29 +04:00
static struct batadv_attribute * batadv_mesh_attrs [ ] = {
2012-05-12 20:33:52 +04:00
& batadv_attr_aggregated_ogms ,
& batadv_attr_bonding ,
2012-01-22 23:00:27 +04:00
# ifdef CONFIG_BATMAN_ADV_BLA
2012-05-12 20:33:52 +04:00
& batadv_attr_bridge_loop_avoidance ,
2012-08-08 20:50:57 +04:00
# endif
# ifdef CONFIG_BATMAN_ADV_DAT
& batadv_attr_distributed_arp_table ,
2014-02-15 20:47:52 +04:00
# endif
# ifdef CONFIG_BATMAN_ADV_MCAST
& batadv_attr_multicast_mode ,
2012-01-22 23:00:27 +04:00
# endif
2012-05-12 20:33:52 +04:00
& batadv_attr_fragmentation ,
& batadv_attr_routing_algo ,
& batadv_attr_gw_mode ,
& batadv_attr_orig_interval ,
& batadv_attr_hop_penalty ,
& batadv_attr_gw_sel_class ,
& batadv_attr_gw_bandwidth ,
2010-12-13 14:19:28 +03:00
# ifdef CONFIG_BATMAN_ADV_DEBUG
2012-05-12 20:33:52 +04:00
& batadv_attr_log_level ,
2013-01-25 14:12:38 +04:00
# endif
# ifdef CONFIG_BATMAN_ADV_NC
& batadv_attr_network_coding ,
2010-12-13 14:19:28 +03:00
# endif
2013-11-16 15:03:47 +04:00
& batadv_attr_isolation_mark ,
2010-12-13 14:19:28 +03:00
NULL ,
} ;
2016-09-01 11:25:12 +03:00
BATADV_ATTR_VLAN_BOOL ( ap_isolation , 0644 , NULL ) ;
2013-07-02 13:04:36 +04:00
2015-09-06 22:38:53 +03:00
/* array of vlan specific sysfs attributes */
2013-07-02 13:04:35 +04:00
static struct batadv_attribute * batadv_vlan_attrs [ ] = {
2013-07-02 13:04:36 +04:00
& batadv_attr_vlan_ap_isolation ,
2013-07-02 13:04:35 +04:00
NULL ,
} ;
2017-12-02 21:51:53 +03:00
/**
* batadv_sysfs_add_meshif ( ) - Add soft interface specific sysfs entries
* @ dev : netdev struct of the soft interface
*
* Return : 0 on success or negative error number in case of failure
*/
2012-05-12 04:09:24 +04:00
int batadv_sysfs_add_meshif ( struct net_device * dev )
2010-12-13 14:19:28 +03:00
{
struct kobject * batif_kobject = & dev - > dev . kobj ;
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( dev ) ;
2012-06-06 00:31:29 +04:00
struct batadv_attribute * * bat_attr ;
2010-12-13 14:19:28 +03:00
int err ;
2012-06-04 00:19:09 +04:00
bat_priv - > mesh_obj = kobject_create_and_add ( BATADV_SYSFS_IF_MESH_SUBDIR ,
2010-12-13 14:19:28 +03:00
batif_kobject ) ;
if ( ! bat_priv - > mesh_obj ) {
2012-05-16 22:23:22 +04:00
batadv_err ( dev , " Can't add sysfs directory: %s/%s \n " , dev - > name ,
2012-06-04 00:19:09 +04:00
BATADV_SYSFS_IF_MESH_SUBDIR ) ;
2010-12-13 14:19:28 +03:00
goto out ;
}
2012-05-12 20:33:52 +04:00
for ( bat_attr = batadv_mesh_attrs ; * bat_attr ; + + bat_attr ) {
2010-12-13 14:19:28 +03:00
err = sysfs_create_file ( bat_priv - > mesh_obj ,
& ( ( * bat_attr ) - > attr ) ) ;
if ( err ) {
2012-05-16 22:23:22 +04:00
batadv_err ( dev , " Can't add sysfs file: %s/%s/%s \n " ,
2012-06-04 00:19:09 +04:00
dev - > name , BATADV_SYSFS_IF_MESH_SUBDIR ,
2012-05-16 22:23:22 +04:00
( ( * bat_attr ) - > attr ) . name ) ;
2010-12-13 14:19:28 +03:00
goto rem_attr ;
}
}
return 0 ;
rem_attr :
2012-05-12 20:33:52 +04:00
for ( bat_attr = batadv_mesh_attrs ; * bat_attr ; + + bat_attr )
2010-12-13 14:19:28 +03:00
sysfs_remove_file ( bat_priv - > mesh_obj , & ( ( * bat_attr ) - > attr ) ) ;
2016-06-13 08:41:32 +03:00
kobject_uevent ( bat_priv - > mesh_obj , KOBJ_REMOVE ) ;
kobject_del ( bat_priv - > mesh_obj ) ;
2010-12-13 14:19:28 +03:00
kobject_put ( bat_priv - > mesh_obj ) ;
bat_priv - > mesh_obj = NULL ;
out :
return - ENOMEM ;
}
2017-12-02 21:51:53 +03:00
/**
* batadv_sysfs_del_meshif ( ) - Remove soft interface specific sysfs entries
* @ dev : netdev struct of the soft interface
*/
2012-05-12 04:09:24 +04:00
void batadv_sysfs_del_meshif ( struct net_device * dev )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( dev ) ;
2012-06-06 00:31:29 +04:00
struct batadv_attribute * * bat_attr ;
2010-12-13 14:19:28 +03:00
2012-05-12 20:33:52 +04:00
for ( bat_attr = batadv_mesh_attrs ; * bat_attr ; + + bat_attr )
2010-12-13 14:19:28 +03:00
sysfs_remove_file ( bat_priv - > mesh_obj , & ( ( * bat_attr ) - > attr ) ) ;
2016-06-13 08:41:32 +03:00
kobject_uevent ( bat_priv - > mesh_obj , KOBJ_REMOVE ) ;
kobject_del ( bat_priv - > mesh_obj ) ;
2010-12-13 14:19:28 +03:00
kobject_put ( bat_priv - > mesh_obj ) ;
bat_priv - > mesh_obj = NULL ;
}
2013-07-02 13:04:35 +04:00
/**
2017-12-02 21:51:47 +03:00
* batadv_sysfs_add_vlan ( ) - add all the needed sysfs objects for the new vlan
2013-07-02 13:04:35 +04:00
* @ dev : netdev of the mesh interface
* @ vlan : private data of the newly added VLAN interface
*
2015-09-15 20:00:48 +03:00
* Return : 0 on success and - ENOMEM if any of the structure allocations fails .
2013-07-02 13:04:35 +04:00
*/
int batadv_sysfs_add_vlan ( struct net_device * dev ,
struct batadv_softif_vlan * vlan )
{
char vlan_subdir [ sizeof ( BATADV_SYSFS_VLAN_SUBDIR_PREFIX ) + 5 ] ;
struct batadv_priv * bat_priv = netdev_priv ( dev ) ;
struct batadv_attribute * * bat_attr ;
int err ;
if ( vlan - > vid & BATADV_VLAN_HAS_TAG ) {
sprintf ( vlan_subdir , BATADV_SYSFS_VLAN_SUBDIR_PREFIX " %hu " ,
vlan - > vid & VLAN_VID_MASK ) ;
vlan - > kobj = kobject_create_and_add ( vlan_subdir ,
bat_priv - > mesh_obj ) ;
if ( ! vlan - > kobj ) {
batadv_err ( dev , " Can't add sysfs directory: %s/%s \n " ,
dev - > name , vlan_subdir ) ;
goto out ;
}
} else {
/* the untagged LAN uses the root folder to store its "VLAN
* specific attributes "
*/
vlan - > kobj = bat_priv - > mesh_obj ;
kobject_get ( bat_priv - > mesh_obj ) ;
}
for ( bat_attr = batadv_vlan_attrs ; * bat_attr ; + + bat_attr ) {
err = sysfs_create_file ( vlan - > kobj ,
& ( ( * bat_attr ) - > attr ) ) ;
if ( err ) {
batadv_err ( dev , " Can't add sysfs file: %s/%s/%s \n " ,
dev - > name , vlan_subdir ,
( ( * bat_attr ) - > attr ) . name ) ;
goto rem_attr ;
}
}
return 0 ;
rem_attr :
for ( bat_attr = batadv_vlan_attrs ; * bat_attr ; + + bat_attr )
sysfs_remove_file ( vlan - > kobj , & ( ( * bat_attr ) - > attr ) ) ;
2016-06-13 08:41:32 +03:00
if ( vlan - > kobj ! = bat_priv - > mesh_obj ) {
kobject_uevent ( vlan - > kobj , KOBJ_REMOVE ) ;
kobject_del ( vlan - > kobj ) ;
}
2013-07-02 13:04:35 +04:00
kobject_put ( vlan - > kobj ) ;
vlan - > kobj = NULL ;
out :
return - ENOMEM ;
}
/**
2017-12-02 21:51:47 +03:00
* batadv_sysfs_del_vlan ( ) - remove all the sysfs objects for a given VLAN
2013-07-02 13:04:35 +04:00
* @ bat_priv : the bat priv with all the soft interface information
* @ vlan : the private data of the VLAN to destroy
*/
void batadv_sysfs_del_vlan ( struct batadv_priv * bat_priv ,
struct batadv_softif_vlan * vlan )
{
struct batadv_attribute * * bat_attr ;
for ( bat_attr = batadv_vlan_attrs ; * bat_attr ; + + bat_attr )
sysfs_remove_file ( vlan - > kobj , & ( ( * bat_attr ) - > attr ) ) ;
2016-06-13 08:41:32 +03:00
if ( vlan - > kobj ! = bat_priv - > mesh_obj ) {
kobject_uevent ( vlan - > kobj , KOBJ_REMOVE ) ;
kobject_del ( vlan - > kobj ) ;
}
2013-07-02 13:04:35 +04:00
kobject_put ( vlan - > kobj ) ;
vlan - > kobj = NULL ;
}
2012-05-12 20:33:52 +04:00
static ssize_t batadv_show_mesh_iface ( struct kobject * kobj ,
struct attribute * attr , char * buff )
2010-12-13 14:19:28 +03:00
{
2012-05-12 20:33:52 +04:00
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ;
2012-06-06 00:31:31 +04:00
struct batadv_hard_iface * hard_iface ;
2010-12-13 14:19:28 +03:00
ssize_t length ;
2012-06-04 00:19:19 +04:00
const char * ifname ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:31 +04:00
hard_iface = batadv_hardif_get_by_netdev ( net_dev ) ;
2011-02-18 15:33:20 +03:00
if ( ! hard_iface )
2010-12-13 14:19:28 +03:00
return 0 ;
2012-06-04 00:19:19 +04:00
if ( hard_iface - > if_status = = BATADV_IF_NOT_IN_USE )
ifname = " none " ;
else
ifname = hard_iface - > soft_iface - > name ;
length = sprintf ( buff , " %s \n " , ifname ) ;
2010-12-13 14:19:28 +03:00
2016-01-17 13:01:10 +03:00
batadv_hardif_put ( hard_iface ) ;
2010-12-13 14:19:28 +03:00
return length ;
}
2016-06-13 08:41:30 +03:00
/**
2017-12-02 21:51:47 +03:00
* batadv_store_mesh_iface_finish ( ) - store new hardif mesh_iface state
2016-06-13 08:41:30 +03:00
* @ net_dev : netdevice to add / remove to / from batman - adv soft - interface
* @ ifname : name of soft - interface to modify
*
* Changes the parts of the hard + soft interface which can not be modified under
* sysfs lock ( to prevent deadlock situations ) .
*
* Return : 0 on success , 0 < on failure
*/
static int batadv_store_mesh_iface_finish ( struct net_device * net_dev ,
char ifname [ IFNAMSIZ ] )
2010-12-13 14:19:28 +03:00
{
2016-04-21 13:57:27 +03:00
struct net * net = dev_net ( net_dev ) ;
2012-06-06 00:31:31 +04:00
struct batadv_hard_iface * hard_iface ;
2016-06-13 08:41:30 +03:00
int status_tmp ;
int ret = 0 ;
ASSERT_RTNL ( ) ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:31 +04:00
hard_iface = batadv_hardif_get_by_netdev ( net_dev ) ;
2011-02-18 15:33:20 +03:00
if ( ! hard_iface )
2016-06-13 08:41:30 +03:00
return 0 ;
2010-12-13 14:19:28 +03:00
2016-06-13 08:41:30 +03:00
if ( strncmp ( ifname , " none " , 4 ) = = 0 )
2012-06-04 00:19:19 +04:00
status_tmp = BATADV_IF_NOT_IN_USE ;
2010-12-13 14:19:28 +03:00
else
2012-06-04 00:19:19 +04:00
status_tmp = BATADV_IF_I_WANT_YOU ;
2010-12-13 14:19:28 +03:00
2011-02-18 15:33:20 +03:00
if ( hard_iface - > if_status = = status_tmp )
goto out ;
2017-08-23 22:52:13 +03:00
if ( hard_iface - > soft_iface & &
strncmp ( hard_iface - > soft_iface - > name , ifname , IFNAMSIZ ) = = 0 )
2011-02-10 17:33:51 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2012-06-04 00:19:19 +04:00
if ( status_tmp = = BATADV_IF_NOT_IN_USE ) {
2013-02-11 13:10:24 +04:00
batadv_hardif_disable_interface ( hard_iface ,
BATADV_IF_CLEANUP_AUTO ) ;
2016-06-13 08:41:30 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
}
/* if the interface already is in use */
2012-06-04 00:19:19 +04:00
if ( hard_iface - > if_status ! = BATADV_IF_NOT_IN_USE )
2013-02-11 13:10:24 +04:00
batadv_hardif_disable_interface ( hard_iface ,
BATADV_IF_CLEANUP_AUTO ) ;
2010-12-13 14:19:28 +03:00
2016-06-13 08:41:30 +03:00
ret = batadv_hardif_enable_interface ( hard_iface , net , ifname ) ;
2011-02-10 17:33:51 +03:00
out :
2016-01-17 13:01:10 +03:00
batadv_hardif_put ( hard_iface ) ;
2010-12-13 14:19:28 +03:00
return ret ;
}
2016-06-13 08:41:30 +03:00
/**
2017-12-02 21:51:47 +03:00
* batadv_store_mesh_iface_work ( ) - store new hardif mesh_iface state
2016-06-13 08:41:30 +03:00
* @ work : work queue item
*
* Changes the parts of the hard + soft interface which can not be modified under
* sysfs lock ( to prevent deadlock situations ) .
*/
static void batadv_store_mesh_iface_work ( struct work_struct * work )
{
struct batadv_store_mesh_work * store_work ;
int ret ;
store_work = container_of ( work , struct batadv_store_mesh_work , work ) ;
rtnl_lock ( ) ;
ret = batadv_store_mesh_iface_finish ( store_work - > net_dev ,
store_work - > soft_iface_name ) ;
rtnl_unlock ( ) ;
if ( ret < 0 )
pr_err ( " Failed to store new mesh_iface state %s for %s: %d \n " ,
store_work - > soft_iface_name , store_work - > net_dev - > name ,
ret ) ;
dev_put ( store_work - > net_dev ) ;
kfree ( store_work ) ;
}
static ssize_t batadv_store_mesh_iface ( struct kobject * kobj ,
struct attribute * attr , char * buff ,
size_t count )
{
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ;
struct batadv_store_mesh_work * store_work ;
if ( buff [ count - 1 ] = = ' \n ' )
buff [ count - 1 ] = ' \0 ' ;
if ( strlen ( buff ) > = IFNAMSIZ ) {
pr_err ( " Invalid parameter for 'mesh_iface' setting received: interface name too long '%s' \n " ,
buff ) ;
return - EINVAL ;
}
store_work = kmalloc ( sizeof ( * store_work ) , GFP_KERNEL ) ;
if ( ! store_work )
return - ENOMEM ;
dev_hold ( net_dev ) ;
INIT_WORK ( & store_work - > work , batadv_store_mesh_iface_work ) ;
store_work - > net_dev = net_dev ;
strlcpy ( store_work - > soft_iface_name , buff ,
sizeof ( store_work - > soft_iface_name ) ) ;
queue_work ( batadv_event_workqueue , & store_work - > work ) ;
return count ;
}
2012-05-12 20:33:52 +04:00
static ssize_t batadv_show_iface_status ( struct kobject * kobj ,
struct attribute * attr , char * buff )
2010-12-13 14:19:28 +03:00
{
2012-05-12 20:33:52 +04:00
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ;
2012-06-06 00:31:31 +04:00
struct batadv_hard_iface * hard_iface ;
2010-12-13 14:19:28 +03:00
ssize_t length ;
2012-06-06 00:31:31 +04:00
hard_iface = batadv_hardif_get_by_netdev ( net_dev ) ;
2011-02-18 15:33:20 +03:00
if ( ! hard_iface )
2010-12-13 14:19:28 +03:00
return 0 ;
2011-02-18 15:33:20 +03:00
switch ( hard_iface - > if_status ) {
2012-06-04 00:19:19 +04:00
case BATADV_IF_TO_BE_REMOVED :
2010-12-13 14:19:28 +03:00
length = sprintf ( buff , " disabling \n " ) ;
break ;
2012-06-04 00:19:19 +04:00
case BATADV_IF_INACTIVE :
2010-12-13 14:19:28 +03:00
length = sprintf ( buff , " inactive \n " ) ;
break ;
2012-06-04 00:19:19 +04:00
case BATADV_IF_ACTIVE :
2010-12-13 14:19:28 +03:00
length = sprintf ( buff , " active \n " ) ;
break ;
2012-06-04 00:19:19 +04:00
case BATADV_IF_TO_BE_ACTIVATED :
2010-12-13 14:19:28 +03:00
length = sprintf ( buff , " enabling \n " ) ;
break ;
2012-06-04 00:19:19 +04:00
case BATADV_IF_NOT_IN_USE :
2010-12-13 14:19:28 +03:00
default :
length = sprintf ( buff , " not in use \n " ) ;
break ;
}
2016-01-17 13:01:10 +03:00
batadv_hardif_put ( hard_iface ) ;
2010-12-13 14:19:28 +03:00
return length ;
}
2016-01-16 11:40:14 +03:00
# ifdef CONFIG_BATMAN_ADV_BATMAN_V
/**
2017-12-02 21:51:47 +03:00
* batadv_store_throughput_override ( ) - parse and store throughput override
2016-01-16 11:40:14 +03:00
* entered by the user
* @ kobj : kobject representing the private mesh sysfs directory
* @ attr : the batman - adv attribute the user is interacting with
* @ buff : the buffer containing the user data
* @ count : number of bytes in the buffer
*
* Return : ' count ' on success or a negative error code in case of failure
*/
static ssize_t batadv_store_throughput_override ( struct kobject * kobj ,
struct attribute * attr ,
char * buff , size_t count )
{
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ;
struct batadv_hard_iface * hard_iface ;
u32 tp_override ;
u32 old_tp_override ;
bool ret ;
hard_iface = batadv_hardif_get_by_netdev ( net_dev ) ;
if ( ! hard_iface )
return - EINVAL ;
if ( buff [ count - 1 ] = = ' \n ' )
buff [ count - 1 ] = ' \0 ' ;
ret = batadv_parse_throughput ( net_dev , buff , " throughput_override " ,
& tp_override ) ;
if ( ! ret )
return count ;
old_tp_override = atomic_read ( & hard_iface - > bat_v . throughput_override ) ;
if ( old_tp_override = = tp_override )
goto out ;
batadv_info ( net_dev , " %s: Changing from: %u.%u MBit to: %u.%u MBit \n " ,
" throughput_override " ,
old_tp_override / 10 , old_tp_override % 10 ,
tp_override / 10 , tp_override % 10 ) ;
atomic_set ( & hard_iface - > bat_v . throughput_override , tp_override ) ;
out :
batadv_hardif_put ( hard_iface ) ;
return count ;
}
static ssize_t batadv_show_throughput_override ( struct kobject * kobj ,
struct attribute * attr ,
char * buff )
{
struct net_device * net_dev = batadv_kobj_to_netdev ( kobj ) ;
struct batadv_hard_iface * hard_iface ;
u32 tp_override ;
hard_iface = batadv_hardif_get_by_netdev ( net_dev ) ;
if ( ! hard_iface )
return - EINVAL ;
tp_override = atomic_read ( & hard_iface - > bat_v . throughput_override ) ;
return sprintf ( buff , " %u.%u MBit \n " , tp_override / 10 ,
tp_override % 10 ) ;
}
# endif
2016-09-01 11:25:12 +03:00
static BATADV_ATTR ( mesh_iface , 0644 , batadv_show_mesh_iface ,
2012-06-04 00:19:07 +04:00
batadv_store_mesh_iface ) ;
2016-09-01 11:25:12 +03:00
static BATADV_ATTR ( iface_status , 0444 , batadv_show_iface_status , NULL ) ;
2016-01-16 11:40:11 +03:00
# ifdef CONFIG_BATMAN_ADV_BATMAN_V
2016-09-01 11:25:12 +03:00
BATADV_ATTR_HIF_UINT ( elp_interval , bat_v . elp_interval , 0644 ,
2016-01-16 11:40:11 +03:00
2 * BATADV_JITTER , INT_MAX , NULL ) ;
2016-09-01 11:25:12 +03:00
static BATADV_ATTR ( throughput_override , 0644 , batadv_show_throughput_override ,
2016-01-16 11:40:14 +03:00
batadv_store_throughput_override ) ;
2016-01-16 11:40:11 +03:00
# endif
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:29 +04:00
static struct batadv_attribute * batadv_batman_attrs [ ] = {
2012-05-12 20:33:52 +04:00
& batadv_attr_mesh_iface ,
& batadv_attr_iface_status ,
2016-01-16 11:40:11 +03:00
# ifdef CONFIG_BATMAN_ADV_BATMAN_V
& batadv_attr_elp_interval ,
2016-01-16 11:40:14 +03:00
& batadv_attr_throughput_override ,
2016-01-16 11:40:11 +03:00
# endif
2010-12-13 14:19:28 +03:00
NULL ,
} ;
2017-12-02 21:51:53 +03:00
/**
* batadv_sysfs_add_hardif ( ) - Add hard interface specific sysfs entries
* @ hardif_obj : address where to store the pointer to new sysfs folder
* @ dev : netdev struct of the hard interface
*
* Return : 0 on success or negative error number in case of failure
*/
2012-05-12 04:09:24 +04:00
int batadv_sysfs_add_hardif ( struct kobject * * hardif_obj , struct net_device * dev )
2010-12-13 14:19:28 +03:00
{
struct kobject * hardif_kobject = & dev - > dev . kobj ;
2012-06-06 00:31:29 +04:00
struct batadv_attribute * * bat_attr ;
2010-12-13 14:19:28 +03:00
int err ;
2012-06-04 00:19:09 +04:00
* hardif_obj = kobject_create_and_add ( BATADV_SYSFS_IF_BAT_SUBDIR ,
hardif_kobject ) ;
2010-12-13 14:19:28 +03:00
if ( ! * hardif_obj ) {
2012-05-16 22:23:22 +04:00
batadv_err ( dev , " Can't add sysfs directory: %s/%s \n " , dev - > name ,
2012-06-04 00:19:09 +04:00
BATADV_SYSFS_IF_BAT_SUBDIR ) ;
2010-12-13 14:19:28 +03:00
goto out ;
}
2012-05-12 20:33:52 +04:00
for ( bat_attr = batadv_batman_attrs ; * bat_attr ; + + bat_attr ) {
2010-12-13 14:19:28 +03:00
err = sysfs_create_file ( * hardif_obj , & ( ( * bat_attr ) - > attr ) ) ;
if ( err ) {
2012-05-16 22:23:22 +04:00
batadv_err ( dev , " Can't add sysfs file: %s/%s/%s \n " ,
2012-06-04 00:19:09 +04:00
dev - > name , BATADV_SYSFS_IF_BAT_SUBDIR ,
2012-05-16 22:23:22 +04:00
( ( * bat_attr ) - > attr ) . name ) ;
2010-12-13 14:19:28 +03:00
goto rem_attr ;
}
}
return 0 ;
rem_attr :
2012-05-12 20:33:52 +04:00
for ( bat_attr = batadv_batman_attrs ; * bat_attr ; + + bat_attr )
2010-12-13 14:19:28 +03:00
sysfs_remove_file ( * hardif_obj , & ( ( * bat_attr ) - > attr ) ) ;
out :
return - ENOMEM ;
}
2017-12-02 21:51:53 +03:00
/**
* batadv_sysfs_del_hardif ( ) - Remove hard interface specific sysfs entries
* @ hardif_obj : address to the pointer to which stores batman - adv sysfs folder
* of the hard interface
*/
2012-05-12 04:09:24 +04:00
void batadv_sysfs_del_hardif ( struct kobject * * hardif_obj )
2010-12-13 14:19:28 +03:00
{
2016-06-13 08:41:32 +03:00
kobject_uevent ( * hardif_obj , KOBJ_REMOVE ) ;
kobject_del ( * hardif_obj ) ;
2010-12-13 14:19:28 +03:00
kobject_put ( * hardif_obj ) ;
* hardif_obj = NULL ;
}
2011-04-26 20:26:01 +04:00
2017-12-02 21:51:53 +03:00
/**
* batadv_throw_uevent ( ) - Send an uevent with batman - adv specific env data
* @ bat_priv : the bat priv with all the soft interface information
* @ type : subsystem type of event . Stored in uevent ' s BATTYPE
* @ action : action type of event . Stored in uevent ' s BATACTION
* @ data : string with additional information to the event ( ignored for
* BATADV_UEV_DEL ) . Stored in uevent ' s BATDATA
*
* Return : 0 on success or negative error number in case of failure
*/
2012-06-06 00:31:31 +04:00
int batadv_throw_uevent ( struct batadv_priv * bat_priv , enum batadv_uev_type type ,
2012-06-04 00:19:22 +04:00
enum batadv_uev_action action , const char * data )
2011-04-26 20:26:01 +04:00
{
2012-05-05 15:27:28 +04:00
int ret = - ENOMEM ;
2011-04-26 20:26:01 +04:00
struct kobject * bat_kobj ;
char * uevent_env [ 4 ] = { NULL , NULL , NULL , NULL } ;
2013-01-12 15:19:06 +04:00
bat_kobj = & bat_priv - > soft_iface - > dev . kobj ;
2011-04-26 20:26:01 +04:00
2014-06-28 22:36:29 +04:00
uevent_env [ 0 ] = kasprintf ( GFP_ATOMIC ,
" %s%s " , BATADV_UEV_TYPE_VAR ,
batadv_uev_type_str [ type ] ) ;
2011-04-26 20:26:01 +04:00
if ( ! uevent_env [ 0 ] )
goto out ;
2014-06-28 22:36:29 +04:00
uevent_env [ 1 ] = kasprintf ( GFP_ATOMIC ,
" %s%s " , BATADV_UEV_ACTION_VAR ,
batadv_uev_action_str [ action ] ) ;
2011-04-26 20:26:01 +04:00
if ( ! uevent_env [ 1 ] )
goto out ;
/* If the event is DEL, ignore the data field */
2012-06-04 00:19:22 +04:00
if ( action ! = BATADV_UEV_DEL ) {
2014-06-28 22:36:29 +04:00
uevent_env [ 2 ] = kasprintf ( GFP_ATOMIC ,
" %s%s " , BATADV_UEV_DATA_VAR , data ) ;
2011-04-26 20:26:01 +04:00
if ( ! uevent_env [ 2 ] )
goto out ;
}
ret = kobject_uevent_env ( bat_kobj , KOBJ_CHANGE , uevent_env ) ;
out :
kfree ( uevent_env [ 0 ] ) ;
kfree ( uevent_env [ 1 ] ) ;
kfree ( uevent_env [ 2 ] ) ;
if ( ret )
2012-06-04 00:19:22 +04:00
batadv_dbg ( BATADV_DBG_BATMAN , bat_priv ,
2012-05-12 15:48:58 +04:00
" Impossible to send uevent for (%s,%s,%s) event (err: %d) \n " ,
2012-05-12 20:33:52 +04:00
batadv_uev_type_str [ type ] ,
batadv_uev_action_str [ action ] ,
2012-06-04 00:19:22 +04:00
( action = = BATADV_UEV_DEL ? " NULL " : data ) , ret ) ;
2011-04-26 20:26:01 +04:00
return ret ;
}