2014-01-04 21:04:25 +04:00
/* Copyright (C) 2009-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"
# include "gateway_common.h"
# include "gateway_client.h"
2013-04-23 17:39:58 +04:00
/**
* batadv_parse_gw_bandwidth - parse supplied string buffer to extract download
* and upload bandwidth information
* @ net_dev : the soft interface net device
* @ buff : string buffer to parse
* @ down : pointer holding the returned download bandwidth information
* @ up : pointer holding the returned upload bandwidth information
*
* Returns false on parse error and true otherwise .
*/
2012-05-12 20:33:56 +04:00
static bool batadv_parse_gw_bandwidth ( struct net_device * net_dev , char * buff ,
2013-04-23 17:39:58 +04:00
uint32_t * down , uint32_t * up )
2010-12-13 14:19:28 +03:00
{
2013-04-23 17:39:58 +04:00
enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT ;
2010-12-13 14:19:28 +03:00
char * slash_ptr , * tmp_ptr ;
2011-05-15 01:14:51 +04:00
long ldown , lup ;
2013-04-23 17:39:58 +04:00
int ret ;
2010-12-13 14:19:28 +03:00
slash_ptr = strchr ( buff , ' / ' ) ;
if ( slash_ptr )
* slash_ptr = 0 ;
if ( strlen ( buff ) > 4 ) {
tmp_ptr = buff + strlen ( buff ) - 4 ;
2014-10-14 02:54:42 +04:00
if ( strncasecmp ( tmp_ptr , " mbit " , 4 ) = = 0 )
2013-04-23 17:39:58 +04:00
bw_unit_type = BATADV_BW_UNIT_MBIT ;
2010-12-13 14:19:28 +03:00
2014-10-14 02:54:42 +04:00
if ( ( strncasecmp ( tmp_ptr , " kbit " , 4 ) = = 0 ) | |
2013-04-23 17:39:58 +04:00
( bw_unit_type = = BATADV_BW_UNIT_MBIT ) )
2010-12-13 14:19:28 +03:00
* tmp_ptr = ' \0 ' ;
}
2011-09-30 15:32:01 +04:00
ret = kstrtol ( buff , 10 , & ldown ) ;
2010-12-13 14:19:28 +03:00
if ( ret ) {
2012-05-16 22:23:22 +04:00
batadv_err ( net_dev ,
" Download speed of gateway mode invalid: %s \n " ,
buff ) ;
2010-12-13 14:19:28 +03:00
return false ;
}
2013-04-23 17:39:58 +04:00
switch ( bw_unit_type ) {
case BATADV_BW_UNIT_MBIT :
* down = ldown * 10 ;
break ;
case BATADV_BW_UNIT_KBIT :
default :
* down = ldown / 100 ;
break ;
}
2010-12-13 14:19:28 +03:00
/* we also got some upload info */
if ( slash_ptr ) {
2013-04-23 17:39:58 +04:00
bw_unit_type = BATADV_BW_UNIT_KBIT ;
2010-12-13 14:19:28 +03:00
if ( strlen ( slash_ptr + 1 ) > 4 ) {
tmp_ptr = slash_ptr + 1 - 4 + strlen ( slash_ptr + 1 ) ;
2014-10-14 02:54:42 +04:00
if ( strncasecmp ( tmp_ptr , " mbit " , 4 ) = = 0 )
2013-04-23 17:39:58 +04:00
bw_unit_type = BATADV_BW_UNIT_MBIT ;
2010-12-13 14:19:28 +03:00
2014-10-14 02:54:42 +04:00
if ( ( strncasecmp ( tmp_ptr , " kbit " , 4 ) = = 0 ) | |
2013-04-23 17:39:58 +04:00
( bw_unit_type = = BATADV_BW_UNIT_MBIT ) )
2010-12-13 14:19:28 +03:00
* tmp_ptr = ' \0 ' ;
}
2011-09-30 15:32:01 +04:00
ret = kstrtol ( slash_ptr + 1 , 10 , & lup ) ;
2010-12-13 14:19:28 +03:00
if ( ret ) {
2012-05-16 22:23:22 +04:00
batadv_err ( net_dev ,
" Upload speed of gateway mode invalid: %s \n " ,
slash_ptr + 1 ) ;
2010-12-13 14:19:28 +03:00
return false ;
}
2013-04-23 17:39:58 +04:00
switch ( bw_unit_type ) {
case BATADV_BW_UNIT_MBIT :
* up = lup * 10 ;
break ;
case BATADV_BW_UNIT_KBIT :
default :
* up = lup / 100 ;
break ;
}
2010-12-13 14:19:28 +03:00
}
return true ;
}
2013-04-23 17:39:58 +04:00
/**
* batadv_gw_tvlv_container_update - update the gw tvlv container after gateway
* setting change
* @ bat_priv : the bat priv with all the soft interface information
*/
void batadv_gw_tvlv_container_update ( struct batadv_priv * bat_priv )
{
struct batadv_tvlv_gateway_data gw ;
uint32_t down , up ;
char gw_mode ;
gw_mode = atomic_read ( & bat_priv - > gw_mode ) ;
switch ( gw_mode ) {
case BATADV_GW_MODE_OFF :
case BATADV_GW_MODE_CLIENT :
batadv_tvlv_container_unregister ( bat_priv , BATADV_TVLV_GW , 1 ) ;
break ;
case BATADV_GW_MODE_SERVER :
down = atomic_read ( & bat_priv - > gw . bandwidth_down ) ;
up = atomic_read ( & bat_priv - > gw . bandwidth_up ) ;
gw . bandwidth_down = htonl ( down ) ;
gw . bandwidth_up = htonl ( up ) ;
batadv_tvlv_container_register ( bat_priv , BATADV_TVLV_GW , 1 ,
& gw , sizeof ( gw ) ) ;
break ;
}
}
2012-05-12 04:09:30 +04:00
ssize_t batadv_gw_bandwidth_set ( struct net_device * net_dev , char * buff ,
size_t count )
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-04-23 17:39:58 +04:00
uint32_t down_curr , up_curr , down_new = 0 , up_new = 0 ;
2010-12-13 14:19:28 +03:00
bool ret ;
2013-04-23 17:39:58 +04:00
down_curr = ( unsigned int ) atomic_read ( & bat_priv - > gw . bandwidth_down ) ;
up_curr = ( unsigned int ) atomic_read ( & bat_priv - > gw . bandwidth_up ) ;
ret = batadv_parse_gw_bandwidth ( net_dev , buff , & down_new , & up_new ) ;
2010-12-13 14:19:28 +03:00
if ( ! ret )
goto end ;
2013-04-23 17:39:58 +04:00
if ( ! down_new )
down_new = 1 ;
2010-12-13 14:19:28 +03:00
2013-04-23 17:39:58 +04:00
if ( ! up_new )
up_new = down_new / 5 ;
2010-12-13 14:19:28 +03:00
2013-04-23 17:39:58 +04:00
if ( ! up_new )
up_new = 1 ;
2010-12-13 14:19:28 +03:00
2013-04-23 17:39:58 +04:00
if ( ( down_curr = = down_new ) & & ( up_curr = = up_new ) )
2012-05-11 12:10:50 +04:00
return count ;
2013-11-04 23:59:41 +04:00
batadv_gw_reselect ( bat_priv ) ;
2012-05-16 22:23:22 +04:00
batadv_info ( net_dev ,
2013-04-23 17:39:58 +04:00
" Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit' \n " ,
down_curr / 10 , down_curr % 10 , up_curr / 10 , up_curr % 10 ,
down_new / 10 , down_new % 10 , up_new / 10 , up_new % 10 ) ;
2010-12-13 14:19:28 +03:00
2013-04-23 17:39:58 +04:00
atomic_set ( & bat_priv - > gw . bandwidth_down , down_new ) ;
atomic_set ( & bat_priv - > gw . bandwidth_up , up_new ) ;
batadv_gw_tvlv_container_update ( bat_priv ) ;
2010-12-13 14:19:28 +03:00
end :
return count ;
}
2013-04-23 17:39:58 +04:00
/**
* batadv_gw_tvlv_ogm_handler_v1 - process incoming gateway tvlv container
* @ bat_priv : the bat priv with all the soft interface information
* @ orig : the orig_node of the ogm
* @ flags : flags indicating the tvlv state ( see batadv_tvlv_handler_flags )
* @ tvlv_value : tvlv buffer containing the gateway data
* @ tvlv_value_len : tvlv buffer length
*/
static void batadv_gw_tvlv_ogm_handler_v1 ( struct batadv_priv * bat_priv ,
struct batadv_orig_node * orig ,
uint8_t flags ,
void * tvlv_value ,
uint16_t tvlv_value_len )
{
struct batadv_tvlv_gateway_data gateway , * gateway_ptr ;
/* only fetch the tvlv value if the handler wasn't called via the
* CIFNOTFND flag and if there is data to fetch
*/
if ( ( flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND ) | |
( tvlv_value_len < sizeof ( gateway ) ) ) {
gateway . bandwidth_down = 0 ;
gateway . bandwidth_up = 0 ;
} else {
gateway_ptr = tvlv_value ;
gateway . bandwidth_down = gateway_ptr - > bandwidth_down ;
gateway . bandwidth_up = gateway_ptr - > bandwidth_up ;
if ( ( gateway . bandwidth_down = = 0 ) | |
( gateway . bandwidth_up = = 0 ) ) {
gateway . bandwidth_down = 0 ;
gateway . bandwidth_up = 0 ;
}
}
batadv_gw_node_update ( bat_priv , orig , & gateway ) ;
/* restart gateway selection if fast or late switching was enabled */
if ( ( gateway . bandwidth_down ! = 0 ) & &
( atomic_read ( & bat_priv - > gw_mode ) = = BATADV_GW_MODE_CLIENT ) & &
( atomic_read ( & bat_priv - > gw_sel_class ) > 2 ) )
batadv_gw_check_election ( bat_priv , orig ) ;
}
/**
* batadv_gw_init - initialise the gateway handling internals
* @ bat_priv : the bat priv with all the soft interface information
*/
void batadv_gw_init ( struct batadv_priv * bat_priv )
{
batadv_tvlv_handler_register ( bat_priv , batadv_gw_tvlv_ogm_handler_v1 ,
NULL , BATADV_TVLV_GW , 1 ,
BATADV_TVLV_HANDLER_OGM_CIFNOTFND ) ;
}
/**
* batadv_gw_free - free the gateway handling internals
* @ bat_priv : the bat priv with all the soft interface information
*/
void batadv_gw_free ( struct batadv_priv * bat_priv )
{
batadv_tvlv_container_unregister ( bat_priv , BATADV_TVLV_GW , 1 ) ;
batadv_tvlv_handler_unregister ( bat_priv , BATADV_TVLV_GW , 1 ) ;
}