2017-11-19 17:05:11 +03:00
// SPDX-License-Identifier: GPL-2.0
2018-01-01 02:00:00 +03:00
/* Copyright (C) 2009-2018 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 "gateway_common.h"
2015-04-17 20:40:28 +03:00
# include "main.h"
# include <linux/atomic.h>
# include <linux/byteorder/generic.h>
2016-05-15 12:07:42 +03:00
# include <linux/errno.h>
2015-04-17 20:40:28 +03:00
# include <linux/kernel.h>
2015-06-21 20:40:09 +03:00
# include <linux/math64.h>
2015-04-17 20:40:28 +03:00
# include <linux/netdevice.h>
# include <linux/stddef.h>
# include <linux/string.h>
2017-12-21 12:17:41 +03:00
# include <uapi/linux/batadv_packet.h>
2015-04-17 20:40:28 +03:00
2010-12-13 14:19:28 +03:00
# include "gateway_client.h"
2016-05-16 00:48:31 +03:00
# include "log.h"
2016-05-15 12:07:43 +03:00
# include "tvlv.h"
2010-12-13 14:19:28 +03:00
2013-04-23 17:39:58 +04:00
/**
2017-12-02 21:51:47 +03:00
* batadv_parse_throughput ( ) - parse supplied string buffer to extract
* throughput information
2013-04-23 17:39:58 +04:00
* @ net_dev : the soft interface net device
* @ buff : string buffer to parse
2015-09-13 10:44:45 +03:00
* @ description : text shown when throughput string cannot be parsed
* @ throughput : pointer holding the returned throughput information
2013-04-23 17:39:58 +04:00
*
2015-09-15 20:00:48 +03:00
* Return : false on parse error and true otherwise .
2013-04-23 17:39:58 +04:00
*/
2016-01-16 11:40:14 +03:00
bool batadv_parse_throughput ( struct net_device * net_dev , char * buff ,
const char * description , u32 * throughput )
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 ;
2015-09-13 10:44:45 +03:00
u64 lthroughput ;
char * tmp_ptr ;
2013-04-23 17:39:58 +04:00
int ret ;
2010-12-13 14:19:28 +03:00
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
2017-08-23 22:52:13 +03:00
if ( strncasecmp ( tmp_ptr , " kbit " , 4 ) = = 0 | |
bw_unit_type = = BATADV_BW_UNIT_MBIT )
2010-12-13 14:19:28 +03:00
* tmp_ptr = ' \0 ' ;
}
2015-09-13 10:44:45 +03:00
ret = kstrtou64 ( buff , 10 , & lthroughput ) ;
2010-12-13 14:19:28 +03:00
if ( ret ) {
2012-05-16 22:23:22 +04:00
batadv_err ( net_dev ,
2015-09-13 10:44:45 +03:00
" Invalid throughput speed for %s: %s \n " ,
description , 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 :
2015-06-21 20:40:09 +03:00
/* prevent overflow */
2015-09-13 10:44:45 +03:00
if ( U64_MAX / 10 < lthroughput ) {
2015-06-21 20:40:09 +03:00
batadv_err ( net_dev ,
2015-09-13 10:44:45 +03:00
" Throughput speed for %s too large: %s \n " ,
description , buff ) ;
2015-06-21 20:40:09 +03:00
return false ;
}
2015-09-13 10:44:45 +03:00
lthroughput * = 10 ;
2013-04-23 17:39:58 +04:00
break ;
case BATADV_BW_UNIT_KBIT :
default :
2015-09-13 10:44:45 +03:00
lthroughput = div_u64 ( lthroughput , 100 ) ;
2013-04-23 17:39:58 +04:00
break ;
}
2010-12-13 14:19:28 +03:00
2015-09-13 10:44:45 +03:00
if ( lthroughput > U32_MAX ) {
2015-06-21 20:40:09 +03:00
batadv_err ( net_dev ,
2015-09-13 10:44:45 +03:00
" Throughput speed for %s too large: %s \n " ,
description , buff ) ;
2015-06-21 20:40:09 +03:00
return false ;
}
2015-09-13 10:44:45 +03:00
* throughput = lthroughput ;
2015-06-21 20:40:09 +03:00
2015-09-13 10:44:45 +03:00
return true ;
}
2010-12-13 14:19:28 +03:00
2015-09-13 10:44:45 +03:00
/**
2017-12-02 21:51:47 +03:00
* batadv_parse_gw_bandwidth ( ) - parse supplied string buffer to extract
* download and upload bandwidth information
2015-09-13 10:44:45 +03:00
* @ 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
*
* Return : false on parse error and true otherwise .
*/
static bool batadv_parse_gw_bandwidth ( struct net_device * net_dev , char * buff ,
u32 * down , u32 * up )
{
char * slash_ptr ;
bool ret ;
2010-12-13 14:19:28 +03:00
2015-09-13 10:44:45 +03:00
slash_ptr = strchr ( buff , ' / ' ) ;
if ( slash_ptr )
* slash_ptr = 0 ;
2010-12-13 14:19:28 +03:00
2015-09-13 10:44:45 +03:00
ret = batadv_parse_throughput ( net_dev , buff , " download gateway speed " ,
down ) ;
if ( ! ret )
return false ;
2015-06-21 20:40:09 +03:00
2015-09-13 10:44:45 +03:00
/* we also got some upload info */
if ( slash_ptr ) {
ret = batadv_parse_throughput ( net_dev , slash_ptr + 1 ,
" upload gateway speed " , up ) ;
if ( ! ret )
2015-06-21 20:40:09 +03:00
return false ;
2010-12-13 14:19:28 +03:00
}
return true ;
}
2013-04-23 17:39:58 +04:00
/**
2017-12-02 21:51:47 +03:00
* batadv_gw_tvlv_container_update ( ) - update the gw tvlv container after
* gateway setting change
2013-04-23 17:39:58 +04:00
* @ 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 ;
2015-05-26 19:34:26 +03:00
u32 down , up ;
2013-04-23 17:39:58 +04:00
char gw_mode ;
2016-05-05 21:46:38 +03:00
gw_mode = atomic_read ( & bat_priv - > gw . mode ) ;
2013-04-23 17:39:58 +04:00
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 ;
}
}
2017-12-02 21:51:53 +03:00
/**
* batadv_gw_bandwidth_set ( ) - Parse and set download / upload gateway bandwidth
* from supplied string buffer
* @ net_dev : netdev struct of the soft interface
* @ 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
*/
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 ) ;
2015-06-09 21:50:49 +03:00
u32 down_curr ;
u32 up_curr ;
u32 down_new = 0 ;
u32 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 )
2015-06-21 15:42:49 +03:00
return - EINVAL ;
2010-12-13 14:19:28 +03:00
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
2017-08-23 22:52:13 +03: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
return count ;
}
2013-04-23 17:39:58 +04:00
/**
2017-12-02 21:51:47 +03:00
* batadv_gw_tvlv_ogm_handler_v1 ( ) - process incoming gateway tvlv container
2013-04-23 17:39:58 +04:00
* @ 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 ,
2015-05-26 19:34:26 +03:00
u8 flags ,
void * tvlv_value , u16 tvlv_value_len )
2013-04-23 17:39:58 +04:00
{
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
*/
2017-08-23 22:52:13 +03:00
if ( flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND | |
tvlv_value_len < sizeof ( gateway ) ) {
2013-04-23 17:39:58 +04:00
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 ;
2017-08-23 22:52:13 +03:00
if ( gateway . bandwidth_down = = 0 | |
gateway . bandwidth_up = = 0 ) {
2013-04-23 17:39:58 +04:00
gateway . bandwidth_down = 0 ;
gateway . bandwidth_up = 0 ;
}
}
batadv_gw_node_update ( bat_priv , orig , & gateway ) ;
2016-07-03 13:46:33 +03:00
/* restart gateway selection */
2017-08-23 22:52:13 +03:00
if ( gateway . bandwidth_down ! = 0 & &
atomic_read ( & bat_priv - > gw . mode ) = = BATADV_GW_MODE_CLIENT )
2013-04-23 17:39:58 +04:00
batadv_gw_check_election ( bat_priv , orig ) ;
}
/**
2017-12-02 21:51:47 +03:00
* batadv_gw_init ( ) - initialise the gateway handling internals
2013-04-23 17:39:58 +04:00
* @ bat_priv : the bat priv with all the soft interface information
*/
void batadv_gw_init ( struct batadv_priv * bat_priv )
{
2017-03-04 17:48:50 +03:00
if ( bat_priv - > algo_ops - > gw . init_sel_class )
bat_priv - > algo_ops - > gw . init_sel_class ( bat_priv ) ;
else
atomic_set ( & bat_priv - > gw . sel_class , 1 ) ;
2013-04-23 17:39:58 +04:00
batadv_tvlv_handler_register ( bat_priv , batadv_gw_tvlv_ogm_handler_v1 ,
NULL , BATADV_TVLV_GW , 1 ,
BATADV_TVLV_HANDLER_OGM_CIFNOTFND ) ;
}
/**
2017-12-02 21:51:47 +03:00
* batadv_gw_free ( ) - free the gateway handling internals
2013-04-23 17:39:58 +04:00
* @ 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 ) ;
}