@@ -32,4 +32,4 @@ EXTRA_CFLAGS += -DREVISION_VERSION=\"r$(REVISION)\"
endif
obj-m += batman-adv.o
-batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o $(shell [ "2" -eq "$(VERSION)" ] && [ "6" -eq "$(PATCHLEVEL)" ] && [ "$(SUBLEVEL)" -le "28" ] && echo bat_printk.o)
+batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o gateway_common.o gateway_client.o $(shell [ "2" -eq "$(VERSION)" ] && [ "6" -eq "$(PATCHLEVEL)" ] && [ "$(SUBLEVEL)" -le "28" ] && echo bat_printk.o)
new file mode 100644
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2009 B.A.T.M.A.N. contributors:
+ * 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
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "main.h"
+#include "gateway_client.h"
+#include "gateway_common.h"
+
+LIST_HEAD(gw_list);
+DEFINE_SPINLOCK(curr_gw_lock);
+DEFINE_SPINLOCK(gw_list_lock);
+atomic_t gw_clnt_class;
+static struct gw_node *curr_gateway;
+
+void gw_deselect(void)
+{
+ spin_lock(&curr_gw_lock);
+ curr_gateway = NULL;
+ spin_unlock(&curr_gw_lock);
+}
+
+void gw_election(void)
+{
+ struct gw_node *gw_node, *curr_gw_tmp = NULL;
+ uint8_t max_tq = 0;
+ uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
+ int down, up;
+
+ /**
+ * The batman daemon checks here if we already passed a full originator
+ * cycle in order to make sure we don't choose the first gateway we
+ * hear about. This check is based on the daemon's uptime which we
+ * don't have.
+ **/
+ if (atomic_read(&gw_clnt_class) == 0)
+ return;
+
+ if (curr_gateway)
+ return;
+
+ rcu_read_lock();
+ if (list_empty(&gw_list)) {
+ rcu_read_unlock();
+
+ if (curr_gateway) {
+ bat_dbg(DBG_BATMAN,
+ "Removing selected gateway - no gateway in range\n");
+ gw_deselect();
+ }
+
+ return;
+ }
+
+ list_for_each_entry_rcu(gw_node, &gw_list, list) {
+ if (!gw_node->orig_node->router)
+ continue;
+
+ if (gw_node->deleted)
+ continue;
+
+ switch (atomic_read(&gw_clnt_class)) {
+ case 1: /* fast connection */
+ gw_srv_class_to_kbit(gw_node->orig_node->gw_flags,
+ &down, &up);
+
+ tmp_gw_factor = (gw_node->orig_node->router->tq_avg *
+ gw_node->orig_node->router->tq_avg *
+ down * 100 * 100) /
+ (TQ_LOCAL_WINDOW_SIZE *
+ TQ_LOCAL_WINDOW_SIZE * 64);
+
+ if ((tmp_gw_factor > max_gw_factor) ||
+ ((tmp_gw_factor == max_gw_factor) &&
+ (gw_node->orig_node->router->tq_avg > max_tq)))
+ curr_gw_tmp = gw_node;
+ break;
+
+ default: /**
+ * 2: stable connection (use best statistic)
+ * 3: fast-switch (use best statistic but change as
+ * soon as a better gateway appears)
+ * XX: late-switch (use best statistic but change as
+ * soon as a better gateway appears which has
+ * $routing_class more tq points)
+ **/
+ if (gw_node->orig_node->router->tq_avg > max_tq)
+ curr_gw_tmp = gw_node;
+ break;
+ }
+
+ if (gw_node->orig_node->router->tq_avg > max_tq)
+ max_tq = gw_node->orig_node->router->tq_avg;
+
+ if (tmp_gw_factor > max_gw_factor)
+ max_gw_factor = tmp_gw_factor;
+ }
+ rcu_read_unlock();
+
+ spin_lock(&curr_gw_lock);
+ if (curr_gateway != curr_gw_tmp) {
+ if ((curr_gateway) && (!curr_gw_tmp))
+ bat_dbg(DBG_BATMAN,
+ "Removing selected gateway - no gateway in range\n");
+ else if ((!curr_gateway) && (curr_gw_tmp))
+ bat_dbg(DBG_BATMAN,
+ "Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
+ curr_gw_tmp->orig_node->orig,
+ curr_gw_tmp->orig_node->gw_flags,
+ curr_gw_tmp->orig_node->router->tq_avg);
+ else
+ bat_dbg(DBG_BATMAN,
+ "Changing route to gateway %pM (gw_flags: %i, tq: %i)\n",
+ curr_gw_tmp->orig_node->orig,
+ curr_gw_tmp->orig_node->gw_flags,
+ curr_gw_tmp->orig_node->router->tq_avg);
+
+ curr_gateway = curr_gw_tmp;
+ }
+ spin_unlock(&curr_gw_lock);
+}
+
+void gw_check_election(struct orig_node *orig_node)
+{
+ struct gw_node *curr_gateway_tmp;
+ uint8_t gw_tq_avg, orig_tq_avg;
+
+ spin_lock(&curr_gw_lock);
+ curr_gateway_tmp = curr_gateway;
+ spin_unlock(&curr_gw_lock);
+
+ if (!curr_gateway_tmp)
+ return;
+
+ /* this node already is the gateway */
+ if (curr_gateway_tmp->orig_node == orig_node)
+ return;
+
+ if (!orig_node->router)
+ return;
+
+ gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg;
+ orig_tq_avg = orig_node->router->tq_avg;
+
+ /* the TQ value has to be better */
+ if (orig_tq_avg < gw_tq_avg)
+ return;
+
+ /**
+ * if the routing class is greater than 3 the value tells us how much
+ * greater the TQ value of the new gateway must be
+ **/
+ if ((atomic_read(&gw_clnt_class) > 3) &&
+ (orig_tq_avg - gw_tq_avg < atomic_read(&gw_clnt_class)))
+ return;
+
+ bat_dbg(DBG_BATMAN,
+ "Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i) \n",
+ gw_tq_avg, orig_tq_avg);
+
+ gw_deselect();
+}
+
+static void gw_node_add(struct orig_node *orig_node, uint8_t new_gwflags)
+{
+ struct gw_node *gw_node;
+ int down, up;
+
+ gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC);
+ if (!gw_node)
+ return;
+
+ memset(gw_node, 0, sizeof(struct gw_node));
+ INIT_LIST_HEAD(&gw_node->list);
+ gw_node->orig_node = orig_node;
+
+ list_add_tail_rcu(&gw_node->list, &gw_list);
+
+ gw_srv_class_to_kbit(new_gwflags, &down, &up);
+ bat_dbg(DBG_BATMAN,
+ "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"));
+}
+
+void gw_node_update(struct orig_node *orig_node, uint8_t new_gwflags)
+{
+ struct gw_node *gw_node;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(gw_node, &gw_list, list) {
+ if (gw_node->orig_node != orig_node)
+ continue;
+
+ bat_dbg(DBG_BATMAN,
+ "Gateway class of originator %pM changed from %i to %i\n",
+ orig_node->orig, gw_node->orig_node->gw_flags,
+ new_gwflags);
+
+ gw_node->deleted = 0;
+
+ if (new_gwflags == 0) {
+ gw_node->deleted = jiffies;
+ bat_dbg(DBG_BATMAN,
+ "Gateway %pM removed from gateway list\n",
+ orig_node->orig);
+
+ if (gw_node == curr_gateway)
+ gw_deselect();
+ }
+
+ return;
+ }
+ rcu_read_unlock();
+
+ if (new_gwflags == 0)
+ return;
+
+ gw_node_add(orig_node, new_gwflags);
+}
+
+void gw_node_delete(struct orig_node *orig_node)
+{
+ return gw_node_update(orig_node, 0);
+}
+
+static void gw_node_free(struct rcu_head *rcu)
+{
+ struct gw_node *gw_node = container_of(rcu, struct gw_node, rcu);
+ kfree(gw_node);
+}
+
+void gw_node_purge_deleted(void)
+{
+ struct gw_node *gw_node, *gw_node_tmp;
+ unsigned long timeout = (2 * PURGE_TIMEOUT * HZ) / 1000;
+
+ spin_lock(&gw_list_lock);
+
+ list_for_each_entry_safe(gw_node, gw_node_tmp, &gw_list, list) {
+ if ((gw_node->deleted) &&
+ (time_after(jiffies, gw_node->deleted + timeout))) {
+
+ list_del_rcu(&gw_node->list);
+ call_rcu(&gw_node->rcu, gw_node_free);
+ }
+ }
+
+ spin_unlock(&gw_list_lock);
+}
+
+void gw_node_list_free(void)
+{
+ struct gw_node *gw_node, *gw_node_tmp;
+
+ spin_lock(&gw_list_lock);
+
+ list_for_each_entry_safe(gw_node, gw_node_tmp, &gw_list, list) {
+ list_del_rcu(&gw_node->list);
+ call_rcu(&gw_node->rcu, gw_node_free);
+ }
+
+ gw_deselect();
+ spin_unlock(&gw_list_lock);
+}
+
+static int _write_buffer_text(unsigned char *buff, int bytes_written,
+ struct gw_node *gw_node)
+{
+ int down, up;
+ char gw_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
+
+ addr_to_string(gw_str, gw_node->orig_node->orig);
+ addr_to_string(router_str, gw_node->orig_node->router->addr);
+ gw_srv_class_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
+
+ return sprintf(buff + bytes_written,
+ "%s %-17s (%3i) %17s [%10s]: %3i - %i%s/%i%s\n",
+ (curr_gateway == gw_node ? "=>" : " "),
+ gw_str,
+ gw_node->orig_node->router->tq_avg,
+ router_str,
+ gw_node->orig_node->router->if_incoming->dev,
+ gw_node->orig_node->gw_flags,
+ (down > 2048 ? down / 1024 : down),
+ (down > 2048 ? "MBit" : "KBit"),
+ (up > 2048 ? up / 1024 : up),
+ (up > 2048 ? "MBit" : "KBit"));
+}
+
+int gw_client_fill_buffer_text(unsigned char *buff, int buff_len)
+{
+ struct gw_node *gw_node;
+ int bytes_written = 0, gw_count = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(gw_node, &gw_list, list) {
+ if (gw_node->deleted)
+ continue;
+
+ if (!gw_node->orig_node->router)
+ continue;
+
+ if (buff_len < bytes_written + (2 * ETH_STR_LEN) + 30)
+ break;
+
+ bytes_written += _write_buffer_text(buff,
+ bytes_written,
+ gw_node);
+ gw_count++;
+ }
+ rcu_read_unlock();
+
+ if (gw_count == 0)
+ sprintf(buff, "No gateways in range ... \n");
+
+ return bytes_written;
+}
new file mode 100644
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 B.A.T.M.A.N. contributors:
+ * 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
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+extern atomic_t gw_clnt_class;
+
+void gw_deselect(void);
+void gw_election(void);
+void gw_check_election(struct orig_node *orig_node);
+void gw_node_update(struct orig_node *orig_node, uint8_t new_gwflags);
+void gw_node_delete(struct orig_node *orig_node);
+void gw_node_purge_deleted(void);
+void gw_node_list_free(void);
+int gw_client_fill_buffer_text(unsigned char *buff, int buff_len);
new file mode 100644
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2009 B.A.T.M.A.N. contributors:
+ * 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
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "main.h"
+#include "gateway_common.h"
+#include "gateway_client.h"
+
+atomic_t gw_mode;
+atomic_t gw_srv_class;
+
+/* calculates the gateway class from kbit */
+void kbit_to_gw_srv_class(int down, int up, long *gw_srv_class)
+{
+ int mdown = 0, tdown, tup, difference;
+ uint8_t sbit, part;
+
+ *gw_srv_class = 0;
+ difference = 0x0FFFFFFF;
+
+ /* test all downspeeds */
+ for (sbit = 0; sbit < 2; sbit++) {
+ for (part = 0; part < 16; part++) {
+ tdown = 32 * (sbit + 2) * (1 << part);
+
+ if (abs(tdown - down) < difference) {
+ *gw_srv_class = (sbit << 7) + (part << 3);
+ difference = abs(tdown - down);
+ mdown = tdown;
+ }
+ }
+ }
+
+ /* test all upspeeds */
+ difference = 0x0FFFFFFF;
+
+ for (part = 0; part < 8; part++) {
+ tup = ((part + 1) * (mdown)) / 8;
+
+ if (abs(tup - up) < difference) {
+ *gw_srv_class = (*gw_srv_class & 0xF8) | part;
+ difference = abs(tup - up);
+ }
+ }
+}
+
+/* returns the up and downspeeds in kbit, calculated from the class */
+void gw_srv_class_to_kbit(uint8_t gw_srv_class, int *down, int *up)
+{
+ char sbit = (gw_srv_class & 0x80) >> 7;
+ char dpart = (gw_srv_class & 0x7C) >> 3;
+ char upart = (gw_srv_class & 0x07);
+
+ if (!gw_srv_class) {
+ *down = 0;
+ *up = 0;
+ return;
+ }
+
+ *down = 32 * (sbit + 2) * (1 << dpart);
+ *up = ((upart + 1) * (*down)) / 8;
+}
+
+static bool parse_gw_mode_tok(char *tokptr, long *gw_mode_tmp,
+ char **gw_mode_tmp_str, long *gw_clnt_class_tmp,
+ long *up, long *down)
+{
+ int ret;
+ char *slash_ptr, *tmp_ptr;
+
+ switch (*gw_mode_tmp) {
+ case GW_MODE_CLIENT:
+ ret = strict_strtol(tokptr, 10, gw_clnt_class_tmp);
+ if (ret) {
+ printk(KERN_ERR "Client class of gateway mode invalid: %s\n",
+ tokptr);
+ return false;
+ }
+
+ if (*gw_clnt_class_tmp > TQ_MAX_VALUE) {
+ printk(KERN_ERR "Client class of gateway mode greater than %i: %ld\n",
+ TQ_MAX_VALUE, *gw_clnt_class_tmp);
+ return false;
+ }
+
+ break;
+ case GW_MODE_SERVER:
+ slash_ptr = strchr(tokptr, '/');
+ if (slash_ptr)
+ *slash_ptr = 0;
+
+ ret = strict_strtol(tokptr, 10, down);
+ if (ret) {
+ printk(KERN_ERR "Download speed of gateway mode invalid: %s\n",
+ tokptr);
+ return false;
+ }
+
+ tmp_ptr = tokptr + strlen(tokptr) - 4;
+
+ if ((strlen(tokptr) > 4) &&
+ ((strncmp(tmp_ptr, "MBit", 4) == 0) ||
+ (strncmp(tmp_ptr, "mbit", 4) == 0) ||
+ (strncmp(tmp_ptr, "Mbit", 4) == 0)))
+ *down *= 1024;
+
+ /* we also got some upload info */
+ if (slash_ptr) {
+ ret = strict_strtol(slash_ptr + 1, 10, up);
+ if (ret) {
+ printk(KERN_ERR "Upload speed of gateway mode invalid: %s\n",
+ slash_ptr + 1);
+ return false;
+ }
+
+ tmp_ptr = slash_ptr + 1 + strlen(slash_ptr + 1) - 4;
+
+ if ((strlen(slash_ptr + 1) > 4) &&
+ ((strncmp(tmp_ptr, "MBit", 4) == 0) ||
+ (strncmp(tmp_ptr, "mbit", 4) == 0) ||
+ (strncmp(tmp_ptr, "Mbit", 4) == 0)))
+ *up *= 1024;
+
+ *slash_ptr = '/';
+ }
+
+ break;
+ default:
+ if (strcmp(tokptr, GW_MODE_OFF_NAME) == 0) {
+ *gw_mode_tmp = GW_MODE_OFF;
+ *gw_mode_tmp_str = GW_MODE_OFF_NAME;
+ }
+
+ if (strcmp(tokptr, GW_MODE_CLIENT_NAME) == 0) {
+ *gw_mode_tmp = GW_MODE_CLIENT;
+ *gw_mode_tmp_str = GW_MODE_CLIENT_NAME;
+ }
+
+ if (strcmp(tokptr, GW_MODE_SERVER_NAME) == 0) {
+ *gw_mode_tmp = GW_MODE_SERVER;
+ *gw_mode_tmp_str = GW_MODE_SERVER_NAME;
+ }
+ }
+
+ return true;
+}
+
+ssize_t gw_mode_set(const char __user *userbuffer, size_t count)
+{
+ char *gw_mode_string, *tokptr, *cp;
+ char *gw_mode_curr_str, *gw_mode_tmp_str = NULL;
+ int finished, not_copied = 0;
+ long gw_mode_curr, gw_mode_tmp = GW_MODE_OFF;
+ long gw_srv_class_tmp = 0, gw_clnt_class_tmp = 0, up = 0, down = 0;
+ bool ret;
+
+ gw_mode_string = kmalloc(count, GFP_KERNEL);
+
+ if (!gw_mode_string)
+ return -ENOMEM;
+
+ not_copied = copy_from_user(gw_mode_string, userbuffer, count);
+ gw_mode_string[count - not_copied - 1] = 0;
+
+ tokptr = gw_mode_string;
+ gw_mode_curr = atomic_read(&gw_mode);
+
+ for (cp = gw_mode_string, finished = 0; !finished; cp++) {
+ switch (*cp) {
+ case 0:
+ finished = 1;
+ case ' ':
+ case '\n':
+ case '\t':
+ *cp = 0;
+ ret = parse_gw_mode_tok(tokptr, &gw_mode_tmp,
+ &gw_mode_tmp_str,
+ &gw_clnt_class_tmp,
+ &up, &down);
+
+ if (!ret)
+ goto end;
+
+ tokptr = cp + 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!gw_mode_tmp_str) {
+ printk(KERN_INFO "Gateway mode can only be set to: '%s', '%s' or '%s' - given value: %s\n",
+ GW_MODE_OFF_NAME, GW_MODE_CLIENT_NAME,
+ GW_MODE_SERVER_NAME, gw_mode_string);
+ goto end;
+ }
+
+ switch (gw_mode_curr) {
+ case GW_MODE_CLIENT:
+ gw_mode_curr_str = GW_MODE_CLIENT_NAME;
+ break;
+ case GW_MODE_SERVER:
+ gw_mode_curr_str = GW_MODE_SERVER_NAME;
+ break;
+ default:
+ gw_mode_curr_str = GW_MODE_OFF_NAME;
+ break;
+ }
+
+ switch (gw_mode_tmp) {
+ case GW_MODE_CLIENT:
+ if ((gw_mode_tmp == GW_MODE_CLIENT) && (!gw_clnt_class_tmp))
+ gw_clnt_class_tmp = 20;
+
+ printk(KERN_INFO "Changing gateway mode from: '%s' to: '%s' (gw_clnt_class: %ld)\n",
+ gw_mode_curr_str, gw_mode_tmp_str,
+ gw_clnt_class_tmp);
+ break;
+ case GW_MODE_SERVER:
+ if (!down)
+ down = 2000;
+
+ if (!up)
+ up = down / 5;
+
+ kbit_to_gw_srv_class(down, up, &gw_srv_class_tmp);
+
+ /**
+ * the gw class we guessed above might not match the given
+ * speeds, hence we need to calculate it back to show the
+ * number that is going to be propagated
+ **/
+ gw_srv_class_to_kbit((uint8_t)gw_srv_class_tmp,
+ (int *)&down, (int *)&up);
+
+ printk(KERN_INFO
+ "Changing gateway mode from: '%s' to: '%s' (gw_srv_class: %ld -> propagating: %ld%s/%ld%s)\n",
+ gw_mode_curr_str, gw_mode_tmp_str,
+ gw_srv_class_tmp,
+ (down > 2048 ? down / 1024 : down),
+ (down > 2048 ? "MBit" : "KBit"),
+ (up > 2048 ? up / 1024 : up),
+ (up > 2048 ? "MBit" : "KBit"));
+ break;
+ default:
+ printk(KERN_INFO "Changing gateway mode from: '%s' to: '%s'\n",
+ gw_mode_curr_str, gw_mode_tmp_str);
+ break;
+ }
+
+ atomic_set(&gw_mode, gw_mode_tmp);
+ atomic_set(&gw_srv_class, gw_srv_class_tmp);
+ atomic_set(&gw_clnt_class, gw_clnt_class_tmp);
+
+ if (gw_clnt_class_tmp == 0)
+ gw_deselect();
+
+end:
+ kfree(gw_mode_string);
+ return count;
+}
new file mode 100644
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 B.A.T.M.A.N. contributors:
+ * 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
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+enum gw_modes {
+ GW_MODE_OFF,
+ GW_MODE_CLIENT,
+ GW_MODE_SERVER,
+};
+
+#define GW_MODE_OFF_NAME "off"
+#define GW_MODE_CLIENT_NAME "client"
+#define GW_MODE_SERVER_NAME "server"
+
+extern atomic_t gw_mode;
+extern atomic_t gw_srv_class;
+
+void gw_srv_class_to_kbit(uint8_t gw_class, int *down, int *up);
+ssize_t gw_mode_set(const char __user *userbuffer, size_t count);
@@ -28,6 +28,8 @@
#include "device.h"
#include "translation-table.h"
#include "hard-interface.h"
+#include "gateway_common.h"
+#include "gateway_client.h"
#include "types.h"
#include "vis.h"
#include "hash.h"
@@ -85,6 +87,9 @@ int init_module(void)
atomic_set(&vis_interval, 1000);/* TODO: raise this later, this is only
* for debugging now. */
atomic_set(&aggregation_enabled, 1);
+ atomic_set(&gw_mode, GW_MODE_OFF);
+ atomic_set(&gw_srv_class, 0);
+ atomic_set(&gw_clnt_class, 0);
/* the name should not be longer than 10 chars - see
* http://lwn.net/Articles/23634/ */
@@ -191,6 +196,7 @@ void shutdown_module(void)
/* TODO: unregister BATMAN pack */
+ gw_node_list_free();
originator_free();
hna_local_free();
@@ -27,7 +27,7 @@
#include "translation-table.h"
#include "routing.h"
#include "compat.h"
-
+#include "gateway_client.h"
static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig);
@@ -241,6 +241,8 @@ void purge_orig(struct work_struct *work)
while (hash_iterate(orig_hash, &hashit)) {
orig_node = hashit.bucket->data;
if (purge_orig_node(orig_node)) {
+ if (orig_node->gw_flags)
+ gw_node_delete(orig_node);
hash_remove_bucket(orig_hash, &hashit);
free_orig_node(orig_node);
}
@@ -248,5 +250,7 @@ void purge_orig(struct work_struct *work)
spin_unlock_irqrestore(&orig_hash_lock, flags);
+ gw_node_purge_deleted();
+ gw_election();
start_purge_timer();
}
@@ -28,7 +28,7 @@
#define BAT_VIS 0x05
/* this file is included by batctl which needs these defines */
-#define COMPAT_VERSION 8
+#define COMPAT_VERSION 9
#define DIRECTLINK 0x40
#define VIS_SERVER 0x20
@@ -53,6 +53,8 @@ struct batman_packet {
uint8_t prev_sender[6];
uint8_t ttl;
uint8_t num_hna;
+ uint8_t gw_flags; /* flags related to gateway class */
+ uint8_t align;
} __attribute__((packed));
#define BAT_PACKET_LEN sizeof(struct batman_packet)
@@ -28,6 +28,8 @@
#include "hash.h"
#include "vis.h"
#include "compat.h"
+#include "gateway_common.h"
+#include "gateway_client.h"
static struct proc_dir_entry *proc_batman_dir, *proc_interface_file;
static struct proc_dir_entry *proc_orig_interval_file, *proc_originators_file;
@@ -35,6 +37,7 @@ static struct proc_dir_entry *proc_transt_local_file;
static struct proc_dir_entry *proc_transt_global_file;
static struct proc_dir_entry *proc_vis_srv_file, *proc_vis_data_file;
static struct proc_dir_entry *proc_aggr_file;
+static struct proc_dir_entry *proc_gw_mode_file, *proc_gw_srv_list_file;
static int proc_interfaces_read(struct seq_file *seq, void *offset)
{
@@ -462,6 +465,99 @@ static int proc_aggr_open(struct inode *inode, struct file *file)
return single_open(file, proc_aggr_read, NULL);
}
+static int proc_gw_mode_read(struct seq_file *seq, void *offset)
+{
+ int down, up;
+ long gw_mode_curr = atomic_read(&gw_mode);
+ uint8_t gw_srv_class_curr = (uint8_t)atomic_read(&gw_srv_class);
+
+ gw_srv_class_to_kbit(gw_srv_class_curr, &down, &up);
+
+ seq_printf(seq, "[%c] %s\n",
+ (gw_mode_curr == GW_MODE_OFF) ? 'x' : ' ',
+ GW_MODE_OFF_NAME);
+
+ if (gw_mode_curr == GW_MODE_CLIENT)
+ seq_printf(seq, "[x] %s (gw_clnt_class: %i)\n",
+ GW_MODE_CLIENT_NAME,
+ atomic_read(&gw_clnt_class));
+ else
+ seq_printf(seq, "[ ] %s\n", GW_MODE_CLIENT_NAME);
+
+ if (gw_mode_curr == GW_MODE_SERVER)
+ seq_printf(seq,
+ "[x] %s (gw_srv_class: %i -> propagating: %i%s/%i%s)\n",
+ GW_MODE_SERVER_NAME,
+ gw_srv_class_curr,
+ (down > 2048 ? down / 1024 : down),
+ (down > 2048 ? "MBit" : "KBit"),
+ (up > 2048 ? up / 1024 : up),
+ (up > 2048 ? "MBit" : "KBit"));
+ else
+ seq_printf(seq, "[ ] %s\n", GW_MODE_SERVER_NAME);
+
+ return 0;
+}
+
+static int proc_gw_mode_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_gw_mode_read, NULL);
+}
+
+static ssize_t proc_gw_mode_write(struct file *instance,
+ const char __user *userbuffer,
+ size_t count, loff_t *data)
+{
+ return gw_mode_set(userbuffer, count);
+}
+
+static int proc_gw_srv_list_read(struct seq_file *seq, void *offset)
+{
+ char *buff;
+ int buffsize = 4096;
+
+ buff = kmalloc(buffsize, GFP_KERNEL);
+ if (!buff)
+ return 0;
+
+ rcu_read_lock();
+ if (list_empty(&if_list)) {
+ rcu_read_unlock();
+ seq_printf(seq,
+ "BATMAN disabled - please specify interfaces to enable it\n");
+ goto end;
+ }
+
+ if (((struct batman_if *)if_list.next)->if_active != IF_ACTIVE) {
+ rcu_read_unlock();
+ seq_printf(seq,
+ "BATMAN disabled - primary interface not active\n");
+ goto end;
+ }
+
+ seq_printf(seq,
+ " %-12s (%s/%i) %17s [%10s]: gw_srv_class ... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s] \n",
+ "Gateway", "#", TQ_MAX_VALUE, "Nexthop",
+ "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
+ ((struct batman_if *)if_list.next)->dev,
+ ((struct batman_if *)if_list.next)->addr_str);
+
+ rcu_read_unlock();
+
+ gw_client_fill_buffer_text(buff, buffsize);
+ seq_printf(seq, "%s", buff);
+
+end:
+ kfree(buff);
+ return 0;
+}
+
+static int proc_gw_srv_list_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_gw_srv_list_read, NULL);
+}
+
+
/* satisfying different prototypes ... */
static ssize_t proc_dummy_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
@@ -469,6 +565,24 @@ static ssize_t proc_dummy_write(struct file *file, const char __user *buffer,
return count;
}
+static const struct file_operations proc_gw_srv_list_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_gw_srv_list_open,
+ .read = seq_read,
+ .write = proc_dummy_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations proc_gw_mode_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_gw_mode_open,
+ .read = seq_read,
+ .write = proc_gw_mode_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static const struct file_operations proc_aggr_fops = {
.owner = THIS_MODULE,
.open = proc_aggr_open,
@@ -567,6 +681,12 @@ void cleanup_procfs(void)
if (proc_aggr_file)
remove_proc_entry(PROC_FILE_AGGR, proc_batman_dir);
+ if (proc_gw_mode_file)
+ remove_proc_entry(PROC_FILE_GW_MODE, proc_batman_dir);
+
+ if (proc_gw_srv_list_file)
+ remove_proc_entry(PROC_FILE_GW_SRV_LIST, proc_batman_dir);
+
if (proc_batman_dir)
#ifdef __NET_NET_NAMESPACE_H
remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net);
@@ -671,5 +791,29 @@ int setup_procfs(void)
return -EFAULT;
}
+ proc_gw_mode_file = create_proc_entry(PROC_FILE_GW_MODE,
+ S_IWUSR | S_IRUGO,
+ proc_batman_dir);
+ if (proc_gw_mode_file) {
+ proc_gw_mode_file->proc_fops = &proc_gw_mode_fops;
+ } else {
+ printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n",
+ PROC_ROOT_DIR, PROC_FILE_GW_MODE);
+ cleanup_procfs();
+ return -EFAULT;
+ }
+
+ proc_gw_srv_list_file = create_proc_entry(PROC_FILE_GW_SRV_LIST,
+ S_IWUSR | S_IRUGO,
+ proc_batman_dir);
+ if (proc_gw_srv_list_file) {
+ proc_gw_srv_list_file->proc_fops = &proc_gw_srv_list_fops;
+ } else {
+ printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n",
+ PROC_ROOT_DIR, PROC_FILE_GW_SRV_LIST);
+ cleanup_procfs();
+ return -EFAULT;
+ }
+
return 0;
}
@@ -34,6 +34,8 @@
#define PROC_FILE_VIS_SRV "vis_server"
#define PROC_FILE_VIS_DATA "vis_data"
#define PROC_FILE_AGGR "aggregate_ogm"
+#define PROC_FILE_GW_MODE "gateway_mode"
+#define PROC_FILE_GW_SRV_LIST "gateway_srv_list"
void cleanup_procfs(void);
int setup_procfs(void);
@@ -33,6 +33,7 @@
#include "vis.h"
#include "aggregation.h"
#include "compat.h"
+#include "gateway_client.h"
DECLARE_WAIT_QUEUE_HEAD(thread_wait);
@@ -306,10 +307,20 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr,
goto update_hna;
update_routes(orig_node, neigh_node, hna_buff, tmp_hna_buff_len);
- return;
+ goto update_gw;
update_hna:
update_routes(orig_node, orig_node->router, hna_buff, tmp_hna_buff_len);
+
+update_gw:
+ if (orig_node->gw_flags != batman_packet->gw_flags)
+ gw_node_update(orig_node, batman_packet->gw_flags);
+
+ orig_node->gw_flags = batman_packet->gw_flags;
+
+ /* restart gateway selection if fast or late switching was enabled */
+ if ((orig_node->gw_flags) && (atomic_read(&gw_clnt_class) > 2))
+ gw_check_election(orig_node);
}
static char count_real_packets(struct ethhdr *ethhdr,
@@ -28,6 +28,7 @@
#include "types.h"
#include "vis.h"
#include "aggregation.h"
+#include "gateway_common.h"
#include "compat.h"
@@ -279,6 +280,8 @@ void schedule_own_packet(struct batman_if *batman_if)
else
batman_packet->flags = 0;
+ batman_packet->gw_flags = (uint8_t)atomic_read(&gw_srv_class);
+
/* could be read by receive_bat_packet() */
atomic_inc(&batman_if->seqno);
@@ -43,7 +43,6 @@ struct batman_if {
unsigned char *packet_buff;
int packet_len;
struct rcu_head rcu;
-
};
struct orig_node { /* structure for orig_list maintaining nodes of mesh */
@@ -55,10 +54,10 @@ struct orig_node { /* structure for orig_list maintaining nodes of
uint8_t tq_own;
int tq_asym_penalty;
unsigned long last_valid; /* when last packet from this node was received */
-/* uint8_t gwflags; * flags related to gateway functions: gateway class */
- uint8_t flags; /* for now only VIS_SERVER flag. */
+ uint8_t gw_flags; /* flags related to gateway class */
+ uint8_t flags; /* for now only VIS_SERVER flag. */
unsigned char *hna_buff;
- int16_t hna_buff_len;
+ int16_t hna_buff_len;
uint16_t last_real_seqno; /* last and best known squence number */
uint8_t last_ttl; /* ttl of last received packet */
TYPE_OF_WORD bcast_bits[NUM_WORDS];
@@ -66,6 +65,13 @@ struct orig_node { /* structure for orig_list maintaining nodes of
struct list_head neigh_list;
};
+struct gw_node {
+ struct list_head list;
+ struct orig_node *orig_node;
+ unsigned long deleted;
+ struct rcu_head rcu;
+};
+
struct neigh_node {
struct list_head list;
uint8_t addr[ETH_ALEN];