You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
net: Add batman-adv meshing protocol
B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is a routing protocol for multi-hop ad-hoc mesh networks. The networks may be wired or wireless. See http://www.open-mesh.org/ for more information and user space tools. Signed-off-by: Sven Eckelmann <sven@narfation.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
b236da6931
commit
c6c8fea297
14
Documentation/ABI/testing/sysfs-class-net-batman-adv
Normal file
14
Documentation/ABI/testing/sysfs-class-net-batman-adv
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
What: /sys/class/net/<iface>/batman-adv/mesh_iface
|
||||
Date: May 2010
|
||||
Contact: Marek Lindner <lindner_marek@yahoo.de>
|
||||
Description:
|
||||
The /sys/class/net/<iface>/batman-adv/mesh_iface file
|
||||
displays the batman mesh interface this <iface>
|
||||
currently is associated with.
|
||||
|
||||
What: /sys/class/net/<iface>/batman-adv/iface_status
|
||||
Date: May 2010
|
||||
Contact: Marek Lindner <lindner_marek@yahoo.de>
|
||||
Description:
|
||||
Indicates the status of <iface> as it is seen by batman.
|
||||
69
Documentation/ABI/testing/sysfs-class-net-mesh
Normal file
69
Documentation/ABI/testing/sysfs-class-net-mesh
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/aggregated_ogms
|
||||
Date: May 2010
|
||||
Contact: Marek Lindner <lindner_marek@yahoo.de>
|
||||
Description:
|
||||
Indicates whether the batman protocol messages of the
|
||||
mesh <mesh_iface> shall be aggregated or not.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/bonding
|
||||
Date: June 2010
|
||||
Contact: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
|
||||
Description:
|
||||
Indicates whether the data traffic going through the
|
||||
mesh will be sent using multiple interfaces at the
|
||||
same time (if available).
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/fragmentation
|
||||
Date: October 2010
|
||||
Contact: Andreas Langer <an.langer@gmx.de>
|
||||
Description:
|
||||
Indicates whether the data traffic going through the
|
||||
mesh will be fragmented or silently discarded if the
|
||||
packet size exceeds the outgoing interface MTU.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/gw_bandwidth
|
||||
Date: October 2010
|
||||
Contact: Marek Lindner <lindner_marek@yahoo.de>
|
||||
Description:
|
||||
Defines the bandwidth which is propagated by this
|
||||
node if gw_mode was set to 'server'.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/gw_mode
|
||||
Date: October 2010
|
||||
Contact: Marek Lindner <lindner_marek@yahoo.de>
|
||||
Description:
|
||||
Defines the state of the gateway features. Can be
|
||||
either 'off', 'client' or 'server'.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/gw_sel_class
|
||||
Date: October 2010
|
||||
Contact: Marek Lindner <lindner_marek@yahoo.de>
|
||||
Description:
|
||||
Defines the selection criteria this node will use
|
||||
to choose a gateway if gw_mode was set to 'client'.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/orig_interval
|
||||
Date: May 2010
|
||||
Contact: Marek Lindner <lindner_marek@yahoo.de>
|
||||
Description:
|
||||
Defines the interval in milliseconds in which batman
|
||||
sends its protocol messages.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/hop_penalty
|
||||
Date: Oct 2010
|
||||
Contact: Linus Lüssing <linus.luessing@web.de>
|
||||
Description:
|
||||
Defines the penalty which will be applied to an
|
||||
originator message's tq-field on every hop.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/vis_mode
|
||||
Date: May 2010
|
||||
Contact: Marek Lindner <lindner_marek@yahoo.de>
|
||||
Description:
|
||||
Each batman node only maintains information about its
|
||||
own local neighborhood, therefore generating graphs
|
||||
showing the topology of the entire mesh is not easily
|
||||
feasible without having a central instance to collect
|
||||
the local topologies from all nodes. This file allows
|
||||
to activate the collecting (server) mode.
|
||||
240
Documentation/networking/batman-adv.txt
Normal file
240
Documentation/networking/batman-adv.txt
Normal file
@@ -0,0 +1,240 @@
|
||||
[state: 21-11-2010]
|
||||
|
||||
BATMAN-ADV
|
||||
----------
|
||||
|
||||
Batman advanced is a new approach to wireless networking which
|
||||
does no longer operate on the IP basis. Unlike the batman daemon,
|
||||
which exchanges information using UDP packets and sets routing
|
||||
tables, batman-advanced operates on ISO/OSI Layer 2 only and uses
|
||||
and routes (or better: bridges) Ethernet Frames. It emulates a
|
||||
virtual network switch of all nodes participating. Therefore all
|
||||
nodes appear to be link local, thus all higher operating proto-
|
||||
cols won't be affected by any changes within the network. You can
|
||||
run almost any protocol above batman advanced, prominent examples
|
||||
are: IPv4, IPv6, DHCP, IPX.
|
||||
|
||||
Batman advanced was implemented as a Linux kernel driver to re-
|
||||
duce the overhead to a minimum. It does not depend on any (other)
|
||||
network driver, and can be used on wifi as well as ethernet lan,
|
||||
vpn, etc ... (anything with ethernet-style layer 2).
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
|
||||
Load the batman-adv module into your kernel:
|
||||
|
||||
# insmod batman-adv.ko
|
||||
|
||||
The module is now waiting for activation. You must add some in-
|
||||
terfaces on which batman can operate. After loading the module
|
||||
batman advanced will scan your systems interfaces to search for
|
||||
compatible interfaces. Once found, it will create subfolders in
|
||||
the /sys directories of each supported interface, e.g.
|
||||
|
||||
# ls /sys/class/net/eth0/batman_adv/
|
||||
# iface_status mesh_iface
|
||||
|
||||
If an interface does not have the "batman_adv" subfolder it prob-
|
||||
ably is not supported. Not supported interfaces are: loopback,
|
||||
non-ethernet and batman's own interfaces.
|
||||
|
||||
Note: After the module was loaded it will continuously watch for
|
||||
new interfaces to verify the compatibility. There is no need to
|
||||
reload the module if you plug your USB wifi adapter into your ma-
|
||||
chine after batman advanced was initially loaded.
|
||||
|
||||
To activate a given interface simply write "bat0" into its
|
||||
"mesh_iface" file inside the batman_adv subfolder:
|
||||
|
||||
# echo bat0 > /sys/class/net/eth0/batman_adv/mesh_iface
|
||||
|
||||
Repeat this step for all interfaces you wish to add. Now batman
|
||||
starts using/broadcasting on this/these interface(s).
|
||||
|
||||
By reading the "iface_status" file you can check its status:
|
||||
|
||||
# cat /sys/class/net/eth0/batman_adv/iface_status
|
||||
# active
|
||||
|
||||
To deactivate an interface you have to write "none" into its
|
||||
"mesh_iface" file:
|
||||
|
||||
# echo none > /sys/class/net/eth0/batman_adv/mesh_iface
|
||||
|
||||
|
||||
All mesh wide settings can be found in batman's own interface
|
||||
folder:
|
||||
|
||||
# ls /sys/class/net/bat0/mesh/
|
||||
# aggregated_ogms bonding fragmentation orig_interval
|
||||
# vis_mode
|
||||
|
||||
|
||||
There is a special folder for debugging informations:
|
||||
|
||||
# ls /sys/kernel/debug/batman_adv/bat0/
|
||||
# originators socket transtable_global transtable_local
|
||||
# vis_data
|
||||
|
||||
|
||||
Some of the files contain all sort of status information regard-
|
||||
ing the mesh network. For example, you can view the table of
|
||||
originators (mesh participants) with:
|
||||
|
||||
# cat /sys/kernel/debug/batman_adv/bat0/originators
|
||||
|
||||
Other files allow to change batman's behaviour to better fit your
|
||||
requirements. For instance, you can check the current originator
|
||||
interval (value in milliseconds which determines how often batman
|
||||
sends its broadcast packets):
|
||||
|
||||
# cat /sys/class/net/bat0/mesh/orig_interval
|
||||
# 1000
|
||||
|
||||
and also change its value:
|
||||
|
||||
# echo 3000 > /sys/class/net/bat0/mesh/orig_interval
|
||||
|
||||
In very mobile scenarios, you might want to adjust the originator
|
||||
interval to a lower value. This will make the mesh more respon-
|
||||
sive to topology changes, but will also increase the overhead.
|
||||
|
||||
|
||||
USAGE
|
||||
-----
|
||||
|
||||
To make use of your newly created mesh, batman advanced provides
|
||||
a new interface "bat0" which you should use from this point on.
|
||||
All interfaces added to batman advanced are not relevant any
|
||||
longer because batman handles them for you. Basically, one "hands
|
||||
over" the data by using the batman interface and batman will make
|
||||
sure it reaches its destination.
|
||||
|
||||
The "bat0" interface can be used like any other regular inter-
|
||||
face. It needs an IP address which can be either statically con-
|
||||
figured or dynamically (by using DHCP or similar services):
|
||||
|
||||
# NodeA: ifconfig bat0 192.168.0.1
|
||||
# NodeB: ifconfig bat0 192.168.0.2
|
||||
# NodeB: ping 192.168.0.1
|
||||
|
||||
Note: In order to avoid problems remove all IP addresses previ-
|
||||
ously assigned to interfaces now used by batman advanced, e.g.
|
||||
|
||||
# ifconfig eth0 0.0.0.0
|
||||
|
||||
|
||||
VISUALIZATION
|
||||
-------------
|
||||
|
||||
If you want topology visualization, at least one mesh node must
|
||||
be configured as VIS-server:
|
||||
|
||||
# echo "server" > /sys/class/net/bat0/mesh/vis_mode
|
||||
|
||||
Each node is either configured as "server" or as "client" (de-
|
||||
fault: "client"). Clients send their topology data to the server
|
||||
next to them, and server synchronize with other servers. If there
|
||||
is no server configured (default) within the mesh, no topology
|
||||
information will be transmitted. With these "synchronizing
|
||||
servers", there can be 1 or more vis servers sharing the same (or
|
||||
at least very similar) data.
|
||||
|
||||
When configured as server, you can get a topology snapshot of
|
||||
your mesh:
|
||||
|
||||
# cat /sys/kernel/debug/batman_adv/bat0/vis_data
|
||||
|
||||
This raw output is intended to be easily parsable and convertable
|
||||
with other tools. Have a look at the batctl README if you want a
|
||||
vis output in dot or json format for instance and how those out-
|
||||
puts could then be visualised in an image.
|
||||
|
||||
The raw format consists of comma separated values per entry where
|
||||
each entry is giving information about a certain source inter-
|
||||
face. Each entry can/has to have the following values:
|
||||
-> "mac" - mac address of an originator's source interface
|
||||
(each line begins with it)
|
||||
-> "TQ mac value" - src mac's link quality towards mac address
|
||||
of a neighbor originator's interface which
|
||||
is being used for routing
|
||||
-> "HNA mac" - HNA announced by source mac
|
||||
-> "PRIMARY" - this is a primary interface
|
||||
-> "SEC mac" - secondary mac address of source
|
||||
(requires preceding PRIMARY)
|
||||
|
||||
The TQ value has a range from 4 to 255 with 255 being the best.
|
||||
The HNA entries are showing which hosts are connected to the mesh
|
||||
via bat0 or being bridged into the mesh network. The PRIMARY/SEC
|
||||
values are only applied on primary interfaces
|
||||
|
||||
|
||||
LOGGING/DEBUGGING
|
||||
-----------------
|
||||
|
||||
All error messages, warnings and information messages are sent to
|
||||
the kernel log. Depending on your operating system distribution
|
||||
this can be read in one of a number of ways. Try using the com-
|
||||
mands: dmesg, logread, or looking in the files /var/log/kern.log
|
||||
or /var/log/syslog. All batman-adv messages are prefixed with
|
||||
"batman-adv:" So to see just these messages try
|
||||
|
||||
# dmesg | grep batman-adv
|
||||
|
||||
When investigating problems with your mesh network it is some-
|
||||
times necessary to see more detail debug messages. This must be
|
||||
enabled when compiling the batman-adv module. When building bat-
|
||||
man-adv as part of kernel, use "make menuconfig" and enable the
|
||||
option "B.A.T.M.A.N. debugging".
|
||||
|
||||
Those additional debug messages can be accessed using a special
|
||||
file in debugfs
|
||||
|
||||
# cat /sys/kernel/debug/batman_adv/bat0/log
|
||||
|
||||
The additional debug output is by default disabled. It can be en-
|
||||
abled during run time. Following log_levels are defined:
|
||||
|
||||
0 - All debug output disabled
|
||||
1 - Enable messages related to routing / flooding / broadcasting
|
||||
2 - Enable route or hna added / changed / deleted
|
||||
3 - Enable all messages
|
||||
|
||||
The debug output can be changed at runtime using the file
|
||||
/sys/class/net/bat0/mesh/log_level. e.g.
|
||||
|
||||
# echo 2 > /sys/class/net/bat0/mesh/log_level
|
||||
|
||||
will enable debug messages for when routes or HNAs change.
|
||||
|
||||
|
||||
BATCTL
|
||||
------
|
||||
|
||||
As batman advanced operates on layer 2 all hosts participating in
|
||||
the virtual switch are completely transparent for all protocols
|
||||
above layer 2. Therefore the common diagnosis tools do not work
|
||||
as expected. To overcome these problems batctl was created. At
|
||||
the moment the batctl contains ping, traceroute, tcpdump and
|
||||
interfaces to the kernel module settings.
|
||||
|
||||
For more information, please see the manpage (man batctl).
|
||||
|
||||
batctl is available on http://www.open-mesh.org/
|
||||
|
||||
|
||||
CONTACT
|
||||
-------
|
||||
|
||||
Please send us comments, experiences, questions, anything :)
|
||||
|
||||
IRC: #batman on irc.freenode.org
|
||||
Mailing-list: b.a.t.m.a.n@b.a.t.m.a.n@lists.open-mesh.org
|
||||
(optional subscription at
|
||||
https://lists.open-mesh.org/mm/listinfo/b.a.t.m.a.n)
|
||||
|
||||
You can also contact the Authors:
|
||||
|
||||
Marek Lindner <lindner_marek@yahoo.de>
|
||||
Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
|
||||
@@ -1264,6 +1264,15 @@ S: Maintained
|
||||
F: drivers/video/backlight/
|
||||
F: include/linux/backlight.h
|
||||
|
||||
BATMAN ADVANCED
|
||||
M: Marek Lindner <lindner_marek@yahoo.de>
|
||||
M: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
|
||||
M: Sven Eckelmann <sven@narfation.org>
|
||||
L: b.a.t.m.a.n@lists.open-mesh.org
|
||||
W: http://www.open-mesh.org/
|
||||
S: Maintained
|
||||
F: net/batman-adv/
|
||||
|
||||
BAYCOM/HDLCDRV DRIVERS FOR AX.25
|
||||
M: Thomas Sailer <t.sailer@alumni.ethz.ch>
|
||||
L: linux-hams@vger.kernel.org
|
||||
|
||||
@@ -214,6 +214,7 @@ source "net/ieee802154/Kconfig"
|
||||
source "net/sched/Kconfig"
|
||||
source "net/dcb/Kconfig"
|
||||
source "net/dns_resolver/Kconfig"
|
||||
source "net/batman-adv/Kconfig"
|
||||
|
||||
config RPS
|
||||
boolean
|
||||
|
||||
@@ -69,3 +69,4 @@ endif
|
||||
obj-$(CONFIG_WIMAX) += wimax/
|
||||
obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/
|
||||
obj-$(CONFIG_CEPH_LIB) += ceph/
|
||||
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
|
||||
|
||||
25
net/batman-adv/Kconfig
Normal file
25
net/batman-adv/Kconfig
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# B.A.T.M.A.N meshing protocol
|
||||
#
|
||||
|
||||
config BATMAN_ADV
|
||||
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
|
||||
depends on NET
|
||||
default n
|
||||
---help---
|
||||
|
||||
B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
|
||||
a routing protocol for multi-hop ad-hoc mesh networks. The
|
||||
networks may be wired or wireless. See
|
||||
http://www.open-mesh.org/ for more information and user space
|
||||
tools.
|
||||
|
||||
config BATMAN_ADV_DEBUG
|
||||
bool "B.A.T.M.A.N. debugging"
|
||||
depends on BATMAN_ADV != n
|
||||
---help---
|
||||
|
||||
This is an option for use by developers; most people should
|
||||
say N here. This enables compilation of support for
|
||||
outputting debugging information to the kernel log. The
|
||||
output is controlled via the module parameter debug.
|
||||
39
net/batman-adv/Makefile
Normal file
39
net/batman-adv/Makefile
Normal file
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
|
||||
#
|
||||
# Marek Lindner, Simon Wunderlich
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
|
||||
batman-adv-y += aggregation.o
|
||||
batman-adv-y += bat_debugfs.o
|
||||
batman-adv-y += bat_sysfs.o
|
||||
batman-adv-y += bitarray.o
|
||||
batman-adv-y += gateway_client.o
|
||||
batman-adv-y += gateway_common.o
|
||||
batman-adv-y += hard-interface.o
|
||||
batman-adv-y += hash.o
|
||||
batman-adv-y += icmp_socket.o
|
||||
batman-adv-y += main.o
|
||||
batman-adv-y += originator.o
|
||||
batman-adv-y += ring_buffer.o
|
||||
batman-adv-y += routing.o
|
||||
batman-adv-y += send.o
|
||||
batman-adv-y += soft-interface.o
|
||||
batman-adv-y += translation-table.o
|
||||
batman-adv-y += unicast.o
|
||||
batman-adv-y += vis.o
|
||||
273
net/batman-adv/aggregation.c
Normal file
273
net/batman-adv/aggregation.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
|
||||
*
|
||||
* Marek Lindner, Simon Wunderlich
|
||||
*
|
||||
* 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 "aggregation.h"
|
||||
#include "send.h"
|
||||
#include "routing.h"
|
||||
|
||||
/* calculate the size of the hna information for a given packet */
|
||||
static int hna_len(struct batman_packet *batman_packet)
|
||||
{
|
||||
return batman_packet->num_hna * ETH_ALEN;
|
||||
}
|
||||
|
||||
/* return true if new_packet can be aggregated with forw_packet */
|
||||
static bool can_aggregate_with(struct batman_packet *new_batman_packet,
|
||||
int packet_len,
|
||||
unsigned long send_time,
|
||||
bool directlink,
|
||||
struct batman_if *if_incoming,
|
||||
struct forw_packet *forw_packet)
|
||||
{
|
||||
struct batman_packet *batman_packet =
|
||||
(struct batman_packet *)forw_packet->skb->data;
|
||||
int aggregated_bytes = forw_packet->packet_len + packet_len;
|
||||
|
||||
/**
|
||||
* we can aggregate the current packet to this aggregated packet
|
||||
* if:
|
||||
*
|
||||
* - the send time is within our MAX_AGGREGATION_MS time
|
||||
* - the resulting packet wont be bigger than
|
||||
* MAX_AGGREGATION_BYTES
|
||||
*/
|
||||
|
||||
if (time_before(send_time, forw_packet->send_time) &&
|
||||
time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),
|
||||
forw_packet->send_time) &&
|
||||
(aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
|
||||
|
||||
/**
|
||||
* check aggregation compatibility
|
||||
* -> direct link packets are broadcasted on
|
||||
* their interface only
|
||||
* -> aggregate packet if the current packet is
|
||||
* a "global" packet as well as the base
|
||||
* packet
|
||||
*/
|
||||
|
||||
/* packets without direct link flag and high TTL
|
||||
* are flooded through the net */
|
||||
if ((!directlink) &&
|
||||
(!(batman_packet->flags & DIRECTLINK)) &&
|
||||
(batman_packet->ttl != 1) &&
|
||||
|
||||
/* own packets originating non-primary
|
||||
* interfaces leave only that interface */
|
||||
((!forw_packet->own) ||
|
||||
(forw_packet->if_incoming->if_num == 0)))
|
||||
return true;
|
||||
|
||||
/* if the incoming packet is sent via this one
|
||||
* interface only - we still can aggregate */
|
||||
if ((directlink) &&
|
||||
(new_batman_packet->ttl == 1) &&
|
||||
(forw_packet->if_incoming == if_incoming) &&
|
||||
|
||||
/* packets from direct neighbors or
|
||||
* own secondary interface packets
|
||||
* (= secondary interface packets in general) */
|
||||
(batman_packet->flags & DIRECTLINK ||
|
||||
(forw_packet->own &&
|
||||
forw_packet->if_incoming->if_num != 0)))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
|
||||
/* create a new aggregated packet and add this packet to it */
|
||||
static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
|
||||
unsigned long send_time, bool direct_link,
|
||||
struct batman_if *if_incoming,
|
||||
int own_packet)
|
||||
{
|
||||
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
|
||||
struct forw_packet *forw_packet_aggr;
|
||||
unsigned char *skb_buff;
|
||||
|
||||
/* own packet should always be scheduled */
|
||||
if (!own_packet) {
|
||||
if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
|
||||
bat_dbg(DBG_BATMAN, bat_priv,
|
||||
"batman packet queue full\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
|
||||
if (!forw_packet_aggr) {
|
||||
if (!own_packet)
|
||||
atomic_inc(&bat_priv->batman_queue_left);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((atomic_read(&bat_priv->aggregated_ogms)) &&
|
||||
(packet_len < MAX_AGGREGATION_BYTES))
|
||||
forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +
|
||||
sizeof(struct ethhdr));
|
||||
else
|
||||
forw_packet_aggr->skb = dev_alloc_skb(packet_len +
|
||||
sizeof(struct ethhdr));
|
||||
|
||||
if (!forw_packet_aggr->skb) {
|
||||
if (!own_packet)
|
||||
atomic_inc(&bat_priv->batman_queue_left);
|
||||
kfree(forw_packet_aggr);
|
||||
return;
|
||||
}
|
||||
skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));
|
||||
|
||||
INIT_HLIST_NODE(&forw_packet_aggr->list);
|
||||
|
||||
skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
|
||||
forw_packet_aggr->packet_len = packet_len;
|
||||
memcpy(skb_buff, packet_buff, packet_len);
|
||||
|
||||
forw_packet_aggr->own = own_packet;
|
||||
forw_packet_aggr->if_incoming = if_incoming;
|
||||
forw_packet_aggr->num_packets = 0;
|
||||
forw_packet_aggr->direct_link_flags = 0;
|
||||
forw_packet_aggr->send_time = send_time;
|
||||
|
||||
/* save packet direct link flag status */
|
||||
if (direct_link)
|
||||
forw_packet_aggr->direct_link_flags |= 1;
|
||||
|
||||
/* add new packet to packet list */
|
||||
spin_lock_bh(&bat_priv->forw_bat_list_lock);
|
||||
hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);
|
||||
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
|
||||
|
||||
/* start timer for this packet */
|
||||
INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
|
||||
send_outstanding_bat_packet);
|
||||
queue_delayed_work(bat_event_workqueue,
|
||||
&forw_packet_aggr->delayed_work,
|
||||
send_time - jiffies);
|
||||
}
|
||||
|
||||
/* aggregate a new packet into the existing aggregation */
|
||||
static void aggregate(struct forw_packet *forw_packet_aggr,
|
||||
unsigned char *packet_buff,
|
||||
int packet_len,
|
||||
bool direct_link)
|
||||
{
|
||||
unsigned char *skb_buff;
|
||||
|
||||
skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
|
||||
memcpy(skb_buff, packet_buff, packet_len);
|
||||
forw_packet_aggr->packet_len += packet_len;
|
||||
forw_packet_aggr->num_packets++;
|
||||
|
||||
/* save packet direct link flag status */
|
||||
if (direct_link)
|
||||
forw_packet_aggr->direct_link_flags |=
|
||||
(1 << forw_packet_aggr->num_packets);
|
||||
}
|
||||
|
||||
void add_bat_packet_to_list(struct bat_priv *bat_priv,
|
||||
unsigned char *packet_buff, int packet_len,
|
||||
struct batman_if *if_incoming, char own_packet,
|
||||
unsigned long send_time)
|
||||
{
|
||||
/**
|
||||
* _aggr -> pointer to the packet we want to aggregate with
|
||||
* _pos -> pointer to the position in the queue
|
||||
*/
|
||||
struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
|
||||
struct hlist_node *tmp_node;
|
||||
struct batman_packet *batman_packet =
|
||||
(struct batman_packet *)packet_buff;
|
||||
bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
|
||||
|
||||
/* find position for the packet in the forward queue */
|
||||
spin_lock_bh(&bat_priv->forw_bat_list_lock);
|
||||
/* own packets are not to be aggregated */
|
||||
if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {
|
||||
hlist_for_each_entry(forw_packet_pos, tmp_node,
|
||||
&bat_priv->forw_bat_list, list) {
|
||||
if (can_aggregate_with(batman_packet,
|
||||
packet_len,
|
||||
send_time,
|
||||
direct_link,
|
||||
if_incoming,
|
||||
forw_packet_pos)) {
|
||||
forw_packet_aggr = forw_packet_pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* nothing to aggregate with - either aggregation disabled or no
|
||||
* suitable aggregation packet found */
|
||||
if (!forw_packet_aggr) {
|
||||
/* the following section can run without the lock */
|
||||
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
|
||||
|
||||
/**
|
||||
* if we could not aggregate this packet with one of the others
|
||||
* we hold it back for a while, so that it might be aggregated
|
||||
* later on
|
||||
*/
|
||||
if ((!own_packet) &&
|
||||
(atomic_read(&bat_priv->aggregated_ogms)))
|
||||
send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);
|
||||
|
||||
new_aggregated_packet(packet_buff, packet_len,
|
||||
send_time, direct_link,
|
||||
if_incoming, own_packet);
|
||||
} else {
|
||||
aggregate(forw_packet_aggr,
|
||||
packet_buff, packet_len,
|
||||
direct_link);
|
||||
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/* unpack the aggregated packets and process them one by one */
|
||||
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
|
||||
int packet_len, struct batman_if *if_incoming)
|
||||
{
|
||||
struct batman_packet *batman_packet;
|
||||
int buff_pos = 0;
|
||||
unsigned char *hna_buff;
|
||||
|
||||
batman_packet = (struct batman_packet *)packet_buff;
|
||||
|
||||
do {
|
||||
/* network to host order for our 32bit seqno, and the
|
||||
orig_interval. */
|
||||
batman_packet->seqno = ntohl(batman_packet->seqno);
|
||||
|
||||
hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
|
||||
receive_bat_packet(ethhdr, batman_packet,
|
||||
hna_buff, hna_len(batman_packet),
|
||||
if_incoming);
|
||||
|
||||
buff_pos += BAT_PACKET_LEN + hna_len(batman_packet);
|
||||
batman_packet = (struct batman_packet *)
|
||||
(packet_buff + buff_pos);
|
||||
} while (aggregated_packet(buff_pos, packet_len,
|
||||
batman_packet->num_hna));
|
||||
}
|
||||
43
net/batman-adv/aggregation.h
Normal file
43
net/batman-adv/aggregation.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
|
||||
*
|
||||
* Marek Lindner, Simon Wunderlich
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NET_BATMAN_ADV_AGGREGATION_H_
|
||||
#define _NET_BATMAN_ADV_AGGREGATION_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
/* is there another aggregated packet here? */
|
||||
static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna)
|
||||
{
|
||||
int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN);
|
||||
|
||||
return (next_buff_pos <= packet_len) &&
|
||||
(next_buff_pos <= MAX_AGGREGATION_BYTES);
|
||||
}
|
||||
|
||||
void add_bat_packet_to_list(struct bat_priv *bat_priv,
|
||||
unsigned char *packet_buff, int packet_len,
|
||||
struct batman_if *if_incoming, char own_packet,
|
||||
unsigned long send_time);
|
||||
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
|
||||
int packet_len, struct batman_if *if_incoming);
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */
|
||||
360
net/batman-adv/bat_debugfs.c
Normal file
360
net/batman-adv/bat_debugfs.c
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 <linux/debugfs.h>
|
||||
|
||||
#include "bat_debugfs.h"
|
||||
#include "translation-table.h"
|
||||
#include "originator.h"
|
||||
#include "hard-interface.h"
|
||||
#include "gateway_common.h"
|
||||
#include "gateway_client.h"
|
||||
#include "soft-interface.h"
|
||||
#include "vis.h"
|
||||
#include "icmp_socket.h"
|
||||
|
||||
static struct dentry *bat_debugfs;
|
||||
|
||||
#ifdef CONFIG_BATMAN_ADV_DEBUG
|
||||
#define LOG_BUFF_MASK (log_buff_len-1)
|
||||
#define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK])
|
||||
|
||||
static int log_buff_len = LOG_BUF_LEN;
|
||||
|
||||
static void emit_log_char(struct debug_log *debug_log, char c)
|
||||
{
|
||||
LOG_BUFF(debug_log->log_end) = c;
|
||||
debug_log->log_end++;
|
||||
|
||||
if (debug_log->log_end - debug_log->log_start > log_buff_len)
|
||||
debug_log->log_start = debug_log->log_end - log_buff_len;
|
||||
}
|
||||
|
||||
static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
|
||||
{
|
||||
int printed_len;
|
||||
va_list args;
|
||||
static char debug_log_buf[256];
|
||||
char *p;
|
||||
|
||||
if (!debug_log)
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&debug_log->lock);
|
||||
va_start(args, fmt);
|
||||
printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf),
|
||||
fmt, args);
|
||||
va_end(args);
|
||||
|
||||
for (p = debug_log_buf; *p != 0; p++)
|
||||
emit_log_char(debug_log, *p);
|
||||
|
||||
spin_unlock_bh(&debug_log->lock);
|
||||
|
||||
wake_up(&debug_log->queue_wait);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int debug_log(struct bat_priv *bat_priv, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char tmp_log_buf[256];
|
||||
|
||||
va_start(args, fmt);
|
||||
vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
|
||||
fdebug_log(bat_priv->debug_log, "[%10u] %s",
|
||||
(jiffies / HZ), tmp_log_buf);
|
||||
va_end(args);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int log_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
nonseekable_open(inode, file);
|
||||
file->private_data = inode->i_private;
|
||||
inc_module_count();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int log_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
dec_module_count();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t log_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct bat_priv *bat_priv = file->private_data;
|
||||
struct debug_log *debug_log = bat_priv->debug_log;
|
||||
int error, i = 0;
|
||||
char c;
|
||||
|
||||
if ((file->f_flags & O_NONBLOCK) &&
|
||||
!(debug_log->log_end - debug_log->log_start))
|
||||
return -EAGAIN;
|
||||
|
||||
if ((!buf) || (count < 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
error = wait_event_interruptible(debug_log->queue_wait,
|
||||
(debug_log->log_start - debug_log->log_end));
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
spin_lock_bh(&debug_log->lock);
|
||||
|
||||
while ((!error) && (i < count) &&
|
||||
(debug_log->log_start != debug_log->log_end)) {
|
||||
c = LOG_BUFF(debug_log->log_start);
|
||||
|
||||
debug_log->log_start++;
|
||||
|
||||
spin_unlock_bh(&debug_log->lock);
|
||||
|
||||
error = __put_user(c, buf);
|
||||
|
||||
spin_lock_bh(&debug_log->lock);
|
||||
|
||||
buf++;
|
||||
i++;
|
||||
|
||||
}
|
||||
|
||||
spin_unlock_bh(&debug_log->lock);
|
||||
|
||||
if (!error)
|
||||
return i;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static unsigned int log_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct bat_priv *bat_priv = file->private_data;
|
||||
struct debug_log *debug_log = bat_priv->debug_log;
|
||||
|
||||
poll_wait(file, &debug_log->queue_wait, wait);
|
||||
|
||||
if (debug_log->log_end - debug_log->log_start)
|
||||
return POLLIN | POLLRDNORM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations log_fops = {
|
||||
.open = log_open,
|
||||
.release = log_release,
|
||||
.read = log_read,
|
||||
.poll = log_poll,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
||||
static int debug_log_setup(struct bat_priv *bat_priv)
|
||||
{
|
||||
struct dentry *d;
|
||||
|
||||
if (!bat_priv->debug_dir)
|
||||
goto err;
|
||||
|
||||
bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC);
|
||||
if (!bat_priv->debug_log)
|
||||
goto err;
|
||||
|
||||
spin_lock_init(&bat_priv->debug_log->lock);
|
||||
init_waitqueue_head(&bat_priv->debug_log->queue_wait);
|
||||
|
||||
d = debugfs_create_file("log", S_IFREG | S_IRUSR,
|
||||
bat_priv->debug_dir, bat_priv, &log_fops);
|
||||
if (d)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void debug_log_cleanup(struct bat_priv *bat_priv)
|
||||
{
|
||||
kfree(bat_priv->debug_log);
|
||||
bat_priv->debug_log = NULL;
|
||||
}
|
||||
#else /* CONFIG_BATMAN_ADV_DEBUG */
|
||||
static int debug_log_setup(struct bat_priv *bat_priv)
|
||||
{
|
||||
bat_priv->debug_log = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void debug_log_cleanup(struct bat_priv *bat_priv)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int originators_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct net_device *net_dev = (struct net_device *)inode->i_private;
|
||||
return single_open(file, orig_seq_print_text, net_dev);
|
||||
}
|
||||
|
||||
static int gateways_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct net_device *net_dev = (struct net_device *)inode->i_private;
|
||||
return single_open(file, gw_client_seq_print_text, net_dev);
|
||||
}
|
||||
|
||||
static int softif_neigh_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct net_device *net_dev = (struct net_device *)inode->i_private;
|
||||
return single_open(file, softif_neigh_seq_print_text, net_dev);
|
||||
}
|
||||
|
||||
static int transtable_global_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct net_device *net_dev = (struct net_device *)inode->i_private;
|
||||
return single_open(file, hna_global_seq_print_text, net_dev);
|
||||
}
|
||||
|
||||
static int transtable_local_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct net_device *net_dev = (struct net_device *)inode->i_private;
|
||||
return single_open(file, hna_local_seq_print_text, net_dev);
|
||||
}
|
||||
|
||||
static int vis_data_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct net_device *net_dev = (struct net_device *)inode->i_private;
|
||||
return single_open(file, vis_seq_print_text, net_dev);
|
||||
}
|
||||
|
||||
struct bat_debuginfo {
|
||||
struct attribute attr;
|
||||
const struct file_operations fops;
|
||||
};
|
||||
|
||||
#define BAT_DEBUGINFO(_name, _mode, _open) \
|
||||
struct bat_debuginfo bat_debuginfo_##_name = { \
|
||||
.attr = { .name = __stringify(_name), \
|
||||
.mode = _mode, }, \
|
||||
.fops = { .owner = THIS_MODULE, \
|
||||
.open = _open, \
|
||||
.read = seq_read, \
|
||||
.llseek = seq_lseek, \
|
||||
.release = single_release, \
|
||||
} \
|
||||
};
|
||||
|
||||
static BAT_DEBUGINFO(originators, S_IRUGO, originators_open);
|
||||
static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open);
|
||||
static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open);
|
||||
static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open);
|
||||
static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open);
|
||||
static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open);
|
||||
|
||||
static struct bat_debuginfo *mesh_debuginfos[] = {
|
||||
&bat_debuginfo_originators,
|
||||
&bat_debuginfo_gateways,
|
||||
&bat_debuginfo_softif_neigh,
|
||||
&bat_debuginfo_transtable_global,
|
||||
&bat_debuginfo_transtable_local,
|
||||
&bat_debuginfo_vis_data,
|
||||
NULL,
|
||||
};
|
||||
|
||||
void debugfs_init(void)
|
||||
{
|
||||
bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL);
|
||||
if (bat_debugfs == ERR_PTR(-ENODEV))
|
||||
bat_debugfs = NULL;
|
||||
}
|
||||
|
||||
void debugfs_destroy(void)
|
||||
{
|
||||
if (bat_debugfs) {
|
||||
debugfs_remove_recursive(bat_debugfs);
|
||||
bat_debugfs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int debugfs_add_meshif(struct net_device *dev)
|
||||
{
|
||||
struct bat_priv *bat_priv = netdev_priv(dev);
|
||||
struct bat_debuginfo **bat_debug;
|
||||
struct dentry *file;
|
||||
|
||||
if (!bat_debugfs)
|
||||
goto out;
|
||||
|
||||
bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs);
|
||||
if (!bat_priv->debug_dir)
|
||||
goto out;
|
||||
|
||||
bat_socket_setup(bat_priv);
|
||||
debug_log_setup(bat_priv);
|
||||
|
||||
for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) {
|
||||
file = debugfs_create_file(((*bat_debug)->attr).name,
|
||||
S_IFREG | ((*bat_debug)->attr).mode,
|
||||
bat_priv->debug_dir,
|
||||
dev, &(*bat_debug)->fops);
|
||||
if (!file) {
|
||||
bat_err(dev, "Can't add debugfs file: %s/%s\n",
|
||||
dev->name, ((*bat_debug)->attr).name);
|
||||
goto rem_attr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
rem_attr:
|
||||
debugfs_remove_recursive(bat_priv->debug_dir);
|
||||
bat_priv->debug_dir = NULL;
|
||||
out:
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
return -ENOMEM;
|
||||
#else
|
||||
return 0;
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
}
|
||||
|
||||
void debugfs_del_meshif(struct net_device *dev)
|
||||
{
|
||||
struct bat_priv *bat_priv = netdev_priv(dev);
|
||||
|
||||
debug_log_cleanup(bat_priv);
|
||||
|
||||
if (bat_debugfs) {
|
||||
debugfs_remove_recursive(bat_priv->debug_dir);
|
||||
bat_priv->debug_dir = NULL;
|
||||
}
|
||||
}
|
||||
33
net/batman-adv/bat_debugfs.h
Normal file
33
net/batman-adv/bat_debugfs.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NET_BATMAN_ADV_DEBUGFS_H_
|
||||
#define _NET_BATMAN_ADV_DEBUGFS_H_
|
||||
|
||||
#define DEBUGFS_BAT_SUBDIR "batman_adv"
|
||||
|
||||
void debugfs_init(void);
|
||||
void debugfs_destroy(void);
|
||||
int debugfs_add_meshif(struct net_device *dev);
|
||||
void debugfs_del_meshif(struct net_device *dev);
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */
|
||||
593
net/batman-adv/bat_sysfs.c
Normal file
593
net/batman-adv/bat_sysfs.c
Normal file
File diff suppressed because it is too large
Load Diff
42
net/batman-adv/bat_sysfs.h
Normal file
42
net/batman-adv/bat_sysfs.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NET_BATMAN_ADV_SYSFS_H_
|
||||
#define _NET_BATMAN_ADV_SYSFS_H_
|
||||
|
||||
#define SYSFS_IF_MESH_SUBDIR "mesh"
|
||||
#define SYSFS_IF_BAT_SUBDIR "batman_adv"
|
||||
|
||||
struct bat_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf);
|
||||
ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf, size_t count);
|
||||
};
|
||||
|
||||
int sysfs_add_meshif(struct net_device *dev);
|
||||
void sysfs_del_meshif(struct net_device *dev);
|
||||
int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
|
||||
void sysfs_del_hardif(struct kobject **hardif_obj);
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_SYSFS_H_ */
|
||||
201
net/batman-adv/bitarray.c
Normal file
201
net/batman-adv/bitarray.c
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2010 B.A.T.M.A.N. contributors:
|
||||
*
|
||||
* Simon Wunderlich, 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 "bitarray.h"
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* returns true if the corresponding bit in the given seq_bits indicates true
|
||||
* and curr_seqno is within range of last_seqno */
|
||||
uint8_t get_bit_status(unsigned long *seq_bits, uint32_t last_seqno,
|
||||
uint32_t curr_seqno)
|
||||
{
|
||||
int32_t diff, word_offset, word_num;
|
||||
|
||||
diff = last_seqno - curr_seqno;
|
||||
if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) {
|
||||
return 0;
|
||||
} else {
|
||||
/* which word */
|
||||
word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE;
|
||||
/* which position in the selected word */
|
||||
word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE;
|
||||
|
||||
if (test_bit(word_offset, &seq_bits[word_num]))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* turn corresponding bit on, so we can remember that we got the packet */
|
||||
void bit_mark(unsigned long *seq_bits, int32_t n)
|
||||
{
|
||||
int32_t word_offset, word_num;
|
||||
|
||||
/* if too old, just drop it */
|
||||
if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE)
|
||||
return;
|
||||
|
||||
/* which word */
|
||||
word_num = n / WORD_BIT_SIZE;
|
||||
/* which position in the selected word */
|
||||
word_offset = n % WORD_BIT_SIZE;
|
||||
|
||||
set_bit(word_offset, &seq_bits[word_num]); /* turn the position on */
|
||||
}
|
||||
|
||||
/* shift the packet array by n places. */
|
||||
static void bit_shift(unsigned long *seq_bits, int32_t n)
|
||||
{
|
||||
int32_t word_offset, word_num;
|
||||
int32_t i;
|
||||
|
||||
if (n <= 0 || n >= TQ_LOCAL_WINDOW_SIZE)
|
||||
return;
|
||||
|
||||
word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */
|
||||
word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */
|
||||
|
||||
for (i = NUM_WORDS - 1; i > word_num; i--) {
|
||||
/* going from old to new, so we don't overwrite the data we copy
|
||||
* from.
|
||||
*
|
||||
* left is high, right is low: FEDC BA98 7654 3210
|
||||
* ^^ ^^
|
||||
* vvvv
|
||||
* ^^^^ = from, vvvvv =to, we'd have word_num==1 and
|
||||
* word_offset==WORD_BIT_SIZE/2 ????? in this example.
|
||||
* (=24 bits)
|
||||
*
|
||||
* our desired output would be: 9876 5432 1000 0000
|
||||
* */
|
||||
|
||||
seq_bits[i] =
|
||||
(seq_bits[i - word_num] << word_offset) +
|
||||
/* take the lower port from the left half, shift it left
|
||||
* to its final position */
|
||||
(seq_bits[i - word_num - 1] >>
|
||||
(WORD_BIT_SIZE-word_offset));
|
||||
/* and the upper part of the right half and shift it left to
|
||||
* it's position */
|
||||
/* for our example that would be: word[0] = 9800 + 0076 =
|
||||
* 9876 */
|
||||
}
|
||||
/* now for our last word, i==word_num, we only have the it's "left"
|
||||
* half. that's the 1000 word in our example.*/
|
||||
|
||||
seq_bits[i] = (seq_bits[i - word_num] << word_offset);
|
||||
|
||||
/* pad the rest with 0, if there is anything */
|
||||
i--;
|
||||
|
||||
for (; i >= 0; i--)
|
||||
seq_bits[i] = 0;
|
||||
}
|
||||
|
||||
static void bit_reset_window(unsigned long *seq_bits)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NUM_WORDS; i++)
|
||||
seq_bits[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* receive and process one packet within the sequence number window.
|
||||
*
|
||||
* returns:
|
||||
* 1 if the window was moved (either new or very old)
|
||||
* 0 if the window was not moved/shifted.
|
||||
*/
|
||||
char bit_get_packet(void *priv, unsigned long *seq_bits,
|
||||
int32_t seq_num_diff, int8_t set_mark)
|
||||
{
|
||||
struct bat_priv *bat_priv = (struct bat_priv *)priv;
|
||||
|
||||
/* sequence number is slightly older. We already got a sequence number
|
||||
* higher than this one, so we just mark it. */
|
||||
|
||||
if ((seq_num_diff <= 0) && (seq_num_diff > -TQ_LOCAL_WINDOW_SIZE)) {
|
||||
if (set_mark)
|
||||
bit_mark(seq_bits, -seq_num_diff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* sequence number is slightly newer, so we shift the window and
|
||||
* set the mark if required */
|
||||
|
||||
if ((seq_num_diff > 0) && (seq_num_diff < TQ_LOCAL_WINDOW_SIZE)) {
|
||||
bit_shift(seq_bits, seq_num_diff);
|
||||
|
||||
if (set_mark)
|
||||
bit_mark(seq_bits, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* sequence number is much newer, probably missed a lot of packets */
|
||||
|
||||
if ((seq_num_diff >= TQ_LOCAL_WINDOW_SIZE)
|
||||
|| (seq_num_diff < EXPECTED_SEQNO_RANGE)) {
|
||||
bat_dbg(DBG_BATMAN, bat_priv,
|
||||
"We missed a lot of packets (%i) !\n",
|
||||
seq_num_diff - 1);
|
||||
bit_reset_window(seq_bits);
|
||||
if (set_mark)
|
||||
bit_mark(seq_bits, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* received a much older packet. The other host either restarted
|
||||
* or the old packet got delayed somewhere in the network. The
|
||||
* packet should be dropped without calling this function if the
|
||||
* seqno window is protected. */
|
||||
|
||||
if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
|
||||
|| (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
|
||||
|
||||
bat_dbg(DBG_BATMAN, bat_priv,
|
||||
"Other host probably restarted!\n");
|
||||
|
||||
bit_reset_window(seq_bits);
|
||||
if (set_mark)
|
||||
bit_mark(seq_bits, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* never reached */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* count the hamming weight, how many good packets did we receive? just count
|
||||
* the 1's.
|
||||
*/
|
||||
int bit_packet_count(unsigned long *seq_bits)
|
||||
{
|
||||
int i, hamming = 0;
|
||||
|
||||
for (i = 0; i < NUM_WORDS; i++)
|
||||
hamming += hweight_long(seq_bits[i]);
|
||||
|
||||
return hamming;
|
||||
}
|
||||
44
net/batman-adv/bitarray.h
Normal file
44
net/batman-adv/bitarray.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2010 B.A.T.M.A.N. contributors:
|
||||
*
|
||||
* Simon Wunderlich, 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NET_BATMAN_ADV_BITARRAY_H_
|
||||
#define _NET_BATMAN_ADV_BITARRAY_H_
|
||||
|
||||
#define WORD_BIT_SIZE (sizeof(unsigned long) * 8)
|
||||
|
||||
/* returns true if the corresponding bit in the given seq_bits indicates true
|
||||
* and curr_seqno is within range of last_seqno */
|
||||
uint8_t get_bit_status(unsigned long *seq_bits, uint32_t last_seqno,
|
||||
uint32_t curr_seqno);
|
||||
|
||||
/* turn corresponding bit on, so we can remember that we got the packet */
|
||||
void bit_mark(unsigned long *seq_bits, int32_t n);
|
||||
|
||||
|
||||
/* receive and process one packet, returns 1 if received seq_num is considered
|
||||
* new, 0 if old */
|
||||
char bit_get_packet(void *priv, unsigned long *seq_bits,
|
||||
int32_t seq_num_diff, int8_t set_mark);
|
||||
|
||||
/* count the hamming weight, how many good packets did we receive? */
|
||||
int bit_packet_count(unsigned long *seq_bits);
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_BITARRAY_H_ */
|
||||
477
net/batman-adv/gateway_client.c
Normal file
477
net/batman-adv/gateway_client.c
Normal file
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2010 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"
|
||||
#include "hard-interface.h"
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/if_vlan.h>
|
||||
|
||||
static void gw_node_free_ref(struct kref *refcount)
|
||||
{
|
||||
struct gw_node *gw_node;
|
||||
|
||||
gw_node = container_of(refcount, struct gw_node, refcount);
|
||||
kfree(gw_node);
|
||||
}
|
||||
|
||||
static void gw_node_free_rcu(struct rcu_head *rcu)
|
||||
{
|
||||
struct gw_node *gw_node;
|
||||
|
||||
gw_node = container_of(rcu, struct gw_node, rcu);
|
||||
kref_put(&gw_node->refcount, gw_node_free_ref);
|
||||
}
|
||||
|
||||
void *gw_get_selected(struct bat_priv *bat_priv)
|
||||
{
|
||||
struct gw_node *curr_gateway_tmp = bat_priv->curr_gw;
|
||||
|
||||
if (!curr_gateway_tmp)
|
||||
return NULL;
|
||||
|
||||
return curr_gateway_tmp->orig_node;
|
||||
}
|
||||
|
||||
void gw_deselect(struct bat_priv *bat_priv)
|
||||
{
|
||||
struct gw_node *gw_node = bat_priv->curr_gw;
|
||||
|
||||
bat_priv->curr_gw = NULL;
|
||||
|
||||
if (gw_node)
|
||||
kref_put(&gw_node->refcount, gw_node_free_ref);
|
||||
}
|
||||
|
||||
static struct gw_node *gw_select(struct bat_priv *bat_priv,
|
||||
struct gw_node *new_gw_node)
|
||||
{
|
||||
struct gw_node *curr_gw_node = bat_priv->curr_gw;
|
||||
|
||||
if (new_gw_node)
|
||||
kref_get(&new_gw_node->refcount);
|
||||
|
||||
bat_priv->curr_gw = new_gw_node;
|
||||
return curr_gw_node;
|
||||
}
|
||||
|
||||
void gw_election(struct bat_priv *bat_priv)
|
||||
{
|
||||
struct hlist_node *node;
|
||||
struct gw_node *gw_node, *curr_gw_tmp = NULL, *old_gw_node = 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(&bat_priv->gw_mode) != GW_MODE_CLIENT)
|
||||
return;
|
||||
|
||||
if (bat_priv->curr_gw)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
if (hlist_empty(&bat_priv->gw_list)) {
|
||||
rcu_read_unlock();
|
||||
|
||||
if (bat_priv->curr_gw) {
|
||||
bat_dbg(DBG_BATMAN, bat_priv,
|
||||
"Removing selected gateway - "
|
||||
"no gateway in range\n");
|
||||
gw_deselect(bat_priv);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
|
||||
if (!gw_node->orig_node->router)
|
||||
continue;
|
||||
|
||||
if (gw_node->deleted)
|
||||
continue;
|
||||
|
||||
switch (atomic_read(&bat_priv->gw_sel_class)) {
|
||||
case 1: /* fast connection */
|
||||
gw_bandwidth_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;
|
||||
}
|
||||
|
||||
if (bat_priv->curr_gw != curr_gw_tmp) {
|
||||
if ((bat_priv->curr_gw) && (!curr_gw_tmp))
|
||||
bat_dbg(DBG_BATMAN, bat_priv,
|
||||
"Removing selected gateway - "
|
||||
"no gateway in range\n");
|
||||
else if ((!bat_priv->curr_gw) && (curr_gw_tmp))
|
||||
bat_dbg(DBG_BATMAN, bat_priv,
|
||||
"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, bat_priv,
|
||||
"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);
|
||||
|
||||
old_gw_node = gw_select(bat_priv, curr_gw_tmp);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* the kfree() has to be outside of the rcu lock */
|
||||
if (old_gw_node)
|
||||
kref_put(&old_gw_node->refcount, gw_node_free_ref);
|
||||
}
|
||||
|
||||
void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
|
||||
{
|
||||
struct gw_node *curr_gateway_tmp = bat_priv->curr_gw;
|
||||
uint8_t gw_tq_avg, orig_tq_avg;
|
||||
|
||||
if (!curr_gateway_tmp)
|
||||
return;
|
||||
|
||||
if (!curr_gateway_tmp->orig_node)
|
||||
goto deselect;
|
||||
|
||||
if (!curr_gateway_tmp->orig_node->router)
|
||||
goto deselect;
|
||||
|
||||
/* 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(&bat_priv->gw_sel_class) > 3) &&
|
||||
(orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class)))
|
||||
return;
|
||||
|
||||
bat_dbg(DBG_BATMAN, bat_priv,
|
||||
"Restarting gateway selection: better gateway found (tq curr: "
|
||||
"%i, tq new: %i)\n",
|
||||
gw_tq_avg, orig_tq_avg);
|
||||
|
||||
deselect:
|
||||
gw_deselect(bat_priv);
|
||||
}
|
||||
|
||||
static void gw_node_add(struct bat_priv *bat_priv,
|
||||
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_HLIST_NODE(&gw_node->list);
|
||||
gw_node->orig_node = orig_node;
|
||||
kref_init(&gw_node->refcount);
|
||||
|
||||
spin_lock_bh(&bat_priv->gw_list_lock);
|
||||
hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list);
|
||||
spin_unlock_bh(&bat_priv->gw_list_lock);
|
||||
|
||||
gw_bandwidth_to_kbit(new_gwflags, &down, &up);
|
||||
bat_dbg(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"));
|
||||
}
|
||||
|
||||
void gw_node_update(struct bat_priv *bat_priv,
|
||||
struct orig_node *orig_node, uint8_t new_gwflags)
|
||||
{
|
||||
struct hlist_node *node;
|
||||
struct gw_node *gw_node;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
|
||||
if (gw_node->orig_node != orig_node)
|
||||
continue;
|
||||
|
||||
bat_dbg(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);
|
||||
|
||||
gw_node->deleted = 0;
|
||||
|
||||
if (new_gwflags == 0) {
|
||||
gw_node->deleted = jiffies;
|
||||
bat_dbg(DBG_BATMAN, bat_priv,
|
||||
"Gateway %pM removed from gateway list\n",
|
||||
orig_node->orig);
|
||||
|
||||
if (gw_node == bat_priv->curr_gw) {
|
||||
rcu_read_unlock();
|
||||
gw_deselect(bat_priv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (new_gwflags == 0)
|
||||
return;
|
||||
|
||||
gw_node_add(bat_priv, orig_node, new_gwflags);
|
||||
}
|
||||
|
||||
void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
|
||||
{
|
||||
return gw_node_update(bat_priv, orig_node, 0);
|
||||
}
|
||||
|
||||
void gw_node_purge(struct bat_priv *bat_priv)
|
||||
{
|
||||
struct gw_node *gw_node;
|
||||
struct hlist_node *node, *node_tmp;
|
||||
unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
|
||||
|
||||
spin_lock_bh(&bat_priv->gw_list_lock);
|
||||
|
||||
hlist_for_each_entry_safe(gw_node, node, node_tmp,
|
||||
&bat_priv->gw_list, list) {
|
||||
if (((!gw_node->deleted) ||
|
||||
(time_before(jiffies, gw_node->deleted + timeout))) &&
|
||||
atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)
|
||||
continue;
|
||||
|
||||
if (bat_priv->curr_gw == gw_node)
|
||||
gw_deselect(bat_priv);
|
||||
|
||||
hlist_del_rcu(&gw_node->list);
|
||||
call_rcu(&gw_node->rcu, gw_node_free_rcu);
|
||||
}
|
||||
|
||||
|
||||
spin_unlock_bh(&bat_priv->gw_list_lock);
|
||||
}
|
||||
|
||||
static int _write_buffer_text(struct bat_priv *bat_priv,
|
||||
struct seq_file *seq, struct gw_node *gw_node)
|
||||
{
|
||||
int down, up;
|
||||
|
||||
gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
|
||||
|
||||
return seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
|
||||
(bat_priv->curr_gw == gw_node ? "=>" : " "),
|
||||
gw_node->orig_node->orig,
|
||||
gw_node->orig_node->router->tq_avg,
|
||||
gw_node->orig_node->router->addr,
|
||||
gw_node->orig_node->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"));
|
||||
}
|
||||
|
||||
int gw_client_seq_print_text(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct net_device *net_dev = (struct net_device *)seq->private;
|
||||
struct bat_priv *bat_priv = netdev_priv(net_dev);
|
||||
struct gw_node *gw_node;
|
||||
struct hlist_node *node;
|
||||
int gw_count = 0;
|
||||
|
||||
if (!bat_priv->primary_if) {
|
||||
|
||||
return seq_printf(seq, "BATMAN mesh %s disabled - please "
|
||||
"specify interfaces to enable it\n",
|
||||
net_dev->name);
|
||||
}
|
||||
|
||||
if (bat_priv->primary_if->if_status != IF_ACTIVE) {
|
||||
|
||||
return seq_printf(seq, "BATMAN mesh %s disabled - "
|
||||
"primary interface not active\n",
|
||||
net_dev->name);
|
||||
}
|
||||
|
||||
seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... "
|
||||
"[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
|
||||
"Gateway", "#", TQ_MAX_VALUE, "Nexthop",
|
||||
"outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
|
||||
bat_priv->primary_if->net_dev->name,
|
||||
bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
|
||||
if (gw_node->deleted)
|
||||
continue;
|
||||
|
||||
if (!gw_node->orig_node->router)
|
||||
continue;
|
||||
|
||||
_write_buffer_text(bat_priv, seq, gw_node);
|
||||
gw_count++;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (gw_count == 0)
|
||||
seq_printf(seq, "No gateways in range ...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
|
||||
{
|
||||
struct ethhdr *ethhdr;
|
||||
struct iphdr *iphdr;
|
||||
struct ipv6hdr *ipv6hdr;
|
||||
struct udphdr *udphdr;
|
||||
unsigned int header_len = 0;
|
||||
|
||||
if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
|
||||
return 0;
|
||||
|
||||
/* check for ethernet header */
|
||||
if (!pskb_may_pull(skb, header_len + ETH_HLEN))
|
||||
return 0;
|
||||
ethhdr = (struct ethhdr *)skb->data;
|
||||
header_len += ETH_HLEN;
|
||||
|
||||
/* check for initial vlan header */
|
||||
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
|
||||
if (!pskb_may_pull(skb, header_len + VLAN_HLEN))
|
||||
return 0;
|
||||
ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
|
||||
header_len += VLAN_HLEN;
|
||||
}
|
||||
|
||||
/* check for ip header */
|
||||
switch (ntohs(ethhdr->h_proto)) {
|
||||
case ETH_P_IP:
|
||||
if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr)))
|
||||
return 0;
|
||||
iphdr = (struct iphdr *)(skb->data + header_len);
|
||||
header_len += iphdr->ihl * 4;
|
||||
|
||||
/* check for udp header */
|
||||
if (iphdr->protocol != IPPROTO_UDP)
|
||||
return 0;
|
||||
|
||||
break;
|
||||
case ETH_P_IPV6:
|
||||
if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr)))
|
||||
return 0;
|
||||
ipv6hdr = (struct ipv6hdr *)(skb->data + header_len);
|
||||
header_len += sizeof(struct ipv6hdr);
|
||||
|
||||
/* check for udp header */
|
||||
if (ipv6hdr->nexthdr != IPPROTO_UDP)
|
||||
return 0;
|
||||
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr)))
|
||||
return 0;
|
||||
udphdr = (struct udphdr *)(skb->data + header_len);
|
||||
header_len += sizeof(struct udphdr);
|
||||
|
||||
/* check for bootp port */
|
||||
if ((ntohs(ethhdr->h_proto) == ETH_P_IP) &&
|
||||
(ntohs(udphdr->dest) != 67))
|
||||
return 0;
|
||||
|
||||
if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) &&
|
||||
(ntohs(udphdr->dest) != 547))
|
||||
return 0;
|
||||
|
||||
if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)
|
||||
return -1;
|
||||
|
||||
if (!bat_priv->curr_gw)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
36
net/batman-adv/gateway_client.h
Normal file
36
net/batman-adv/gateway_client.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2010 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
|
||||
#define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
|
||||
|
||||
void gw_deselect(struct bat_priv *bat_priv);
|
||||
void gw_election(struct bat_priv *bat_priv);
|
||||
void *gw_get_selected(struct bat_priv *bat_priv);
|
||||
void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node);
|
||||
void gw_node_update(struct bat_priv *bat_priv,
|
||||
struct orig_node *orig_node, uint8_t new_gwflags);
|
||||
void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
|
||||
void gw_node_purge(struct bat_priv *bat_priv);
|
||||
int gw_client_seq_print_text(struct seq_file *seq, void *offset);
|
||||
int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
|
||||
177
net/batman-adv/gateway_common.c
Normal file
177
net/batman-adv/gateway_common.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2010 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"
|
||||
|
||||
/* calculates the gateway class from kbit */
|
||||
static void kbit_to_gw_bandwidth(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_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up)
|
||||
{
|
||||
char sbit = (gw_srv_class & 0x80) >> 7;
|
||||
char dpart = (gw_srv_class & 0x78) >> 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_bandwidth(struct net_device *net_dev, char *buff,
|
||||
long *up, long *down)
|
||||
{
|
||||
int ret, multi = 1;
|
||||
char *slash_ptr, *tmp_ptr;
|
||||
|
||||
slash_ptr = strchr(buff, '/');
|
||||
if (slash_ptr)
|
||||
*slash_ptr = 0;
|
||||
|
||||
if (strlen(buff) > 4) {
|
||||
tmp_ptr = buff + strlen(buff) - 4;
|
||||
|
||||
if (strnicmp(tmp_ptr, "mbit", 4) == 0)
|
||||
multi = 1024;
|
||||
|
||||
if ((strnicmp(tmp_ptr, "kbit", 4) == 0) ||
|
||||
(multi > 1))
|
||||
*tmp_ptr = '\0';
|
||||
}
|
||||
|
||||
ret = strict_strtoul(buff, 10, down);
|
||||
if (ret) {
|
||||
bat_err(net_dev,
|
||||
"Download speed of gateway mode invalid: %s\n",
|
||||
buff);
|
||||
return false;
|
||||
}
|
||||
|
||||
*down *= multi;
|
||||
|
||||
/* we also got some upload info */
|
||||
if (slash_ptr) {
|
||||
multi = 1;
|
||||
|
||||
if (strlen(slash_ptr + 1) > 4) {
|
||||
tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1);
|
||||
|
||||
if (strnicmp(tmp_ptr, "mbit", 4) == 0)
|
||||
multi = 1024;
|
||||
|
||||
if ((strnicmp(tmp_ptr, "kbit", 4) == 0) ||
|
||||
(multi > 1))
|
||||
*tmp_ptr = '\0';
|
||||
}
|
||||
|
||||
ret = strict_strtoul(slash_ptr + 1, 10, up);
|
||||
if (ret) {
|
||||
bat_err(net_dev,
|
||||
"Upload speed of gateway mode invalid: "
|
||||
"%s\n", slash_ptr + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
*up *= multi;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count)
|
||||
{
|
||||
struct bat_priv *bat_priv = netdev_priv(net_dev);
|
||||
long gw_bandwidth_tmp = 0, up = 0, down = 0;
|
||||
bool ret;
|
||||
|
||||
ret = parse_gw_bandwidth(net_dev, buff, &up, &down);
|
||||
if (!ret)
|
||||
goto end;
|
||||
|
||||
if ((!down) || (down < 256))
|
||||
down = 2000;
|
||||
|
||||
if (!up)
|
||||
up = down / 5;
|
||||
|
||||
kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp);
|
||||
|
||||
/**
|
||||
* the gw bandwidth 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_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp,
|
||||
(int *)&down, (int *)&up);
|
||||
|
||||
gw_deselect(bat_priv);
|
||||
bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' "
|
||||
"(propagating: %ld%s/%ld%s)\n",
|
||||
atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp,
|
||||
(down > 2048 ? down / 1024 : down),
|
||||
(down > 2048 ? "MBit" : "KBit"),
|
||||
(up > 2048 ? up / 1024 : up),
|
||||
(up > 2048 ? "MBit" : "KBit"));
|
||||
|
||||
atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp);
|
||||
|
||||
end:
|
||||
return count;
|
||||
}
|
||||
38
net/batman-adv/gateway_common.h
Normal file
38
net/batman-adv/gateway_common.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2010 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_
|
||||
#define _NET_BATMAN_ADV_GATEWAY_COMMON_H_
|
||||
|
||||
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"
|
||||
|
||||
void gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up);
|
||||
ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count);
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user