2017-11-19 17:05:11 +03:00
// SPDX-License-Identifier: GPL-2.0
2020-01-01 02:00:01 +03:00
/* Copyright (C) 2007-2020 B.A.T.M.A.N. contributors:
2016-05-15 12:07:44 +03:00
*
* Marek Lindner , Simon Wunderlich
*/
# include "main.h"
# include <linux/errno.h>
# include <linux/list.h>
# include <linux/moduleparam.h>
2016-07-03 14:31:35 +03:00
# include <linux/netlink.h>
2016-05-15 12:07:44 +03:00
# include <linux/printk.h>
# include <linux/seq_file.h>
2016-07-03 14:31:35 +03:00
# include <linux/skbuff.h>
2016-05-15 12:07:44 +03:00
# include <linux/stddef.h>
# include <linux/string.h>
2016-07-03 14:31:35 +03:00
# include <net/genetlink.h>
# include <net/netlink.h>
# include <uapi/linux/batman_adv.h>
2016-05-15 12:07:44 +03:00
# include "bat_algo.h"
2016-07-03 14:31:35 +03:00
# include "netlink.h"
2016-05-15 12:07:44 +03:00
char batadv_routing_algo [ 20 ] = " BATMAN_IV " ;
static struct hlist_head batadv_algo_list ;
/**
2017-12-02 21:51:47 +03:00
* batadv_algo_init ( ) - Initialize batman - adv algorithm management data
* structures
2016-05-15 12:07:44 +03:00
*/
void batadv_algo_init ( void )
{
INIT_HLIST_HEAD ( & batadv_algo_list ) ;
}
static struct batadv_algo_ops * batadv_algo_get ( char * name )
{
struct batadv_algo_ops * bat_algo_ops = NULL , * bat_algo_ops_tmp ;
hlist_for_each_entry ( bat_algo_ops_tmp , & batadv_algo_list , list ) {
if ( strcmp ( bat_algo_ops_tmp - > name , name ) ! = 0 )
continue ;
bat_algo_ops = bat_algo_ops_tmp ;
break ;
}
return bat_algo_ops ;
}
2017-12-02 21:51:53 +03:00
/**
* batadv_algo_register ( ) - Register callbacks for a mesh algorithm
* @ bat_algo_ops : mesh algorithm callbacks to add
*
* Return : 0 on success or negative error number in case of failure
*/
2016-05-15 12:07:44 +03:00
int batadv_algo_register ( struct batadv_algo_ops * bat_algo_ops )
{
struct batadv_algo_ops * bat_algo_ops_tmp ;
bat_algo_ops_tmp = batadv_algo_get ( bat_algo_ops - > name ) ;
if ( bat_algo_ops_tmp ) {
pr_info ( " Trying to register already registered routing algorithm: %s \n " ,
bat_algo_ops - > name ) ;
return - EEXIST ;
}
/* all algorithms must implement all ops (for now) */
2016-05-25 18:27:31 +03:00
if ( ! bat_algo_ops - > iface . enable | |
! bat_algo_ops - > iface . disable | |
! bat_algo_ops - > iface . update_mac | |
! bat_algo_ops - > iface . primary_set | |
! bat_algo_ops - > neigh . cmp | |
! bat_algo_ops - > neigh . is_similar_or_better ) {
2016-05-15 12:07:44 +03:00
pr_info ( " Routing algo '%s' does not implement required ops \n " ,
bat_algo_ops - > name ) ;
return - EINVAL ;
}
INIT_HLIST_NODE ( & bat_algo_ops - > list ) ;
hlist_add_head ( & bat_algo_ops - > list , & batadv_algo_list ) ;
return 0 ;
}
2017-12-02 21:51:53 +03:00
/**
* batadv_algo_select ( ) - Select algorithm of soft interface
* @ bat_priv : the bat priv with all the soft interface information
* @ name : name of the algorithm to select
*
* The algorithm callbacks for the soft interface will be set when the algorithm
* with the correct name was found . Any previous selected algorithm will not be
* deinitialized and the new selected algorithm will also not be initialized .
* It is therefore not allowed to call batadv_algo_select outside the creation
* function of the soft interface .
*
* Return : 0 on success or negative error number in case of failure
*/
2016-05-15 12:07:44 +03:00
int batadv_algo_select ( struct batadv_priv * bat_priv , char * name )
{
struct batadv_algo_ops * bat_algo_ops ;
bat_algo_ops = batadv_algo_get ( name ) ;
if ( ! bat_algo_ops )
return - EINVAL ;
2016-05-25 18:27:31 +03:00
bat_priv - > algo_ops = bat_algo_ops ;
2016-05-15 12:07:44 +03:00
return 0 ;
}
2016-07-16 10:31:20 +03:00
# ifdef CONFIG_BATMAN_ADV_DEBUGFS
2017-12-02 21:51:53 +03:00
/**
* batadv_algo_seq_print_text ( ) - Print the supported algorithms in a seq file
* @ seq : seq file to print on
* @ offset : not used
*
* Return : always 0
*/
2016-05-15 12:07:44 +03:00
int batadv_algo_seq_print_text ( struct seq_file * seq , void * offset )
{
struct batadv_algo_ops * bat_algo_ops ;
seq_puts ( seq , " Available routing algorithms: \n " ) ;
hlist_for_each_entry ( bat_algo_ops , & batadv_algo_list , list ) {
seq_printf ( seq , " * %s \n " , bat_algo_ops - > name ) ;
}
return 0 ;
}
2016-07-16 10:31:20 +03:00
# endif
2016-05-15 12:07:44 +03:00
static int batadv_param_set_ra ( const char * val , const struct kernel_param * kp )
{
struct batadv_algo_ops * bat_algo_ops ;
char * algo_name = ( char * ) val ;
size_t name_len = strlen ( algo_name ) ;
if ( name_len > 0 & & algo_name [ name_len - 1 ] = = ' \n ' )
algo_name [ name_len - 1 ] = ' \0 ' ;
bat_algo_ops = batadv_algo_get ( algo_name ) ;
if ( ! bat_algo_ops ) {
pr_err ( " Routing algorithm '%s' is not supported \n " , algo_name ) ;
return - EINVAL ;
}
return param_set_copystring ( algo_name , kp ) ;
}
static const struct kernel_param_ops batadv_param_ops_ra = {
. set = batadv_param_set_ra ,
. get = param_get_string ,
} ;
static struct kparam_string batadv_param_string_ra = {
. maxlen = sizeof ( batadv_routing_algo ) ,
. string = batadv_routing_algo ,
} ;
module_param_cb ( routing_algo , & batadv_param_ops_ra , & batadv_param_string_ra ,
0644 ) ;
2016-07-03 14:31:35 +03:00
/**
2017-12-02 21:51:47 +03:00
* batadv_algo_dump_entry ( ) - fill in information about one supported routing
2016-07-03 14:31:35 +03:00
* algorithm
* @ msg : netlink message to be sent back
* @ portid : Port to reply to
* @ seq : Sequence number of message
* @ bat_algo_ops : Algorithm to be dumped
*
* Return : Error number , or 0 on success
*/
static int batadv_algo_dump_entry ( struct sk_buff * msg , u32 portid , u32 seq ,
struct batadv_algo_ops * bat_algo_ops )
{
void * hdr ;
hdr = genlmsg_put ( msg , portid , seq , & batadv_netlink_family ,
NLM_F_MULTI , BATADV_CMD_GET_ROUTING_ALGOS ) ;
if ( ! hdr )
return - EMSGSIZE ;
if ( nla_put_string ( msg , BATADV_ATTR_ALGO_NAME , bat_algo_ops - > name ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
/**
2017-12-02 21:51:47 +03:00
* batadv_algo_dump ( ) - fill in information about supported routing
2016-07-03 14:31:35 +03:00
* algorithms
* @ msg : netlink message to be sent back
* @ cb : Parameters to the netlink request
*
* Return : Length of reply message .
*/
int batadv_algo_dump ( struct sk_buff * msg , struct netlink_callback * cb )
{
int portid = NETLINK_CB ( cb - > skb ) . portid ;
struct batadv_algo_ops * bat_algo_ops ;
int skip = cb - > args [ 0 ] ;
int i = 0 ;
hlist_for_each_entry ( bat_algo_ops , & batadv_algo_list , list ) {
if ( i + + < skip )
continue ;
if ( batadv_algo_dump_entry ( msg , portid , cb - > nlh - > nlmsg_seq ,
bat_algo_ops ) ) {
i - - ;
break ;
}
}
cb - > args [ 0 ] = i ;
return msg - > len ;
}