@@ -20,8 +20,10 @@
#include <linux/bug.h>
#include <linux/cache.h>
+#include <linux/errno.h>
#include <linux/init.h>
#include <linux/jiffies.h>
+#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>
@@ -33,6 +35,8 @@
#include "bat_algo.h"
#include "bat_v_elp.h"
#include "bat_v_ogm.h"
+#include "gateway_client.h"
+#include "gateway_common.h"
#include "hard-interface.h"
#include "hash.h"
#include "originator.h"
@@ -319,6 +323,32 @@ err_ifinfo1:
return ret;
}
+static ssize_t batadv_v_store_sel_class(struct batadv_priv *bat_priv,
+ char *buff, size_t count)
+{
+ u32 old_class, class;
+
+ if (!batadv_parse_throughput(bat_priv->soft_iface, buff,
+ "B.A.T.M.A.N. V GW selection class",
+ &class))
+ return -EINVAL;
+
+ old_class = atomic_read(&bat_priv->gw.sel_class);
+ atomic_set(&bat_priv->gw.sel_class, class);
+
+ if (old_class != class)
+ batadv_gw_reselect(bat_priv);
+
+ return count;
+}
+
+static ssize_t batadv_v_show_sel_class(struct batadv_priv *bat_priv, char *buff)
+{
+ u32 class = atomic_read(&bat_priv->gw.sel_class);
+
+ return sprintf(buff, "%u.%u MBit\n", class / 10, class % 10);
+}
+
static struct batadv_algo_ops batadv_batman_v __read_mostly = {
.name = "BATMAN_V",
.bat_iface_activate = batadv_v_iface_activate,
@@ -331,6 +361,10 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
.bat_neigh_cmp = batadv_v_neigh_cmp,
.bat_neigh_is_similar_or_better = batadv_v_neigh_is_sob,
.bat_neigh_print = batadv_v_neigh_print,
+ .gw = {
+ .bat_store_sel_class = batadv_v_store_sel_class,
+ .bat_show_sel_class = batadv_v_show_sel_class,
+ },
};
/**
@@ -514,6 +514,38 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj,
return count;
}
+static ssize_t batadv_show_gw_sel_class(struct kobject *kobj,
+ struct attribute *attr, char *buff)
+{
+ struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
+
+ if (bat_priv->bat_algo_ops->gw.bat_show_sel_class)
+ return bat_priv->bat_algo_ops->gw.bat_show_sel_class(bat_priv,
+ buff);
+
+ return sprintf(buff, "%i\n", atomic_read(&bat_priv->gw.sel_class));
+}
+
+static ssize_t batadv_store_gw_sel_class(struct kobject *kobj,
+ struct attribute *attr, char *buff,
+ size_t count)
+{
+ struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
+
+ if (buff[count - 1] == '\n')
+ buff[count - 1] = '\0';
+
+ if (bat_priv->bat_algo_ops->gw.bat_store_sel_class)
+ return bat_priv->bat_algo_ops->gw.bat_store_sel_class(bat_priv,
+ buff,
+ count);
+
+ return __batadv_store_uint_attr(buff, count, 1, BATADV_TQ_MAX_VALUE,
+ batadv_post_gw_reselect, attr,
+ &bat_priv->gw.sel_class,
+ bat_priv->soft_iface);
+}
+
static ssize_t batadv_show_gw_bwidth(struct kobject *kobj,
struct attribute *attr, char *buff)
{
@@ -625,8 +657,8 @@ BATADV_ATTR_SIF_UINT(orig_interval, orig_interval, S_IRUGO | S_IWUSR,
2 * BATADV_JITTER, INT_MAX, NULL);
BATADV_ATTR_SIF_UINT(hop_penalty, hop_penalty, S_IRUGO | S_IWUSR, 0,
BATADV_TQ_MAX_VALUE, NULL);
-BATADV_ATTR_SIF_UINT(gw_sel_class, gw.sel_class, S_IRUGO | S_IWUSR, 1,
- BATADV_TQ_MAX_VALUE, batadv_post_gw_reselect);
+static BATADV_ATTR(gw_sel_class, S_IRUGO | S_IWUSR, batadv_show_gw_sel_class,
+ batadv_store_gw_sel_class);
static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,
batadv_store_gw_bwidth);
#ifdef CONFIG_BATMAN_ADV_MCAST
@@ -1388,6 +1388,17 @@ struct batadv_forw_packet {
};
/**
+ * struct batadv_algo_gw_ops - mesh algorithm callbacks (GW specific)
+ * @bat_store_sel_class: parse and stores a new GW selection class
+ * @bat_show_sel_class: prints the current GW selection class
+ */
+struct batadv_algo_gw_ops {
+ ssize_t (*bat_store_sel_class)(struct batadv_priv *bat_priv, char *buff,
+ size_t count);
+ ssize_t (*bat_show_sel_class)(struct batadv_priv *bat_priv, char *buff);
+};
+
+/**
* struct batadv_algo_ops - mesh algorithm callbacks
* @list: list node for the batadv_algo_list
* @name: name of the algorithm
@@ -1412,6 +1423,7 @@ struct batadv_forw_packet {
* the orig_node due to a new hard-interface being added into the mesh
* @bat_orig_del_if: ask the routing algorithm to apply the needed changes to
* the orig_node due to an hard-interface being removed from the mesh
+ * @gw: callbacks related to GW mode
*/
struct batadv_algo_ops {
struct hlist_node list;
@@ -1441,6 +1453,7 @@ struct batadv_algo_ops {
int max_if_num);
int (*bat_orig_del_if)(struct batadv_orig_node *orig_node,
int max_if_num, int del_if_num);
+ struct batadv_algo_gw_ops gw;
};
/**