summaryrefslogtreecommitdiffstats
path: root/net/batman-adv/gateway_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv/gateway_client.c')
-rw-r--r--net/batman-adv/gateway_client.c187
1 files changed, 121 insertions, 66 deletions
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 1ce4b8763ef2..1bce63aa5f5f 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -118,7 +118,6 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
uint32_t gw_divisor;
uint8_t max_tq = 0;
- int down, up;
uint8_t tq_avg;
struct batadv_orig_node *orig_node;
@@ -142,10 +141,9 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
switch (atomic_read(&bat_priv->gw_sel_class)) {
case 1: /* fast connection */
- batadv_gw_bandwidth_to_kbit(orig_node->gw_flags,
- &down, &up);
-
- tmp_gw_factor = tq_avg * tq_avg * down * 100 * 100;
+ tmp_gw_factor = tq_avg * tq_avg;
+ tmp_gw_factor *= gw_node->bandwidth_down;
+ tmp_gw_factor *= 100 * 100;
tmp_gw_factor /= gw_divisor;
if ((tmp_gw_factor > max_gw_factor) ||
@@ -258,16 +256,22 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
NULL);
} else if ((!curr_gw) && (next_gw)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
+ "Adding route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n",
next_gw->orig_node->orig,
- next_gw->orig_node->gw_flags, router->tq_avg);
+ next_gw->bandwidth_down / 10,
+ next_gw->bandwidth_down % 10,
+ next_gw->bandwidth_up / 10,
+ next_gw->bandwidth_up % 10, router->tq_avg);
batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD,
gw_addr);
} else {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "Changing route to gateway %pM (gw_flags: %i, tq: %i)\n",
+ "Changing route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n",
next_gw->orig_node->orig,
- next_gw->orig_node->gw_flags, router->tq_avg);
+ next_gw->bandwidth_down / 10,
+ next_gw->bandwidth_down % 10,
+ next_gw->bandwidth_up / 10,
+ next_gw->bandwidth_up % 10, router->tq_avg);
batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE,
gw_addr);
}
@@ -337,12 +341,20 @@ out:
return;
}
+/**
+ * batadv_gw_node_add - add gateway node to list of available gateways
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: originator announcing gateway capabilities
+ * @gateway: announced bandwidth information
+ */
static void batadv_gw_node_add(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
- uint8_t new_gwflags)
+ struct batadv_tvlv_gateway_data *gateway)
{
struct batadv_gw_node *gw_node;
- int down, up;
+
+ if (gateway->bandwidth_down == 0)
+ return;
gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
if (!gw_node)
@@ -356,73 +368,116 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.list);
spin_unlock_bh(&bat_priv->gw.list_lock);
- batadv_gw_bandwidth_to_kbit(new_gwflags, &down, &up);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n",
- orig_node->orig, new_gwflags,
- (down > 2048 ? down / 1024 : down),
- (down > 2048 ? "MBit" : "KBit"),
- (up > 2048 ? up / 1024 : up),
- (up > 2048 ? "MBit" : "KBit"));
+ "Found new gateway %pM -> gw bandwidth: %u.%u/%u.%u MBit\n",
+ orig_node->orig,
+ ntohl(gateway->bandwidth_down) / 10,
+ ntohl(gateway->bandwidth_down) % 10,
+ ntohl(gateway->bandwidth_up) / 10,
+ ntohl(gateway->bandwidth_up) % 10);
}
-void batadv_gw_node_update(struct batadv_priv *bat_priv,
- struct batadv_orig_node *orig_node,
- uint8_t new_gwflags)
+/**
+ * batadv_gw_node_get - retrieve gateway node from list of available gateways
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: originator announcing gateway capabilities
+ *
+ * Returns gateway node if found or NULL otherwise.
+ */
+static struct batadv_gw_node *
+batadv_gw_node_get(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node)
{
- struct batadv_gw_node *gw_node, *curr_gw;
-
- /* Note: We don't need a NULL check here, since curr_gw never gets
- * dereferenced. If curr_gw is NULL we also should not exit as we may
- * have this gateway in our list (duplication check!) even though we
- * have no currently selected gateway.
- */
- curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
+ struct batadv_gw_node *gw_node_tmp, *gw_node = NULL;
rcu_read_lock();
- hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
- if (gw_node->orig_node != orig_node)
+ hlist_for_each_entry_rcu(gw_node_tmp, &bat_priv->gw.list, list) {
+ if (gw_node_tmp->orig_node != orig_node)
continue;
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "Gateway class of originator %pM changed from %i to %i\n",
- orig_node->orig, gw_node->orig_node->gw_flags,
- new_gwflags);
+ if (gw_node_tmp->deleted)
+ continue;
- gw_node->deleted = 0;
+ if (!atomic_inc_not_zero(&gw_node_tmp->refcount))
+ continue;
- if (new_gwflags == BATADV_NO_FLAGS) {
- gw_node->deleted = jiffies;
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "Gateway %pM removed from gateway list\n",
- orig_node->orig);
+ gw_node = gw_node_tmp;
+ break;
+ }
+ rcu_read_unlock();
- if (gw_node == curr_gw)
- goto deselect;
- }
+ return gw_node;
+}
- goto unlock;
+/**
+ * batadv_gw_node_update - update list of available gateways with changed
+ * bandwidth information
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: originator announcing gateway capabilities
+ * @gateway: announced bandwidth information
+ */
+void batadv_gw_node_update(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node,
+ struct batadv_tvlv_gateway_data *gateway)
+{
+ struct batadv_gw_node *gw_node, *curr_gw = NULL;
+
+ gw_node = batadv_gw_node_get(bat_priv, orig_node);
+ if (!gw_node) {
+ batadv_gw_node_add(bat_priv, orig_node, gateway);
+ goto out;
}
- if (new_gwflags == BATADV_NO_FLAGS)
- goto unlock;
+ if ((gw_node->bandwidth_down == ntohl(gateway->bandwidth_down)) &&
+ (gw_node->bandwidth_up == ntohl(gateway->bandwidth_up)))
+ goto out;
- batadv_gw_node_add(bat_priv, orig_node, new_gwflags);
- goto unlock;
+ batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+ "Gateway bandwidth of originator %pM changed from %u.%u/%u.%u MBit to %u.%u/%u.%u MBit\n",
+ orig_node->orig,
+ gw_node->bandwidth_down / 10,
+ gw_node->bandwidth_down % 10,
+ gw_node->bandwidth_up / 10,
+ gw_node->bandwidth_up % 10,
+ ntohl(gateway->bandwidth_down) / 10,
+ ntohl(gateway->bandwidth_down) % 10,
+ ntohl(gateway->bandwidth_up) / 10,
+ ntohl(gateway->bandwidth_up) % 10);
+
+ gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
+ gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
+
+ gw_node->deleted = 0;
+ if (ntohl(gateway->bandwidth_down) == 0) {
+ gw_node->deleted = jiffies;
+ batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+ "Gateway %pM removed from gateway list\n",
+ orig_node->orig);
-deselect:
- batadv_gw_deselect(bat_priv);
-unlock:
- rcu_read_unlock();
+ /* Note: We don't need a NULL check here, since curr_gw never
+ * gets dereferenced.
+ */
+ curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
+ if (gw_node == curr_gw)
+ batadv_gw_deselect(bat_priv);
+ }
+out:
if (curr_gw)
batadv_gw_node_free_ref(curr_gw);
+ if (gw_node)
+ batadv_gw_node_free_ref(gw_node);
}
void batadv_gw_node_delete(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node)
{
- batadv_gw_node_update(bat_priv, orig_node, 0);
+ struct batadv_tvlv_gateway_data gateway;
+
+ gateway.bandwidth_down = 0;
+ gateway.bandwidth_up = 0;
+
+ batadv_gw_node_update(bat_priv, orig_node, &gateway);
}
void batadv_gw_node_purge(struct batadv_priv *bat_priv)
@@ -467,9 +522,7 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
{
struct batadv_gw_node *curr_gw;
struct batadv_neigh_node *router;
- int down, up, ret = -1;
-
- batadv_gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
+ int ret = -1;
router = batadv_orig_node_get_router(gw_node->orig_node);
if (!router)
@@ -477,16 +530,15 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
- ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
+ ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n",
(curr_gw == gw_node ? "=>" : " "),
gw_node->orig_node->orig,
router->tq_avg, router->addr,
router->if_incoming->net_dev->name,
- gw_node->orig_node->gw_flags,
- (down > 2048 ? down / 1024 : down),
- (down > 2048 ? "MBit" : "KBit"),
- (up > 2048 ? up / 1024 : up),
- (up > 2048 ? "MBit" : "KBit"));
+ gw_node->bandwidth_down / 10,
+ gw_node->bandwidth_down % 10,
+ gw_node->bandwidth_up / 10,
+ gw_node->bandwidth_up % 10);
batadv_neigh_node_free_ref(router);
if (curr_gw)
@@ -508,7 +560,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
goto out;
seq_printf(seq,
- " %-12s (%s/%i) %17s [%10s]: gw_class ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
+ " %-12s (%s/%i) %17s [%10s]: advertised uplink bandwidth ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
"Gateway", "#", BATADV_TQ_MAX_VALUE, "Nexthop", "outgoingIF",
BATADV_SOURCE_VERSION, primary_if->net_dev->name,
primary_if->net_dev->dev_addr, net_dev->name);
@@ -675,7 +727,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
{
struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
struct batadv_orig_node *orig_dst_node = NULL;
- struct batadv_gw_node *curr_gw = NULL;
+ struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL;
struct ethhdr *ethhdr;
bool ret, out_of_range = false;
unsigned int header_len = 0;
@@ -691,7 +743,8 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
if (!orig_dst_node)
goto out;
- if (!orig_dst_node->gw_flags)
+ gw_node = batadv_gw_node_get(bat_priv, orig_dst_node);
+ if (!gw_node->bandwidth_down == 0)
goto out;
ret = batadv_is_type_dhcprequest(skb, header_len);
@@ -742,6 +795,8 @@ out:
batadv_orig_node_free_ref(orig_dst_node);
if (curr_gw)
batadv_gw_node_free_ref(curr_gw);
+ if (gw_node)
+ batadv_gw_node_free_ref(gw_node);
if (neigh_old)
batadv_neigh_node_free_ref(neigh_old);
if (neigh_curr)