diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index b05399d8a127248e38189d1c6de17d1ae0cb2e42..bdb317faa1dc1e031cf72473f6b327ac117acbf0 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -685,6 +685,12 @@ enum batadv_ifla_attrs { */ IFLA_BATADV_UNSPEC, + /** + * @IFLA_BATADV_ALGO_NAME: routing algorithm (name) which should be + * used by the newly registered batadv net_device. + */ + IFLA_BATADV_ALGO_NAME, + /* add attributes above here, update the policy in soft-interface.c */ /** diff --git a/net/batman-adv/bat_algo.c b/net/batman-adv/bat_algo.c index 382fbe51fd3400a85ca7426992bede668210598e..500db94a6b504b8cff420cc0477add1f6410b8b1 100644 --- a/net/batman-adv/bat_algo.c +++ b/net/batman-adv/bat_algo.c @@ -34,7 +34,13 @@ void batadv_algo_init(void) INIT_HLIST_HEAD(&batadv_algo_list); } -static struct batadv_algo_ops *batadv_algo_get(char *name) +/** + * batadv_algo_get() - Search for algorithm with specific name + * @name: algorithm name to find + * + * Return: Pointer to batadv_algo_ops on success, NULL otherwise + */ +struct batadv_algo_ops *batadv_algo_get(const char *name) { struct batadv_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp; @@ -97,7 +103,7 @@ int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops) * * Return: 0 on success or negative error number in case of failure */ -int batadv_algo_select(struct batadv_priv *bat_priv, char *name) +int batadv_algo_select(struct batadv_priv *bat_priv, const char *name) { struct batadv_algo_ops *bat_algo_ops; diff --git a/net/batman-adv/bat_algo.h b/net/batman-adv/bat_algo.h index 686a60bc9492caacf920e477bc437f7cca154475..2ae140eac45d3b4d75cce47d026d1d98f01eb10c 100644 --- a/net/batman-adv/bat_algo.h +++ b/net/batman-adv/bat_algo.h @@ -18,8 +18,9 @@ extern char batadv_routing_algo[]; extern struct list_head batadv_hardif_list; void batadv_algo_init(void); +struct batadv_algo_ops *batadv_algo_get(const char *name); int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops); -int batadv_algo_select(struct batadv_priv *bat_priv, char *name); +int batadv_algo_select(struct batadv_priv *bat_priv, const char *name); int batadv_algo_seq_print_text(struct seq_file *seq, void *offset); int batadv_algo_dump(struct sk_buff *msg, struct netlink_callback *cb); diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 9c7b89689c97d7f646e02d0e5534761f86836b54..8116631c11c5e969359acc422cd0ac7b9304f0a0 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -846,9 +846,11 @@ static int batadv_softif_init_late(struct net_device *dev) batadv_nc_init_bat_priv(bat_priv); - ret = batadv_algo_select(bat_priv, batadv_routing_algo); - if (ret < 0) - goto free_bat_counters; + if (!bat_priv->algo_ops) { + ret = batadv_algo_select(bat_priv, batadv_routing_algo); + if (ret < 0) + goto free_bat_counters; + } ret = batadv_debugfs_add_meshif(dev); if (ret < 0) @@ -1085,6 +1087,17 @@ static void batadv_softif_init_early(struct net_device *dev) static int batadv_softif_validate(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { + struct batadv_algo_ops *algo_ops; + + if (!data) + return 0; + + if (data[IFLA_BATADV_ALGO_NAME]) { + algo_ops = batadv_algo_get(nla_data(data[IFLA_BATADV_ALGO_NAME])); + if (!algo_ops) + return -EINVAL; + } + return 0; } @@ -1102,6 +1115,17 @@ static int batadv_softif_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { + struct batadv_priv *bat_priv = netdev_priv(dev); + const char *algo_name; + int err; + + if (data && data[IFLA_BATADV_ALGO_NAME]) { + algo_name = nla_data(data[IFLA_BATADV_ALGO_NAME]); + err = batadv_algo_select(bat_priv, algo_name); + if (err) + return -EINVAL; + } + return register_netdevice(dev); } @@ -1204,6 +1228,7 @@ bool batadv_softif_is_valid(const struct net_device *net_dev) } static const struct nla_policy batadv_ifla_policy[IFLA_BATADV_MAX + 1] = { + [IFLA_BATADV_ALGO_NAME] = { .type = NLA_NUL_STRING }, }; struct rtnl_link_ops batadv_link_ops __read_mostly = {