2014-01-04 21:04:25 +04:00
/* Copyright (C) 2010-2014 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
*/
# include "main.h"
2012-06-11 01:58:51 +04:00
# include "sysfs.h"
2010-12-13 14:19:28 +03:00
# include "translation-table.h"
2012-08-08 20:50:57 +04:00
# include "distributed-arp-table.h"
2013-04-23 17:40:00 +04:00
# include "network-coding.h"
2010-12-13 14:19:28 +03:00
# include "originator.h"
# include "hard-interface.h"
2013-07-02 13:04:35 +04:00
# include "soft-interface.h"
2010-12-13 14:19:28 +03:00
# include "gateway_common.h"
# include "gateway_client.h"
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 ) ;
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 ) ;
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
/**
* batadv_vlan_kobj_to_batpriv - convert a vlan kobj in the associated batpriv
* @ obj : kobject to covert
*
* Returns the associated batadv_priv struct .
*/
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 ) ;
}
/**
* batadv_kobj_to_vlan - convert a kobj in the associated softif_vlan struct
* @ obj : kobject to covert
*
* Returns the associated softif_vlan struct if found , NULL otherwise .
*/
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 ;
if ( ! atomic_inc_not_zero ( & vlan_tmp - > refcount ) )
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 " ,
" change "
} ;
2012-05-12 20:33:52 +04:00
static char * batadv_uev_type_str [ ] = {
2011-04-26 20:26:01 +04:00
" gw "
} ;
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 , \
} ;
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 , \
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 ) ; \
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 ) ; \
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
2012-06-04 00:19:07 +04:00
# define BATADV_ATTR_SIF_STORE_UINT(_name, _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 ) ; \
2012-05-12 20:33:52 +04:00
return __batadv_store_uint_attr ( buff , count , _min , _max , \
_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_UINT(_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 ) ; \
2010-12-13 14:19:28 +03:00
return sprintf ( buff , " %i \n " , atomic_read ( & bat_priv - > _name ) ) ; \
} \
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
*/
2012-06-04 00:19:07 +04:00
# define BATADV_ATTR_SIF_UINT(_name, _mode, _min, _max, _post_func) \
static BATADV_ATTR_SIF_STORE_UINT ( _name , _min , _max , _post_func ) \
static BATADV_ATTR_SIF_SHOW_UINT ( _name ) \
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 ) ; \
batadv_softif_vlan_free_ref ( vlan ) ; \
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 " ) ; \
batadv_softif_vlan_free_ref ( vlan ) ; \
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 )
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 ,
const char * attr_name , atomic_t * attr )
2010-12-13 14:19:28 +03:00
{
int enabled = - 1 ;
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
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
{
int ret ;
2012-05-12 20:33:52 +04:00
ret = batadv_store_bool_attr ( buff , count , net_dev , attr - > name ,
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 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 ;
}
2012-05-12 20:33:52 +04:00
static inline 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 ) ;
2011-11-28 20:15:37 +04:00
return sprintf ( buff , " %s \n " , bat_priv - > bat_algo_ops - > name ) ;
}
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 ) ;
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 ;
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 ;
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 ;
}
if ( atomic_read ( & bat_priv - > gw_mode ) = = gw_mode_tmp )
return count ;
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 ) ;
2012-04-15 09:58:06 +04: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 ;
}
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 ) ;
2013-04-23 17:39:58 +04:00
uint32_t down , up ;
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
/**
* batadv_show_isolation_mark - print the current isolation mark / mask
* @ 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
*
* Returns the number of bytes written into ' buff ' on success or a negative
* 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 ) ;
}
/**
* batadv_store_isolation_mark - parse and store the isolation mark / mask 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
*
* Returns ' count ' on success or a negative error code in case of failure
*/
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 ) ;
uint32_t mark , mask ;
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 ;
}
2012-06-04 00:19:07 +04:00
BATADV_ATTR_SIF_BOOL ( aggregated_ogms , S_IRUGO | S_IWUSR , NULL ) ;
BATADV_ATTR_SIF_BOOL ( bonding , S_IRUGO | S_IWUSR , NULL ) ;
2012-01-22 23:00:27 +04:00
# ifdef CONFIG_BATMAN_ADV_BLA
2012-06-04 00:19:07 +04:00
BATADV_ATTR_SIF_BOOL ( bridge_loop_avoidance , S_IRUGO | S_IWUSR , NULL ) ;
2012-01-22 23:00:27 +04:00
# endif
2012-08-08 20:50:57 +04:00
# ifdef CONFIG_BATMAN_ADV_DAT
2013-04-23 17:39:59 +04:00
BATADV_ATTR_SIF_BOOL ( distributed_arp_table , S_IRUGO | S_IWUSR ,
batadv_dat_status_update ) ;
2012-08-08 20:50:57 +04:00
# endif
2012-06-04 00:19:07 +04:00
BATADV_ATTR_SIF_BOOL ( fragmentation , S_IRUGO | S_IWUSR , batadv_update_min_mtu ) ;
static BATADV_ATTR ( routing_algo , S_IRUGO , batadv_show_bat_algo , NULL ) ;
static BATADV_ATTR ( gw_mode , S_IRUGO | S_IWUSR , batadv_show_gw_mode ,
batadv_store_gw_mode ) ;
2012-06-04 00:19:17 +04:00
BATADV_ATTR_SIF_UINT ( orig_interval , S_IRUGO | S_IWUSR , 2 * BATADV_JITTER ,
INT_MAX , NULL ) ;
BATADV_ATTR_SIF_UINT ( hop_penalty , S_IRUGO | S_IWUSR , 0 , BATADV_TQ_MAX_VALUE ,
2012-06-04 00:19:07 +04:00
NULL ) ;
2012-06-04 00:19:17 +04:00
BATADV_ATTR_SIF_UINT ( gw_sel_class , S_IRUGO | S_IWUSR , 1 , BATADV_TQ_MAX_VALUE ,
2013-11-04 23:59:41 +04:00
batadv_post_gw_reselect ) ;
2012-06-04 00:19:07 +04:00
static BATADV_ATTR ( gw_bandwidth , S_IRUGO | S_IWUSR , batadv_show_gw_bwidth ,
batadv_store_gw_bwidth ) ;
2014-02-15 20:47:52 +04:00
# ifdef CONFIG_BATMAN_ADV_MCAST
BATADV_ATTR_SIF_BOOL ( multicast_mode , S_IRUGO | S_IWUSR , NULL ) ;
# endif
2010-12-13 14:19:28 +03:00
# ifdef CONFIG_BATMAN_ADV_DEBUG
2012-06-04 00:19:22 +04:00
BATADV_ATTR_SIF_UINT ( log_level , S_IRUGO | S_IWUSR , 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
2013-04-23 17:40:00 +04:00
BATADV_ATTR_SIF_BOOL ( network_coding , S_IRUGO | S_IWUSR ,
batadv_nc_status_update ) ;
2013-01-25 14:12:38 +04:00
# endif
2013-11-16 15:03:47 +04:00
static BATADV_ATTR ( isolation_mark , S_IRUGO | S_IWUSR ,
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 ,
} ;
2013-07-02 13:04:36 +04:00
BATADV_ATTR_VLAN_BOOL ( ap_isolation , S_IRUGO | S_IWUSR , NULL ) ;
2013-07-02 13:04:35 +04:00
/**
* batadv_vlan_attrs - array of vlan specific sysfs attributes
*/
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 ,
} ;
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 ) ) ;
kobject_put ( bat_priv - > mesh_obj ) ;
bat_priv - > mesh_obj = NULL ;
out :
return - ENOMEM ;
}
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 ) ) ;
kobject_put ( bat_priv - > mesh_obj ) ;
bat_priv - > mesh_obj = NULL ;
}
2013-07-02 13:04:35 +04:00
/**
* batadv_sysfs_add_vlan - add all the needed sysfs objects for the new vlan
* @ dev : netdev of the mesh interface
* @ vlan : private data of the newly added VLAN interface
*
* Returns 0 on success and - ENOMEM if any of the structure allocations fails .
*/
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 ) ) ;
kobject_put ( vlan - > kobj ) ;
vlan - > kobj = NULL ;
out :
return - ENOMEM ;
}
/**
* batadv_sysfs_del_vlan - remove all the sysfs objects for a given VLAN
* @ 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 ) ) ;
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
2012-05-12 15:48:54 +04:00
batadv_hardif_free_ref ( hard_iface ) ;
2010-12-13 14:19:28 +03:00
return length ;
}
2012-05-12 20:33:52 +04:00
static ssize_t batadv_store_mesh_iface ( 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_hard_iface * hard_iface ;
2010-12-13 14:19:28 +03:00
int status_tmp = - 1 ;
2011-02-10 17:33:51 +03:00
int ret = count ;
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 count ;
if ( buff [ count - 1 ] = = ' \n ' )
buff [ count - 1 ] = ' \0 ' ;
if ( strlen ( buff ) > = IFNAMSIZ ) {
2012-03-07 12:07:45 +04:00
pr_err ( " Invalid parameter for 'mesh_iface' setting received: interface name too long '%s' \n " ,
buff ) ;
2012-05-12 15:48:54 +04:00
batadv_hardif_free_ref ( hard_iface ) ;
2010-12-13 14:19:28 +03:00
return - EINVAL ;
}
if ( strncmp ( buff , " 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 ;
if ( ( hard_iface - > soft_iface ) & &
( strncmp ( hard_iface - > soft_iface - > name , buff , IFNAMSIZ ) = = 0 ) )
2011-02-10 17:33:51 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2013-05-28 19:32:32 +04:00
rtnl_lock ( ) ;
2011-05-03 15:10:06 +04: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 ) ;
2011-05-03 15:10:06 +04:00
goto unlock ;
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
2012-05-12 04:09:31 +04:00
ret = batadv_hardif_enable_interface ( hard_iface , buff ) ;
2010-12-13 14:19:28 +03:00
2011-05-03 15:10:06 +04:00
unlock :
rtnl_unlock ( ) ;
2011-02-10 17:33:51 +03:00
out :
2012-05-12 15:48:54 +04:00
batadv_hardif_free_ref ( hard_iface ) ;
2010-12-13 14:19:28 +03:00
return ret ;
}
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 ;
}
2012-05-12 15:48:54 +04:00
batadv_hardif_free_ref ( hard_iface ) ;
2010-12-13 14:19:28 +03:00
return length ;
}
2012-06-04 00:19:07 +04:00
static BATADV_ATTR ( mesh_iface , S_IRUGO | S_IWUSR , batadv_show_mesh_iface ,
batadv_store_mesh_iface ) ;
static BATADV_ATTR ( iface_status , S_IRUGO , batadv_show_iface_status , NULL ) ;
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 ,
2010-12-13 14:19:28 +03:00
NULL ,
} ;
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 ;
}
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
{
kobject_put ( * hardif_obj ) ;
* hardif_obj = NULL ;
}
2011-04-26 20:26:01 +04:00
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
2012-06-04 00:19:07 +04:00
uevent_env [ 0 ] = kmalloc ( strlen ( BATADV_UEV_TYPE_VAR ) +
2012-05-12 20:33:52 +04:00
strlen ( batadv_uev_type_str [ type ] ) + 1 ,
2011-04-26 20:26:01 +04:00
GFP_ATOMIC ) ;
if ( ! uevent_env [ 0 ] )
goto out ;
2012-06-04 00:19:07 +04:00
sprintf ( uevent_env [ 0 ] , " %s%s " , BATADV_UEV_TYPE_VAR ,
batadv_uev_type_str [ type ] ) ;
2011-04-26 20:26:01 +04:00
2012-06-04 00:19:07 +04:00
uevent_env [ 1 ] = kmalloc ( strlen ( BATADV_UEV_ACTION_VAR ) +
2012-05-12 20:33:52 +04:00
strlen ( batadv_uev_action_str [ action ] ) + 1 ,
2011-04-26 20:26:01 +04:00
GFP_ATOMIC ) ;
if ( ! uevent_env [ 1 ] )
goto out ;
2012-06-04 00:19:07 +04:00
sprintf ( uevent_env [ 1 ] , " %s%s " , BATADV_UEV_ACTION_VAR ,
2012-05-12 20:33:52 +04:00
batadv_uev_action_str [ action ] ) ;
2011-04-26 20:26:01 +04:00
/* If the event is DEL, ignore the data field */
2012-06-04 00:19:22 +04:00
if ( action ! = BATADV_UEV_DEL ) {
2012-06-04 00:19:07 +04:00
uevent_env [ 2 ] = kmalloc ( strlen ( BATADV_UEV_DATA_VAR ) +
2011-04-26 20:26:01 +04:00
strlen ( data ) + 1 , GFP_ATOMIC ) ;
if ( ! uevent_env [ 2 ] )
goto out ;
2012-06-04 00:19:07 +04:00
sprintf ( uevent_env [ 2 ] , " %s%s " , BATADV_UEV_DATA_VAR , data ) ;
2011-04-26 20:26:01 +04:00
}
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 ;
}