aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Eckelmann <sven@narfation.org>2010-12-13 06:19:28 -0500
committerDavid S. Miller <davem@davemloft.net>2010-12-16 16:44:24 -0500
commitc6c8fea29769d998d94fcec9b9f14d4b52b349d3 (patch)
tree2c8dc8d1a64d48c5737a5745e3c510ff53a23047
parentb236da6931e2482bfe44a7865dd4e7bb036f3496 (diff)
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>
-rw-r--r--Documentation/ABI/testing/sysfs-class-net-batman-adv14
-rw-r--r--Documentation/ABI/testing/sysfs-class-net-mesh69
-rw-r--r--Documentation/networking/batman-adv.txt240
-rw-r--r--MAINTAINERS9
-rw-r--r--net/Kconfig1
-rw-r--r--net/Makefile1
-rw-r--r--net/batman-adv/Kconfig25
-rw-r--r--net/batman-adv/Makefile39
-rw-r--r--net/batman-adv/aggregation.c273
-rw-r--r--net/batman-adv/aggregation.h43
-rw-r--r--net/batman-adv/bat_debugfs.c360
-rw-r--r--net/batman-adv/bat_debugfs.h33
-rw-r--r--net/batman-adv/bat_sysfs.c593
-rw-r--r--net/batman-adv/bat_sysfs.h42
-rw-r--r--net/batman-adv/bitarray.c201
-rw-r--r--net/batman-adv/bitarray.h44
-rw-r--r--net/batman-adv/gateway_client.c477
-rw-r--r--net/batman-adv/gateway_client.h36
-rw-r--r--net/batman-adv/gateway_common.c177
-rw-r--r--net/batman-adv/gateway_common.h38
-rw-r--r--net/batman-adv/hard-interface.c651
-rw-r--r--net/batman-adv/hard-interface.h53
-rw-r--r--net/batman-adv/hash.c62
-rw-r--r--net/batman-adv/hash.h176
-rw-r--r--net/batman-adv/icmp_socket.c356
-rw-r--r--net/batman-adv/icmp_socket.h34
-rw-r--r--net/batman-adv/main.c187
-rw-r--r--net/batman-adv/main.h183
-rw-r--r--net/batman-adv/originator.c564
-rw-r--r--net/batman-adv/originator.h64
-rw-r--r--net/batman-adv/packet.h136
-rw-r--r--net/batman-adv/ring_buffer.c52
-rw-r--r--net/batman-adv/ring_buffer.h28
-rw-r--r--net/batman-adv/routing.c1397
-rw-r--r--net/batman-adv/routing.h48
-rw-r--r--net/batman-adv/send.c585
-rw-r--r--net/batman-adv/send.h41
-rw-r--r--net/batman-adv/soft-interface.c697
-rw-r--r--net/batman-adv/soft-interface.h35
-rw-r--r--net/batman-adv/translation-table.c534
-rw-r--r--net/batman-adv/translation-table.h45
-rw-r--r--net/batman-adv/types.h271
-rw-r--r--net/batman-adv/unicast.c343
-rw-r--r--net/batman-adv/unicast.h35
-rw-r--r--net/batman-adv/vis.c949
-rw-r--r--net/batman-adv/vis.h37
46 files changed, 10278 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-net-batman-adv b/Documentation/ABI/testing/sysfs-class-net-batman-adv
new file mode 100644
index 000000000000..38dd762def4b
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-net-batman-adv
@@ -0,0 +1,14 @@
1
2What: /sys/class/net/<iface>/batman-adv/mesh_iface
3Date: May 2010
4Contact: Marek Lindner <lindner_marek@yahoo.de>
5Description:
6 The /sys/class/net/<iface>/batman-adv/mesh_iface file
7 displays the batman mesh interface this <iface>
8 currently is associated with.
9
10What: /sys/class/net/<iface>/batman-adv/iface_status
11Date: May 2010
12Contact: Marek Lindner <lindner_marek@yahoo.de>
13Description:
14 Indicates the status of <iface> as it is seen by batman.
diff --git a/Documentation/ABI/testing/sysfs-class-net-mesh b/Documentation/ABI/testing/sysfs-class-net-mesh
new file mode 100644
index 000000000000..748fe1701d25
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-net-mesh
@@ -0,0 +1,69 @@
1
2What: /sys/class/net/<mesh_iface>/mesh/aggregated_ogms
3Date: May 2010
4Contact: Marek Lindner <lindner_marek@yahoo.de>
5Description:
6 Indicates whether the batman protocol messages of the
7 mesh <mesh_iface> shall be aggregated or not.
8
9What: /sys/class/net/<mesh_iface>/mesh/bonding
10Date: June 2010
11Contact: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
12Description:
13 Indicates whether the data traffic going through the
14 mesh will be sent using multiple interfaces at the
15 same time (if available).
16
17What: /sys/class/net/<mesh_iface>/mesh/fragmentation
18Date: October 2010
19Contact: Andreas Langer <an.langer@gmx.de>
20Description:
21 Indicates whether the data traffic going through the
22 mesh will be fragmented or silently discarded if the
23 packet size exceeds the outgoing interface MTU.
24
25What: /sys/class/net/<mesh_iface>/mesh/gw_bandwidth
26Date: October 2010
27Contact: Marek Lindner <lindner_marek@yahoo.de>
28Description:
29 Defines the bandwidth which is propagated by this
30 node if gw_mode was set to 'server'.
31
32What: /sys/class/net/<mesh_iface>/mesh/gw_mode
33Date: October 2010
34Contact: Marek Lindner <lindner_marek@yahoo.de>
35Description:
36 Defines the state of the gateway features. Can be
37 either 'off', 'client' or 'server'.
38
39What: /sys/class/net/<mesh_iface>/mesh/gw_sel_class
40Date: October 2010
41Contact: Marek Lindner <lindner_marek@yahoo.de>
42Description:
43 Defines the selection criteria this node will use
44 to choose a gateway if gw_mode was set to 'client'.
45
46What: /sys/class/net/<mesh_iface>/mesh/orig_interval
47Date: May 2010
48Contact: Marek Lindner <lindner_marek@yahoo.de>
49Description:
50 Defines the interval in milliseconds in which batman
51 sends its protocol messages.
52
53What: /sys/class/net/<mesh_iface>/mesh/hop_penalty
54Date: Oct 2010
55Contact: Linus Lüssing <linus.luessing@web.de>
56Description:
57 Defines the penalty which will be applied to an
58 originator message's tq-field on every hop.
59
60What: /sys/class/net/<mesh_iface>/mesh/vis_mode
61Date: May 2010
62Contact: Marek Lindner <lindner_marek@yahoo.de>
63Description:
64 Each batman node only maintains information about its
65 own local neighborhood, therefore generating graphs
66 showing the topology of the entire mesh is not easily
67 feasible without having a central instance to collect
68 the local topologies from all nodes. This file allows
69 to activate the collecting (server) mode.
diff --git a/Documentation/networking/batman-adv.txt b/Documentation/networking/batman-adv.txt
new file mode 100644
index 000000000000..77f0cdd5b0dd
--- /dev/null
+++ b/Documentation/networking/batman-adv.txt
@@ -0,0 +1,240 @@
1[state: 21-11-2010]
2
3BATMAN-ADV
4----------
5
6Batman advanced is a new approach to wireless networking which
7does no longer operate on the IP basis. Unlike the batman daemon,
8which exchanges information using UDP packets and sets routing
9tables, batman-advanced operates on ISO/OSI Layer 2 only and uses
10and routes (or better: bridges) Ethernet Frames. It emulates a
11virtual network switch of all nodes participating. Therefore all
12nodes appear to be link local, thus all higher operating proto-
13cols won't be affected by any changes within the network. You can
14run almost any protocol above batman advanced, prominent examples
15are: IPv4, IPv6, DHCP, IPX.
16
17Batman advanced was implemented as a Linux kernel driver to re-
18duce the overhead to a minimum. It does not depend on any (other)
19network driver, and can be used on wifi as well as ethernet lan,
20vpn, etc ... (anything with ethernet-style layer 2).
21
22CONFIGURATION
23-------------
24
25Load the batman-adv module into your kernel:
26
27# insmod batman-adv.ko
28
29The module is now waiting for activation. You must add some in-
30terfaces on which batman can operate. After loading the module
31batman advanced will scan your systems interfaces to search for
32compatible interfaces. Once found, it will create subfolders in
33the /sys directories of each supported interface, e.g.
34
35# ls /sys/class/net/eth0/batman_adv/
36# iface_status mesh_iface
37
38If an interface does not have the "batman_adv" subfolder it prob-
39ably is not supported. Not supported interfaces are: loopback,
40non-ethernet and batman's own interfaces.
41
42Note: After the module was loaded it will continuously watch for
43new interfaces to verify the compatibility. There is no need to
44reload the module if you plug your USB wifi adapter into your ma-
45chine after batman advanced was initially loaded.
46
47To activate a given interface simply write "bat0" into its
48"mesh_iface" file inside the batman_adv subfolder:
49
50# echo bat0 > /sys/class/net/eth0/batman_adv/mesh_iface
51
52Repeat this step for all interfaces you wish to add. Now batman
53starts using/broadcasting on this/these interface(s).
54
55By reading the "iface_status" file you can check its status:
56
57# cat /sys/class/net/eth0/batman_adv/iface_status
58# active
59
60To deactivate an interface you have to write "none" into its
61"mesh_iface" file:
62
63# echo none > /sys/class/net/eth0/batman_adv/mesh_iface
64
65
66All mesh wide settings can be found in batman's own interface
67folder:
68
69# ls /sys/class/net/bat0/mesh/
70# aggregated_ogms bonding fragmentation orig_interval
71# vis_mode
72
73
74There is a special folder for debugging informations:
75
76# ls /sys/kernel/debug/batman_adv/bat0/
77# originators socket transtable_global transtable_local
78# vis_data
79
80
81Some of the files contain all sort of status information regard-
82ing the mesh network. For example, you can view the table of
83originators (mesh participants) with:
84
85# cat /sys/kernel/debug/batman_adv/bat0/originators
86
87Other files allow to change batman's behaviour to better fit your
88requirements. For instance, you can check the current originator
89interval (value in milliseconds which determines how often batman
90sends its broadcast packets):
91
92# cat /sys/class/net/bat0/mesh/orig_interval
93# 1000
94
95and also change its value:
96
97# echo 3000 > /sys/class/net/bat0/mesh/orig_interval
98
99In very mobile scenarios, you might want to adjust the originator
100interval to a lower value. This will make the mesh more respon-
101sive to topology changes, but will also increase the overhead.
102
103
104USAGE
105-----
106
107To make use of your newly created mesh, batman advanced provides
108a new interface "bat0" which you should use from this point on.
109All interfaces added to batman advanced are not relevant any
110longer because batman handles them for you. Basically, one "hands
111over" the data by using the batman interface and batman will make
112sure it reaches its destination.
113
114The "bat0" interface can be used like any other regular inter-
115face. It needs an IP address which can be either statically con-
116figured or dynamically (by using DHCP or similar services):
117
118# NodeA: ifconfig bat0 192.168.0.1
119# NodeB: ifconfig bat0 192.168.0.2
120# NodeB: ping 192.168.0.1
121
122Note: In order to avoid problems remove all IP addresses previ-
123ously assigned to interfaces now used by batman advanced, e.g.
124
125# ifconfig eth0 0.0.0.0
126
127
128VISUALIZATION
129-------------
130
131If you want topology visualization, at least one mesh node must
132be configured as VIS-server:
133
134# echo "server" > /sys/class/net/bat0/mesh/vis_mode
135
136Each node is either configured as "server" or as "client" (de-
137fault: "client"). Clients send their topology data to the server
138next to them, and server synchronize with other servers. If there
139is no server configured (default) within the mesh, no topology
140information will be transmitted. With these "synchronizing
141servers", there can be 1 or more vis servers sharing the same (or
142at least very similar) data.
143
144When configured as server, you can get a topology snapshot of
145your mesh:
146
147# cat /sys/kernel/debug/batman_adv/bat0/vis_data
148
149This raw output is intended to be easily parsable and convertable
150with other tools. Have a look at the batctl README if you want a
151vis output in dot or json format for instance and how those out-
152puts could then be visualised in an image.
153
154The raw format consists of comma separated values per entry where
155each entry is giving information about a certain source inter-
156face. Each entry can/has to have the following values:
157-> "mac" - mac address of an originator's source interface
158 (each line begins with it)
159-> "TQ mac value" - src mac's link quality towards mac address
160 of a neighbor originator's interface which
161 is being used for routing
162-> "HNA mac" - HNA announced by source mac
163-> "PRIMARY" - this is a primary interface
164-> "SEC mac" - secondary mac address of source
165 (requires preceding PRIMARY)
166
167The TQ value has a range from 4 to 255 with 255 being the best.
168The HNA entries are showing which hosts are connected to the mesh
169via bat0 or being bridged into the mesh network. The PRIMARY/SEC
170values are only applied on primary interfaces
171
172
173LOGGING/DEBUGGING
174-----------------
175
176All error messages, warnings and information messages are sent to
177the kernel log. Depending on your operating system distribution
178this can be read in one of a number of ways. Try using the com-
179mands: dmesg, logread, or looking in the files /var/log/kern.log
180or /var/log/syslog. All batman-adv messages are prefixed with
181"batman-adv:" So to see just these messages try
182
183# dmesg | grep batman-adv
184
185When investigating problems with your mesh network it is some-
186times necessary to see more detail debug messages. This must be
187enabled when compiling the batman-adv module. When building bat-
188man-adv as part of kernel, use "make menuconfig" and enable the
189option "B.A.T.M.A.N. debugging".
190
191Those additional debug messages can be accessed using a special
192file in debugfs
193
194# cat /sys/kernel/debug/batman_adv/bat0/log
195
196The additional debug output is by default disabled. It can be en-
197abled during run time. Following log_levels are defined:
198
1990 - All debug output disabled
2001 - Enable messages related to routing / flooding / broadcasting
2012 - Enable route or hna added / changed / deleted
2023 - Enable all messages
203
204The debug output can be changed at runtime using the file
205/sys/class/net/bat0/mesh/log_level. e.g.
206
207# echo 2 > /sys/class/net/bat0/mesh/log_level
208
209will enable debug messages for when routes or HNAs change.
210
211
212BATCTL
213------
214
215As batman advanced operates on layer 2 all hosts participating in
216the virtual switch are completely transparent for all protocols
217above layer 2. Therefore the common diagnosis tools do not work
218as expected. To overcome these problems batctl was created. At
219the moment the batctl contains ping, traceroute, tcpdump and
220interfaces to the kernel module settings.
221
222For more information, please see the manpage (man batctl).
223
224batctl is available on http://www.open-mesh.org/
225
226
227CONTACT
228-------
229
230Please send us comments, experiences, questions, anything :)
231
232IRC: #batman on irc.freenode.org
233Mailing-list: b.a.t.m.a.n@b.a.t.m.a.n@lists.open-mesh.org
234 (optional subscription at
235 https://lists.open-mesh.org/mm/listinfo/b.a.t.m.a.n)
236
237You can also contact the Authors:
238
239Marek Lindner <lindner_marek@yahoo.de>
240Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
diff --git a/MAINTAINERS b/MAINTAINERS
index f16ce8f46934..2a5e60fb3b5d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1264,6 +1264,15 @@ S: Maintained
1264F: drivers/video/backlight/ 1264F: drivers/video/backlight/
1265F: include/linux/backlight.h 1265F: include/linux/backlight.h
1266 1266
1267BATMAN ADVANCED
1268M: Marek Lindner <lindner_marek@yahoo.de>
1269M: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
1270M: Sven Eckelmann <sven@narfation.org>
1271L: b.a.t.m.a.n@lists.open-mesh.org
1272W: http://www.open-mesh.org/
1273S: Maintained
1274F: net/batman-adv/
1275
1267BAYCOM/HDLCDRV DRIVERS FOR AX.25 1276BAYCOM/HDLCDRV DRIVERS FOR AX.25
1268M: Thomas Sailer <t.sailer@alumni.ethz.ch> 1277M: Thomas Sailer <t.sailer@alumni.ethz.ch>
1269L: linux-hams@vger.kernel.org 1278L: linux-hams@vger.kernel.org
diff --git a/net/Kconfig b/net/Kconfig
index 126c2af0fc1f..ad0aafe903f8 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -214,6 +214,7 @@ source "net/ieee802154/Kconfig"
214source "net/sched/Kconfig" 214source "net/sched/Kconfig"
215source "net/dcb/Kconfig" 215source "net/dcb/Kconfig"
216source "net/dns_resolver/Kconfig" 216source "net/dns_resolver/Kconfig"
217source "net/batman-adv/Kconfig"
217 218
218config RPS 219config RPS
219 boolean 220 boolean
diff --git a/net/Makefile b/net/Makefile
index 6b7bfd7f1416..a3330ebe2c53 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -69,3 +69,4 @@ endif
69obj-$(CONFIG_WIMAX) += wimax/ 69obj-$(CONFIG_WIMAX) += wimax/
70obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/ 70obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/
71obj-$(CONFIG_CEPH_LIB) += ceph/ 71obj-$(CONFIG_CEPH_LIB) += ceph/
72obj-$(CONFIG_BATMAN_ADV) += batman-adv/
diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
new file mode 100644
index 000000000000..6c051ad833eb
--- /dev/null
+++ b/net/batman-adv/Kconfig
@@ -0,0 +1,25 @@
1#
2# B.A.T.M.A.N meshing protocol
3#
4
5config BATMAN_ADV
6 tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
7 depends on NET
8 default n
9 ---help---
10
11 B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
12 a routing protocol for multi-hop ad-hoc mesh networks. The
13 networks may be wired or wireless. See
14 http://www.open-mesh.org/ for more information and user space
15 tools.
16
17config BATMAN_ADV_DEBUG
18 bool "B.A.T.M.A.N. debugging"
19 depends on BATMAN_ADV != n
20 ---help---
21
22 This is an option for use by developers; most people should
23 say N here. This enables compilation of support for
24 outputting debugging information to the kernel log. The
25 output is controlled via the module parameter debug.
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile
new file mode 100644
index 000000000000..d936aeccd194
--- /dev/null
+++ b/net/batman-adv/Makefile
@@ -0,0 +1,39 @@
1#
2# Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3#
4# Marek Lindner, Simon Wunderlich
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of version 2 of the GNU General Public
8# License as published by the Free Software Foundation.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18# 02110-1301, USA
19#
20
21obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
22batman-adv-y += aggregation.o
23batman-adv-y += bat_debugfs.o
24batman-adv-y += bat_sysfs.o
25batman-adv-y += bitarray.o
26batman-adv-y += gateway_client.o
27batman-adv-y += gateway_common.o
28batman-adv-y += hard-interface.o
29batman-adv-y += hash.o
30batman-adv-y += icmp_socket.o
31batman-adv-y += main.o
32batman-adv-y += originator.o
33batman-adv-y += ring_buffer.o
34batman-adv-y += routing.o
35batman-adv-y += send.o
36batman-adv-y += soft-interface.o
37batman-adv-y += translation-table.o
38batman-adv-y += unicast.o
39batman-adv-y += vis.o
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c
new file mode 100644
index 000000000000..3850a3ecf947
--- /dev/null
+++ b/net/batman-adv/aggregation.c
@@ -0,0 +1,273 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "aggregation.h"
24#include "send.h"
25#include "routing.h"
26
27/* calculate the size of the hna information for a given packet */
28static int hna_len(struct batman_packet *batman_packet)
29{
30 return batman_packet->num_hna * ETH_ALEN;
31}
32
33/* return true if new_packet can be aggregated with forw_packet */
34static bool can_aggregate_with(struct batman_packet *new_batman_packet,
35 int packet_len,
36 unsigned long send_time,
37 bool directlink,
38 struct batman_if *if_incoming,
39 struct forw_packet *forw_packet)
40{
41 struct batman_packet *batman_packet =
42 (struct batman_packet *)forw_packet->skb->data;
43 int aggregated_bytes = forw_packet->packet_len + packet_len;
44
45 /**
46 * we can aggregate the current packet to this aggregated packet
47 * if:
48 *
49 * - the send time is within our MAX_AGGREGATION_MS time
50 * - the resulting packet wont be bigger than
51 * MAX_AGGREGATION_BYTES
52 */
53
54 if (time_before(send_time, forw_packet->send_time) &&
55 time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),
56 forw_packet->send_time) &&
57 (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
58
59 /**
60 * check aggregation compatibility
61 * -> direct link packets are broadcasted on
62 * their interface only
63 * -> aggregate packet if the current packet is
64 * a "global" packet as well as the base
65 * packet
66 */
67
68 /* packets without direct link flag and high TTL
69 * are flooded through the net */
70 if ((!directlink) &&
71 (!(batman_packet->flags & DIRECTLINK)) &&
72 (batman_packet->ttl != 1) &&
73
74 /* own packets originating non-primary
75 * interfaces leave only that interface */
76 ((!forw_packet->own) ||
77 (forw_packet->if_incoming->if_num == 0)))
78 return true;
79
80 /* if the incoming packet is sent via this one
81 * interface only - we still can aggregate */
82 if ((directlink) &&
83 (new_batman_packet->ttl == 1) &&
84 (forw_packet->if_incoming == if_incoming) &&
85
86 /* packets from direct neighbors or
87 * own secondary interface packets
88 * (= secondary interface packets in general) */
89 (batman_packet->flags & DIRECTLINK ||
90 (forw_packet->own &&
91 forw_packet->if_incoming->if_num != 0)))
92 return true;
93 }
94
95 return false;
96}
97
98#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
99/* create a new aggregated packet and add this packet to it */
100static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
101 unsigned long send_time, bool direct_link,
102 struct batman_if *if_incoming,
103 int own_packet)
104{
105 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
106 struct forw_packet *forw_packet_aggr;
107 unsigned char *skb_buff;
108
109 /* own packet should always be scheduled */
110 if (!own_packet) {
111 if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
112 bat_dbg(DBG_BATMAN, bat_priv,
113 "batman packet queue full\n");
114 return;
115 }
116 }
117
118 forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
119 if (!forw_packet_aggr) {
120 if (!own_packet)
121 atomic_inc(&bat_priv->batman_queue_left);
122 return;
123 }
124
125 if ((atomic_read(&bat_priv->aggregated_ogms)) &&
126 (packet_len < MAX_AGGREGATION_BYTES))
127 forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +
128 sizeof(struct ethhdr));
129 else
130 forw_packet_aggr->skb = dev_alloc_skb(packet_len +
131 sizeof(struct ethhdr));
132
133 if (!forw_packet_aggr->skb) {
134 if (!own_packet)
135 atomic_inc(&bat_priv->batman_queue_left);
136 kfree(forw_packet_aggr);
137 return;
138 }
139 skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));
140
141 INIT_HLIST_NODE(&forw_packet_aggr->list);
142
143 skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
144 forw_packet_aggr->packet_len = packet_len;
145 memcpy(skb_buff, packet_buff, packet_len);
146
147 forw_packet_aggr->own = own_packet;
148 forw_packet_aggr->if_incoming = if_incoming;
149 forw_packet_aggr->num_packets = 0;
150 forw_packet_aggr->direct_link_flags = 0;
151 forw_packet_aggr->send_time = send_time;
152
153 /* save packet direct link flag status */
154 if (direct_link)
155 forw_packet_aggr->direct_link_flags |= 1;
156
157 /* add new packet to packet list */
158 spin_lock_bh(&bat_priv->forw_bat_list_lock);
159 hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);
160 spin_unlock_bh(&bat_priv->forw_bat_list_lock);
161
162 /* start timer for this packet */
163 INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
164 send_outstanding_bat_packet);
165 queue_delayed_work(bat_event_workqueue,
166 &forw_packet_aggr->delayed_work,
167 send_time - jiffies);
168}
169
170/* aggregate a new packet into the existing aggregation */
171static void aggregate(struct forw_packet *forw_packet_aggr,
172 unsigned char *packet_buff,
173 int packet_len,
174 bool direct_link)
175{
176 unsigned char *skb_buff;
177
178 skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
179 memcpy(skb_buff, packet_buff, packet_len);
180 forw_packet_aggr->packet_len += packet_len;
181 forw_packet_aggr->num_packets++;
182
183 /* save packet direct link flag status */
184 if (direct_link)
185 forw_packet_aggr->direct_link_flags |=
186 (1 << forw_packet_aggr->num_packets);
187}
188
189void add_bat_packet_to_list(struct bat_priv *bat_priv,
190 unsigned char *packet_buff, int packet_len,
191 struct batman_if *if_incoming, char own_packet,
192 unsigned long send_time)
193{
194 /**
195 * _aggr -> pointer to the packet we want to aggregate with
196 * _pos -> pointer to the position in the queue
197 */
198 struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
199 struct hlist_node *tmp_node;
200 struct batman_packet *batman_packet =
201 (struct batman_packet *)packet_buff;
202 bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
203
204 /* find position for the packet in the forward queue */
205 spin_lock_bh(&bat_priv->forw_bat_list_lock);
206 /* own packets are not to be aggregated */
207 if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {
208 hlist_for_each_entry(forw_packet_pos, tmp_node,
209 &bat_priv->forw_bat_list, list) {
210 if (can_aggregate_with(batman_packet,
211 packet_len,
212 send_time,
213 direct_link,
214 if_incoming,
215 forw_packet_pos)) {
216 forw_packet_aggr = forw_packet_pos;
217 break;
218 }
219 }
220 }
221
222 /* nothing to aggregate with - either aggregation disabled or no
223 * suitable aggregation packet found */
224 if (!forw_packet_aggr) {
225 /* the following section can run without the lock */
226 spin_unlock_bh(&bat_priv->forw_bat_list_lock);
227
228 /**
229 * if we could not aggregate this packet with one of the others
230 * we hold it back for a while, so that it might be aggregated
231 * later on
232 */
233 if ((!own_packet) &&
234 (atomic_read(&bat_priv->aggregated_ogms)))
235 send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);
236
237 new_aggregated_packet(packet_buff, packet_len,
238 send_time, direct_link,
239 if_incoming, own_packet);
240 } else {
241 aggregate(forw_packet_aggr,
242 packet_buff, packet_len,
243 direct_link);
244 spin_unlock_bh(&bat_priv->forw_bat_list_lock);
245 }
246}
247
248/* unpack the aggregated packets and process them one by one */
249void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
250 int packet_len, struct batman_if *if_incoming)
251{
252 struct batman_packet *batman_packet;
253 int buff_pos = 0;
254 unsigned char *hna_buff;
255
256 batman_packet = (struct batman_packet *)packet_buff;
257
258 do {
259 /* network to host order for our 32bit seqno, and the
260 orig_interval. */
261 batman_packet->seqno = ntohl(batman_packet->seqno);
262
263 hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
264 receive_bat_packet(ethhdr, batman_packet,
265 hna_buff, hna_len(batman_packet),
266 if_incoming);
267
268 buff_pos += BAT_PACKET_LEN + hna_len(batman_packet);
269 batman_packet = (struct batman_packet *)
270 (packet_buff + buff_pos);
271 } while (aggregated_packet(buff_pos, packet_len,
272 batman_packet->num_hna));
273}
diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h
new file mode 100644
index 000000000000..71a91b3da913
--- /dev/null
+++ b/net/batman-adv/aggregation.h
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_AGGREGATION_H_
23#define _NET_BATMAN_ADV_AGGREGATION_H_
24
25#include "main.h"
26
27/* is there another aggregated packet here? */
28static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna)
29{
30 int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN);
31
32 return (next_buff_pos <= packet_len) &&
33 (next_buff_pos <= MAX_AGGREGATION_BYTES);
34}
35
36void add_bat_packet_to_list(struct bat_priv *bat_priv,
37 unsigned char *packet_buff, int packet_len,
38 struct batman_if *if_incoming, char own_packet,
39 unsigned long send_time);
40void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
41 int packet_len, struct batman_if *if_incoming);
42
43#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */
diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c
new file mode 100644
index 000000000000..0ae81d07f102
--- /dev/null
+++ b/net/batman-adv/bat_debugfs.c
@@ -0,0 +1,360 @@
1/*
2 * Copyright (C) 2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23
24#include <linux/debugfs.h>
25
26#include "bat_debugfs.h"
27#include "translation-table.h"
28#include "originator.h"
29#include "hard-interface.h"
30#include "gateway_common.h"
31#include "gateway_client.h"
32#include "soft-interface.h"
33#include "vis.h"
34#include "icmp_socket.h"
35
36static struct dentry *bat_debugfs;
37
38#ifdef CONFIG_BATMAN_ADV_DEBUG
39#define LOG_BUFF_MASK (log_buff_len-1)
40#define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK])
41
42static int log_buff_len = LOG_BUF_LEN;
43
44static void emit_log_char(struct debug_log *debug_log, char c)
45{
46 LOG_BUFF(debug_log->log_end) = c;
47 debug_log->log_end++;
48
49 if (debug_log->log_end - debug_log->log_start > log_buff_len)
50 debug_log->log_start = debug_log->log_end - log_buff_len;
51}
52
53static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
54{
55 int printed_len;
56 va_list args;
57 static char debug_log_buf[256];
58 char *p;
59
60 if (!debug_log)
61 return 0;
62
63 spin_lock_bh(&debug_log->lock);
64 va_start(args, fmt);
65 printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf),
66 fmt, args);
67 va_end(args);
68
69 for (p = debug_log_buf; *p != 0; p++)
70 emit_log_char(debug_log, *p);
71
72 spin_unlock_bh(&debug_log->lock);
73
74 wake_up(&debug_log->queue_wait);
75
76 return 0;
77}
78
79int debug_log(struct bat_priv *bat_priv, char *fmt, ...)
80{
81 va_list args;
82 char tmp_log_buf[256];
83
84 va_start(args, fmt);
85 vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
86 fdebug_log(bat_priv->debug_log, "[%10u] %s",
87 (jiffies / HZ), tmp_log_buf);
88 va_end(args);
89
90 return 0;
91}
92
93static int log_open(struct inode *inode, struct file *file)
94{
95 nonseekable_open(inode, file);
96 file->private_data = inode->i_private;
97 inc_module_count();
98 return 0;
99}
100
101static int log_release(struct inode *inode, struct file *file)
102{
103 dec_module_count();
104 return 0;
105}
106
107static ssize_t log_read(struct file *file, char __user *buf,
108 size_t count, loff_t *ppos)
109{
110 struct bat_priv *bat_priv = file->private_data;
111 struct debug_log *debug_log = bat_priv->debug_log;
112 int error, i = 0;
113 char c;
114
115 if ((file->f_flags & O_NONBLOCK) &&
116 !(debug_log->log_end - debug_log->log_start))
117 return -EAGAIN;
118
119 if ((!buf) || (count < 0))
120 return -EINVAL;
121
122 if (count == 0)
123 return 0;
124
125 if (!access_ok(VERIFY_WRITE, buf, count))
126 return -EFAULT;
127
128 error = wait_event_interruptible(debug_log->queue_wait,
129 (debug_log->log_start - debug_log->log_end));
130
131 if (error)
132 return error;
133
134 spin_lock_bh(&debug_log->lock);
135
136 while ((!error) && (i < count) &&
137 (debug_log->log_start != debug_log->log_end)) {
138 c = LOG_BUFF(debug_log->log_start);
139
140 debug_log->log_start++;
141
142 spin_unlock_bh(&debug_log->lock);
143
144 error = __put_user(c, buf);
145
146 spin_lock_bh(&debug_log->lock);
147
148 buf++;
149 i++;
150
151 }
152
153 spin_unlock_bh(&debug_log->lock);
154
155 if (!error)
156 return i;
157
158 return error;
159}
160
161static unsigned int log_poll(struct file *file, poll_table *wait)
162{
163 struct bat_priv *bat_priv = file->private_data;
164 struct debug_log *debug_log = bat_priv->debug_log;
165
166 poll_wait(file, &debug_log->queue_wait, wait);
167
168 if (debug_log->log_end - debug_log->log_start)
169 return POLLIN | POLLRDNORM;
170
171 return 0;
172}
173
174static const struct file_operations log_fops = {
175 .open = log_open,
176 .release = log_release,
177 .read = log_read,
178 .poll = log_poll,
179 .llseek = no_llseek,
180};
181
182static int debug_log_setup(struct bat_priv *bat_priv)
183{
184 struct dentry *d;
185
186 if (!bat_priv->debug_dir)
187 goto err;
188
189 bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC);
190 if (!bat_priv->debug_log)
191 goto err;
192
193 spin_lock_init(&bat_priv->debug_log->lock);
194 init_waitqueue_head(&bat_priv->debug_log->queue_wait);
195
196 d = debugfs_create_file("log", S_IFREG | S_IRUSR,
197 bat_priv->debug_dir, bat_priv, &log_fops);
198 if (d)
199 goto err;
200
201 return 0;
202
203err:
204 return 1;
205}
206
207static void debug_log_cleanup(struct bat_priv *bat_priv)
208{
209 kfree(bat_priv->debug_log);
210 bat_priv->debug_log = NULL;
211}
212#else /* CONFIG_BATMAN_ADV_DEBUG */
213static int debug_log_setup(struct bat_priv *bat_priv)
214{
215 bat_priv->debug_log = NULL;
216 return 0;
217}
218
219static void debug_log_cleanup(struct bat_priv *bat_priv)
220{
221 return;
222}
223#endif
224
225static int originators_open(struct inode *inode, struct file *file)
226{
227 struct net_device *net_dev = (struct net_device *)inode->i_private;
228 return single_open(file, orig_seq_print_text, net_dev);
229}
230
231static int gateways_open(struct inode *inode, struct file *file)
232{
233 struct net_device *net_dev = (struct net_device *)inode->i_private;
234 return single_open(file, gw_client_seq_print_text, net_dev);
235}
236
237static int softif_neigh_open(struct inode *inode, struct file *file)
238{
239 struct net_device *net_dev = (struct net_device *)inode->i_private;
240 return single_open(file, softif_neigh_seq_print_text, net_dev);
241}
242
243static int transtable_global_open(struct inode *inode, struct file *file)
244{
245 struct net_device *net_dev = (struct net_device *)inode->i_private;
246 return single_open(file, hna_global_seq_print_text, net_dev);
247}
248
249static int transtable_local_open(struct inode *inode, struct file *file)
250{
251 struct net_device *net_dev = (struct net_device *)inode->i_private;
252 return single_open(file, hna_local_seq_print_text, net_dev);
253}
254
255static int vis_data_open(struct inode *inode, struct file *file)
256{
257 struct net_device *net_dev = (struct net_device *)inode->i_private;
258 return single_open(file, vis_seq_print_text, net_dev);
259}
260
261struct bat_debuginfo {
262 struct attribute attr;
263 const struct file_operations fops;
264};
265
266#define BAT_DEBUGINFO(_name, _mode, _open) \
267struct bat_debuginfo bat_debuginfo_##_name = { \
268 .attr = { .name = __stringify(_name), \
269 .mode = _mode, }, \
270 .fops = { .owner = THIS_MODULE, \
271 .open = _open, \
272 .read = seq_read, \
273 .llseek = seq_lseek, \
274 .release = single_release, \
275 } \
276};
277
278static BAT_DEBUGINFO(originators, S_IRUGO, originators_open);
279static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open);
280static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open);
281static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open);
282static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open);
283static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open);
284
285static struct bat_debuginfo *mesh_debuginfos[] = {
286 &bat_debuginfo_originators,
287 &bat_debuginfo_gateways,
288 &bat_debuginfo_softif_neigh,
289 &bat_debuginfo_transtable_global,
290 &bat_debuginfo_transtable_local,
291 &bat_debuginfo_vis_data,
292 NULL,
293};
294
295void debugfs_init(void)
296{
297 bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL);
298 if (bat_debugfs == ERR_PTR(-ENODEV))
299 bat_debugfs = NULL;
300}
301
302void debugfs_destroy(void)
303{
304 if (bat_debugfs) {
305 debugfs_remove_recursive(bat_debugfs);
306 bat_debugfs = NULL;
307 }
308}
309
310int debugfs_add_meshif(struct net_device *dev)
311{
312 struct bat_priv *bat_priv = netdev_priv(dev);
313 struct bat_debuginfo **bat_debug;
314 struct dentry *file;
315
316 if (!bat_debugfs)
317 goto out;
318
319 bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs);
320 if (!bat_priv->debug_dir)
321 goto out;
322
323 bat_socket_setup(bat_priv);
324 debug_log_setup(bat_priv);
325
326 for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) {
327 file = debugfs_create_file(((*bat_debug)->attr).name,
328 S_IFREG | ((*bat_debug)->attr).mode,
329 bat_priv->debug_dir,
330 dev, &(*bat_debug)->fops);
331 if (!file) {
332 bat_err(dev, "Can't add debugfs file: %s/%s\n",
333 dev->name, ((*bat_debug)->attr).name);
334 goto rem_attr;
335 }
336 }
337
338 return 0;
339rem_attr:
340 debugfs_remove_recursive(bat_priv->debug_dir);
341 bat_priv->debug_dir = NULL;
342out:
343#ifdef CONFIG_DEBUG_FS
344 return -ENOMEM;
345#else
346 return 0;
347#endif /* CONFIG_DEBUG_FS */
348}
349
350void debugfs_del_meshif(struct net_device *dev)
351{
352 struct bat_priv *bat_priv = netdev_priv(dev);
353
354 debug_log_cleanup(bat_priv);
355
356 if (bat_debugfs) {
357 debugfs_remove_recursive(bat_priv->debug_dir);
358 bat_priv->debug_dir = NULL;
359 }
360}
diff --git a/net/batman-adv/bat_debugfs.h b/net/batman-adv/bat_debugfs.h
new file mode 100644
index 000000000000..72df532b7d5f
--- /dev/null
+++ b/net/batman-adv/bat_debugfs.h
@@ -0,0 +1,33 @@
1/*
2 * Copyright (C) 2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22
23#ifndef _NET_BATMAN_ADV_DEBUGFS_H_
24#define _NET_BATMAN_ADV_DEBUGFS_H_
25
26#define DEBUGFS_BAT_SUBDIR "batman_adv"
27
28void debugfs_init(void);
29void debugfs_destroy(void);
30int debugfs_add_meshif(struct net_device *dev);
31void debugfs_del_meshif(struct net_device *dev);
32
33#endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c
new file mode 100644
index 000000000000..cd7bb51825f1
--- /dev/null
+++ b/net/batman-adv/bat_sysfs.c
@@ -0,0 +1,593 @@
1/*
2 * Copyright (C) 2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "bat_sysfs.h"
24#include "translation-table.h"
25#include "originator.h"
26#include "hard-interface.h"
27#include "gateway_common.h"
28#include "gateway_client.h"
29#include "vis.h"
30
31#define to_dev(obj) container_of(obj, struct device, kobj)
32#define kobj_to_netdev(obj) to_net_dev(to_dev(obj->parent))
33#define kobj_to_batpriv(obj) netdev_priv(kobj_to_netdev(obj))
34
35/* Use this, if you have customized show and store functions */
36#define BAT_ATTR(_name, _mode, _show, _store) \
37struct bat_attribute bat_attr_##_name = { \
38 .attr = {.name = __stringify(_name), \
39 .mode = _mode }, \
40 .show = _show, \
41 .store = _store, \
42};
43
44#define BAT_ATTR_STORE_BOOL(_name, _post_func) \
45ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \
46 char *buff, size_t count) \
47{ \
48 struct net_device *net_dev = kobj_to_netdev(kobj); \
49 struct bat_priv *bat_priv = netdev_priv(net_dev); \
50 return __store_bool_attr(buff, count, _post_func, attr, \
51 &bat_priv->_name, net_dev); \
52}
53
54#define BAT_ATTR_SHOW_BOOL(_name) \
55ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \
56 char *buff) \
57{ \
58 struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \
59 return sprintf(buff, "%s\n", \
60 atomic_read(&bat_priv->_name) == 0 ? \
61 "disabled" : "enabled"); \
62} \
63
64/* Use this, if you are going to turn a [name] in bat_priv on or off */
65#define BAT_ATTR_BOOL(_name, _mode, _post_func) \
66 static BAT_ATTR_STORE_BOOL(_name, _post_func) \
67 static BAT_ATTR_SHOW_BOOL(_name) \
68 static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
69
70
71#define BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \
72ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \
73 char *buff, size_t count) \
74{ \
75 struct net_device *net_dev = kobj_to_netdev(kobj); \
76 struct bat_priv *bat_priv = netdev_priv(net_dev); \
77 return __store_uint_attr(buff, count, _min, _max, _post_func, \
78 attr, &bat_priv->_name, net_dev); \
79}
80
81#define BAT_ATTR_SHOW_UINT(_name) \
82ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \
83 char *buff) \
84{ \
85 struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \
86 return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \
87} \
88
89/* Use this, if you are going to set [name] in bat_priv to unsigned integer
90 * values only */
91#define BAT_ATTR_UINT(_name, _mode, _min, _max, _post_func) \
92 static BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \
93 static BAT_ATTR_SHOW_UINT(_name) \
94 static BAT_ATTR(_name, _mode, show_##_name, store_##_name)
95
96
97static int store_bool_attr(char *buff, size_t count,
98 struct net_device *net_dev,
99 char *attr_name, atomic_t *attr)
100{
101 int enabled = -1;
102
103 if (buff[count - 1] == '\n')
104 buff[count - 1] = '\0';
105
106 if ((strncmp(buff, "1", 2) == 0) ||
107 (strncmp(buff, "enable", 7) == 0) ||
108 (strncmp(buff, "enabled", 8) == 0))
109 enabled = 1;
110
111 if ((strncmp(buff, "0", 2) == 0) ||
112 (strncmp(buff, "disable", 8) == 0) ||
113 (strncmp(buff, "disabled", 9) == 0))
114 enabled = 0;
115
116 if (enabled < 0) {
117 bat_info(net_dev,
118 "%s: Invalid parameter received: %s\n",
119 attr_name, buff);
120 return -EINVAL;
121 }
122
123 if (atomic_read(attr) == enabled)
124 return count;
125
126 bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name,
127 atomic_read(attr) == 1 ? "enabled" : "disabled",
128 enabled == 1 ? "enabled" : "disabled");
129
130 atomic_set(attr, (unsigned)enabled);
131 return count;
132}
133
134static inline ssize_t __store_bool_attr(char *buff, size_t count,
135 void (*post_func)(struct net_device *),
136 struct attribute *attr,
137 atomic_t *attr_store, struct net_device *net_dev)
138{
139 int ret;
140
141 ret = store_bool_attr(buff, count, net_dev, (char *)attr->name,
142 attr_store);
143 if (post_func && ret)
144 post_func(net_dev);
145
146 return ret;
147}
148
149static int store_uint_attr(char *buff, size_t count,
150 struct net_device *net_dev, char *attr_name,
151 unsigned int min, unsigned int max, atomic_t *attr)
152{
153 unsigned long uint_val;
154 int ret;
155
156 ret = strict_strtoul(buff, 10, &uint_val);
157 if (ret) {
158 bat_info(net_dev,
159 "%s: Invalid parameter received: %s\n",
160 attr_name, buff);
161 return -EINVAL;
162 }
163
164 if (uint_val < min) {
165 bat_info(net_dev, "%s: Value is too small: %lu min: %u\n",
166 attr_name, uint_val, min);
167 return -EINVAL;
168 }
169
170 if (uint_val > max) {
171 bat_info(net_dev, "%s: Value is too big: %lu max: %u\n",
172 attr_name, uint_val, max);
173 return -EINVAL;
174 }
175
176 if (atomic_read(attr) == uint_val)
177 return count;
178
179 bat_info(net_dev, "%s: Changing from: %i to: %lu\n",
180 attr_name, atomic_read(attr), uint_val);
181
182 atomic_set(attr, uint_val);
183 return count;
184}
185
186static inline ssize_t __store_uint_attr(char *buff, size_t count,
187 int min, int max,
188 void (*post_func)(struct net_device *),
189 struct attribute *attr,
190 atomic_t *attr_store, struct net_device *net_dev)
191{
192 int ret;
193
194 ret = store_uint_attr(buff, count, net_dev, (char *)attr->name,
195 min, max, attr_store);
196 if (post_func && ret)
197 post_func(net_dev);
198
199 return ret;
200}
201
202static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr,
203 char *buff)
204{
205 struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
206 int vis_mode = atomic_read(&bat_priv->vis_mode);
207
208 return sprintf(buff, "%s\n",
209 vis_mode == VIS_TYPE_CLIENT_UPDATE ?
210 "client" : "server");
211}
212
213static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
214 char *buff, size_t count)
215{
216 struct net_device *net_dev = kobj_to_netdev(kobj);
217 struct bat_priv *bat_priv = netdev_priv(net_dev);
218 unsigned long val;
219 int ret, vis_mode_tmp = -1;
220
221 ret = strict_strtoul(buff, 10, &val);
222
223 if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) ||
224 (strncmp(buff, "client", 6) == 0) ||
225 (strncmp(buff, "off", 3) == 0))
226 vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE;
227
228 if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) ||
229 (strncmp(buff, "server", 6) == 0))
230 vis_mode_tmp = VIS_TYPE_SERVER_SYNC;
231
232 if (vis_mode_tmp < 0) {
233 if (buff[count - 1] == '\n')
234 buff[count - 1] = '\0';
235
236 bat_info(net_dev,
237 "Invalid parameter for 'vis mode' setting received: "
238 "%s\n", buff);
239 return -EINVAL;
240 }
241
242 if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp)
243 return count;
244
245 bat_info(net_dev, "Changing vis mode from: %s to: %s\n",
246 atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ?
247 "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ?
248 "client" : "server");
249
250 atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp);
251 return count;
252}
253
254static void post_gw_deselect(struct net_device *net_dev)
255{
256 struct bat_priv *bat_priv = netdev_priv(net_dev);
257 gw_deselect(bat_priv);
258}
259
260static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr,
261 char *buff)
262{
263 struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
264 int bytes_written;
265
266 switch (atomic_read(&bat_priv->gw_mode)) {
267 case GW_MODE_CLIENT:
268 bytes_written = sprintf(buff, "%s\n", GW_MODE_CLIENT_NAME);
269 break;
270 case GW_MODE_SERVER:
271 bytes_written = sprintf(buff, "%s\n", GW_MODE_SERVER_NAME);
272 break;
273 default:
274 bytes_written = sprintf(buff, "%s\n", GW_MODE_OFF_NAME);
275 break;
276 }
277
278 return bytes_written;
279}
280
281static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr,
282 char *buff, size_t count)
283{
284 struct net_device *net_dev = kobj_to_netdev(kobj);
285 struct bat_priv *bat_priv = netdev_priv(net_dev);
286 char *curr_gw_mode_str;
287 int gw_mode_tmp = -1;
288
289 if (buff[count - 1] == '\n')
290 buff[count - 1] = '\0';
291
292 if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0)
293 gw_mode_tmp = GW_MODE_OFF;
294
295 if (strncmp(buff, GW_MODE_CLIENT_NAME,
296 strlen(GW_MODE_CLIENT_NAME)) == 0)
297 gw_mode_tmp = GW_MODE_CLIENT;
298
299 if (strncmp(buff, GW_MODE_SERVER_NAME,
300 strlen(GW_MODE_SERVER_NAME)) == 0)
301 gw_mode_tmp = GW_MODE_SERVER;
302
303 if (gw_mode_tmp < 0) {
304 bat_info(net_dev,
305 "Invalid parameter for 'gw mode' setting received: "
306 "%s\n", buff);
307 return -EINVAL;
308 }
309
310 if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp)
311 return count;
312
313 switch (atomic_read(&bat_priv->gw_mode)) {
314 case GW_MODE_CLIENT:
315 curr_gw_mode_str = GW_MODE_CLIENT_NAME;
316 break;
317 case GW_MODE_SERVER:
318 curr_gw_mode_str = GW_MODE_SERVER_NAME;
319 break;
320 default:
321 curr_gw_mode_str = GW_MODE_OFF_NAME;
322 break;
323 }
324
325 bat_info(net_dev, "Changing gw mode from: %s to: %s\n",
326 curr_gw_mode_str, buff);
327
328 gw_deselect(bat_priv);
329 atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp);
330 return count;
331}
332
333static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr,
334 char *buff)
335{
336 struct bat_priv *bat_priv = kobj_to_batpriv(kobj);
337 int down, up;
338 int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth);
339
340 gw_bandwidth_to_kbit(gw_bandwidth, &down, &up);
341 return sprintf(buff, "%i%s/%i%s\n",
342 (down > 2048 ? down / 1024 : down),
343 (down > 2048 ? "MBit" : "KBit"),
344 (up > 2048 ? up / 1024 : up),
345 (up > 2048 ? "MBit" : "KBit"));
346}
347
348static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr,
349 char *buff, size_t count)
350{
351 struct net_device *net_dev = kobj_to_netdev(kobj);
352
353 if (buff[count - 1] == '\n')
354 buff[count - 1] = '\0';
355
356 return gw_bandwidth_set(net_dev, buff, count);
357}
358
359BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
360BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
361BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu);
362static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
363static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode);
364BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL);
365BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL);
366BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
367 post_gw_deselect);
368static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth,
369 store_gw_bwidth);
370#ifdef CONFIG_BATMAN_ADV_DEBUG
371BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL);
372#endif
373
374static struct bat_attribute *mesh_attrs[] = {
375 &bat_attr_aggregated_ogms,
376 &bat_attr_bonding,
377 &bat_attr_fragmentation,
378 &bat_attr_vis_mode,
379 &bat_attr_gw_mode,
380 &bat_attr_orig_interval,
381 &bat_attr_hop_penalty,
382 &bat_attr_gw_sel_class,
383 &bat_attr_gw_bandwidth,
384#ifdef CONFIG_BATMAN_ADV_DEBUG
385 &bat_attr_log_level,
386#endif
387 NULL,
388};
389
390int sysfs_add_meshif(struct net_device *dev)
391{
392 struct kobject *batif_kobject = &dev->dev.kobj;
393 struct bat_priv *bat_priv = netdev_priv(dev);
394 struct bat_attribute **bat_attr;
395 int err;
396
397 bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR,
398 batif_kobject);
399 if (!bat_priv->mesh_obj) {
400 bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
401 SYSFS_IF_MESH_SUBDIR);
402 goto out;
403 }
404
405 for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) {
406 err = sysfs_create_file(bat_priv->mesh_obj,
407 &((*bat_attr)->attr));
408 if (err) {
409 bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
410 dev->name, SYSFS_IF_MESH_SUBDIR,
411 ((*bat_attr)->attr).name);
412 goto rem_attr;
413 }
414 }
415
416 return 0;
417
418rem_attr:
419 for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
420 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
421
422 kobject_put(bat_priv->mesh_obj);
423 bat_priv->mesh_obj = NULL;
424out:
425 return -ENOMEM;
426}
427
428void sysfs_del_meshif(struct net_device *dev)
429{
430 struct bat_priv *bat_priv = netdev_priv(dev);
431 struct bat_attribute **bat_attr;
432
433 for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
434 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
435
436 kobject_put(bat_priv->mesh_obj);
437 bat_priv->mesh_obj = NULL;
438}
439
440static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
441 char *buff)
442{
443 struct net_device *net_dev = kobj_to_netdev(kobj);
444 struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
445 ssize_t length;
446
447 if (!batman_if)
448 return 0;
449
450 length = sprintf(buff, "%s\n", batman_if->if_status == IF_NOT_IN_USE ?
451 "none" : batman_if->soft_iface->name);
452
453 kref_put(&batman_if->refcount, hardif_free_ref);
454
455 return length;
456}
457
458static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
459 char *buff, size_t count)
460{
461 struct net_device *net_dev = kobj_to_netdev(kobj);
462 struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
463 int status_tmp = -1;
464 int ret;
465
466 if (!batman_if)
467 return count;
468
469 if (buff[count - 1] == '\n')
470 buff[count - 1] = '\0';
471
472 if (strlen(buff) >= IFNAMSIZ) {
473 pr_err("Invalid parameter for 'mesh_iface' setting received: "
474 "interface name too long '%s'\n", buff);
475 kref_put(&batman_if->refcount, hardif_free_ref);
476 return -EINVAL;
477 }
478
479 if (strncmp(buff, "none", 4) == 0)
480 status_tmp = IF_NOT_IN_USE;
481 else
482 status_tmp = IF_I_WANT_YOU;
483
484 if ((batman_if->if_status == status_tmp) || ((batman_if->soft_iface) &&
485 (strncmp(batman_if->soft_iface->name, buff, IFNAMSIZ) == 0))) {
486 kref_put(&batman_if->refcount, hardif_free_ref);
487 return count;
488 }
489
490 if (status_tmp == IF_NOT_IN_USE) {
491 rtnl_lock();
492 hardif_disable_interface(batman_if);
493 rtnl_unlock();
494 kref_put(&batman_if->refcount, hardif_free_ref);
495 return count;
496 }
497
498 /* if the interface already is in use */
499 if (batman_if->if_status != IF_NOT_IN_USE) {
500 rtnl_lock();
501 hardif_disable_interface(batman_if);
502 rtnl_unlock();
503 }
504
505 ret = hardif_enable_interface(batman_if, buff);
506 kref_put(&batman_if->refcount, hardif_free_ref);
507
508 return ret;
509}
510
511static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
512 char *buff)
513{
514 struct net_device *net_dev = kobj_to_netdev(kobj);
515 struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
516 ssize_t length;
517
518 if (!batman_if)
519 return 0;
520
521 switch (batman_if->if_status) {
522 case IF_TO_BE_REMOVED:
523 length = sprintf(buff, "disabling\n");
524 break;
525 case IF_INACTIVE:
526 length = sprintf(buff, "inactive\n");
527 break;
528 case IF_ACTIVE:
529 length = sprintf(buff, "active\n");
530 break;
531 case IF_TO_BE_ACTIVATED:
532 length = sprintf(buff, "enabling\n");
533 break;
534 case IF_NOT_IN_USE:
535 default:
536 length = sprintf(buff, "not in use\n");
537 break;
538 }
539
540 kref_put(&batman_if->refcount, hardif_free_ref);
541
542 return length;
543}
544
545static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR,
546 show_mesh_iface, store_mesh_iface);
547static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL);
548
549static struct bat_attribute *batman_attrs[] = {
550 &bat_attr_mesh_iface,
551 &bat_attr_iface_status,
552 NULL,
553};
554
555int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
556{
557 struct kobject *hardif_kobject = &dev->dev.kobj;
558 struct bat_attribute **bat_attr;
559 int err;
560
561 *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR,
562 hardif_kobject);
563
564 if (!*hardif_obj) {
565 bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
566 SYSFS_IF_BAT_SUBDIR);
567 goto out;
568 }
569
570 for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) {
571 err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr));
572 if (err) {
573 bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
574 dev->name, SYSFS_IF_BAT_SUBDIR,
575 ((*bat_attr)->attr).name);
576 goto rem_attr;
577 }
578 }
579
580 return 0;
581
582rem_attr:
583 for (bat_attr = batman_attrs; *bat_attr; ++bat_attr)
584 sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr));
585out:
586 return -ENOMEM;
587}
588
589void sysfs_del_hardif(struct kobject **hardif_obj)
590{
591 kobject_put(*hardif_obj);
592 *hardif_obj = NULL;
593}
diff --git a/net/batman-adv/bat_sysfs.h b/net/batman-adv/bat_sysfs.h
new file mode 100644
index 000000000000..7f186c007b4f
--- /dev/null
+++ b/net/batman-adv/bat_sysfs.h
@@ -0,0 +1,42 @@
1/*
2 * Copyright (C) 2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22
23#ifndef _NET_BATMAN_ADV_SYSFS_H_
24#define _NET_BATMAN_ADV_SYSFS_H_
25
26#define SYSFS_IF_MESH_SUBDIR "mesh"
27#define SYSFS_IF_BAT_SUBDIR "batman_adv"
28
29struct bat_attribute {
30 struct attribute attr;
31 ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
32 char *buf);
33 ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
34 char *buf, size_t count);
35};
36
37int sysfs_add_meshif(struct net_device *dev);
38void sysfs_del_meshif(struct net_device *dev);
39int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
40void sysfs_del_hardif(struct kobject **hardif_obj);
41
42#endif /* _NET_BATMAN_ADV_SYSFS_H_ */
diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c
new file mode 100644
index 000000000000..bbcd8f744cdd
--- /dev/null
+++ b/net/batman-adv/bitarray.c
@@ -0,0 +1,201 @@
1/*
2 * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors:
3 *
4 * Simon Wunderlich, Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "bitarray.h"
24
25#include <linux/bitops.h>
26
27/* returns true if the corresponding bit in the given seq_bits indicates true
28 * and curr_seqno is within range of last_seqno */
29uint8_t get_bit_status(unsigned long *seq_bits, uint32_t last_seqno,
30 uint32_t curr_seqno)
31{
32 int32_t diff, word_offset, word_num;
33
34 diff = last_seqno - curr_seqno;
35 if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) {
36 return 0;
37 } else {
38 /* which word */
39 word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE;
40 /* which position in the selected word */
41 word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE;
42
43 if (test_bit(word_offset, &seq_bits[word_num]))
44 return 1;
45 else
46 return 0;
47 }
48}
49
50/* turn corresponding bit on, so we can remember that we got the packet */
51void bit_mark(unsigned long *seq_bits, int32_t n)
52{
53 int32_t word_offset, word_num;
54
55 /* if too old, just drop it */
56 if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE)
57 return;
58
59 /* which word */
60 word_num = n / WORD_BIT_SIZE;
61 /* which position in the selected word */
62 word_offset = n % WORD_BIT_SIZE;
63
64 set_bit(word_offset, &seq_bits[word_num]); /* turn the position on */
65}
66
67/* shift the packet array by n places. */
68static void bit_shift(unsigned long *seq_bits, int32_t n)
69{
70 int32_t word_offset, word_num;
71 int32_t i;
72
73 if (n <= 0 || n >= TQ_LOCAL_WINDOW_SIZE)
74 return;
75
76 word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */
77 word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */
78
79 for (i = NUM_WORDS - 1; i > word_num; i--) {
80 /* going from old to new, so we don't overwrite the data we copy
81 * from.
82 *
83 * left is high, right is low: FEDC BA98 7654 3210
84 * ^^ ^^
85 * vvvv
86 * ^^^^ = from, vvvvv =to, we'd have word_num==1 and
87 * word_offset==WORD_BIT_SIZE/2 ????? in this example.
88 * (=24 bits)
89 *
90 * our desired output would be: 9876 5432 1000 0000
91 * */
92
93 seq_bits[i] =
94 (seq_bits[i - word_num] << word_offset) +
95 /* take the lower port from the left half, shift it left
96 * to its final position */
97 (seq_bits[i - word_num - 1] >>
98 (WORD_BIT_SIZE-word_offset));
99 /* and the upper part of the right half and shift it left to
100 * it's position */
101 /* for our example that would be: word[0] = 9800 + 0076 =
102 * 9876 */
103 }
104 /* now for our last word, i==word_num, we only have the it's "left"
105 * half. that's the 1000 word in our example.*/
106
107 seq_bits[i] = (seq_bits[i - word_num] << word_offset);
108
109 /* pad the rest with 0, if there is anything */
110 i--;
111
112 for (; i >= 0; i--)
113 seq_bits[i] = 0;
114}
115
116static void bit_reset_window(unsigned long *seq_bits)
117{
118 int i;
119 for (i = 0; i < NUM_WORDS; i++)
120 seq_bits[i] = 0;
121}
122
123
124/* receive and process one packet within the sequence number window.
125 *
126 * returns:
127 * 1 if the window was moved (either new or very old)
128 * 0 if the window was not moved/shifted.
129 */
130char bit_get_packet(void *priv, unsigned long *seq_bits,
131 int32_t seq_num_diff, int8_t set_mark)
132{
133 struct bat_priv *bat_priv = (struct bat_priv *)priv;
134
135 /* sequence number is slightly older. We already got a sequence number
136 * higher than this one, so we just mark it. */
137
138 if ((seq_num_diff <= 0) && (seq_num_diff > -TQ_LOCAL_WINDOW_SIZE)) {
139 if (set_mark)
140 bit_mark(seq_bits, -seq_num_diff);
141 return 0;
142 }
143
144 /* sequence number is slightly newer, so we shift the window and
145 * set the mark if required */
146
147 if ((seq_num_diff > 0) && (seq_num_diff < TQ_LOCAL_WINDOW_SIZE)) {
148 bit_shift(seq_bits, seq_num_diff);
149
150 if (set_mark)
151 bit_mark(seq_bits, 0);
152 return 1;
153 }
154
155 /* sequence number is much newer, probably missed a lot of packets */
156
157 if ((seq_num_diff >= TQ_LOCAL_WINDOW_SIZE)
158 || (seq_num_diff < EXPECTED_SEQNO_RANGE)) {
159 bat_dbg(DBG_BATMAN, bat_priv,
160 "We missed a lot of packets (%i) !\n",
161 seq_num_diff - 1);
162 bit_reset_window(seq_bits);
163 if (set_mark)
164 bit_mark(seq_bits, 0);
165 return 1;
166 }
167
168 /* received a much older packet. The other host either restarted
169 * or the old packet got delayed somewhere in the network. The
170 * packet should be dropped without calling this function if the
171 * seqno window is protected. */
172
173 if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
174 || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
175
176 bat_dbg(DBG_BATMAN, bat_priv,
177 "Other host probably restarted!\n");
178
179 bit_reset_window(seq_bits);
180 if (set_mark)
181 bit_mark(seq_bits, 0);
182
183 return 1;
184 }
185
186 /* never reached */
187 return 0;
188}
189
190/* count the hamming weight, how many good packets did we receive? just count
191 * the 1's.
192 */
193int bit_packet_count(unsigned long *seq_bits)
194{
195 int i, hamming = 0;
196
197 for (i = 0; i < NUM_WORDS; i++)
198 hamming += hweight_long(seq_bits[i]);
199
200 return hamming;
201}
diff --git a/net/batman-adv/bitarray.h b/net/batman-adv/bitarray.h
new file mode 100644
index 000000000000..ac54017601b1
--- /dev/null
+++ b/net/batman-adv/bitarray.h
@@ -0,0 +1,44 @@
1/*
2 * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors:
3 *
4 * Simon Wunderlich, Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_BITARRAY_H_
23#define _NET_BATMAN_ADV_BITARRAY_H_
24
25#define WORD_BIT_SIZE (sizeof(unsigned long) * 8)
26
27/* returns true if the corresponding bit in the given seq_bits indicates true
28 * and curr_seqno is within range of last_seqno */
29uint8_t get_bit_status(unsigned long *seq_bits, uint32_t last_seqno,
30 uint32_t curr_seqno);
31
32/* turn corresponding bit on, so we can remember that we got the packet */
33void bit_mark(unsigned long *seq_bits, int32_t n);
34
35
36/* receive and process one packet, returns 1 if received seq_num is considered
37 * new, 0 if old */
38char bit_get_packet(void *priv, unsigned long *seq_bits,
39 int32_t seq_num_diff, int8_t set_mark);
40
41/* count the hamming weight, how many good packets did we receive? */
42int bit_packet_count(unsigned long *seq_bits);
43
44#endif /* _NET_BATMAN_ADV_BITARRAY_H_ */
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
new file mode 100644
index 000000000000..0065ffb8d96d
--- /dev/null
+++ b/net/batman-adv/gateway_client.c
@@ -0,0 +1,477 @@
1/*
2 * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "gateway_client.h"
24#include "gateway_common.h"
25#include "hard-interface.h"
26#include <linux/ip.h>
27#include <linux/ipv6.h>
28#include <linux/udp.h>
29#include <linux/if_vlan.h>
30
31static void gw_node_free_ref(struct kref *refcount)
32{
33 struct gw_node *gw_node;
34
35 gw_node = container_of(refcount, struct gw_node, refcount);
36 kfree(gw_node);
37}
38
39static void gw_node_free_rcu(struct rcu_head *rcu)
40{
41 struct gw_node *gw_node;
42
43 gw_node = container_of(rcu, struct gw_node, rcu);
44 kref_put(&gw_node->refcount, gw_node_free_ref);
45}
46
47void *gw_get_selected(struct bat_priv *bat_priv)
48{
49 struct gw_node *curr_gateway_tmp = bat_priv->curr_gw;
50
51 if (!curr_gateway_tmp)
52 return NULL;
53
54 return curr_gateway_tmp->orig_node;
55}
56
57void gw_deselect(struct bat_priv *bat_priv)
58{
59 struct gw_node *gw_node = bat_priv->curr_gw;
60
61 bat_priv->curr_gw = NULL;
62
63 if (gw_node)
64 kref_put(&gw_node->refcount, gw_node_free_ref);
65}
66
67static struct gw_node *gw_select(struct bat_priv *bat_priv,
68 struct gw_node *new_gw_node)
69{
70 struct gw_node *curr_gw_node = bat_priv->curr_gw;
71
72 if (new_gw_node)
73 kref_get(&new_gw_node->refcount);
74
75 bat_priv->curr_gw = new_gw_node;
76 return curr_gw_node;
77}
78
79void gw_election(struct bat_priv *bat_priv)
80{
81 struct hlist_node *node;
82 struct gw_node *gw_node, *curr_gw_tmp = NULL, *old_gw_node = NULL;
83 uint8_t max_tq = 0;
84 uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
85 int down, up;
86
87 /**
88 * The batman daemon checks here if we already passed a full originator
89 * cycle in order to make sure we don't choose the first gateway we
90 * hear about. This check is based on the daemon's uptime which we
91 * don't have.
92 **/
93 if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
94 return;
95
96 if (bat_priv->curr_gw)
97 return;
98
99 rcu_read_lock();
100 if (hlist_empty(&bat_priv->gw_list)) {
101 rcu_read_unlock();
102
103 if (bat_priv->curr_gw) {
104 bat_dbg(DBG_BATMAN, bat_priv,
105 "Removing selected gateway - "
106 "no gateway in range\n");
107 gw_deselect(bat_priv);
108 }
109
110 return;
111 }
112
113 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
114 if (!gw_node->orig_node->router)
115 continue;
116
117 if (gw_node->deleted)
118 continue;
119
120 switch (atomic_read(&bat_priv->gw_sel_class)) {
121 case 1: /* fast connection */
122 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
123 &down, &up);
124
125 tmp_gw_factor = (gw_node->orig_node->router->tq_avg *
126 gw_node->orig_node->router->tq_avg *
127 down * 100 * 100) /
128 (TQ_LOCAL_WINDOW_SIZE *
129 TQ_LOCAL_WINDOW_SIZE * 64);
130
131 if ((tmp_gw_factor > max_gw_factor) ||
132 ((tmp_gw_factor == max_gw_factor) &&
133 (gw_node->orig_node->router->tq_avg > max_tq)))
134 curr_gw_tmp = gw_node;
135 break;
136
137 default: /**
138 * 2: stable connection (use best statistic)
139 * 3: fast-switch (use best statistic but change as
140 * soon as a better gateway appears)
141 * XX: late-switch (use best statistic but change as
142 * soon as a better gateway appears which has
143 * $routing_class more tq points)
144 **/
145 if (gw_node->orig_node->router->tq_avg > max_tq)
146 curr_gw_tmp = gw_node;
147 break;
148 }
149
150 if (gw_node->orig_node->router->tq_avg > max_tq)
151 max_tq = gw_node->orig_node->router->tq_avg;
152
153 if (tmp_gw_factor > max_gw_factor)
154 max_gw_factor = tmp_gw_factor;
155 }
156
157 if (bat_priv->curr_gw != curr_gw_tmp) {
158 if ((bat_priv->curr_gw) && (!curr_gw_tmp))
159 bat_dbg(DBG_BATMAN, bat_priv,
160 "Removing selected gateway - "
161 "no gateway in range\n");
162 else if ((!bat_priv->curr_gw) && (curr_gw_tmp))
163 bat_dbg(DBG_BATMAN, bat_priv,
164 "Adding route to gateway %pM "
165 "(gw_flags: %i, tq: %i)\n",
166 curr_gw_tmp->orig_node->orig,
167 curr_gw_tmp->orig_node->gw_flags,
168 curr_gw_tmp->orig_node->router->tq_avg);
169 else
170 bat_dbg(DBG_BATMAN, bat_priv,
171 "Changing route to gateway %pM "
172 "(gw_flags: %i, tq: %i)\n",
173 curr_gw_tmp->orig_node->orig,
174 curr_gw_tmp->orig_node->gw_flags,
175 curr_gw_tmp->orig_node->router->tq_avg);
176
177 old_gw_node = gw_select(bat_priv, curr_gw_tmp);
178 }
179
180 rcu_read_unlock();
181
182 /* the kfree() has to be outside of the rcu lock */
183 if (old_gw_node)
184 kref_put(&old_gw_node->refcount, gw_node_free_ref);
185}
186
187void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
188{
189 struct gw_node *curr_gateway_tmp = bat_priv->curr_gw;
190 uint8_t gw_tq_avg, orig_tq_avg;
191
192 if (!curr_gateway_tmp)
193 return;
194
195 if (!curr_gateway_tmp->orig_node)
196 goto deselect;
197
198 if (!curr_gateway_tmp->orig_node->router)
199 goto deselect;
200
201 /* this node already is the gateway */
202 if (curr_gateway_tmp->orig_node == orig_node)
203 return;
204
205 if (!orig_node->router)
206 return;
207
208 gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg;
209 orig_tq_avg = orig_node->router->tq_avg;
210
211 /* the TQ value has to be better */
212 if (orig_tq_avg < gw_tq_avg)
213 return;
214
215 /**
216 * if the routing class is greater than 3 the value tells us how much
217 * greater the TQ value of the new gateway must be
218 **/
219 if ((atomic_read(&bat_priv->gw_sel_class) > 3) &&
220 (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class)))
221 return;
222
223 bat_dbg(DBG_BATMAN, bat_priv,
224 "Restarting gateway selection: better gateway found (tq curr: "
225 "%i, tq new: %i)\n",
226 gw_tq_avg, orig_tq_avg);
227
228deselect:
229 gw_deselect(bat_priv);
230}
231
232static void gw_node_add(struct bat_priv *bat_priv,
233 struct orig_node *orig_node, uint8_t new_gwflags)
234{
235 struct gw_node *gw_node;
236 int down, up;
237
238 gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC);
239 if (!gw_node)
240 return;
241
242 memset(gw_node, 0, sizeof(struct gw_node));
243 INIT_HLIST_NODE(&gw_node->list);
244 gw_node->orig_node = orig_node;
245 kref_init(&gw_node->refcount);
246
247 spin_lock_bh(&bat_priv->gw_list_lock);
248 hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list);
249 spin_unlock_bh(&bat_priv->gw_list_lock);
250
251 gw_bandwidth_to_kbit(new_gwflags, &down, &up);
252 bat_dbg(DBG_BATMAN, bat_priv,
253 "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n",
254 orig_node->orig, new_gwflags,
255 (down > 2048 ? down / 1024 : down),
256 (down > 2048 ? "MBit" : "KBit"),
257 (up > 2048 ? up / 1024 : up),
258 (up > 2048 ? "MBit" : "KBit"));
259}
260
261void gw_node_update(struct bat_priv *bat_priv,
262 struct orig_node *orig_node, uint8_t new_gwflags)
263{
264 struct hlist_node *node;
265 struct gw_node *gw_node;
266
267 rcu_read_lock();
268 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
269 if (gw_node->orig_node != orig_node)
270 continue;
271
272 bat_dbg(DBG_BATMAN, bat_priv,
273 "Gateway class of originator %pM changed from "
274 "%i to %i\n",
275 orig_node->orig, gw_node->orig_node->gw_flags,
276 new_gwflags);
277
278 gw_node->deleted = 0;
279
280 if (new_gwflags == 0) {
281 gw_node->deleted = jiffies;
282 bat_dbg(DBG_BATMAN, bat_priv,
283 "Gateway %pM removed from gateway list\n",
284 orig_node->orig);
285
286 if (gw_node == bat_priv->curr_gw) {
287 rcu_read_unlock();
288 gw_deselect(bat_priv);
289 return;
290 }
291 }
292
293 rcu_read_unlock();
294 return;
295 }
296 rcu_read_unlock();
297
298 if (new_gwflags == 0)
299 return;
300
301 gw_node_add(bat_priv, orig_node, new_gwflags);
302}
303
304void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
305{
306 return gw_node_update(bat_priv, orig_node, 0);
307}
308
309void gw_node_purge(struct bat_priv *bat_priv)
310{
311 struct gw_node *gw_node;
312 struct hlist_node *node, *node_tmp;
313 unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
314
315 spin_lock_bh(&bat_priv->gw_list_lock);
316
317 hlist_for_each_entry_safe(gw_node, node, node_tmp,
318 &bat_priv->gw_list, list) {
319 if (((!gw_node->deleted) ||
320 (time_before(jiffies, gw_node->deleted + timeout))) &&
321 atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)
322 continue;
323
324 if (bat_priv->curr_gw == gw_node)
325 gw_deselect(bat_priv);
326
327 hlist_del_rcu(&gw_node->list);
328 call_rcu(&gw_node->rcu, gw_node_free_rcu);
329 }
330
331
332 spin_unlock_bh(&bat_priv->gw_list_lock);
333}
334
335static int _write_buffer_text(struct bat_priv *bat_priv,
336 struct seq_file *seq, struct gw_node *gw_node)
337{
338 int down, up;
339
340 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
341
342 return seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
343 (bat_priv->curr_gw == gw_node ? "=>" : " "),
344 gw_node->orig_node->orig,
345 gw_node->orig_node->router->tq_avg,
346 gw_node->orig_node->router->addr,
347 gw_node->orig_node->router->if_incoming->net_dev->name,
348 gw_node->orig_node->gw_flags,
349 (down > 2048 ? down / 1024 : down),
350 (down > 2048 ? "MBit" : "KBit"),
351 (up > 2048 ? up / 1024 : up),
352 (up > 2048 ? "MBit" : "KBit"));
353}
354
355int gw_client_seq_print_text(struct seq_file *seq, void *offset)
356{
357 struct net_device *net_dev = (struct net_device *)seq->private;
358 struct bat_priv *bat_priv = netdev_priv(net_dev);
359 struct gw_node *gw_node;
360 struct hlist_node *node;
361 int gw_count = 0;
362
363 if (!bat_priv->primary_if) {
364
365 return seq_printf(seq, "BATMAN mesh %s disabled - please "
366 "specify interfaces to enable it\n",
367 net_dev->name);
368 }
369
370 if (bat_priv->primary_if->if_status != IF_ACTIVE) {
371
372 return seq_printf(seq, "BATMAN mesh %s disabled - "
373 "primary interface not active\n",
374 net_dev->name);
375 }
376
377 seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... "
378 "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
379 "Gateway", "#", TQ_MAX_VALUE, "Nexthop",
380 "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
381 bat_priv->primary_if->net_dev->name,
382 bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
383
384 rcu_read_lock();
385 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
386 if (gw_node->deleted)
387 continue;
388
389 if (!gw_node->orig_node->router)
390 continue;
391
392 _write_buffer_text(bat_priv, seq, gw_node);
393 gw_count++;
394 }
395 rcu_read_unlock();
396
397 if (gw_count == 0)
398 seq_printf(seq, "No gateways in range ...\n");
399
400 return 0;
401}
402
403int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
404{
405 struct ethhdr *ethhdr;
406 struct iphdr *iphdr;
407 struct ipv6hdr *ipv6hdr;
408 struct udphdr *udphdr;
409 unsigned int header_len = 0;
410
411 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
412 return 0;
413
414 /* check for ethernet header */
415 if (!pskb_may_pull(skb, header_len + ETH_HLEN))
416 return 0;
417 ethhdr = (struct ethhdr *)skb->data;
418 header_len += ETH_HLEN;
419
420 /* check for initial vlan header */
421 if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
422 if (!pskb_may_pull(skb, header_len + VLAN_HLEN))
423 return 0;
424 ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
425 header_len += VLAN_HLEN;
426 }
427
428 /* check for ip header */
429 switch (ntohs(ethhdr->h_proto)) {
430 case ETH_P_IP:
431 if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr)))
432 return 0;
433 iphdr = (struct iphdr *)(skb->data + header_len);
434 header_len += iphdr->ihl * 4;
435
436 /* check for udp header */
437 if (iphdr->protocol != IPPROTO_UDP)
438 return 0;
439
440 break;
441 case ETH_P_IPV6:
442 if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr)))
443 return 0;
444 ipv6hdr = (struct ipv6hdr *)(skb->data + header_len);
445 header_len += sizeof(struct ipv6hdr);
446
447 /* check for udp header */
448 if (ipv6hdr->nexthdr != IPPROTO_UDP)
449 return 0;
450
451 break;
452 default:
453 return 0;
454 }
455
456 if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr)))
457 return 0;
458 udphdr = (struct udphdr *)(skb->data + header_len);
459 header_len += sizeof(struct udphdr);
460
461 /* check for bootp port */
462 if ((ntohs(ethhdr->h_proto) == ETH_P_IP) &&
463 (ntohs(udphdr->dest) != 67))
464 return 0;
465
466 if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) &&
467 (ntohs(udphdr->dest) != 547))
468 return 0;
469
470 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)
471 return -1;
472
473 if (!bat_priv->curr_gw)
474 return 0;
475
476 return 1;
477}
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h
new file mode 100644
index 000000000000..4585e6549844
--- /dev/null
+++ b/net/batman-adv/gateway_client.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
23#define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
24
25void gw_deselect(struct bat_priv *bat_priv);
26void gw_election(struct bat_priv *bat_priv);
27void *gw_get_selected(struct bat_priv *bat_priv);
28void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node);
29void gw_node_update(struct bat_priv *bat_priv,
30 struct orig_node *orig_node, uint8_t new_gwflags);
31void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
32void gw_node_purge(struct bat_priv *bat_priv);
33int gw_client_seq_print_text(struct seq_file *seq, void *offset);
34int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
35
36#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c
new file mode 100644
index 000000000000..b962982f017e
--- /dev/null
+++ b/net/batman-adv/gateway_common.c
@@ -0,0 +1,177 @@
1/*
2 * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "gateway_common.h"
24#include "gateway_client.h"
25
26/* calculates the gateway class from kbit */
27static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class)
28{
29 int mdown = 0, tdown, tup, difference;
30 uint8_t sbit, part;
31
32 *gw_srv_class = 0;
33 difference = 0x0FFFFFFF;
34
35 /* test all downspeeds */
36 for (sbit = 0; sbit < 2; sbit++) {
37 for (part = 0; part < 16; part++) {
38 tdown = 32 * (sbit + 2) * (1 << part);
39
40 if (abs(tdown - down) < difference) {
41 *gw_srv_class = (sbit << 7) + (part << 3);
42 difference = abs(tdown - down);
43 mdown = tdown;
44 }
45 }
46 }
47
48 /* test all upspeeds */
49 difference = 0x0FFFFFFF;
50
51 for (part = 0; part < 8; part++) {
52 tup = ((part + 1) * (mdown)) / 8;
53
54 if (abs(tup - up) < difference) {
55 *gw_srv_class = (*gw_srv_class & 0xF8) | part;
56 difference = abs(tup - up);
57 }
58 }
59}
60
61/* returns the up and downspeeds in kbit, calculated from the class */
62void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up)
63{
64 char sbit = (gw_srv_class & 0x80) >> 7;
65 char dpart = (gw_srv_class & 0x78) >> 3;
66 char upart = (gw_srv_class & 0x07);
67
68 if (!gw_srv_class) {
69 *down = 0;
70 *up = 0;
71 return;
72 }
73
74 *down = 32 * (sbit + 2) * (1 << dpart);
75 *up = ((upart + 1) * (*down)) / 8;
76}
77
78static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
79 long *up, long *down)
80{
81 int ret, multi = 1;
82 char *slash_ptr, *tmp_ptr;
83
84 slash_ptr = strchr(buff, '/');
85 if (slash_ptr)
86 *slash_ptr = 0;
87
88 if (strlen(buff) > 4) {
89 tmp_ptr = buff + strlen(buff) - 4;
90
91 if (strnicmp(tmp_ptr, "mbit", 4) == 0)
92 multi = 1024;
93
94 if ((strnicmp(tmp_ptr, "kbit", 4) == 0) ||
95 (multi > 1))
96 *tmp_ptr = '\0';
97 }
98
99 ret = strict_strtoul(buff, 10, down);
100 if (ret) {
101 bat_err(net_dev,
102 "Download speed of gateway mode invalid: %s\n",
103 buff);
104 return false;
105 }
106
107 *down *= multi;
108
109 /* we also got some upload info */
110 if (slash_ptr) {
111 multi = 1;
112
113 if (strlen(slash_ptr + 1) > 4) {
114 tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1);
115
116 if (strnicmp(tmp_ptr, "mbit", 4) == 0)
117 multi = 1024;
118
119 if ((strnicmp(tmp_ptr, "kbit", 4) == 0) ||
120 (multi > 1))
121 *tmp_ptr = '\0';
122 }
123
124 ret = strict_strtoul(slash_ptr + 1, 10, up);
125 if (ret) {
126 bat_err(net_dev,
127 "Upload speed of gateway mode invalid: "
128 "%s\n", slash_ptr + 1);
129 return false;
130 }
131
132 *up *= multi;
133 }
134
135 return true;
136}
137
138ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count)
139{
140 struct bat_priv *bat_priv = netdev_priv(net_dev);
141 long gw_bandwidth_tmp = 0, up = 0, down = 0;
142 bool ret;
143
144 ret = parse_gw_bandwidth(net_dev, buff, &up, &down);
145 if (!ret)
146 goto end;
147
148 if ((!down) || (down < 256))
149 down = 2000;
150
151 if (!up)
152 up = down / 5;
153
154 kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp);
155
156 /**
157 * the gw bandwidth we guessed above might not match the given
158 * speeds, hence we need to calculate it back to show the number
159 * that is going to be propagated
160 **/
161 gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp,
162 (int *)&down, (int *)&up);
163
164 gw_deselect(bat_priv);
165 bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' "
166 "(propagating: %ld%s/%ld%s)\n",
167 atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp,
168 (down > 2048 ? down / 1024 : down),
169 (down > 2048 ? "MBit" : "KBit"),
170 (up > 2048 ? up / 1024 : up),
171 (up > 2048 ? "MBit" : "KBit"));
172
173 atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp);
174
175end:
176 return count;
177}
diff --git a/net/batman-adv/gateway_common.h b/net/batman-adv/gateway_common.h
new file mode 100644
index 000000000000..5e728d0b7959
--- /dev/null
+++ b/net/batman-adv/gateway_common.h
@@ -0,0 +1,38 @@
1/*
2 * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_
23#define _NET_BATMAN_ADV_GATEWAY_COMMON_H_
24
25enum gw_modes {
26 GW_MODE_OFF,
27 GW_MODE_CLIENT,
28 GW_MODE_SERVER,
29};
30
31#define GW_MODE_OFF_NAME "off"
32#define GW_MODE_CLIENT_NAME "client"
33#define GW_MODE_SERVER_NAME "server"
34
35void gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up);
36ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count);
37
38#endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
new file mode 100644
index 000000000000..4f95777ce080
--- /dev/null
+++ b/net/batman-adv/hard-interface.c
@@ -0,0 +1,651 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "hard-interface.h"
24#include "soft-interface.h"
25#include "send.h"
26#include "translation-table.h"
27#include "routing.h"
28#include "bat_sysfs.h"
29#include "originator.h"
30#include "hash.h"
31
32#include <linux/if_arp.h>
33
34/* protect update critical side of if_list - but not the content */
35static DEFINE_SPINLOCK(if_list_lock);
36
37static void hardif_free_rcu(struct rcu_head *rcu)
38{
39 struct batman_if *batman_if;
40
41 batman_if = container_of(rcu, struct batman_if, rcu);
42 dev_put(batman_if->net_dev);
43 kref_put(&batman_if->refcount, hardif_free_ref);
44}
45
46struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev)
47{
48 struct batman_if *batman_if;
49
50 rcu_read_lock();
51 list_for_each_entry_rcu(batman_if, &if_list, list) {
52 if (batman_if->net_dev == net_dev)
53 goto out;
54 }
55
56 batman_if = NULL;
57
58out:
59 if (batman_if)
60 kref_get(&batman_if->refcount);
61
62 rcu_read_unlock();
63 return batman_if;
64}
65
66static int is_valid_iface(struct net_device *net_dev)
67{
68 if (net_dev->flags & IFF_LOOPBACK)
69 return 0;
70
71 if (net_dev->type != ARPHRD_ETHER)
72 return 0;
73
74 if (net_dev->addr_len != ETH_ALEN)
75 return 0;
76
77 /* no batman over batman */
78#ifdef HAVE_NET_DEVICE_OPS
79 if (net_dev->netdev_ops->ndo_start_xmit == interface_tx)
80 return 0;
81#else
82 if (net_dev->hard_start_xmit == interface_tx)
83 return 0;
84#endif
85
86 /* Device is being bridged */
87 /* if (net_dev->priv_flags & IFF_BRIDGE_PORT)
88 return 0; */
89
90 return 1;
91}
92
93static struct batman_if *get_active_batman_if(struct net_device *soft_iface)
94{
95 struct batman_if *batman_if;
96
97 rcu_read_lock();
98 list_for_each_entry_rcu(batman_if, &if_list, list) {
99 if (batman_if->soft_iface != soft_iface)
100 continue;
101
102 if (batman_if->if_status == IF_ACTIVE)
103 goto out;
104 }
105
106 batman_if = NULL;
107
108out:
109 if (batman_if)
110 kref_get(&batman_if->refcount);
111
112 rcu_read_unlock();
113 return batman_if;
114}
115
116static void update_primary_addr(struct bat_priv *bat_priv)
117{
118 struct vis_packet *vis_packet;
119
120 vis_packet = (struct vis_packet *)
121 bat_priv->my_vis_info->skb_packet->data;
122 memcpy(vis_packet->vis_orig,
123 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
124 memcpy(vis_packet->sender_orig,
125 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
126}
127
128static void set_primary_if(struct bat_priv *bat_priv,
129 struct batman_if *batman_if)
130{
131 struct batman_packet *batman_packet;
132 struct batman_if *old_if;
133
134 if (batman_if)
135 kref_get(&batman_if->refcount);
136
137 old_if = bat_priv->primary_if;
138 bat_priv->primary_if = batman_if;
139
140 if (old_if)
141 kref_put(&old_if->refcount, hardif_free_ref);
142
143 if (!bat_priv->primary_if)
144 return;
145
146 batman_packet = (struct batman_packet *)(batman_if->packet_buff);
147 batman_packet->flags = PRIMARIES_FIRST_HOP;
148 batman_packet->ttl = TTL;
149
150 update_primary_addr(bat_priv);
151
152 /***
153 * hacky trick to make sure that we send the HNA information via
154 * our new primary interface
155 */
156 atomic_set(&bat_priv->hna_local_changed, 1);
157}
158
159static bool hardif_is_iface_up(struct batman_if *batman_if)
160{
161 if (batman_if->net_dev->flags & IFF_UP)
162 return true;
163
164 return false;
165}
166
167static void update_mac_addresses(struct batman_if *batman_if)
168{
169 memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig,
170 batman_if->net_dev->dev_addr, ETH_ALEN);
171 memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender,
172 batman_if->net_dev->dev_addr, ETH_ALEN);
173}
174
175static void check_known_mac_addr(struct net_device *net_dev)
176{
177 struct batman_if *batman_if;
178
179 rcu_read_lock();
180 list_for_each_entry_rcu(batman_if, &if_list, list) {
181 if ((batman_if->if_status != IF_ACTIVE) &&
182 (batman_if->if_status != IF_TO_BE_ACTIVATED))
183 continue;
184
185 if (batman_if->net_dev == net_dev)
186 continue;
187
188 if (!compare_orig(batman_if->net_dev->dev_addr,
189 net_dev->dev_addr))
190 continue;
191
192 pr_warning("The newly added mac address (%pM) already exists "
193 "on: %s\n", net_dev->dev_addr,
194 batman_if->net_dev->name);
195 pr_warning("It is strongly recommended to keep mac addresses "
196 "unique to avoid problems!\n");
197 }
198 rcu_read_unlock();
199}
200
201int hardif_min_mtu(struct net_device *soft_iface)
202{
203 struct bat_priv *bat_priv = netdev_priv(soft_iface);
204 struct batman_if *batman_if;
205 /* allow big frames if all devices are capable to do so
206 * (have MTU > 1500 + BAT_HEADER_LEN) */
207 int min_mtu = ETH_DATA_LEN;
208
209 if (atomic_read(&bat_priv->fragmentation))
210 goto out;
211
212 rcu_read_lock();
213 list_for_each_entry_rcu(batman_if, &if_list, list) {
214 if ((batman_if->if_status != IF_ACTIVE) &&
215 (batman_if->if_status != IF_TO_BE_ACTIVATED))
216 continue;
217
218 if (batman_if->soft_iface != soft_iface)
219 continue;
220
221 min_mtu = min_t(int, batman_if->net_dev->mtu - BAT_HEADER_LEN,
222 min_mtu);
223 }
224 rcu_read_unlock();
225out:
226 return min_mtu;
227}
228
229/* adjusts the MTU if a new interface with a smaller MTU appeared. */
230void update_min_mtu(struct net_device *soft_iface)
231{
232 int min_mtu;
233
234 min_mtu = hardif_min_mtu(soft_iface);
235 if (soft_iface->mtu != min_mtu)
236 soft_iface->mtu = min_mtu;
237}
238
239static void hardif_activate_interface(struct batman_if *batman_if)
240{
241 struct bat_priv *bat_priv;
242
243 if (batman_if->if_status != IF_INACTIVE)
244 return;
245
246 bat_priv = netdev_priv(batman_if->soft_iface);
247
248 update_mac_addresses(batman_if);
249 batman_if->if_status = IF_TO_BE_ACTIVATED;
250
251 /**
252 * the first active interface becomes our primary interface or
253 * the next active interface after the old primay interface was removed
254 */
255 if (!bat_priv->primary_if)
256 set_primary_if(bat_priv, batman_if);
257
258 bat_info(batman_if->soft_iface, "Interface activated: %s\n",
259 batman_if->net_dev->name);
260
261 update_min_mtu(batman_if->soft_iface);
262 return;
263}
264
265static void hardif_deactivate_interface(struct batman_if *batman_if)
266{
267 if ((batman_if->if_status != IF_ACTIVE) &&
268 (batman_if->if_status != IF_TO_BE_ACTIVATED))
269 return;
270
271 batman_if->if_status = IF_INACTIVE;
272
273 bat_info(batman_if->soft_iface, "Interface deactivated: %s\n",
274 batman_if->net_dev->name);
275
276 update_min_mtu(batman_if->soft_iface);
277}
278
279int hardif_enable_interface(struct batman_if *batman_if, char *iface_name)
280{
281 struct bat_priv *bat_priv;
282 struct batman_packet *batman_packet;
283
284 if (batman_if->if_status != IF_NOT_IN_USE)
285 goto out;
286
287 batman_if->soft_iface = dev_get_by_name(&init_net, iface_name);
288
289 if (!batman_if->soft_iface) {
290 batman_if->soft_iface = softif_create(iface_name);
291
292 if (!batman_if->soft_iface)
293 goto err;
294
295 /* dev_get_by_name() increases the reference counter for us */
296 dev_hold(batman_if->soft_iface);
297 }
298
299 bat_priv = netdev_priv(batman_if->soft_iface);
300 batman_if->packet_len = BAT_PACKET_LEN;
301 batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_ATOMIC);
302
303 if (!batman_if->packet_buff) {
304 bat_err(batman_if->soft_iface, "Can't add interface packet "
305 "(%s): out of memory\n", batman_if->net_dev->name);
306 goto err;
307 }
308
309 batman_packet = (struct batman_packet *)(batman_if->packet_buff);
310 batman_packet->packet_type = BAT_PACKET;
311 batman_packet->version = COMPAT_VERSION;
312 batman_packet->flags = 0;
313 batman_packet->ttl = 2;
314 batman_packet->tq = TQ_MAX_VALUE;
315 batman_packet->num_hna = 0;
316
317 batman_if->if_num = bat_priv->num_ifaces;
318 bat_priv->num_ifaces++;
319 batman_if->if_status = IF_INACTIVE;
320 orig_hash_add_if(batman_if, bat_priv->num_ifaces);
321
322 batman_if->batman_adv_ptype.type = __constant_htons(ETH_P_BATMAN);
323 batman_if->batman_adv_ptype.func = batman_skb_recv;
324 batman_if->batman_adv_ptype.dev = batman_if->net_dev;
325 kref_get(&batman_if->refcount);
326 dev_add_pack(&batman_if->batman_adv_ptype);
327
328 atomic_set(&batman_if->seqno, 1);
329 atomic_set(&batman_if->frag_seqno, 1);
330 bat_info(batman_if->soft_iface, "Adding interface: %s\n",
331 batman_if->net_dev->name);
332
333 if (atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu <
334 ETH_DATA_LEN + BAT_HEADER_LEN)
335 bat_info(batman_if->soft_iface,
336 "The MTU of interface %s is too small (%i) to handle "
337 "the transport of batman-adv packets. Packets going "
338 "over this interface will be fragmented on layer2 "
339 "which could impact the performance. Setting the MTU "
340 "to %zi would solve the problem.\n",
341 batman_if->net_dev->name, batman_if->net_dev->mtu,
342 ETH_DATA_LEN + BAT_HEADER_LEN);
343
344 if (!atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu <
345 ETH_DATA_LEN + BAT_HEADER_LEN)
346 bat_info(batman_if->soft_iface,
347 "The MTU of interface %s is too small (%i) to handle "
348 "the transport of batman-adv packets. If you experience"
349 " problems getting traffic through try increasing the "
350 "MTU to %zi.\n",
351 batman_if->net_dev->name, batman_if->net_dev->mtu,
352 ETH_DATA_LEN + BAT_HEADER_LEN);
353
354 if (hardif_is_iface_up(batman_if))
355 hardif_activate_interface(batman_if);
356 else
357 bat_err(batman_if->soft_iface, "Not using interface %s "
358 "(retrying later): interface not active\n",
359 batman_if->net_dev->name);
360
361 /* begin scheduling originator messages on that interface */
362 schedule_own_packet(batman_if);
363
364out:
365 return 0;
366
367err:
368 return -ENOMEM;
369}
370
371void hardif_disable_interface(struct batman_if *batman_if)
372{
373 struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
374
375 if (batman_if->if_status == IF_ACTIVE)
376 hardif_deactivate_interface(batman_if);
377
378 if (batman_if->if_status != IF_INACTIVE)
379 return;
380
381 bat_info(batman_if->soft_iface, "Removing interface: %s\n",
382 batman_if->net_dev->name);
383 dev_remove_pack(&batman_if->batman_adv_ptype);
384 kref_put(&batman_if->refcount, hardif_free_ref);
385
386 bat_priv->num_ifaces--;
387 orig_hash_del_if(batman_if, bat_priv->num_ifaces);
388
389 if (batman_if == bat_priv->primary_if) {
390 struct batman_if *new_if;
391
392 new_if = get_active_batman_if(batman_if->soft_iface);
393 set_primary_if(bat_priv, new_if);
394
395 if (new_if)
396 kref_put(&new_if->refcount, hardif_free_ref);
397 }
398
399 kfree(batman_if->packet_buff);
400 batman_if->packet_buff = NULL;
401 batman_if->if_status = IF_NOT_IN_USE;
402
403 /* delete all references to this batman_if */
404 purge_orig_ref(bat_priv);
405 purge_outstanding_packets(bat_priv, batman_if);
406 dev_put(batman_if->soft_iface);
407
408 /* nobody uses this interface anymore */
409 if (!bat_priv->num_ifaces)
410 softif_destroy(batman_if->soft_iface);
411
412 batman_if->soft_iface = NULL;
413}
414
415static struct batman_if *hardif_add_interface(struct net_device *net_dev)
416{
417 struct batman_if *batman_if;
418 int ret;
419
420 ret = is_valid_iface(net_dev);
421 if (ret != 1)
422 goto out;
423
424 dev_hold(net_dev);
425
426 batman_if = kmalloc(sizeof(struct batman_if), GFP_ATOMIC);
427 if (!batman_if) {
428 pr_err("Can't add interface (%s): out of memory\n",
429 net_dev->name);
430 goto release_dev;
431 }
432
433 ret = sysfs_add_hardif(&batman_if->hardif_obj, net_dev);
434 if (ret)
435 goto free_if;
436
437 batman_if->if_num = -1;
438 batman_if->net_dev = net_dev;
439 batman_if->soft_iface = NULL;
440 batman_if->if_status = IF_NOT_IN_USE;
441 INIT_LIST_HEAD(&batman_if->list);
442 kref_init(&batman_if->refcount);
443
444 check_known_mac_addr(batman_if->net_dev);
445
446 spin_lock(&if_list_lock);
447 list_add_tail_rcu(&batman_if->list, &if_list);
448 spin_unlock(&if_list_lock);
449
450 /* extra reference for return */
451 kref_get(&batman_if->refcount);
452 return batman_if;
453
454free_if:
455 kfree(batman_if);
456release_dev:
457 dev_put(net_dev);
458out:
459 return NULL;
460}
461
462static void hardif_remove_interface(struct batman_if *batman_if)
463{
464 /* first deactivate interface */
465 if (batman_if->if_status != IF_NOT_IN_USE)
466 hardif_disable_interface(batman_if);
467
468 if (batman_if->if_status != IF_NOT_IN_USE)
469 return;
470
471 batman_if->if_status = IF_TO_BE_REMOVED;
472 sysfs_del_hardif(&batman_if->hardif_obj);
473 call_rcu(&batman_if->rcu, hardif_free_rcu);
474}
475
476void hardif_remove_interfaces(void)
477{
478 struct batman_if *batman_if, *batman_if_tmp;
479 struct list_head if_queue;
480
481 INIT_LIST_HEAD(&if_queue);
482
483 spin_lock(&if_list_lock);
484 list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) {
485 list_del_rcu(&batman_if->list);
486 list_add_tail(&batman_if->list, &if_queue);
487 }
488 spin_unlock(&if_list_lock);
489
490 rtnl_lock();
491 list_for_each_entry_safe(batman_if, batman_if_tmp, &if_queue, list) {
492 hardif_remove_interface(batman_if);
493 }
494 rtnl_unlock();
495}
496
497static int hard_if_event(struct notifier_block *this,
498 unsigned long event, void *ptr)
499{
500 struct net_device *net_dev = (struct net_device *)ptr;
501 struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
502 struct bat_priv *bat_priv;
503
504 if (!batman_if && event == NETDEV_REGISTER)
505 batman_if = hardif_add_interface(net_dev);
506
507 if (!batman_if)
508 goto out;
509
510 switch (event) {
511 case NETDEV_UP:
512 hardif_activate_interface(batman_if);
513 break;
514 case NETDEV_GOING_DOWN:
515 case NETDEV_DOWN:
516 hardif_deactivate_interface(batman_if);
517 break;
518 case NETDEV_UNREGISTER:
519 spin_lock(&if_list_lock);
520 list_del_rcu(&batman_if->list);
521 spin_unlock(&if_list_lock);
522
523 hardif_remove_interface(batman_if);
524 break;
525 case NETDEV_CHANGEMTU:
526 if (batman_if->soft_iface)
527 update_min_mtu(batman_if->soft_iface);
528 break;
529 case NETDEV_CHANGEADDR:
530 if (batman_if->if_status == IF_NOT_IN_USE)
531 goto hardif_put;
532
533 check_known_mac_addr(batman_if->net_dev);
534 update_mac_addresses(batman_if);
535
536 bat_priv = netdev_priv(batman_if->soft_iface);
537 if (batman_if == bat_priv->primary_if)
538 update_primary_addr(bat_priv);
539 break;
540 default:
541 break;
542 };
543
544hardif_put:
545 kref_put(&batman_if->refcount, hardif_free_ref);
546out:
547 return NOTIFY_DONE;
548}
549
550/* receive a packet with the batman ethertype coming on a hard
551 * interface */
552int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
553 struct packet_type *ptype, struct net_device *orig_dev)
554{
555 struct bat_priv *bat_priv;
556 struct batman_packet *batman_packet;
557 struct batman_if *batman_if;
558 int ret;
559
560 batman_if = container_of(ptype, struct batman_if, batman_adv_ptype);
561 skb = skb_share_check(skb, GFP_ATOMIC);
562
563 /* skb was released by skb_share_check() */
564 if (!skb)
565 goto err_out;
566
567 /* packet should hold at least type and version */
568 if (unlikely(!pskb_may_pull(skb, 2)))
569 goto err_free;
570
571 /* expect a valid ethernet header here. */
572 if (unlikely(skb->mac_len != sizeof(struct ethhdr)
573 || !skb_mac_header(skb)))
574 goto err_free;
575
576 if (!batman_if->soft_iface)
577 goto err_free;
578
579 bat_priv = netdev_priv(batman_if->soft_iface);
580
581 if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
582 goto err_free;
583
584 /* discard frames on not active interfaces */
585 if (batman_if->if_status != IF_ACTIVE)
586 goto err_free;
587
588 batman_packet = (struct batman_packet *)skb->data;
589
590 if (batman_packet->version != COMPAT_VERSION) {
591 bat_dbg(DBG_BATMAN, bat_priv,
592 "Drop packet: incompatible batman version (%i)\n",
593 batman_packet->version);
594 goto err_free;
595 }
596
597 /* all receive handlers return whether they received or reused
598 * the supplied skb. if not, we have to free the skb. */
599
600 switch (batman_packet->packet_type) {
601 /* batman originator packet */
602 case BAT_PACKET:
603 ret = recv_bat_packet(skb, batman_if);
604 break;
605
606 /* batman icmp packet */
607 case BAT_ICMP:
608 ret = recv_icmp_packet(skb, batman_if);
609 break;
610
611 /* unicast packet */
612 case BAT_UNICAST:
613 ret = recv_unicast_packet(skb, batman_if);
614 break;
615
616 /* fragmented unicast packet */
617 case BAT_UNICAST_FRAG:
618 ret = recv_ucast_frag_packet(skb, batman_if);
619 break;
620
621 /* broadcast packet */
622 case BAT_BCAST:
623 ret = recv_bcast_packet(skb, batman_if);
624 break;
625
626 /* vis packet */
627 case BAT_VIS:
628 ret = recv_vis_packet(skb, batman_if);
629 break;
630 default:
631 ret = NET_RX_DROP;
632 }
633
634 if (ret == NET_RX_DROP)
635 kfree_skb(skb);
636
637 /* return NET_RX_SUCCESS in any case as we
638 * most probably dropped the packet for
639 * routing-logical reasons. */
640
641 return NET_RX_SUCCESS;
642
643err_free:
644 kfree_skb(skb);
645err_out:
646 return NET_RX_DROP;
647}
648
649struct notifier_block hard_if_notifier = {
650 .notifier_call = hard_if_event,
651};
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
new file mode 100644
index 000000000000..30ec3b8db459
--- /dev/null
+++ b/net/batman-adv/hard-interface.h
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_
23#define _NET_BATMAN_ADV_HARD_INTERFACE_H_
24
25#define IF_NOT_IN_USE 0
26#define IF_TO_BE_REMOVED 1
27#define IF_INACTIVE 2
28#define IF_ACTIVE 3
29#define IF_TO_BE_ACTIVATED 4
30#define IF_I_WANT_YOU 5
31
32extern struct notifier_block hard_if_notifier;
33
34struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev);
35int hardif_enable_interface(struct batman_if *batman_if, char *iface_name);
36void hardif_disable_interface(struct batman_if *batman_if);
37void hardif_remove_interfaces(void);
38int batman_skb_recv(struct sk_buff *skb,
39 struct net_device *dev,
40 struct packet_type *ptype,
41 struct net_device *orig_dev);
42int hardif_min_mtu(struct net_device *soft_iface);
43void update_min_mtu(struct net_device *soft_iface);
44
45static inline void hardif_free_ref(struct kref *refcount)
46{
47 struct batman_if *batman_if;
48
49 batman_if = container_of(refcount, struct batman_if, refcount);
50 kfree(batman_if);
51}
52
53#endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */
diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c
new file mode 100644
index 000000000000..26e623eb9def
--- /dev/null
+++ b/net/batman-adv/hash.c
@@ -0,0 +1,62 @@
1/*
2 * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors:
3 *
4 * Simon Wunderlich, Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "hash.h"
24
25/* clears the hash */
26static void hash_init(struct hashtable_t *hash)
27{
28 int i;
29
30 for (i = 0 ; i < hash->size; i++)
31 INIT_HLIST_HEAD(&hash->table[i]);
32}
33
34/* free only the hashtable and the hash itself. */
35void hash_destroy(struct hashtable_t *hash)
36{
37 kfree(hash->table);
38 kfree(hash);
39}
40
41/* allocates and clears the hash */
42struct hashtable_t *hash_new(int size)
43{
44 struct hashtable_t *hash;
45
46 hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC);
47
48 if (!hash)
49 return NULL;
50
51 hash->size = size;
52 hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC);
53
54 if (!hash->table) {
55 kfree(hash);
56 return NULL;
57 }
58
59 hash_init(hash);
60
61 return hash;
62}
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h
new file mode 100644
index 000000000000..09216ade16f1
--- /dev/null
+++ b/net/batman-adv/hash.h
@@ -0,0 +1,176 @@
1/*
2 * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors:
3 *
4 * Simon Wunderlich, Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_HASH_H_
23#define _NET_BATMAN_ADV_HASH_H_
24
25#include <linux/list.h>
26
27/* callback to a compare function. should
28 * compare 2 element datas for their keys,
29 * return 0 if same and not 0 if not
30 * same */
31typedef int (*hashdata_compare_cb)(void *, void *);
32
33/* the hashfunction, should return an index
34 * based on the key in the data of the first
35 * argument and the size the second */
36typedef int (*hashdata_choose_cb)(void *, int);
37typedef void (*hashdata_free_cb)(void *, void *);
38
39struct element_t {
40 void *data; /* pointer to the data */
41 struct hlist_node hlist; /* bucket list pointer */
42};
43
44struct hashtable_t {
45 struct hlist_head *table; /* the hashtable itself, with the buckets */
46 int size; /* size of hashtable */
47};
48
49/* allocates and clears the hash */
50struct hashtable_t *hash_new(int size);
51
52/* remove element if you already found the element you want to delete and don't
53 * need the overhead to find it again with hash_remove(). But usually, you
54 * don't want to use this function, as it fiddles with hash-internals. */
55void *hash_remove_element(struct hashtable_t *hash, struct element_t *elem);
56
57/* free only the hashtable and the hash itself. */
58void hash_destroy(struct hashtable_t *hash);
59
60/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
61 * called to remove the elements inside of the hash. if you don't remove the
62 * elements, memory might be leaked. */
63static inline void hash_delete(struct hashtable_t *hash,
64 hashdata_free_cb free_cb, void *arg)
65{
66 struct hlist_head *head;
67 struct hlist_node *walk, *safe;
68 struct element_t *bucket;
69 int i;
70
71 for (i = 0; i < hash->size; i++) {
72 head = &hash->table[i];
73
74 hlist_for_each_safe(walk, safe, head) {
75 bucket = hlist_entry(walk, struct element_t, hlist);
76 if (free_cb)
77 free_cb(bucket->data, arg);
78
79 hlist_del(walk);
80 kfree(bucket);
81 }
82 }
83
84 hash_destroy(hash);
85}
86
87/* adds data to the hashtable. returns 0 on success, -1 on error */
88static inline int hash_add(struct hashtable_t *hash,
89 hashdata_compare_cb compare,
90 hashdata_choose_cb choose, void *data)
91{
92 int index;
93 struct hlist_head *head;
94 struct hlist_node *walk, *safe;
95 struct element_t *bucket;
96
97 if (!hash)
98 return -1;
99
100 index = choose(data, hash->size);
101 head = &hash->table[index];
102
103 hlist_for_each_safe(walk, safe, head) {
104 bucket = hlist_entry(walk, struct element_t, hlist);
105 if (compare(bucket->data, data))
106 return -1;
107 }
108
109 /* no duplicate found in list, add new element */
110 bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC);
111
112 if (!bucket)
113 return -1;
114
115 bucket->data = data;
116 hlist_add_head(&bucket->hlist, head);
117
118 return 0;
119}
120
121/* removes data from hash, if found. returns pointer do data on success, so you
122 * can remove the used structure yourself, or NULL on error . data could be the
123 * structure you use with just the key filled, we just need the key for
124 * comparing. */
125static inline void *hash_remove(struct hashtable_t *hash,
126 hashdata_compare_cb compare,
127 hashdata_choose_cb choose, void *data)
128{
129 size_t index;
130 struct hlist_node *walk;
131 struct element_t *bucket;
132 struct hlist_head *head;
133 void *data_save;
134
135 index = choose(data, hash->size);
136 head = &hash->table[index];
137
138 hlist_for_each_entry(bucket, walk, head, hlist) {
139 if (compare(bucket->data, data)) {
140 data_save = bucket->data;
141 hlist_del(walk);
142 kfree(bucket);
143 return data_save;
144 }
145 }
146
147 return NULL;
148}
149
150/* finds data, based on the key in keydata. returns the found data on success,
151 * or NULL on error */
152static inline void *hash_find(struct hashtable_t *hash,
153 hashdata_compare_cb compare,
154 hashdata_choose_cb choose, void *keydata)
155{
156 int index;
157 struct hlist_head *head;
158 struct hlist_node *walk;
159 struct element_t *bucket;
160
161 if (!hash)
162 return NULL;
163
164 index = choose(keydata , hash->size);
165 head = &hash->table[index];
166
167 hlist_for_each(walk, head) {
168 bucket = hlist_entry(walk, struct element_t, hlist);
169 if (compare(bucket->data, keydata))
170 return bucket->data;
171 }
172
173 return NULL;
174}
175
176#endif /* _NET_BATMAN_ADV_HASH_H_ */
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
new file mode 100644
index 000000000000..ecf6d7ffab2e
--- /dev/null
+++ b/net/batman-adv/icmp_socket.c
@@ -0,0 +1,356 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include <linux/debugfs.h>
24#include <linux/slab.h>
25#include "icmp_socket.h"
26#include "send.h"
27#include "types.h"
28#include "hash.h"
29#include "originator.h"
30#include "hard-interface.h"
31
32static struct socket_client *socket_client_hash[256];
33
34static void bat_socket_add_packet(struct socket_client *socket_client,
35 struct icmp_packet_rr *icmp_packet,
36 size_t icmp_len);
37
38void bat_socket_init(void)
39{
40 memset(socket_client_hash, 0, sizeof(socket_client_hash));
41}
42
43static int bat_socket_open(struct inode *inode, struct file *file)
44{
45 unsigned int i;
46 struct socket_client *socket_client;
47
48 nonseekable_open(inode, file);
49
50 socket_client = kmalloc(sizeof(struct socket_client), GFP_KERNEL);
51
52 if (!socket_client)
53 return -ENOMEM;
54
55 for (i = 0; i < ARRAY_SIZE(socket_client_hash); i++) {
56 if (!socket_client_hash[i]) {
57 socket_client_hash[i] = socket_client;
58 break;
59 }
60 }
61
62 if (i == ARRAY_SIZE(socket_client_hash)) {
63 pr_err("Error - can't add another packet client: "
64 "maximum number of clients reached\n");
65 kfree(socket_client);
66 return -EXFULL;
67 }
68
69 INIT_LIST_HEAD(&socket_client->queue_list);
70 socket_client->queue_len = 0;
71 socket_client->index = i;
72 socket_client->bat_priv = inode->i_private;
73 spin_lock_init(&socket_client->lock);
74 init_waitqueue_head(&socket_client->queue_wait);
75
76 file->private_data = socket_client;
77
78 inc_module_count();
79 return 0;
80}
81
82static int bat_socket_release(struct inode *inode, struct file *file)
83{
84 struct socket_client *socket_client = file->private_data;
85 struct socket_packet *socket_packet;
86 struct list_head *list_pos, *list_pos_tmp;
87
88 spin_lock_bh(&socket_client->lock);
89
90 /* for all packets in the queue ... */
91 list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) {
92 socket_packet = list_entry(list_pos,
93 struct socket_packet, list);
94
95 list_del(list_pos);
96 kfree(socket_packet);
97 }
98
99 socket_client_hash[socket_client->index] = NULL;
100 spin_unlock_bh(&socket_client->lock);
101
102 kfree(socket_client);
103 dec_module_count();
104
105 return 0;
106}
107
108static ssize_t bat_socket_read(struct file *file, char __user *buf,
109 size_t count, loff_t *ppos)
110{
111 struct socket_client *socket_client = file->private_data;
112 struct socket_packet *socket_packet;
113 size_t packet_len;
114 int error;
115
116 if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0))
117 return -EAGAIN;
118
119 if ((!buf) || (count < sizeof(struct icmp_packet)))
120 return -EINVAL;
121
122 if (!access_ok(VERIFY_WRITE, buf, count))
123 return -EFAULT;
124
125 error = wait_event_interruptible(socket_client->queue_wait,
126 socket_client->queue_len);
127
128 if (error)
129 return error;
130
131 spin_lock_bh(&socket_client->lock);
132
133 socket_packet = list_first_entry(&socket_client->queue_list,
134 struct socket_packet, list);
135 list_del(&socket_packet->list);
136 socket_client->queue_len--;
137
138 spin_unlock_bh(&socket_client->lock);
139
140 error = __copy_to_user(buf, &socket_packet->icmp_packet,
141 socket_packet->icmp_len);
142
143 packet_len = socket_packet->icmp_len;
144 kfree(socket_packet);
145
146 if (error)
147 return -EFAULT;
148
149 return packet_len;
150}
151
152static ssize_t bat_socket_write(struct file *file, const char __user *buff,
153 size_t len, loff_t *off)
154{
155 struct socket_client *socket_client = file->private_data;
156 struct bat_priv *bat_priv = socket_client->bat_priv;
157 struct sk_buff *skb;
158 struct icmp_packet_rr *icmp_packet;
159
160 struct orig_node *orig_node;
161 struct batman_if *batman_if;
162 size_t packet_len = sizeof(struct icmp_packet);
163 uint8_t dstaddr[ETH_ALEN];
164
165 if (len < sizeof(struct icmp_packet)) {
166 bat_dbg(DBG_BATMAN, bat_priv,
167 "Error - can't send packet from char device: "
168 "invalid packet size\n");
169 return -EINVAL;
170 }
171
172 if (!bat_priv->primary_if)
173 return -EFAULT;
174
175 if (len >= sizeof(struct icmp_packet_rr))
176 packet_len = sizeof(struct icmp_packet_rr);
177
178 skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr));
179 if (!skb)
180 return -ENOMEM;
181
182 skb_reserve(skb, sizeof(struct ethhdr));
183 icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len);
184
185 if (!access_ok(VERIFY_READ, buff, packet_len)) {
186 len = -EFAULT;
187 goto free_skb;
188 }
189
190 if (__copy_from_user(icmp_packet, buff, packet_len)) {
191 len = -EFAULT;
192 goto free_skb;
193 }
194
195 if (icmp_packet->packet_type != BAT_ICMP) {
196 bat_dbg(DBG_BATMAN, bat_priv,
197 "Error - can't send packet from char device: "
198 "got bogus packet type (expected: BAT_ICMP)\n");
199 len = -EINVAL;
200 goto free_skb;
201 }
202
203 if (icmp_packet->msg_type != ECHO_REQUEST) {
204 bat_dbg(DBG_BATMAN, bat_priv,
205 "Error - can't send packet from char device: "
206 "got bogus message type (expected: ECHO_REQUEST)\n");
207 len = -EINVAL;
208 goto free_skb;
209 }
210
211 icmp_packet->uid = socket_client->index;
212
213 if (icmp_packet->version != COMPAT_VERSION) {
214 icmp_packet->msg_type = PARAMETER_PROBLEM;
215 icmp_packet->ttl = COMPAT_VERSION;
216 bat_socket_add_packet(socket_client, icmp_packet, packet_len);
217 goto free_skb;
218 }
219
220 if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
221 goto dst_unreach;
222
223 spin_lock_bh(&bat_priv->orig_hash_lock);
224 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
225 compare_orig, choose_orig,
226 icmp_packet->dst));
227
228 if (!orig_node)
229 goto unlock;
230
231 if (!orig_node->router)
232 goto unlock;
233
234 batman_if = orig_node->router->if_incoming;
235 memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
236
237 spin_unlock_bh(&bat_priv->orig_hash_lock);
238
239 if (!batman_if)
240 goto dst_unreach;
241
242 if (batman_if->if_status != IF_ACTIVE)
243 goto dst_unreach;
244
245 memcpy(icmp_packet->orig,
246 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
247
248 if (packet_len == sizeof(struct icmp_packet_rr))
249 memcpy(icmp_packet->rr, batman_if->net_dev->dev_addr, ETH_ALEN);
250
251
252 send_skb_packet(skb, batman_if, dstaddr);
253
254 goto out;
255
256unlock:
257 spin_unlock_bh(&bat_priv->orig_hash_lock);
258dst_unreach:
259 icmp_packet->msg_type = DESTINATION_UNREACHABLE;
260 bat_socket_add_packet(socket_client, icmp_packet, packet_len);
261free_skb:
262 kfree_skb(skb);
263out:
264 return len;
265}
266
267static unsigned int bat_socket_poll(struct file *file, poll_table *wait)
268{
269 struct socket_client *socket_client = file->private_data;
270
271 poll_wait(file, &socket_client->queue_wait, wait);
272
273 if (socket_client->queue_len > 0)
274 return POLLIN | POLLRDNORM;
275
276 return 0;
277}
278
279static const struct file_operations fops = {
280 .owner = THIS_MODULE,
281 .open = bat_socket_open,
282 .release = bat_socket_release,
283 .read = bat_socket_read,
284 .write = bat_socket_write,
285 .poll = bat_socket_poll,
286 .llseek = no_llseek,
287};
288
289int bat_socket_setup(struct bat_priv *bat_priv)
290{
291 struct dentry *d;
292
293 if (!bat_priv->debug_dir)
294 goto err;
295
296 d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR,
297 bat_priv->debug_dir, bat_priv, &fops);
298 if (d)
299 goto err;
300
301 return 0;
302
303err:
304 return 1;
305}
306
307static void bat_socket_add_packet(struct socket_client *socket_client,
308 struct icmp_packet_rr *icmp_packet,
309 size_t icmp_len)
310{
311 struct socket_packet *socket_packet;
312
313 socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC);
314
315 if (!socket_packet)
316 return;
317
318 INIT_LIST_HEAD(&socket_packet->list);
319 memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len);
320 socket_packet->icmp_len = icmp_len;
321
322 spin_lock_bh(&socket_client->lock);
323
324 /* while waiting for the lock the socket_client could have been
325 * deleted */
326 if (!socket_client_hash[icmp_packet->uid]) {
327 spin_unlock_bh(&socket_client->lock);
328 kfree(socket_packet);
329 return;
330 }
331
332 list_add_tail(&socket_packet->list, &socket_client->queue_list);
333 socket_client->queue_len++;
334
335 if (socket_client->queue_len > 100) {
336 socket_packet = list_first_entry(&socket_client->queue_list,
337 struct socket_packet, list);
338
339 list_del(&socket_packet->list);
340 kfree(socket_packet);
341 socket_client->queue_len--;
342 }
343
344 spin_unlock_bh(&socket_client->lock);
345
346 wake_up(&socket_client->queue_wait);
347}
348
349void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
350 size_t icmp_len)
351{
352 struct socket_client *hash = socket_client_hash[icmp_packet->uid];
353
354 if (hash)
355 bat_socket_add_packet(hash, icmp_packet, icmp_len);
356}
diff --git a/net/batman-adv/icmp_socket.h b/net/batman-adv/icmp_socket.h
new file mode 100644
index 000000000000..bf9b348cde27
--- /dev/null
+++ b/net/batman-adv/icmp_socket.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_
23#define _NET_BATMAN_ADV_ICMP_SOCKET_H_
24
25#include "types.h"
26
27#define ICMP_SOCKET "socket"
28
29void bat_socket_init(void);
30int bat_socket_setup(struct bat_priv *bat_priv);
31void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
32 size_t icmp_len);
33
34#endif /* _NET_BATMAN_ADV_ICMP_SOCKET_H_ */
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
new file mode 100644
index 000000000000..b827f6a158cb
--- /dev/null
+++ b/net/batman-adv/main.c
@@ -0,0 +1,187 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "bat_sysfs.h"
24#include "bat_debugfs.h"
25#include "routing.h"
26#include "send.h"
27#include "originator.h"
28#include "soft-interface.h"
29#include "icmp_socket.h"
30#include "translation-table.h"
31#include "hard-interface.h"
32#include "gateway_client.h"
33#include "types.h"
34#include "vis.h"
35#include "hash.h"
36
37struct list_head if_list;
38
39unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
40
41struct workqueue_struct *bat_event_workqueue;
42
43static int __init batman_init(void)
44{
45 INIT_LIST_HEAD(&if_list);
46
47 /* the name should not be longer than 10 chars - see
48 * http://lwn.net/Articles/23634/ */
49 bat_event_workqueue = create_singlethread_workqueue("bat_events");
50
51 if (!bat_event_workqueue)
52 return -ENOMEM;
53
54 bat_socket_init();
55 debugfs_init();
56
57 register_netdevice_notifier(&hard_if_notifier);
58
59 pr_info("B.A.T.M.A.N. advanced %s%s (compatibility version %i) "
60 "loaded\n", SOURCE_VERSION, REVISION_VERSION_STR,
61 COMPAT_VERSION);
62
63 return 0;
64}
65
66static void __exit batman_exit(void)
67{
68 debugfs_destroy();
69 unregister_netdevice_notifier(&hard_if_notifier);
70 hardif_remove_interfaces();
71
72 flush_workqueue(bat_event_workqueue);
73 destroy_workqueue(bat_event_workqueue);
74 bat_event_workqueue = NULL;
75
76 rcu_barrier();
77}
78
79int mesh_init(struct net_device *soft_iface)
80{
81 struct bat_priv *bat_priv = netdev_priv(soft_iface);
82
83 spin_lock_init(&bat_priv->orig_hash_lock);
84 spin_lock_init(&bat_priv->forw_bat_list_lock);
85 spin_lock_init(&bat_priv->forw_bcast_list_lock);
86 spin_lock_init(&bat_priv->hna_lhash_lock);
87 spin_lock_init(&bat_priv->hna_ghash_lock);
88 spin_lock_init(&bat_priv->gw_list_lock);
89 spin_lock_init(&bat_priv->vis_hash_lock);
90 spin_lock_init(&bat_priv->vis_list_lock);
91 spin_lock_init(&bat_priv->softif_neigh_lock);
92
93 INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
94 INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
95 INIT_HLIST_HEAD(&bat_priv->gw_list);
96 INIT_HLIST_HEAD(&bat_priv->softif_neigh_list);
97
98 if (originator_init(bat_priv) < 1)
99 goto err;
100
101 if (hna_local_init(bat_priv) < 1)
102 goto err;
103
104 if (hna_global_init(bat_priv) < 1)
105 goto err;
106
107 hna_local_add(soft_iface, soft_iface->dev_addr);
108
109 if (vis_init(bat_priv) < 1)
110 goto err;
111
112 atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
113 goto end;
114
115err:
116 pr_err("Unable to allocate memory for mesh information structures: "
117 "out of mem ?\n");
118 mesh_free(soft_iface);
119 return -1;
120
121end:
122 return 0;
123}
124
125void mesh_free(struct net_device *soft_iface)
126{
127 struct bat_priv *bat_priv = netdev_priv(soft_iface);
128
129 atomic_set(&bat_priv->mesh_state, MESH_DEACTIVATING);
130
131 purge_outstanding_packets(bat_priv, NULL);
132
133 vis_quit(bat_priv);
134
135 gw_node_purge(bat_priv);
136 originator_free(bat_priv);
137
138 hna_local_free(bat_priv);
139 hna_global_free(bat_priv);
140
141 softif_neigh_purge(bat_priv);
142
143 atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
144}
145
146void inc_module_count(void)
147{
148 try_module_get(THIS_MODULE);
149}
150
151void dec_module_count(void)
152{
153 module_put(THIS_MODULE);
154}
155
156int is_my_mac(uint8_t *addr)
157{
158 struct batman_if *batman_if;
159
160 rcu_read_lock();
161 list_for_each_entry_rcu(batman_if, &if_list, list) {
162 if (batman_if->if_status != IF_ACTIVE)
163 continue;
164
165 if (compare_orig(batman_if->net_dev->dev_addr, addr)) {
166 rcu_read_unlock();
167 return 1;
168 }
169 }
170 rcu_read_unlock();
171 return 0;
172
173}
174
175module_init(batman_init);
176module_exit(batman_exit);
177
178MODULE_LICENSE("GPL");
179
180MODULE_AUTHOR(DRIVER_AUTHOR);
181MODULE_DESCRIPTION(DRIVER_DESC);
182MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE);
183#ifdef REVISION_VERSION
184MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION);
185#else
186MODULE_VERSION(SOURCE_VERSION);
187#endif
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
new file mode 100644
index 000000000000..d4d9926c2201
--- /dev/null
+++ b/net/batman-adv/main.h
@@ -0,0 +1,183 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_MAIN_H_
23#define _NET_BATMAN_ADV_MAIN_H_
24
25/* Kernel Programming */
26#define LINUX
27
28#define DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, " \
29 "Simon Wunderlich <siwu@hrz.tu-chemnitz.de>"
30#define DRIVER_DESC "B.A.T.M.A.N. advanced"
31#define DRIVER_DEVICE "batman-adv"
32
33#define SOURCE_VERSION "next"
34
35
36/* B.A.T.M.A.N. parameters */
37
38#define TQ_MAX_VALUE 255
39#define JITTER 20
40#define TTL 50 /* Time To Live of broadcast messages */
41
42#define PURGE_TIMEOUT 200 /* purge originators after time in seconds if no
43 * valid packet comes in -> TODO: check
44 * influence on TQ_LOCAL_WINDOW_SIZE */
45#define LOCAL_HNA_TIMEOUT 3600 /* in seconds */
46
47#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator
48 * messages in squence numbers (should be a
49 * multiple of our word size) */
50#define TQ_GLOBAL_WINDOW_SIZE 5
51#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
52#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
53#define TQ_TOTAL_BIDRECT_LIMIT 1
54
55#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
56
57#define PACKBUFF_SIZE 2000
58#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
59
60#define VIS_INTERVAL 5000 /* 5 seconds */
61
62/* how much worse secondary interfaces may be to
63 * to be considered as bonding candidates */
64
65#define BONDING_TQ_THRESHOLD 50
66
67#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or
68 * change the size of
69 * forw_packet->direct_link_flags */
70#define MAX_AGGREGATION_MS 100
71
72#define SOFTIF_NEIGH_TIMEOUT 180000 /* 3 minutes */
73
74#define RESET_PROTECTION_MS 30000
75#define EXPECTED_SEQNO_RANGE 65536
76/* don't reset again within 30 seconds */
77
78#define MESH_INACTIVE 0
79#define MESH_ACTIVE 1
80#define MESH_DEACTIVATING 2
81
82#define BCAST_QUEUE_LEN 256
83#define BATMAN_QUEUE_LEN 256
84
85/*
86 * Debug Messages
87 */
88#ifdef pr_fmt
89#undef pr_fmt
90#endif
91#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Append 'batman-adv: ' before
92 * kernel messages */
93
94#define DBG_BATMAN 1 /* all messages related to routing / flooding /
95 * broadcasting / etc */
96#define DBG_ROUTES 2 /* route or hna added / changed / deleted */
97#define DBG_ALL 3
98
99#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
100
101
102/*
103 * Vis
104 */
105
106/* #define VIS_SUBCLUSTERS_DISABLED */
107
108/*
109 * Kernel headers
110 */
111
112#include <linux/mutex.h> /* mutex */
113#include <linux/module.h> /* needed by all modules */
114#include <linux/netdevice.h> /* netdevice */
115#include <linux/etherdevice.h> /* ethernet address classifaction */
116#include <linux/if_ether.h> /* ethernet header */
117#include <linux/poll.h> /* poll_table */
118#include <linux/kthread.h> /* kernel threads */
119#include <linux/pkt_sched.h> /* schedule types */
120#include <linux/workqueue.h> /* workqueue */
121#include <linux/slab.h>
122#include <net/sock.h> /* struct sock */
123#include <linux/jiffies.h>
124#include <linux/seq_file.h>
125#include "types.h"
126
127#ifndef REVISION_VERSION
128#define REVISION_VERSION_STR ""
129#else
130#define REVISION_VERSION_STR " "REVISION_VERSION
131#endif
132
133extern struct list_head if_list;
134
135extern unsigned char broadcast_addr[];
136extern struct workqueue_struct *bat_event_workqueue;
137
138int mesh_init(struct net_device *soft_iface);
139void mesh_free(struct net_device *soft_iface);
140void inc_module_count(void);
141void dec_module_count(void);
142int is_my_mac(uint8_t *addr);
143
144#ifdef CONFIG_BATMAN_ADV_DEBUG
145int debug_log(struct bat_priv *bat_priv, char *fmt, ...);
146
147#define bat_dbg(type, bat_priv, fmt, arg...) \
148 do { \
149 if (atomic_read(&bat_priv->log_level) & type) \
150 debug_log(bat_priv, fmt, ## arg); \
151 } \
152 while (0)
153#else /* !CONFIG_BATMAN_ADV_DEBUG */
154static inline void bat_dbg(char type __attribute__((unused)),
155 struct bat_priv *bat_priv __attribute__((unused)),
156 char *fmt __attribute__((unused)), ...)
157{
158}
159#endif
160
161#define bat_warning(net_dev, fmt, arg...) \
162 do { \
163 struct net_device *_netdev = (net_dev); \
164 struct bat_priv *_batpriv = netdev_priv(_netdev); \
165 bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
166 pr_warning("%s: " fmt, _netdev->name, ## arg); \
167 } while (0)
168#define bat_info(net_dev, fmt, arg...) \
169 do { \
170 struct net_device *_netdev = (net_dev); \
171 struct bat_priv *_batpriv = netdev_priv(_netdev); \
172 bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
173 pr_info("%s: " fmt, _netdev->name, ## arg); \
174 } while (0)
175#define bat_err(net_dev, fmt, arg...) \
176 do { \
177 struct net_device *_netdev = (net_dev); \
178 struct bat_priv *_batpriv = netdev_priv(_netdev); \
179 bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
180 pr_err("%s: " fmt, _netdev->name, ## arg); \
181 } while (0)
182
183#endif /* _NET_BATMAN_ADV_MAIN_H_ */
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
new file mode 100644
index 000000000000..6b7fb6b7e6f9
--- /dev/null
+++ b/net/batman-adv/originator.c
@@ -0,0 +1,564 @@
1/*
2 * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22/* increase the reference counter for this originator */
23
24#include "main.h"
25#include "originator.h"
26#include "hash.h"
27#include "translation-table.h"
28#include "routing.h"
29#include "gateway_client.h"
30#include "hard-interface.h"
31#include "unicast.h"
32#include "soft-interface.h"
33
34static void purge_orig(struct work_struct *work);
35
36static void start_purge_timer(struct bat_priv *bat_priv)
37{
38 INIT_DELAYED_WORK(&bat_priv->orig_work, purge_orig);
39 queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ);
40}
41
42int originator_init(struct bat_priv *bat_priv)
43{
44 if (bat_priv->orig_hash)
45 return 1;
46
47 spin_lock_bh(&bat_priv->orig_hash_lock);
48 bat_priv->orig_hash = hash_new(1024);
49
50 if (!bat_priv->orig_hash)
51 goto err;
52
53 spin_unlock_bh(&bat_priv->orig_hash_lock);
54 start_purge_timer(bat_priv);
55 return 1;
56
57err:
58 spin_unlock_bh(&bat_priv->orig_hash_lock);
59 return 0;
60}
61
62struct neigh_node *
63create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
64 uint8_t *neigh, struct batman_if *if_incoming)
65{
66 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
67 struct neigh_node *neigh_node;
68
69 bat_dbg(DBG_BATMAN, bat_priv,
70 "Creating new last-hop neighbor of originator\n");
71
72 neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC);
73 if (!neigh_node)
74 return NULL;
75
76 INIT_LIST_HEAD(&neigh_node->list);
77
78 memcpy(neigh_node->addr, neigh, ETH_ALEN);
79 neigh_node->orig_node = orig_neigh_node;
80 neigh_node->if_incoming = if_incoming;
81
82 list_add_tail(&neigh_node->list, &orig_node->neigh_list);
83 return neigh_node;
84}
85
86static void free_orig_node(void *data, void *arg)
87{
88 struct list_head *list_pos, *list_pos_tmp;
89 struct neigh_node *neigh_node;
90 struct orig_node *orig_node = (struct orig_node *)data;
91 struct bat_priv *bat_priv = (struct bat_priv *)arg;
92
93 /* for all neighbors towards this originator ... */
94 list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
95 neigh_node = list_entry(list_pos, struct neigh_node, list);
96
97 list_del(list_pos);
98 kfree(neigh_node);
99 }
100
101 frag_list_free(&orig_node->frag_list);
102 hna_global_del_orig(bat_priv, orig_node, "originator timed out");
103
104 kfree(orig_node->bcast_own);
105 kfree(orig_node->bcast_own_sum);
106 kfree(orig_node);
107}
108
109void originator_free(struct bat_priv *bat_priv)
110{
111 if (!bat_priv->orig_hash)
112 return;
113
114 cancel_delayed_work_sync(&bat_priv->orig_work);
115
116 spin_lock_bh(&bat_priv->orig_hash_lock);
117 hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv);
118 bat_priv->orig_hash = NULL;
119 spin_unlock_bh(&bat_priv->orig_hash_lock);
120}
121
122/* this function finds or creates an originator entry for the given
123 * address if it does not exits */
124struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
125{
126 struct orig_node *orig_node;
127 int size;
128 int hash_added;
129
130 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
131 compare_orig, choose_orig,
132 addr));
133
134 if (orig_node)
135 return orig_node;
136
137 bat_dbg(DBG_BATMAN, bat_priv,
138 "Creating new originator: %pM\n", addr);
139
140 orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC);
141 if (!orig_node)
142 return NULL;
143
144 INIT_LIST_HEAD(&orig_node->neigh_list);
145
146 memcpy(orig_node->orig, addr, ETH_ALEN);
147 orig_node->router = NULL;
148 orig_node->hna_buff = NULL;
149 orig_node->bcast_seqno_reset = jiffies - 1
150 - msecs_to_jiffies(RESET_PROTECTION_MS);
151 orig_node->batman_seqno_reset = jiffies - 1
152 - msecs_to_jiffies(RESET_PROTECTION_MS);
153
154 size = bat_priv->num_ifaces * sizeof(unsigned long) * NUM_WORDS;
155
156 orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
157 if (!orig_node->bcast_own)
158 goto free_orig_node;
159
160 size = bat_priv->num_ifaces * sizeof(uint8_t);
161 orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
162
163 INIT_LIST_HEAD(&orig_node->frag_list);
164 orig_node->last_frag_packet = 0;
165
166 if (!orig_node->bcast_own_sum)
167 goto free_bcast_own;
168
169 hash_added = hash_add(bat_priv->orig_hash, compare_orig, choose_orig,
170 orig_node);
171 if (hash_added < 0)
172 goto free_bcast_own_sum;
173
174 return orig_node;
175free_bcast_own_sum:
176 kfree(orig_node->bcast_own_sum);
177free_bcast_own:
178 kfree(orig_node->bcast_own);
179free_orig_node:
180 kfree(orig_node);
181 return NULL;
182}
183
184static bool purge_orig_neighbors(struct bat_priv *bat_priv,
185 struct orig_node *orig_node,
186 struct neigh_node **best_neigh_node)
187{
188 struct list_head *list_pos, *list_pos_tmp;
189 struct neigh_node *neigh_node;
190 bool neigh_purged = false;
191
192 *best_neigh_node = NULL;
193
194 /* for all neighbors towards this originator ... */
195 list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
196 neigh_node = list_entry(list_pos, struct neigh_node, list);
197
198 if ((time_after(jiffies,
199 neigh_node->last_valid + PURGE_TIMEOUT * HZ)) ||
200 (neigh_node->if_incoming->if_status == IF_INACTIVE) ||
201 (neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) {
202
203 if (neigh_node->if_incoming->if_status ==
204 IF_TO_BE_REMOVED)
205 bat_dbg(DBG_BATMAN, bat_priv,
206 "neighbor purge: originator %pM, "
207 "neighbor: %pM, iface: %s\n",
208 orig_node->orig, neigh_node->addr,
209 neigh_node->if_incoming->net_dev->name);
210 else
211 bat_dbg(DBG_BATMAN, bat_priv,
212 "neighbor timeout: originator %pM, "
213 "neighbor: %pM, last_valid: %lu\n",
214 orig_node->orig, neigh_node->addr,
215 (neigh_node->last_valid / HZ));
216
217 neigh_purged = true;
218 list_del(list_pos);
219 kfree(neigh_node);
220 } else {
221 if ((!*best_neigh_node) ||
222 (neigh_node->tq_avg > (*best_neigh_node)->tq_avg))
223 *best_neigh_node = neigh_node;
224 }
225 }
226 return neigh_purged;
227}
228
229static bool purge_orig_node(struct bat_priv *bat_priv,
230 struct orig_node *orig_node)
231{
232 struct neigh_node *best_neigh_node;
233
234 if (time_after(jiffies,
235 orig_node->last_valid + 2 * PURGE_TIMEOUT * HZ)) {
236
237 bat_dbg(DBG_BATMAN, bat_priv,
238 "Originator timeout: originator %pM, last_valid %lu\n",
239 orig_node->orig, (orig_node->last_valid / HZ));
240 return true;
241 } else {
242 if (purge_orig_neighbors(bat_priv, orig_node,
243 &best_neigh_node)) {
244 update_routes(bat_priv, orig_node,
245 best_neigh_node,
246 orig_node->hna_buff,
247 orig_node->hna_buff_len);
248 /* update bonding candidates, we could have lost
249 * some candidates. */
250 update_bonding_candidates(bat_priv, orig_node);
251 }
252 }
253
254 return false;
255}
256
257static void _purge_orig(struct bat_priv *bat_priv)
258{
259 struct hashtable_t *hash = bat_priv->orig_hash;
260 struct hlist_node *walk, *safe;
261 struct hlist_head *head;
262 struct element_t *bucket;
263 struct orig_node *orig_node;
264 int i;
265
266 if (!hash)
267 return;
268
269 spin_lock_bh(&bat_priv->orig_hash_lock);
270
271 /* for all origins... */
272 for (i = 0; i < hash->size; i++) {
273 head = &hash->table[i];
274
275 hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
276 orig_node = bucket->data;
277
278 if (purge_orig_node(bat_priv, orig_node)) {
279 if (orig_node->gw_flags)
280 gw_node_delete(bat_priv, orig_node);
281 hlist_del(walk);
282 kfree(bucket);
283 free_orig_node(orig_node, bat_priv);
284 }
285
286 if (time_after(jiffies, orig_node->last_frag_packet +
287 msecs_to_jiffies(FRAG_TIMEOUT)))
288 frag_list_free(&orig_node->frag_list);
289 }
290 }
291
292 spin_unlock_bh(&bat_priv->orig_hash_lock);
293
294 gw_node_purge(bat_priv);
295 gw_election(bat_priv);
296
297 softif_neigh_purge(bat_priv);
298}
299
300static void purge_orig(struct work_struct *work)
301{
302 struct delayed_work *delayed_work =
303 container_of(work, struct delayed_work, work);
304 struct bat_priv *bat_priv =
305 container_of(delayed_work, struct bat_priv, orig_work);
306
307 _purge_orig(bat_priv);
308 start_purge_timer(bat_priv);
309}
310
311void purge_orig_ref(struct bat_priv *bat_priv)
312{
313 _purge_orig(bat_priv);
314}
315
316int orig_seq_print_text(struct seq_file *seq, void *offset)
317{
318 struct net_device *net_dev = (struct net_device *)seq->private;
319 struct bat_priv *bat_priv = netdev_priv(net_dev);
320 struct hashtable_t *hash = bat_priv->orig_hash;
321 struct hlist_node *walk;
322 struct hlist_head *head;
323 struct element_t *bucket;
324 struct orig_node *orig_node;
325 struct neigh_node *neigh_node;
326 int batman_count = 0;
327 int last_seen_secs;
328 int last_seen_msecs;
329 int i;
330
331 if ((!bat_priv->primary_if) ||
332 (bat_priv->primary_if->if_status != IF_ACTIVE)) {
333 if (!bat_priv->primary_if)
334 return seq_printf(seq, "BATMAN mesh %s disabled - "
335 "please specify interfaces to enable it\n",
336 net_dev->name);
337
338 return seq_printf(seq, "BATMAN mesh %s "
339 "disabled - primary interface not active\n",
340 net_dev->name);
341 }
342
343 seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
344 SOURCE_VERSION, REVISION_VERSION_STR,
345 bat_priv->primary_if->net_dev->name,
346 bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
347 seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
348 "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
349 "outgoingIF", "Potential nexthops");
350
351 spin_lock_bh(&bat_priv->orig_hash_lock);
352
353 for (i = 0; i < hash->size; i++) {
354 head = &hash->table[i];
355
356 hlist_for_each_entry(bucket, walk, head, hlist) {
357 orig_node = bucket->data;
358
359 if (!orig_node->router)
360 continue;
361
362 if (orig_node->router->tq_avg == 0)
363 continue;
364
365 last_seen_secs = jiffies_to_msecs(jiffies -
366 orig_node->last_valid) / 1000;
367 last_seen_msecs = jiffies_to_msecs(jiffies -
368 orig_node->last_valid) % 1000;
369
370 neigh_node = orig_node->router;
371 seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:",
372 orig_node->orig, last_seen_secs,
373 last_seen_msecs, neigh_node->tq_avg,
374 neigh_node->addr,
375 neigh_node->if_incoming->net_dev->name);
376
377 list_for_each_entry(neigh_node, &orig_node->neigh_list,
378 list) {
379 seq_printf(seq, " %pM (%3i)", neigh_node->addr,
380 neigh_node->tq_avg);
381 }
382
383 seq_printf(seq, "\n");
384 batman_count++;
385 }
386 }
387
388 spin_unlock_bh(&bat_priv->orig_hash_lock);
389
390 if ((batman_count == 0))
391 seq_printf(seq, "No batman nodes in range ...\n");
392
393 return 0;
394}
395
396static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
397{
398 void *data_ptr;
399
400 data_ptr = kmalloc(max_if_num * sizeof(unsigned long) * NUM_WORDS,
401 GFP_ATOMIC);
402 if (!data_ptr) {
403 pr_err("Can't resize orig: out of memory\n");
404 return -1;
405 }
406
407 memcpy(data_ptr, orig_node->bcast_own,
408 (max_if_num - 1) * sizeof(unsigned long) * NUM_WORDS);
409 kfree(orig_node->bcast_own);
410 orig_node->bcast_own = data_ptr;
411
412 data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
413 if (!data_ptr) {
414 pr_err("Can't resize orig: out of memory\n");
415 return -1;
416 }
417
418 memcpy(data_ptr, orig_node->bcast_own_sum,
419 (max_if_num - 1) * sizeof(uint8_t));
420 kfree(orig_node->bcast_own_sum);
421 orig_node->bcast_own_sum = data_ptr;
422
423 return 0;
424}
425
426int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
427{
428 struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
429 struct hashtable_t *hash = bat_priv->orig_hash;
430 struct hlist_node *walk;
431 struct hlist_head *head;
432 struct element_t *bucket;
433 struct orig_node *orig_node;
434 int i;
435
436 /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
437 * if_num */
438 spin_lock_bh(&bat_priv->orig_hash_lock);
439
440 for (i = 0; i < hash->size; i++) {
441 head = &hash->table[i];
442
443 hlist_for_each_entry(bucket, walk, head, hlist) {
444 orig_node = bucket->data;
445
446 if (orig_node_add_if(orig_node, max_if_num) == -1)
447 goto err;
448 }
449 }
450
451 spin_unlock_bh(&bat_priv->orig_hash_lock);
452 return 0;
453
454err:
455 spin_unlock_bh(&bat_priv->orig_hash_lock);
456 return -ENOMEM;
457}
458
459static int orig_node_del_if(struct orig_node *orig_node,
460 int max_if_num, int del_if_num)
461{
462 void *data_ptr = NULL;
463 int chunk_size;
464
465 /* last interface was removed */
466 if (max_if_num == 0)
467 goto free_bcast_own;
468
469 chunk_size = sizeof(unsigned long) * NUM_WORDS;
470 data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC);
471 if (!data_ptr) {
472 pr_err("Can't resize orig: out of memory\n");
473 return -1;
474 }
475
476 /* copy first part */
477 memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
478
479 /* copy second part */
480 memcpy(data_ptr + del_if_num * chunk_size,
481 orig_node->bcast_own + ((del_if_num + 1) * chunk_size),
482 (max_if_num - del_if_num) * chunk_size);
483
484free_bcast_own:
485 kfree(orig_node->bcast_own);
486 orig_node->bcast_own = data_ptr;
487
488 if (max_if_num == 0)
489 goto free_own_sum;
490
491 data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
492 if (!data_ptr) {
493 pr_err("Can't resize orig: out of memory\n");
494 return -1;
495 }
496
497 memcpy(data_ptr, orig_node->bcast_own_sum,
498 del_if_num * sizeof(uint8_t));
499
500 memcpy(data_ptr + del_if_num * sizeof(uint8_t),
501 orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)),
502 (max_if_num - del_if_num) * sizeof(uint8_t));
503
504free_own_sum:
505 kfree(orig_node->bcast_own_sum);
506 orig_node->bcast_own_sum = data_ptr;
507
508 return 0;
509}
510
511int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
512{
513 struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
514 struct hashtable_t *hash = bat_priv->orig_hash;
515 struct hlist_node *walk;
516 struct hlist_head *head;
517 struct element_t *bucket;
518 struct batman_if *batman_if_tmp;
519 struct orig_node *orig_node;
520 int i, ret;
521
522 /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
523 * if_num */
524 spin_lock_bh(&bat_priv->orig_hash_lock);
525
526 for (i = 0; i < hash->size; i++) {
527 head = &hash->table[i];
528
529 hlist_for_each_entry(bucket, walk, head, hlist) {
530 orig_node = bucket->data;
531
532 ret = orig_node_del_if(orig_node, max_if_num,
533 batman_if->if_num);
534
535 if (ret == -1)
536 goto err;
537 }
538 }
539
540 /* renumber remaining batman interfaces _inside_ of orig_hash_lock */
541 rcu_read_lock();
542 list_for_each_entry_rcu(batman_if_tmp, &if_list, list) {
543 if (batman_if_tmp->if_status == IF_NOT_IN_USE)
544 continue;
545
546 if (batman_if == batman_if_tmp)
547 continue;
548
549 if (batman_if->soft_iface != batman_if_tmp->soft_iface)
550 continue;
551
552 if (batman_if_tmp->if_num > batman_if->if_num)
553 batman_if_tmp->if_num--;
554 }
555 rcu_read_unlock();
556
557 batman_if->if_num = -1;
558 spin_unlock_bh(&bat_priv->orig_hash_lock);
559 return 0;
560
561err:
562 spin_unlock_bh(&bat_priv->orig_hash_lock);
563 return -ENOMEM;
564}
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
new file mode 100644
index 000000000000..d474ceb2a4eb
--- /dev/null
+++ b/net/batman-adv/originator.h
@@ -0,0 +1,64 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_ORIGINATOR_H_
23#define _NET_BATMAN_ADV_ORIGINATOR_H_
24
25int originator_init(struct bat_priv *bat_priv);
26void originator_free(struct bat_priv *bat_priv);
27void purge_orig_ref(struct bat_priv *bat_priv);
28struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
29struct neigh_node *
30create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
31 uint8_t *neigh, struct batman_if *if_incoming);
32int orig_seq_print_text(struct seq_file *seq, void *offset);
33int orig_hash_add_if(struct batman_if *batman_if, int max_if_num);
34int orig_hash_del_if(struct batman_if *batman_if, int max_if_num);
35
36
37/* returns 1 if they are the same originator */
38static inline int compare_orig(void *data1, void *data2)
39{
40 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
41}
42
43/* hashfunction to choose an entry in a hash table of given size */
44/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
45static inline int choose_orig(void *data, int32_t size)
46{
47 unsigned char *key = data;
48 uint32_t hash = 0;
49 size_t i;
50
51 for (i = 0; i < 6; i++) {
52 hash += key[i];
53 hash += (hash << 10);
54 hash ^= (hash >> 6);
55 }
56
57 hash += (hash << 3);
58 hash ^= (hash >> 11);
59 hash += (hash << 15);
60
61 return hash % size;
62}
63
64#endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
new file mode 100644
index 000000000000..b49fdf70a6d5
--- /dev/null
+++ b/net/batman-adv/packet.h
@@ -0,0 +1,136 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_PACKET_H_
23#define _NET_BATMAN_ADV_PACKET_H_
24
25#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
26
27#define BAT_PACKET 0x01
28#define BAT_ICMP 0x02
29#define BAT_UNICAST 0x03
30#define BAT_BCAST 0x04
31#define BAT_VIS 0x05
32#define BAT_UNICAST_FRAG 0x06
33
34/* this file is included by batctl which needs these defines */
35#define COMPAT_VERSION 12
36#define DIRECTLINK 0x40
37#define VIS_SERVER 0x20
38#define PRIMARIES_FIRST_HOP 0x10
39
40/* ICMP message types */
41#define ECHO_REPLY 0
42#define DESTINATION_UNREACHABLE 3
43#define ECHO_REQUEST 8
44#define TTL_EXCEEDED 11
45#define PARAMETER_PROBLEM 12
46
47/* vis defines */
48#define VIS_TYPE_SERVER_SYNC 0
49#define VIS_TYPE_CLIENT_UPDATE 1
50
51/* fragmentation defines */
52#define UNI_FRAG_HEAD 0x01
53
54struct batman_packet {
55 uint8_t packet_type;
56 uint8_t version; /* batman version field */
57 uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
58 uint8_t tq;
59 uint32_t seqno;
60 uint8_t orig[6];
61 uint8_t prev_sender[6];
62 uint8_t ttl;
63 uint8_t num_hna;
64 uint8_t gw_flags; /* flags related to gateway class */
65 uint8_t align;
66} __attribute__((packed));
67
68#define BAT_PACKET_LEN sizeof(struct batman_packet)
69
70struct icmp_packet {
71 uint8_t packet_type;
72 uint8_t version; /* batman version field */
73 uint8_t msg_type; /* see ICMP message types above */
74 uint8_t ttl;
75 uint8_t dst[6];
76 uint8_t orig[6];
77 uint16_t seqno;
78 uint8_t uid;
79} __attribute__((packed));
80
81#define BAT_RR_LEN 16
82
83/* icmp_packet_rr must start with all fields from imcp_packet
84 * as this is assumed by code that handles ICMP packets */
85struct icmp_packet_rr {
86 uint8_t packet_type;
87 uint8_t version; /* batman version field */
88 uint8_t msg_type; /* see ICMP message types above */
89 uint8_t ttl;
90 uint8_t dst[6];
91 uint8_t orig[6];
92 uint16_t seqno;
93 uint8_t uid;
94 uint8_t rr_cur;
95 uint8_t rr[BAT_RR_LEN][ETH_ALEN];
96} __attribute__((packed));
97
98struct unicast_packet {
99 uint8_t packet_type;
100 uint8_t version; /* batman version field */
101 uint8_t dest[6];
102 uint8_t ttl;
103} __attribute__((packed));
104
105struct unicast_frag_packet {
106 uint8_t packet_type;
107 uint8_t version; /* batman version field */
108 uint8_t dest[6];
109 uint8_t ttl;
110 uint8_t flags;
111 uint8_t orig[6];
112 uint16_t seqno;
113} __attribute__((packed));
114
115struct bcast_packet {
116 uint8_t packet_type;
117 uint8_t version; /* batman version field */
118 uint8_t orig[6];
119 uint8_t ttl;
120 uint32_t seqno;
121} __attribute__((packed));
122
123struct vis_packet {
124 uint8_t packet_type;
125 uint8_t version; /* batman version field */
126 uint8_t vis_type; /* which type of vis-participant sent this? */
127 uint8_t entries; /* number of entries behind this struct */
128 uint32_t seqno; /* sequence number */
129 uint8_t ttl; /* TTL */
130 uint8_t vis_orig[6]; /* originator that informs about its
131 * neighbors */
132 uint8_t target_orig[6]; /* who should receive this packet */
133 uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
134} __attribute__((packed));
135
136#endif /* _NET_BATMAN_ADV_PACKET_H_ */
diff --git a/net/batman-adv/ring_buffer.c b/net/batman-adv/ring_buffer.c
new file mode 100644
index 000000000000..defd37c9be1f
--- /dev/null
+++ b/net/batman-adv/ring_buffer.c
@@ -0,0 +1,52 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "ring_buffer.h"
24
25void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value)
26{
27 lq_recv[*lq_index] = value;
28 *lq_index = (*lq_index + 1) % TQ_GLOBAL_WINDOW_SIZE;
29}
30
31uint8_t ring_buffer_avg(uint8_t lq_recv[])
32{
33 uint8_t *ptr;
34 uint16_t count = 0, i = 0, sum = 0;
35
36 ptr = lq_recv;
37
38 while (i < TQ_GLOBAL_WINDOW_SIZE) {
39 if (*ptr != 0) {
40 count++;
41 sum += *ptr;
42 }
43
44 i++;
45 ptr++;
46 }
47
48 if (count == 0)
49 return 0;
50
51 return (uint8_t)(sum / count);
52}
diff --git a/net/batman-adv/ring_buffer.h b/net/batman-adv/ring_buffer.h
new file mode 100644
index 000000000000..6b0cb9aaeba5
--- /dev/null
+++ b/net/batman-adv/ring_buffer.h
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_RING_BUFFER_H_
23#define _NET_BATMAN_ADV_RING_BUFFER_H_
24
25void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value);
26uint8_t ring_buffer_avg(uint8_t lq_recv[]);
27
28#endif /* _NET_BATMAN_ADV_RING_BUFFER_H_ */
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
new file mode 100644
index 000000000000..8828eddd3f72
--- /dev/null
+++ b/net/batman-adv/routing.c
@@ -0,0 +1,1397 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "routing.h"
24#include "send.h"
25#include "hash.h"
26#include "soft-interface.h"
27#include "hard-interface.h"
28#include "icmp_socket.h"
29#include "translation-table.h"
30#include "originator.h"
31#include "types.h"
32#include "ring_buffer.h"
33#include "vis.h"
34#include "aggregation.h"
35#include "gateway_common.h"
36#include "gateway_client.h"
37#include "unicast.h"
38
39void slide_own_bcast_window(struct batman_if *batman_if)
40{
41 struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
42 struct hashtable_t *hash = bat_priv->orig_hash;
43 struct hlist_node *walk;
44 struct hlist_head *head;
45 struct element_t *bucket;
46 struct orig_node *orig_node;
47 unsigned long *word;
48 int i;
49 size_t word_index;
50
51 spin_lock_bh(&bat_priv->orig_hash_lock);
52
53 for (i = 0; i < hash->size; i++) {
54 head = &hash->table[i];
55
56 hlist_for_each_entry(bucket, walk, head, hlist) {
57 orig_node = bucket->data;
58 word_index = batman_if->if_num * NUM_WORDS;
59 word = &(orig_node->bcast_own[word_index]);
60
61 bit_get_packet(bat_priv, word, 1, 0);
62 orig_node->bcast_own_sum[batman_if->if_num] =
63 bit_packet_count(word);
64 }
65 }
66
67 spin_unlock_bh(&bat_priv->orig_hash_lock);
68}
69
70static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node,
71 unsigned char *hna_buff, int hna_buff_len)
72{
73 if ((hna_buff_len != orig_node->hna_buff_len) ||
74 ((hna_buff_len > 0) &&
75 (orig_node->hna_buff_len > 0) &&
76 (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) {
77
78 if (orig_node->hna_buff_len > 0)
79 hna_global_del_orig(bat_priv, orig_node,
80 "originator changed hna");
81
82 if ((hna_buff_len > 0) && (hna_buff))
83 hna_global_add_orig(bat_priv, orig_node,
84 hna_buff, hna_buff_len);
85 }
86}
87
88static void update_route(struct bat_priv *bat_priv,
89 struct orig_node *orig_node,
90 struct neigh_node *neigh_node,
91 unsigned char *hna_buff, int hna_buff_len)
92{
93 /* route deleted */
94 if ((orig_node->router) && (!neigh_node)) {
95
96 bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
97 orig_node->orig);
98 hna_global_del_orig(bat_priv, orig_node,
99 "originator timed out");
100
101 /* route added */
102 } else if ((!orig_node->router) && (neigh_node)) {
103
104 bat_dbg(DBG_ROUTES, bat_priv,
105 "Adding route towards: %pM (via %pM)\n",
106 orig_node->orig, neigh_node->addr);
107 hna_global_add_orig(bat_priv, orig_node,
108 hna_buff, hna_buff_len);
109
110 /* route changed */
111 } else {
112 bat_dbg(DBG_ROUTES, bat_priv,
113 "Changing route towards: %pM "
114 "(now via %pM - was via %pM)\n",
115 orig_node->orig, neigh_node->addr,
116 orig_node->router->addr);
117 }
118
119 orig_node->router = neigh_node;
120}
121
122
123void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
124 struct neigh_node *neigh_node, unsigned char *hna_buff,
125 int hna_buff_len)
126{
127
128 if (!orig_node)
129 return;
130
131 if (orig_node->router != neigh_node)
132 update_route(bat_priv, orig_node, neigh_node,
133 hna_buff, hna_buff_len);
134 /* may be just HNA changed */
135 else
136 update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len);
137}
138
139static int is_bidirectional_neigh(struct orig_node *orig_node,
140 struct orig_node *orig_neigh_node,
141 struct batman_packet *batman_packet,
142 struct batman_if *if_incoming)
143{
144 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
145 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
146 unsigned char total_count;
147
148 if (orig_node == orig_neigh_node) {
149 list_for_each_entry(tmp_neigh_node,
150 &orig_node->neigh_list,
151 list) {
152
153 if (compare_orig(tmp_neigh_node->addr,
154 orig_neigh_node->orig) &&
155 (tmp_neigh_node->if_incoming == if_incoming))
156 neigh_node = tmp_neigh_node;
157 }
158
159 if (!neigh_node)
160 neigh_node = create_neighbor(orig_node,
161 orig_neigh_node,
162 orig_neigh_node->orig,
163 if_incoming);
164 /* create_neighbor failed, return 0 */
165 if (!neigh_node)
166 return 0;
167
168 neigh_node->last_valid = jiffies;
169 } else {
170 /* find packet count of corresponding one hop neighbor */
171 list_for_each_entry(tmp_neigh_node,
172 &orig_neigh_node->neigh_list, list) {
173
174 if (compare_orig(tmp_neigh_node->addr,
175 orig_neigh_node->orig) &&
176 (tmp_neigh_node->if_incoming == if_incoming))
177 neigh_node = tmp_neigh_node;
178 }
179
180 if (!neigh_node)
181 neigh_node = create_neighbor(orig_neigh_node,
182 orig_neigh_node,
183 orig_neigh_node->orig,
184 if_incoming);
185 /* create_neighbor failed, return 0 */
186 if (!neigh_node)
187 return 0;
188 }
189
190 orig_node->last_valid = jiffies;
191
192 /* pay attention to not get a value bigger than 100 % */
193 total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] >
194 neigh_node->real_packet_count ?
195 neigh_node->real_packet_count :
196 orig_neigh_node->bcast_own_sum[if_incoming->if_num]);
197
198 /* if we have too few packets (too less data) we set tq_own to zero */
199 /* if we receive too few packets it is not considered bidirectional */
200 if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
201 (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
202 orig_neigh_node->tq_own = 0;
203 else
204 /* neigh_node->real_packet_count is never zero as we
205 * only purge old information when getting new
206 * information */
207 orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) /
208 neigh_node->real_packet_count;
209
210 /*
211 * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
212 * affect the nearly-symmetric links only a little, but
213 * punishes asymmetric links more. This will give a value
214 * between 0 and TQ_MAX_VALUE
215 */
216 orig_neigh_node->tq_asym_penalty =
217 TQ_MAX_VALUE -
218 (TQ_MAX_VALUE *
219 (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
220 (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
221 (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) /
222 (TQ_LOCAL_WINDOW_SIZE *
223 TQ_LOCAL_WINDOW_SIZE *
224 TQ_LOCAL_WINDOW_SIZE);
225
226 batman_packet->tq = ((batman_packet->tq *
227 orig_neigh_node->tq_own *
228 orig_neigh_node->tq_asym_penalty) /
229 (TQ_MAX_VALUE * TQ_MAX_VALUE));
230
231 bat_dbg(DBG_BATMAN, bat_priv,
232 "bidirectional: "
233 "orig = %-15pM neigh = %-15pM => own_bcast = %2i, "
234 "real recv = %2i, local tq: %3i, asym_penalty: %3i, "
235 "total tq: %3i\n",
236 orig_node->orig, orig_neigh_node->orig, total_count,
237 neigh_node->real_packet_count, orig_neigh_node->tq_own,
238 orig_neigh_node->tq_asym_penalty, batman_packet->tq);
239
240 /* if link has the minimum required transmission quality
241 * consider it bidirectional */
242 if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
243 return 1;
244
245 return 0;
246}
247
248static void update_orig(struct bat_priv *bat_priv,
249 struct orig_node *orig_node,
250 struct ethhdr *ethhdr,
251 struct batman_packet *batman_packet,
252 struct batman_if *if_incoming,
253 unsigned char *hna_buff, int hna_buff_len,
254 char is_duplicate)
255{
256 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
257 int tmp_hna_buff_len;
258
259 bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
260 "Searching and updating originator entry of received packet\n");
261
262 list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
263 if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
264 (tmp_neigh_node->if_incoming == if_incoming)) {
265 neigh_node = tmp_neigh_node;
266 continue;
267 }
268
269 if (is_duplicate)
270 continue;
271
272 ring_buffer_set(tmp_neigh_node->tq_recv,
273 &tmp_neigh_node->tq_index, 0);
274 tmp_neigh_node->tq_avg =
275 ring_buffer_avg(tmp_neigh_node->tq_recv);
276 }
277
278 if (!neigh_node) {
279 struct orig_node *orig_tmp;
280
281 orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);
282 if (!orig_tmp)
283 return;
284
285 neigh_node = create_neighbor(orig_node, orig_tmp,
286 ethhdr->h_source, if_incoming);
287 if (!neigh_node)
288 return;
289 } else
290 bat_dbg(DBG_BATMAN, bat_priv,
291 "Updating existing last-hop neighbor of originator\n");
292
293 orig_node->flags = batman_packet->flags;
294 neigh_node->last_valid = jiffies;
295
296 ring_buffer_set(neigh_node->tq_recv,
297 &neigh_node->tq_index,
298 batman_packet->tq);
299 neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
300
301 if (!is_duplicate) {
302 orig_node->last_ttl = batman_packet->ttl;
303 neigh_node->last_ttl = batman_packet->ttl;
304 }
305
306 tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ?
307 batman_packet->num_hna * ETH_ALEN : hna_buff_len);
308
309 /* if this neighbor already is our next hop there is nothing
310 * to change */
311 if (orig_node->router == neigh_node)
312 goto update_hna;
313
314 /* if this neighbor does not offer a better TQ we won't consider it */
315 if ((orig_node->router) &&
316 (orig_node->router->tq_avg > neigh_node->tq_avg))
317 goto update_hna;
318
319 /* if the TQ is the same and the link not more symetric we
320 * won't consider it either */
321 if ((orig_node->router) &&
322 ((neigh_node->tq_avg == orig_node->router->tq_avg) &&
323 (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num]
324 >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num])))
325 goto update_hna;
326
327 update_routes(bat_priv, orig_node, neigh_node,
328 hna_buff, tmp_hna_buff_len);
329 goto update_gw;
330
331update_hna:
332 update_routes(bat_priv, orig_node, orig_node->router,
333 hna_buff, tmp_hna_buff_len);
334
335update_gw:
336 if (orig_node->gw_flags != batman_packet->gw_flags)
337 gw_node_update(bat_priv, orig_node, batman_packet->gw_flags);
338
339 orig_node->gw_flags = batman_packet->gw_flags;
340
341 /* restart gateway selection if fast or late switching was enabled */
342 if ((orig_node->gw_flags) &&
343 (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) &&
344 (atomic_read(&bat_priv->gw_sel_class) > 2))
345 gw_check_election(bat_priv, orig_node);
346}
347
348/* checks whether the host restarted and is in the protection time.
349 * returns:
350 * 0 if the packet is to be accepted
351 * 1 if the packet is to be ignored.
352 */
353static int window_protected(struct bat_priv *bat_priv,
354 int32_t seq_num_diff,
355 unsigned long *last_reset)
356{
357 if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
358 || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
359 if (time_after(jiffies, *last_reset +
360 msecs_to_jiffies(RESET_PROTECTION_MS))) {
361
362 *last_reset = jiffies;
363 bat_dbg(DBG_BATMAN, bat_priv,
364 "old packet received, start protection\n");
365
366 return 0;
367 } else
368 return 1;
369 }
370 return 0;
371}
372
373/* processes a batman packet for all interfaces, adjusts the sequence number and
374 * finds out whether it is a duplicate.
375 * returns:
376 * 1 the packet is a duplicate
377 * 0 the packet has not yet been received
378 * -1 the packet is old and has been received while the seqno window
379 * was protected. Caller should drop it.
380 */
381static char count_real_packets(struct ethhdr *ethhdr,
382 struct batman_packet *batman_packet,
383 struct batman_if *if_incoming)
384{
385 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
386 struct orig_node *orig_node;
387 struct neigh_node *tmp_neigh_node;
388 char is_duplicate = 0;
389 int32_t seq_diff;
390 int need_update = 0;
391 int set_mark;
392
393 orig_node = get_orig_node(bat_priv, batman_packet->orig);
394 if (!orig_node)
395 return 0;
396
397 seq_diff = batman_packet->seqno - orig_node->last_real_seqno;
398
399 /* signalize caller that the packet is to be dropped. */
400 if (window_protected(bat_priv, seq_diff,
401 &orig_node->batman_seqno_reset))
402 return -1;
403
404 list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
405
406 is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
407 orig_node->last_real_seqno,
408 batman_packet->seqno);
409
410 if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
411 (tmp_neigh_node->if_incoming == if_incoming))
412 set_mark = 1;
413 else
414 set_mark = 0;
415
416 /* if the window moved, set the update flag. */
417 need_update |= bit_get_packet(bat_priv,
418 tmp_neigh_node->real_bits,
419 seq_diff, set_mark);
420
421 tmp_neigh_node->real_packet_count =
422 bit_packet_count(tmp_neigh_node->real_bits);
423 }
424
425 if (need_update) {
426 bat_dbg(DBG_BATMAN, bat_priv,
427 "updating last_seqno: old %d, new %d\n",
428 orig_node->last_real_seqno, batman_packet->seqno);
429 orig_node->last_real_seqno = batman_packet->seqno;
430 }
431
432 return is_duplicate;
433}
434
435/* copy primary address for bonding */
436static void mark_bonding_address(struct bat_priv *bat_priv,
437 struct orig_node *orig_node,
438 struct orig_node *orig_neigh_node,
439 struct batman_packet *batman_packet)
440
441{
442 if (batman_packet->flags & PRIMARIES_FIRST_HOP)
443 memcpy(orig_neigh_node->primary_addr,
444 orig_node->orig, ETH_ALEN);
445
446 return;
447}
448
449/* mark possible bond.candidates in the neighbor list */
450void update_bonding_candidates(struct bat_priv *bat_priv,
451 struct orig_node *orig_node)
452{
453 int candidates;
454 int interference_candidate;
455 int best_tq;
456 struct neigh_node *tmp_neigh_node, *tmp_neigh_node2;
457 struct neigh_node *first_candidate, *last_candidate;
458
459 /* update the candidates for this originator */
460 if (!orig_node->router) {
461 orig_node->bond.candidates = 0;
462 return;
463 }
464
465 best_tq = orig_node->router->tq_avg;
466
467 /* update bond.candidates */
468
469 candidates = 0;
470
471 /* mark other nodes which also received "PRIMARIES FIRST HOP" packets
472 * as "bonding partner" */
473
474 /* first, zero the list */
475 list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
476 tmp_neigh_node->next_bond_candidate = NULL;
477 }
478
479 first_candidate = NULL;
480 last_candidate = NULL;
481 list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
482
483 /* only consider if it has the same primary address ... */
484 if (memcmp(orig_node->orig,
485 tmp_neigh_node->orig_node->primary_addr,
486 ETH_ALEN) != 0)
487 continue;
488
489 /* ... and is good enough to be considered */
490 if (tmp_neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD)
491 continue;
492
493 /* check if we have another candidate with the same
494 * mac address or interface. If we do, we won't
495 * select this candidate because of possible interference. */
496
497 interference_candidate = 0;
498 list_for_each_entry(tmp_neigh_node2,
499 &orig_node->neigh_list, list) {
500
501 if (tmp_neigh_node2 == tmp_neigh_node)
502 continue;
503
504 /* we only care if the other candidate is even
505 * considered as candidate. */
506 if (!tmp_neigh_node2->next_bond_candidate)
507 continue;
508
509
510 if ((tmp_neigh_node->if_incoming ==
511 tmp_neigh_node2->if_incoming)
512 || (memcmp(tmp_neigh_node->addr,
513 tmp_neigh_node2->addr, ETH_ALEN) == 0)) {
514
515 interference_candidate = 1;
516 break;
517 }
518 }
519 /* don't care further if it is an interference candidate */
520 if (interference_candidate)
521 continue;
522
523 if (!first_candidate) {
524 first_candidate = tmp_neigh_node;
525 tmp_neigh_node->next_bond_candidate = first_candidate;
526 } else
527 tmp_neigh_node->next_bond_candidate = last_candidate;
528
529 last_candidate = tmp_neigh_node;
530
531 candidates++;
532 }
533
534 if (candidates > 0) {
535 first_candidate->next_bond_candidate = last_candidate;
536 orig_node->bond.selected = first_candidate;
537 }
538
539 orig_node->bond.candidates = candidates;
540}
541
542void receive_bat_packet(struct ethhdr *ethhdr,
543 struct batman_packet *batman_packet,
544 unsigned char *hna_buff, int hna_buff_len,
545 struct batman_if *if_incoming)
546{
547 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
548 struct batman_if *batman_if;
549 struct orig_node *orig_neigh_node, *orig_node;
550 char has_directlink_flag;
551 char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
552 char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
553 char is_duplicate;
554 uint32_t if_incoming_seqno;
555
556 /* Silently drop when the batman packet is actually not a
557 * correct packet.
558 *
559 * This might happen if a packet is padded (e.g. Ethernet has a
560 * minimum frame length of 64 byte) and the aggregation interprets
561 * it as an additional length.
562 *
563 * TODO: A more sane solution would be to have a bit in the
564 * batman_packet to detect whether the packet is the last
565 * packet in an aggregation. Here we expect that the padding
566 * is always zero (or not 0x01)
567 */
568 if (batman_packet->packet_type != BAT_PACKET)
569 return;
570
571 /* could be changed by schedule_own_packet() */
572 if_incoming_seqno = atomic_read(&if_incoming->seqno);
573
574 has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0);
575
576 is_single_hop_neigh = (compare_orig(ethhdr->h_source,
577 batman_packet->orig) ? 1 : 0);
578
579 bat_dbg(DBG_BATMAN, bat_priv,
580 "Received BATMAN packet via NB: %pM, IF: %s [%pM] "
581 "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, "
582 "TTL %d, V %d, IDF %d)\n",
583 ethhdr->h_source, if_incoming->net_dev->name,
584 if_incoming->net_dev->dev_addr, batman_packet->orig,
585 batman_packet->prev_sender, batman_packet->seqno,
586 batman_packet->tq, batman_packet->ttl, batman_packet->version,
587 has_directlink_flag);
588
589 rcu_read_lock();
590 list_for_each_entry_rcu(batman_if, &if_list, list) {
591 if (batman_if->if_status != IF_ACTIVE)
592 continue;
593
594 if (batman_if->soft_iface != if_incoming->soft_iface)
595 continue;
596
597 if (compare_orig(ethhdr->h_source,
598 batman_if->net_dev->dev_addr))
599 is_my_addr = 1;
600
601 if (compare_orig(batman_packet->orig,
602 batman_if->net_dev->dev_addr))
603 is_my_orig = 1;
604
605 if (compare_orig(batman_packet->prev_sender,
606 batman_if->net_dev->dev_addr))
607 is_my_oldorig = 1;
608
609 if (compare_orig(ethhdr->h_source, broadcast_addr))
610 is_broadcast = 1;
611 }
612 rcu_read_unlock();
613
614 if (batman_packet->version != COMPAT_VERSION) {
615 bat_dbg(DBG_BATMAN, bat_priv,
616 "Drop packet: incompatible batman version (%i)\n",
617 batman_packet->version);
618 return;
619 }
620
621 if (is_my_addr) {
622 bat_dbg(DBG_BATMAN, bat_priv,
623 "Drop packet: received my own broadcast (sender: %pM"
624 ")\n",
625 ethhdr->h_source);
626 return;
627 }
628
629 if (is_broadcast) {
630 bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
631 "ignoring all packets with broadcast source addr (sender: %pM"
632 ")\n", ethhdr->h_source);
633 return;
634 }
635
636 if (is_my_orig) {
637 unsigned long *word;
638 int offset;
639
640 orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
641
642 if (!orig_neigh_node)
643 return;
644
645 /* neighbor has to indicate direct link and it has to
646 * come via the corresponding interface */
647 /* if received seqno equals last send seqno save new
648 * seqno for bidirectional check */
649 if (has_directlink_flag &&
650 compare_orig(if_incoming->net_dev->dev_addr,
651 batman_packet->orig) &&
652 (batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
653 offset = if_incoming->if_num * NUM_WORDS;
654 word = &(orig_neigh_node->bcast_own[offset]);
655 bit_mark(word, 0);
656 orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
657 bit_packet_count(word);
658 }
659
660 bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
661 "originator packet from myself (via neighbor)\n");
662 return;
663 }
664
665 if (is_my_oldorig) {
666 bat_dbg(DBG_BATMAN, bat_priv,
667 "Drop packet: ignoring all rebroadcast echos (sender: "
668 "%pM)\n", ethhdr->h_source);
669 return;
670 }
671
672 orig_node = get_orig_node(bat_priv, batman_packet->orig);
673 if (!orig_node)
674 return;
675
676 is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming);
677
678 if (is_duplicate == -1) {
679 bat_dbg(DBG_BATMAN, bat_priv,
680 "Drop packet: packet within seqno protection time "
681 "(sender: %pM)\n", ethhdr->h_source);
682 return;
683 }
684
685 if (batman_packet->tq == 0) {
686 bat_dbg(DBG_BATMAN, bat_priv,
687 "Drop packet: originator packet with tq equal 0\n");
688 return;
689 }
690
691 /* avoid temporary routing loops */
692 if ((orig_node->router) &&
693 (orig_node->router->orig_node->router) &&
694 (compare_orig(orig_node->router->addr,
695 batman_packet->prev_sender)) &&
696 !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) &&
697 (compare_orig(orig_node->router->addr,
698 orig_node->router->orig_node->router->addr))) {
699 bat_dbg(DBG_BATMAN, bat_priv,
700 "Drop packet: ignoring all rebroadcast packets that "
701 "may make me loop (sender: %pM)\n", ethhdr->h_source);
702 return;
703 }
704
705 /* if sender is a direct neighbor the sender mac equals
706 * originator mac */
707 orig_neigh_node = (is_single_hop_neigh ?
708 orig_node :
709 get_orig_node(bat_priv, ethhdr->h_source));
710 if (!orig_neigh_node)
711 return;
712
713 /* drop packet if sender is not a direct neighbor and if we
714 * don't route towards it */
715 if (!is_single_hop_neigh && (!orig_neigh_node->router)) {
716 bat_dbg(DBG_BATMAN, bat_priv,
717 "Drop packet: OGM via unknown neighbor!\n");
718 return;
719 }
720
721 is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
722 batman_packet, if_incoming);
723
724 /* update ranking if it is not a duplicate or has the same
725 * seqno and similar ttl as the non-duplicate */
726 if (is_bidirectional &&
727 (!is_duplicate ||
728 ((orig_node->last_real_seqno == batman_packet->seqno) &&
729 (orig_node->last_ttl - 3 <= batman_packet->ttl))))
730 update_orig(bat_priv, orig_node, ethhdr, batman_packet,
731 if_incoming, hna_buff, hna_buff_len, is_duplicate);
732
733 mark_bonding_address(bat_priv, orig_node,
734 orig_neigh_node, batman_packet);
735 update_bonding_candidates(bat_priv, orig_node);
736
737 /* is single hop (direct) neighbor */
738 if (is_single_hop_neigh) {
739
740 /* mark direct link on incoming interface */
741 schedule_forward_packet(orig_node, ethhdr, batman_packet,
742 1, hna_buff_len, if_incoming);
743
744 bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
745 "rebroadcast neighbor packet with direct link flag\n");
746 return;
747 }
748
749 /* multihop originator */
750 if (!is_bidirectional) {
751 bat_dbg(DBG_BATMAN, bat_priv,
752 "Drop packet: not received via bidirectional link\n");
753 return;
754 }
755
756 if (is_duplicate) {
757 bat_dbg(DBG_BATMAN, bat_priv,
758 "Drop packet: duplicate packet received\n");
759 return;
760 }
761
762 bat_dbg(DBG_BATMAN, bat_priv,
763 "Forwarding packet: rebroadcast originator packet\n");
764 schedule_forward_packet(orig_node, ethhdr, batman_packet,
765 0, hna_buff_len, if_incoming);
766}
767
768int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if)
769{
770 struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
771 struct ethhdr *ethhdr;
772
773 /* drop packet if it has not necessary minimum size */
774 if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet))))
775 return NET_RX_DROP;
776
777 ethhdr = (struct ethhdr *)skb_mac_header(skb);
778
779 /* packet with broadcast indication but unicast recipient */
780 if (!is_broadcast_ether_addr(ethhdr->h_dest))
781 return NET_RX_DROP;
782
783 /* packet with broadcast sender address */
784 if (is_broadcast_ether_addr(ethhdr->h_source))
785 return NET_RX_DROP;
786
787 /* create a copy of the skb, if needed, to modify it. */
788 if (skb_cow(skb, 0) < 0)
789 return NET_RX_DROP;
790
791 /* keep skb linear */
792 if (skb_linearize(skb) < 0)
793 return NET_RX_DROP;
794
795 ethhdr = (struct ethhdr *)skb_mac_header(skb);
796
797 spin_lock_bh(&bat_priv->orig_hash_lock);
798 receive_aggr_bat_packet(ethhdr,
799 skb->data,
800 skb_headlen(skb),
801 batman_if);
802 spin_unlock_bh(&bat_priv->orig_hash_lock);
803
804 kfree_skb(skb);
805 return NET_RX_SUCCESS;
806}
807
808static int recv_my_icmp_packet(struct bat_priv *bat_priv,
809 struct sk_buff *skb, size_t icmp_len)
810{
811 struct orig_node *orig_node;
812 struct icmp_packet_rr *icmp_packet;
813 struct ethhdr *ethhdr;
814 struct batman_if *batman_if;
815 int ret;
816 uint8_t dstaddr[ETH_ALEN];
817
818 icmp_packet = (struct icmp_packet_rr *)skb->data;
819 ethhdr = (struct ethhdr *)skb_mac_header(skb);
820
821 /* add data to device queue */
822 if (icmp_packet->msg_type != ECHO_REQUEST) {
823 bat_socket_receive_packet(icmp_packet, icmp_len);
824 return NET_RX_DROP;
825 }
826
827 if (!bat_priv->primary_if)
828 return NET_RX_DROP;
829
830 /* answer echo request (ping) */
831 /* get routing information */
832 spin_lock_bh(&bat_priv->orig_hash_lock);
833 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
834 compare_orig, choose_orig,
835 icmp_packet->orig));
836 ret = NET_RX_DROP;
837
838 if ((orig_node) && (orig_node->router)) {
839
840 /* don't lock while sending the packets ... we therefore
841 * copy the required data before sending */
842 batman_if = orig_node->router->if_incoming;
843 memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
844 spin_unlock_bh(&bat_priv->orig_hash_lock);
845
846 /* create a copy of the skb, if needed, to modify it. */
847 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
848 return NET_RX_DROP;
849
850 icmp_packet = (struct icmp_packet_rr *)skb->data;
851 ethhdr = (struct ethhdr *)skb_mac_header(skb);
852
853 memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
854 memcpy(icmp_packet->orig,
855 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
856 icmp_packet->msg_type = ECHO_REPLY;
857 icmp_packet->ttl = TTL;
858
859 send_skb_packet(skb, batman_if, dstaddr);
860 ret = NET_RX_SUCCESS;
861
862 } else
863 spin_unlock_bh(&bat_priv->orig_hash_lock);
864
865 return ret;
866}
867
868static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
869 struct sk_buff *skb, size_t icmp_len)
870{
871 struct orig_node *orig_node;
872 struct icmp_packet *icmp_packet;
873 struct ethhdr *ethhdr;
874 struct batman_if *batman_if;
875 int ret;
876 uint8_t dstaddr[ETH_ALEN];
877
878 icmp_packet = (struct icmp_packet *)skb->data;
879 ethhdr = (struct ethhdr *)skb_mac_header(skb);
880
881 /* send TTL exceeded if packet is an echo request (traceroute) */
882 if (icmp_packet->msg_type != ECHO_REQUEST) {
883 pr_debug("Warning - can't forward icmp packet from %pM to "
884 "%pM: ttl exceeded\n", icmp_packet->orig,
885 icmp_packet->dst);
886 return NET_RX_DROP;
887 }
888
889 if (!bat_priv->primary_if)
890 return NET_RX_DROP;
891
892 /* get routing information */
893 spin_lock_bh(&bat_priv->orig_hash_lock);
894 orig_node = ((struct orig_node *)
895 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
896 icmp_packet->orig));
897 ret = NET_RX_DROP;
898
899 if ((orig_node) && (orig_node->router)) {
900
901 /* don't lock while sending the packets ... we therefore
902 * copy the required data before sending */
903 batman_if = orig_node->router->if_incoming;
904 memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
905 spin_unlock_bh(&bat_priv->orig_hash_lock);
906
907 /* create a copy of the skb, if needed, to modify it. */
908 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
909 return NET_RX_DROP;
910
911 icmp_packet = (struct icmp_packet *) skb->data;
912 ethhdr = (struct ethhdr *)skb_mac_header(skb);
913
914 memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
915 memcpy(icmp_packet->orig,
916 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
917 icmp_packet->msg_type = TTL_EXCEEDED;
918 icmp_packet->ttl = TTL;
919
920 send_skb_packet(skb, batman_if, dstaddr);
921 ret = NET_RX_SUCCESS;
922
923 } else
924 spin_unlock_bh(&bat_priv->orig_hash_lock);
925
926 return ret;
927}
928
929
930int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
931{
932 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
933 struct icmp_packet_rr *icmp_packet;
934 struct ethhdr *ethhdr;
935 struct orig_node *orig_node;
936 struct batman_if *batman_if;
937 int hdr_size = sizeof(struct icmp_packet);
938 int ret;
939 uint8_t dstaddr[ETH_ALEN];
940
941 /**
942 * we truncate all incoming icmp packets if they don't match our size
943 */
944 if (skb->len >= sizeof(struct icmp_packet_rr))
945 hdr_size = sizeof(struct icmp_packet_rr);
946
947 /* drop packet if it has not necessary minimum size */
948 if (unlikely(!pskb_may_pull(skb, hdr_size)))
949 return NET_RX_DROP;
950
951 ethhdr = (struct ethhdr *)skb_mac_header(skb);
952
953 /* packet with unicast indication but broadcast recipient */
954 if (is_broadcast_ether_addr(ethhdr->h_dest))
955 return NET_RX_DROP;
956
957 /* packet with broadcast sender address */
958 if (is_broadcast_ether_addr(ethhdr->h_source))
959 return NET_RX_DROP;
960
961 /* not for me */
962 if (!is_my_mac(ethhdr->h_dest))
963 return NET_RX_DROP;
964
965 icmp_packet = (struct icmp_packet_rr *)skb->data;
966
967 /* add record route information if not full */
968 if ((hdr_size == sizeof(struct icmp_packet_rr)) &&
969 (icmp_packet->rr_cur < BAT_RR_LEN)) {
970 memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]),
971 ethhdr->h_dest, ETH_ALEN);
972 icmp_packet->rr_cur++;
973 }
974
975 /* packet for me */
976 if (is_my_mac(icmp_packet->dst))
977 return recv_my_icmp_packet(bat_priv, skb, hdr_size);
978
979 /* TTL exceeded */
980 if (icmp_packet->ttl < 2)
981 return recv_icmp_ttl_exceeded(bat_priv, skb, hdr_size);
982
983 ret = NET_RX_DROP;
984
985 /* get routing information */
986 spin_lock_bh(&bat_priv->orig_hash_lock);
987 orig_node = ((struct orig_node *)
988 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
989 icmp_packet->dst));
990
991 if ((orig_node) && (orig_node->router)) {
992
993 /* don't lock while sending the packets ... we therefore
994 * copy the required data before sending */
995 batman_if = orig_node->router->if_incoming;
996 memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
997 spin_unlock_bh(&bat_priv->orig_hash_lock);
998
999 /* create a copy of the skb, if needed, to modify it. */
1000 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
1001 return NET_RX_DROP;
1002
1003 icmp_packet = (struct icmp_packet_rr *)skb->data;
1004 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1005
1006 /* decrement ttl */
1007 icmp_packet->ttl--;
1008
1009 /* route it */
1010 send_skb_packet(skb, batman_if, dstaddr);
1011 ret = NET_RX_SUCCESS;
1012
1013 } else
1014 spin_unlock_bh(&bat_priv->orig_hash_lock);
1015
1016 return ret;
1017}
1018
1019/* find a suitable router for this originator, and use
1020 * bonding if possible. */
1021struct neigh_node *find_router(struct bat_priv *bat_priv,
1022 struct orig_node *orig_node,
1023 struct batman_if *recv_if)
1024{
1025 struct orig_node *primary_orig_node;
1026 struct orig_node *router_orig;
1027 struct neigh_node *router, *first_candidate, *best_router;
1028 static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
1029 int bonding_enabled;
1030
1031 if (!orig_node)
1032 return NULL;
1033
1034 if (!orig_node->router)
1035 return NULL;
1036
1037 /* without bonding, the first node should
1038 * always choose the default router. */
1039
1040 bonding_enabled = atomic_read(&bat_priv->bonding);
1041
1042 if ((!recv_if) && (!bonding_enabled))
1043 return orig_node->router;
1044
1045 router_orig = orig_node->router->orig_node;
1046
1047 /* if we have something in the primary_addr, we can search
1048 * for a potential bonding candidate. */
1049 if (memcmp(router_orig->primary_addr, zero_mac, ETH_ALEN) == 0)
1050 return orig_node->router;
1051
1052 /* find the orig_node which has the primary interface. might
1053 * even be the same as our router_orig in many cases */
1054
1055 if (memcmp(router_orig->primary_addr,
1056 router_orig->orig, ETH_ALEN) == 0) {
1057 primary_orig_node = router_orig;
1058 } else {
1059 primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig,
1060 choose_orig,
1061 router_orig->primary_addr);
1062
1063 if (!primary_orig_node)
1064 return orig_node->router;
1065 }
1066
1067 /* with less than 2 candidates, we can't do any
1068 * bonding and prefer the original router. */
1069
1070 if (primary_orig_node->bond.candidates < 2)
1071 return orig_node->router;
1072
1073
1074 /* all nodes between should choose a candidate which
1075 * is is not on the interface where the packet came
1076 * in. */
1077 first_candidate = primary_orig_node->bond.selected;
1078 router = first_candidate;
1079
1080 if (bonding_enabled) {
1081 /* in the bonding case, send the packets in a round
1082 * robin fashion over the remaining interfaces. */
1083 do {
1084 /* recv_if == NULL on the first node. */
1085 if (router->if_incoming != recv_if)
1086 break;
1087
1088 router = router->next_bond_candidate;
1089 } while (router != first_candidate);
1090
1091 primary_orig_node->bond.selected = router->next_bond_candidate;
1092
1093 } else {
1094 /* if bonding is disabled, use the best of the
1095 * remaining candidates which are not using
1096 * this interface. */
1097 best_router = first_candidate;
1098
1099 do {
1100 /* recv_if == NULL on the first node. */
1101 if ((router->if_incoming != recv_if) &&
1102 (router->tq_avg > best_router->tq_avg))
1103 best_router = router;
1104
1105 router = router->next_bond_candidate;
1106 } while (router != first_candidate);
1107
1108 router = best_router;
1109 }
1110
1111 return router;
1112}
1113
1114static int check_unicast_packet(struct sk_buff *skb, int hdr_size)
1115{
1116 struct ethhdr *ethhdr;
1117
1118 /* drop packet if it has not necessary minimum size */
1119 if (unlikely(!pskb_may_pull(skb, hdr_size)))
1120 return -1;
1121
1122 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1123
1124 /* packet with unicast indication but broadcast recipient */
1125 if (is_broadcast_ether_addr(ethhdr->h_dest))
1126 return -1;
1127
1128 /* packet with broadcast sender address */
1129 if (is_broadcast_ether_addr(ethhdr->h_source))
1130 return -1;
1131
1132 /* not for me */
1133 if (!is_my_mac(ethhdr->h_dest))
1134 return -1;
1135
1136 return 0;
1137}
1138
1139int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
1140 int hdr_size)
1141{
1142 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1143 struct orig_node *orig_node;
1144 struct neigh_node *router;
1145 struct batman_if *batman_if;
1146 uint8_t dstaddr[ETH_ALEN];
1147 struct unicast_packet *unicast_packet;
1148 struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
1149 int ret;
1150 struct sk_buff *new_skb;
1151
1152 unicast_packet = (struct unicast_packet *)skb->data;
1153
1154 /* TTL exceeded */
1155 if (unicast_packet->ttl < 2) {
1156 pr_debug("Warning - can't forward unicast packet from %pM to "
1157 "%pM: ttl exceeded\n", ethhdr->h_source,
1158 unicast_packet->dest);
1159 return NET_RX_DROP;
1160 }
1161
1162 /* get routing information */
1163 spin_lock_bh(&bat_priv->orig_hash_lock);
1164 orig_node = ((struct orig_node *)
1165 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
1166 unicast_packet->dest));
1167
1168 router = find_router(bat_priv, orig_node, recv_if);
1169
1170 if (!router) {
1171 spin_unlock_bh(&bat_priv->orig_hash_lock);
1172 return NET_RX_DROP;
1173 }
1174
1175 /* don't lock while sending the packets ... we therefore
1176 * copy the required data before sending */
1177
1178 batman_if = router->if_incoming;
1179 memcpy(dstaddr, router->addr, ETH_ALEN);
1180
1181 spin_unlock_bh(&bat_priv->orig_hash_lock);
1182
1183 /* create a copy of the skb, if needed, to modify it. */
1184 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
1185 return NET_RX_DROP;
1186
1187 unicast_packet = (struct unicast_packet *)skb->data;
1188
1189 if (unicast_packet->packet_type == BAT_UNICAST &&
1190 atomic_read(&bat_priv->fragmentation) &&
1191 skb->len > batman_if->net_dev->mtu)
1192 return frag_send_skb(skb, bat_priv, batman_if,
1193 dstaddr);
1194
1195 if (unicast_packet->packet_type == BAT_UNICAST_FRAG &&
1196 2 * skb->len - hdr_size <= batman_if->net_dev->mtu) {
1197
1198 ret = frag_reassemble_skb(skb, bat_priv, &new_skb);
1199
1200 if (ret == NET_RX_DROP)
1201 return NET_RX_DROP;
1202
1203 /* packet was buffered for late merge */
1204 if (!new_skb)
1205 return NET_RX_SUCCESS;
1206
1207 skb = new_skb;
1208 unicast_packet = (struct unicast_packet *)skb->data;
1209 }
1210
1211 /* decrement ttl */
1212 unicast_packet->ttl--;
1213
1214 /* route it */
1215 send_skb_packet(skb, batman_if, dstaddr);
1216
1217 return NET_RX_SUCCESS;
1218}
1219
1220int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
1221{
1222 struct unicast_packet *unicast_packet;
1223 int hdr_size = sizeof(struct unicast_packet);
1224
1225 if (check_unicast_packet(skb, hdr_size) < 0)
1226 return NET_RX_DROP;
1227
1228 unicast_packet = (struct unicast_packet *)skb->data;
1229
1230 /* packet for me */
1231 if (is_my_mac(unicast_packet->dest)) {
1232 interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
1233 return NET_RX_SUCCESS;
1234 }
1235
1236 return route_unicast_packet(skb, recv_if, hdr_size);
1237}
1238
1239int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if)
1240{
1241 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1242 struct unicast_frag_packet *unicast_packet;
1243 int hdr_size = sizeof(struct unicast_frag_packet);
1244 struct sk_buff *new_skb = NULL;
1245 int ret;
1246
1247 if (check_unicast_packet(skb, hdr_size) < 0)
1248 return NET_RX_DROP;
1249
1250 unicast_packet = (struct unicast_frag_packet *)skb->data;
1251
1252 /* packet for me */
1253 if (is_my_mac(unicast_packet->dest)) {
1254
1255 ret = frag_reassemble_skb(skb, bat_priv, &new_skb);
1256
1257 if (ret == NET_RX_DROP)
1258 return NET_RX_DROP;
1259
1260 /* packet was buffered for late merge */
1261 if (!new_skb)
1262 return NET_RX_SUCCESS;
1263
1264 interface_rx(recv_if->soft_iface, new_skb, recv_if,
1265 sizeof(struct unicast_packet));
1266 return NET_RX_SUCCESS;
1267 }
1268
1269 return route_unicast_packet(skb, recv_if, hdr_size);
1270}
1271
1272
1273int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if)
1274{
1275 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1276 struct orig_node *orig_node;
1277 struct bcast_packet *bcast_packet;
1278 struct ethhdr *ethhdr;
1279 int hdr_size = sizeof(struct bcast_packet);
1280 int32_t seq_diff;
1281
1282 /* drop packet if it has not necessary minimum size */
1283 if (unlikely(!pskb_may_pull(skb, hdr_size)))
1284 return NET_RX_DROP;
1285
1286 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1287
1288 /* packet with broadcast indication but unicast recipient */
1289 if (!is_broadcast_ether_addr(ethhdr->h_dest))
1290 return NET_RX_DROP;
1291
1292 /* packet with broadcast sender address */
1293 if (is_broadcast_ether_addr(ethhdr->h_source))
1294 return NET_RX_DROP;
1295
1296 /* ignore broadcasts sent by myself */
1297 if (is_my_mac(ethhdr->h_source))
1298 return NET_RX_DROP;
1299
1300 bcast_packet = (struct bcast_packet *)skb->data;
1301
1302 /* ignore broadcasts originated by myself */
1303 if (is_my_mac(bcast_packet->orig))
1304 return NET_RX_DROP;
1305
1306 if (bcast_packet->ttl < 2)
1307 return NET_RX_DROP;
1308
1309 spin_lock_bh(&bat_priv->orig_hash_lock);
1310 orig_node = ((struct orig_node *)
1311 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
1312 bcast_packet->orig));
1313
1314 if (!orig_node) {
1315 spin_unlock_bh(&bat_priv->orig_hash_lock);
1316 return NET_RX_DROP;
1317 }
1318
1319 /* check whether the packet is a duplicate */
1320 if (get_bit_status(orig_node->bcast_bits,
1321 orig_node->last_bcast_seqno,
1322 ntohl(bcast_packet->seqno))) {
1323 spin_unlock_bh(&bat_priv->orig_hash_lock);
1324 return NET_RX_DROP;
1325 }
1326
1327 seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
1328
1329 /* check whether the packet is old and the host just restarted. */
1330 if (window_protected(bat_priv, seq_diff,
1331 &orig_node->bcast_seqno_reset)) {
1332 spin_unlock_bh(&bat_priv->orig_hash_lock);
1333 return NET_RX_DROP;
1334 }
1335
1336 /* mark broadcast in flood history, update window position
1337 * if required. */
1338 if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
1339 orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
1340
1341 spin_unlock_bh(&bat_priv->orig_hash_lock);
1342 /* rebroadcast packet */
1343 add_bcast_packet_to_list(bat_priv, skb);
1344
1345 /* broadcast for me */
1346 interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
1347
1348 return NET_RX_SUCCESS;
1349}
1350
1351int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if)
1352{
1353 struct vis_packet *vis_packet;
1354 struct ethhdr *ethhdr;
1355 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1356 int hdr_size = sizeof(struct vis_packet);
1357
1358 /* keep skb linear */
1359 if (skb_linearize(skb) < 0)
1360 return NET_RX_DROP;
1361
1362 if (unlikely(!pskb_may_pull(skb, hdr_size)))
1363 return NET_RX_DROP;
1364
1365 vis_packet = (struct vis_packet *)skb->data;
1366 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1367
1368 /* not for me */
1369 if (!is_my_mac(ethhdr->h_dest))
1370 return NET_RX_DROP;
1371
1372 /* ignore own packets */
1373 if (is_my_mac(vis_packet->vis_orig))
1374 return NET_RX_DROP;
1375
1376 if (is_my_mac(vis_packet->sender_orig))
1377 return NET_RX_DROP;
1378
1379 switch (vis_packet->vis_type) {
1380 case VIS_TYPE_SERVER_SYNC:
1381 receive_server_sync_packet(bat_priv, vis_packet,
1382 skb_headlen(skb));
1383 break;
1384
1385 case VIS_TYPE_CLIENT_UPDATE:
1386 receive_client_update_packet(bat_priv, vis_packet,
1387 skb_headlen(skb));
1388 break;
1389
1390 default: /* ignore unknown packet */
1391 break;
1392 }
1393
1394 /* We take a copy of the data in the packet, so we should
1395 always free the skbuf. */
1396 return NET_RX_DROP;
1397}
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
new file mode 100644
index 000000000000..f108f230bfdb
--- /dev/null
+++ b/net/batman-adv/routing.h
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_ROUTING_H_
23#define _NET_BATMAN_ADV_ROUTING_H_
24
25#include "types.h"
26
27void slide_own_bcast_window(struct batman_if *batman_if);
28void receive_bat_packet(struct ethhdr *ethhdr,
29 struct batman_packet *batman_packet,
30 unsigned char *hna_buff, int hna_buff_len,
31 struct batman_if *if_incoming);
32void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
33 struct neigh_node *neigh_node, unsigned char *hna_buff,
34 int hna_buff_len);
35int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
36 int hdr_size);
37int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if);
38int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if);
39int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if);
40int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if);
41int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if);
42int recv_bat_packet(struct sk_buff *skb, struct batman_if *recv_if);
43struct neigh_node *find_router(struct bat_priv *bat_priv,
44 struct orig_node *orig_node, struct batman_if *recv_if);
45void update_bonding_candidates(struct bat_priv *bat_priv,
46 struct orig_node *orig_node);
47
48#endif /* _NET_BATMAN_ADV_ROUTING_H_ */
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
new file mode 100644
index 000000000000..b89b9f7709ae
--- /dev/null
+++ b/net/batman-adv/send.c
@@ -0,0 +1,585 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "send.h"
24#include "routing.h"
25#include "translation-table.h"
26#include "soft-interface.h"
27#include "hard-interface.h"
28#include "types.h"
29#include "vis.h"
30#include "aggregation.h"
31#include "gateway_common.h"
32#include "originator.h"
33
34static void send_outstanding_bcast_packet(struct work_struct *work);
35
36/* apply hop penalty for a normal link */
37static uint8_t hop_penalty(const uint8_t tq, struct bat_priv *bat_priv)
38{
39 int hop_penalty = atomic_read(&bat_priv->hop_penalty);
40 return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE);
41}
42
43/* when do we schedule our own packet to be sent */
44static unsigned long own_send_time(struct bat_priv *bat_priv)
45{
46 return jiffies + msecs_to_jiffies(
47 atomic_read(&bat_priv->orig_interval) -
48 JITTER + (random32() % 2*JITTER));
49}
50
51/* when do we schedule a forwarded packet to be sent */
52static unsigned long forward_send_time(struct bat_priv *bat_priv)
53{
54 return jiffies + msecs_to_jiffies(random32() % (JITTER/2));
55}
56
57/* send out an already prepared packet to the given address via the
58 * specified batman interface */
59int send_skb_packet(struct sk_buff *skb,
60 struct batman_if *batman_if,
61 uint8_t *dst_addr)
62{
63 struct ethhdr *ethhdr;
64
65 if (batman_if->if_status != IF_ACTIVE)
66 goto send_skb_err;
67
68 if (unlikely(!batman_if->net_dev))
69 goto send_skb_err;
70
71 if (!(batman_if->net_dev->flags & IFF_UP)) {
72 pr_warning("Interface %s is not up - can't send packet via "
73 "that interface!\n", batman_if->net_dev->name);
74 goto send_skb_err;
75 }
76
77 /* push to the ethernet header. */
78 if (my_skb_head_push(skb, sizeof(struct ethhdr)) < 0)
79 goto send_skb_err;
80
81 skb_reset_mac_header(skb);
82
83 ethhdr = (struct ethhdr *) skb_mac_header(skb);
84 memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN);
85 memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
86 ethhdr->h_proto = __constant_htons(ETH_P_BATMAN);
87
88 skb_set_network_header(skb, ETH_HLEN);
89 skb->priority = TC_PRIO_CONTROL;
90 skb->protocol = __constant_htons(ETH_P_BATMAN);
91
92 skb->dev = batman_if->net_dev;
93
94 /* dev_queue_xmit() returns a negative result on error. However on
95 * congestion and traffic shaping, it drops and returns NET_XMIT_DROP
96 * (which is > 0). This will not be treated as an error. */
97
98 return dev_queue_xmit(skb);
99send_skb_err:
100 kfree_skb(skb);
101 return NET_XMIT_DROP;
102}
103
104/* Send a packet to a given interface */
105static void send_packet_to_if(struct forw_packet *forw_packet,
106 struct batman_if *batman_if)
107{
108 struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
109 char *fwd_str;
110 uint8_t packet_num;
111 int16_t buff_pos;
112 struct batman_packet *batman_packet;
113 struct sk_buff *skb;
114
115 if (batman_if->if_status != IF_ACTIVE)
116 return;
117
118 packet_num = 0;
119 buff_pos = 0;
120 batman_packet = (struct batman_packet *)forw_packet->skb->data;
121
122 /* adjust all flags and log packets */
123 while (aggregated_packet(buff_pos,
124 forw_packet->packet_len,
125 batman_packet->num_hna)) {
126
127 /* we might have aggregated direct link packets with an
128 * ordinary base packet */
129 if ((forw_packet->direct_link_flags & (1 << packet_num)) &&
130 (forw_packet->if_incoming == batman_if))
131 batman_packet->flags |= DIRECTLINK;
132 else
133 batman_packet->flags &= ~DIRECTLINK;
134
135 fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
136 "Sending own" :
137 "Forwarding"));
138 bat_dbg(DBG_BATMAN, bat_priv,
139 "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
140 " IDF %s) on interface %s [%pM]\n",
141 fwd_str, (packet_num > 0 ? "aggregated " : ""),
142 batman_packet->orig, ntohl(batman_packet->seqno),
143 batman_packet->tq, batman_packet->ttl,
144 (batman_packet->flags & DIRECTLINK ?
145 "on" : "off"),
146 batman_if->net_dev->name, batman_if->net_dev->dev_addr);
147
148 buff_pos += sizeof(struct batman_packet) +
149 (batman_packet->num_hna * ETH_ALEN);
150 packet_num++;
151 batman_packet = (struct batman_packet *)
152 (forw_packet->skb->data + buff_pos);
153 }
154
155 /* create clone because function is called more than once */
156 skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
157 if (skb)
158 send_skb_packet(skb, batman_if, broadcast_addr);
159}
160
161/* send a batman packet */
162static void send_packet(struct forw_packet *forw_packet)
163{
164 struct batman_if *batman_if;
165 struct net_device *soft_iface;
166 struct bat_priv *bat_priv;
167 struct batman_packet *batman_packet =
168 (struct batman_packet *)(forw_packet->skb->data);
169 unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
170
171 if (!forw_packet->if_incoming) {
172 pr_err("Error - can't forward packet: incoming iface not "
173 "specified\n");
174 return;
175 }
176
177 soft_iface = forw_packet->if_incoming->soft_iface;
178 bat_priv = netdev_priv(soft_iface);
179
180 if (forw_packet->if_incoming->if_status != IF_ACTIVE)
181 return;
182
183 /* multihomed peer assumed */
184 /* non-primary OGMs are only broadcasted on their interface */
185 if ((directlink && (batman_packet->ttl == 1)) ||
186 (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
187
188 /* FIXME: what about aggregated packets ? */
189 bat_dbg(DBG_BATMAN, bat_priv,
190 "%s packet (originator %pM, seqno %d, TTL %d) "
191 "on interface %s [%pM]\n",
192 (forw_packet->own ? "Sending own" : "Forwarding"),
193 batman_packet->orig, ntohl(batman_packet->seqno),
194 batman_packet->ttl,
195 forw_packet->if_incoming->net_dev->name,
196 forw_packet->if_incoming->net_dev->dev_addr);
197
198 /* skb is only used once and than forw_packet is free'd */
199 send_skb_packet(forw_packet->skb, forw_packet->if_incoming,
200 broadcast_addr);
201 forw_packet->skb = NULL;
202
203 return;
204 }
205
206 /* broadcast on every interface */
207 rcu_read_lock();
208 list_for_each_entry_rcu(batman_if, &if_list, list) {
209 if (batman_if->soft_iface != soft_iface)
210 continue;
211
212 send_packet_to_if(forw_packet, batman_if);
213 }
214 rcu_read_unlock();
215}
216
217static void rebuild_batman_packet(struct bat_priv *bat_priv,
218 struct batman_if *batman_if)
219{
220 int new_len;
221 unsigned char *new_buff;
222 struct batman_packet *batman_packet;
223
224 new_len = sizeof(struct batman_packet) +
225 (bat_priv->num_local_hna * ETH_ALEN);
226 new_buff = kmalloc(new_len, GFP_ATOMIC);
227
228 /* keep old buffer if kmalloc should fail */
229 if (new_buff) {
230 memcpy(new_buff, batman_if->packet_buff,
231 sizeof(struct batman_packet));
232 batman_packet = (struct batman_packet *)new_buff;
233
234 batman_packet->num_hna = hna_local_fill_buffer(bat_priv,
235 new_buff + sizeof(struct batman_packet),
236 new_len - sizeof(struct batman_packet));
237
238 kfree(batman_if->packet_buff);
239 batman_if->packet_buff = new_buff;
240 batman_if->packet_len = new_len;
241 }
242}
243
244void schedule_own_packet(struct batman_if *batman_if)
245{
246 struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
247 unsigned long send_time;
248 struct batman_packet *batman_packet;
249 int vis_server;
250
251 if ((batman_if->if_status == IF_NOT_IN_USE) ||
252 (batman_if->if_status == IF_TO_BE_REMOVED))
253 return;
254
255 vis_server = atomic_read(&bat_priv->vis_mode);
256
257 /**
258 * the interface gets activated here to avoid race conditions between
259 * the moment of activating the interface in
260 * hardif_activate_interface() where the originator mac is set and
261 * outdated packets (especially uninitialized mac addresses) in the
262 * packet queue
263 */
264 if (batman_if->if_status == IF_TO_BE_ACTIVATED)
265 batman_if->if_status = IF_ACTIVE;
266
267 /* if local hna has changed and interface is a primary interface */
268 if ((atomic_read(&bat_priv->hna_local_changed)) &&
269 (batman_if == bat_priv->primary_if))
270 rebuild_batman_packet(bat_priv, batman_if);
271
272 /**
273 * NOTE: packet_buff might just have been re-allocated in
274 * rebuild_batman_packet()
275 */
276 batman_packet = (struct batman_packet *)batman_if->packet_buff;
277
278 /* change sequence number to network order */
279 batman_packet->seqno =
280 htonl((uint32_t)atomic_read(&batman_if->seqno));
281
282 if (vis_server == VIS_TYPE_SERVER_SYNC)
283 batman_packet->flags |= VIS_SERVER;
284 else
285 batman_packet->flags &= ~VIS_SERVER;
286
287 if ((batman_if == bat_priv->primary_if) &&
288 (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER))
289 batman_packet->gw_flags =
290 (uint8_t)atomic_read(&bat_priv->gw_bandwidth);
291 else
292 batman_packet->gw_flags = 0;
293
294 atomic_inc(&batman_if->seqno);
295
296 slide_own_bcast_window(batman_if);
297 send_time = own_send_time(bat_priv);
298 add_bat_packet_to_list(bat_priv,
299 batman_if->packet_buff,
300 batman_if->packet_len,
301 batman_if, 1, send_time);
302}
303
304void schedule_forward_packet(struct orig_node *orig_node,
305 struct ethhdr *ethhdr,
306 struct batman_packet *batman_packet,
307 uint8_t directlink, int hna_buff_len,
308 struct batman_if *if_incoming)
309{
310 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
311 unsigned char in_tq, in_ttl, tq_avg = 0;
312 unsigned long send_time;
313
314 if (batman_packet->ttl <= 1) {
315 bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
316 return;
317 }
318
319 in_tq = batman_packet->tq;
320 in_ttl = batman_packet->ttl;
321
322 batman_packet->ttl--;
323 memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
324
325 /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
326 * of our best tq value */
327 if ((orig_node->router) && (orig_node->router->tq_avg != 0)) {
328
329 /* rebroadcast ogm of best ranking neighbor as is */
330 if (!compare_orig(orig_node->router->addr, ethhdr->h_source)) {
331 batman_packet->tq = orig_node->router->tq_avg;
332
333 if (orig_node->router->last_ttl)
334 batman_packet->ttl = orig_node->router->last_ttl
335 - 1;
336 }
337
338 tq_avg = orig_node->router->tq_avg;
339 }
340
341 /* apply hop penalty */
342 batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv);
343
344 bat_dbg(DBG_BATMAN, bat_priv,
345 "Forwarding packet: tq_orig: %i, tq_avg: %i, "
346 "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n",
347 in_tq, tq_avg, batman_packet->tq, in_ttl - 1,
348 batman_packet->ttl);
349
350 batman_packet->seqno = htonl(batman_packet->seqno);
351
352 /* switch of primaries first hop flag when forwarding */
353 batman_packet->flags &= ~PRIMARIES_FIRST_HOP;
354 if (directlink)
355 batman_packet->flags |= DIRECTLINK;
356 else
357 batman_packet->flags &= ~DIRECTLINK;
358
359 send_time = forward_send_time(bat_priv);
360 add_bat_packet_to_list(bat_priv,
361 (unsigned char *)batman_packet,
362 sizeof(struct batman_packet) + hna_buff_len,
363 if_incoming, 0, send_time);
364}
365
366static void forw_packet_free(struct forw_packet *forw_packet)
367{
368 if (forw_packet->skb)
369 kfree_skb(forw_packet->skb);
370 kfree(forw_packet);
371}
372
373static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
374 struct forw_packet *forw_packet,
375 unsigned long send_time)
376{
377 INIT_HLIST_NODE(&forw_packet->list);
378
379 /* add new packet to packet list */
380 spin_lock_bh(&bat_priv->forw_bcast_list_lock);
381 hlist_add_head(&forw_packet->list, &bat_priv->forw_bcast_list);
382 spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
383
384 /* start timer for this packet */
385 INIT_DELAYED_WORK(&forw_packet->delayed_work,
386 send_outstanding_bcast_packet);
387 queue_delayed_work(bat_event_workqueue, &forw_packet->delayed_work,
388 send_time);
389}
390
391#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
392/* add a broadcast packet to the queue and setup timers. broadcast packets
393 * are sent multiple times to increase probability for beeing received.
394 *
395 * This function returns NETDEV_TX_OK on success and NETDEV_TX_BUSY on
396 * errors.
397 *
398 * The skb is not consumed, so the caller should make sure that the
399 * skb is freed. */
400int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
401{
402 struct forw_packet *forw_packet;
403 struct bcast_packet *bcast_packet;
404
405 if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) {
406 bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n");
407 goto out;
408 }
409
410 if (!bat_priv->primary_if)
411 goto out;
412
413 forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
414
415 if (!forw_packet)
416 goto out_and_inc;
417
418 skb = skb_copy(skb, GFP_ATOMIC);
419 if (!skb)
420 goto packet_free;
421
422 /* as we have a copy now, it is safe to decrease the TTL */
423 bcast_packet = (struct bcast_packet *)skb->data;
424 bcast_packet->ttl--;
425
426 skb_reset_mac_header(skb);
427
428 forw_packet->skb = skb;
429 forw_packet->if_incoming = bat_priv->primary_if;
430
431 /* how often did we send the bcast packet ? */
432 forw_packet->num_packets = 0;
433
434 _add_bcast_packet_to_list(bat_priv, forw_packet, 1);
435 return NETDEV_TX_OK;
436
437packet_free:
438 kfree(forw_packet);
439out_and_inc:
440 atomic_inc(&bat_priv->bcast_queue_left);
441out:
442 return NETDEV_TX_BUSY;
443}
444
445static void send_outstanding_bcast_packet(struct work_struct *work)
446{
447 struct batman_if *batman_if;
448 struct delayed_work *delayed_work =
449 container_of(work, struct delayed_work, work);
450 struct forw_packet *forw_packet =
451 container_of(delayed_work, struct forw_packet, delayed_work);
452 struct sk_buff *skb1;
453 struct net_device *soft_iface = forw_packet->if_incoming->soft_iface;
454 struct bat_priv *bat_priv = netdev_priv(soft_iface);
455
456 spin_lock_bh(&bat_priv->forw_bcast_list_lock);
457 hlist_del(&forw_packet->list);
458 spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
459
460 if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING)
461 goto out;
462
463 /* rebroadcast packet */
464 rcu_read_lock();
465 list_for_each_entry_rcu(batman_if, &if_list, list) {
466 if (batman_if->soft_iface != soft_iface)
467 continue;
468
469 /* send a copy of the saved skb */
470 skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
471 if (skb1)
472 send_skb_packet(skb1, batman_if, broadcast_addr);
473 }
474 rcu_read_unlock();
475
476 forw_packet->num_packets++;
477
478 /* if we still have some more bcasts to send */
479 if (forw_packet->num_packets < 3) {
480 _add_bcast_packet_to_list(bat_priv, forw_packet,
481 ((5 * HZ) / 1000));
482 return;
483 }
484
485out:
486 forw_packet_free(forw_packet);
487 atomic_inc(&bat_priv->bcast_queue_left);
488}
489
490void send_outstanding_bat_packet(struct work_struct *work)
491{
492 struct delayed_work *delayed_work =
493 container_of(work, struct delayed_work, work);
494 struct forw_packet *forw_packet =
495 container_of(delayed_work, struct forw_packet, delayed_work);
496 struct bat_priv *bat_priv;
497
498 bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
499 spin_lock_bh(&bat_priv->forw_bat_list_lock);
500 hlist_del(&forw_packet->list);
501 spin_unlock_bh(&bat_priv->forw_bat_list_lock);
502
503 if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING)
504 goto out;
505
506 send_packet(forw_packet);
507
508 /**
509 * we have to have at least one packet in the queue
510 * to determine the queues wake up time unless we are
511 * shutting down
512 */
513 if (forw_packet->own)
514 schedule_own_packet(forw_packet->if_incoming);
515
516out:
517 /* don't count own packet */
518 if (!forw_packet->own)
519 atomic_inc(&bat_priv->batman_queue_left);
520
521 forw_packet_free(forw_packet);
522}
523
524void purge_outstanding_packets(struct bat_priv *bat_priv,
525 struct batman_if *batman_if)
526{
527 struct forw_packet *forw_packet;
528 struct hlist_node *tmp_node, *safe_tmp_node;
529
530 if (batman_if)
531 bat_dbg(DBG_BATMAN, bat_priv,
532 "purge_outstanding_packets(): %s\n",
533 batman_if->net_dev->name);
534 else
535 bat_dbg(DBG_BATMAN, bat_priv,
536 "purge_outstanding_packets()\n");
537
538 /* free bcast list */
539 spin_lock_bh(&bat_priv->forw_bcast_list_lock);
540 hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
541 &bat_priv->forw_bcast_list, list) {
542
543 /**
544 * if purge_outstanding_packets() was called with an argmument
545 * we delete only packets belonging to the given interface
546 */
547 if ((batman_if) &&
548 (forw_packet->if_incoming != batman_if))
549 continue;
550
551 spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
552
553 /**
554 * send_outstanding_bcast_packet() will lock the list to
555 * delete the item from the list
556 */
557 cancel_delayed_work_sync(&forw_packet->delayed_work);
558 spin_lock_bh(&bat_priv->forw_bcast_list_lock);
559 }
560 spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
561
562 /* free batman packet list */
563 spin_lock_bh(&bat_priv->forw_bat_list_lock);
564 hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
565 &bat_priv->forw_bat_list, list) {
566
567 /**
568 * if purge_outstanding_packets() was called with an argmument
569 * we delete only packets belonging to the given interface
570 */
571 if ((batman_if) &&
572 (forw_packet->if_incoming != batman_if))
573 continue;
574
575 spin_unlock_bh(&bat_priv->forw_bat_list_lock);
576
577 /**
578 * send_outstanding_bat_packet() will lock the list to
579 * delete the item from the list
580 */
581 cancel_delayed_work_sync(&forw_packet->delayed_work);
582 spin_lock_bh(&bat_priv->forw_bat_list_lock);
583 }
584 spin_unlock_bh(&bat_priv->forw_bat_list_lock);
585}
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
new file mode 100644
index 000000000000..c4cefa8e4f85
--- /dev/null
+++ b/net/batman-adv/send.h
@@ -0,0 +1,41 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_SEND_H_
23#define _NET_BATMAN_ADV_SEND_H_
24
25#include "types.h"
26
27int send_skb_packet(struct sk_buff *skb,
28 struct batman_if *batman_if,
29 uint8_t *dst_addr);
30void schedule_own_packet(struct batman_if *batman_if);
31void schedule_forward_packet(struct orig_node *orig_node,
32 struct ethhdr *ethhdr,
33 struct batman_packet *batman_packet,
34 uint8_t directlink, int hna_buff_len,
35 struct batman_if *if_outgoing);
36int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb);
37void send_outstanding_bat_packet(struct work_struct *work);
38void purge_outstanding_packets(struct bat_priv *bat_priv,
39 struct batman_if *batman_if);
40
41#endif /* _NET_BATMAN_ADV_SEND_H_ */
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
new file mode 100644
index 000000000000..e89ede192ed0
--- /dev/null
+++ b/net/batman-adv/soft-interface.c
@@ -0,0 +1,697 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "soft-interface.h"
24#include "hard-interface.h"
25#include "routing.h"
26#include "send.h"
27#include "bat_debugfs.h"
28#include "translation-table.h"
29#include "types.h"
30#include "hash.h"
31#include "gateway_common.h"
32#include "gateway_client.h"
33#include "send.h"
34#include "bat_sysfs.h"
35#include <linux/slab.h>
36#include <linux/ethtool.h>
37#include <linux/etherdevice.h>
38#include <linux/if_vlan.h>
39#include "unicast.h"
40#include "routing.h"
41
42
43static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
44static void bat_get_drvinfo(struct net_device *dev,
45 struct ethtool_drvinfo *info);
46static u32 bat_get_msglevel(struct net_device *dev);
47static void bat_set_msglevel(struct net_device *dev, u32 value);
48static u32 bat_get_link(struct net_device *dev);
49static u32 bat_get_rx_csum(struct net_device *dev);
50static int bat_set_rx_csum(struct net_device *dev, u32 data);
51
52static const struct ethtool_ops bat_ethtool_ops = {
53 .get_settings = bat_get_settings,
54 .get_drvinfo = bat_get_drvinfo,
55 .get_msglevel = bat_get_msglevel,
56 .set_msglevel = bat_set_msglevel,
57 .get_link = bat_get_link,
58 .get_rx_csum = bat_get_rx_csum,
59 .set_rx_csum = bat_set_rx_csum
60};
61
62int my_skb_head_push(struct sk_buff *skb, unsigned int len)
63{
64 int result;
65
66 /**
67 * TODO: We must check if we can release all references to non-payload
68 * data using skb_header_release in our skbs to allow skb_cow_header to
69 * work optimally. This means that those skbs are not allowed to read
70 * or write any data which is before the current position of skb->data
71 * after that call and thus allow other skbs with the same data buffer
72 * to write freely in that area.
73 */
74 result = skb_cow_head(skb, len);
75 if (result < 0)
76 return result;
77
78 skb_push(skb, len);
79 return 0;
80}
81
82static void softif_neigh_free_ref(struct kref *refcount)
83{
84 struct softif_neigh *softif_neigh;
85
86 softif_neigh = container_of(refcount, struct softif_neigh, refcount);
87 kfree(softif_neigh);
88}
89
90static void softif_neigh_free_rcu(struct rcu_head *rcu)
91{
92 struct softif_neigh *softif_neigh;
93
94 softif_neigh = container_of(rcu, struct softif_neigh, rcu);
95 kref_put(&softif_neigh->refcount, softif_neigh_free_ref);
96}
97
98void softif_neigh_purge(struct bat_priv *bat_priv)
99{
100 struct softif_neigh *softif_neigh, *softif_neigh_tmp;
101 struct hlist_node *node, *node_tmp;
102
103 spin_lock_bh(&bat_priv->softif_neigh_lock);
104
105 hlist_for_each_entry_safe(softif_neigh, node, node_tmp,
106 &bat_priv->softif_neigh_list, list) {
107
108 if ((!time_after(jiffies, softif_neigh->last_seen +
109 msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) &&
110 (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
111 continue;
112
113 hlist_del_rcu(&softif_neigh->list);
114
115 if (bat_priv->softif_neigh == softif_neigh) {
116 bat_dbg(DBG_ROUTES, bat_priv,
117 "Current mesh exit point '%pM' vanished "
118 "(vid: %d).\n",
119 softif_neigh->addr, softif_neigh->vid);
120 softif_neigh_tmp = bat_priv->softif_neigh;
121 bat_priv->softif_neigh = NULL;
122 kref_put(&softif_neigh_tmp->refcount,
123 softif_neigh_free_ref);
124 }
125
126 call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu);
127 }
128
129 spin_unlock_bh(&bat_priv->softif_neigh_lock);
130}
131
132static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
133 uint8_t *addr, short vid)
134{
135 struct softif_neigh *softif_neigh;
136 struct hlist_node *node;
137
138 rcu_read_lock();
139 hlist_for_each_entry_rcu(softif_neigh, node,
140 &bat_priv->softif_neigh_list, list) {
141 if (memcmp(softif_neigh->addr, addr, ETH_ALEN) != 0)
142 continue;
143
144 if (softif_neigh->vid != vid)
145 continue;
146
147 softif_neigh->last_seen = jiffies;
148 goto found;
149 }
150
151 softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC);
152 if (!softif_neigh)
153 goto out;
154
155 memcpy(softif_neigh->addr, addr, ETH_ALEN);
156 softif_neigh->vid = vid;
157 softif_neigh->last_seen = jiffies;
158 kref_init(&softif_neigh->refcount);
159
160 INIT_HLIST_NODE(&softif_neigh->list);
161 spin_lock_bh(&bat_priv->softif_neigh_lock);
162 hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list);
163 spin_unlock_bh(&bat_priv->softif_neigh_lock);
164
165found:
166 kref_get(&softif_neigh->refcount);
167out:
168 rcu_read_unlock();
169 return softif_neigh;
170}
171
172int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
173{
174 struct net_device *net_dev = (struct net_device *)seq->private;
175 struct bat_priv *bat_priv = netdev_priv(net_dev);
176 struct softif_neigh *softif_neigh;
177 struct hlist_node *node;
178 size_t buf_size, pos;
179 char *buff;
180
181 if (!bat_priv->primary_if) {
182 return seq_printf(seq, "BATMAN mesh %s disabled - "
183 "please specify interfaces to enable it\n",
184 net_dev->name);
185 }
186
187 seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
188
189 buf_size = 1;
190 /* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */
191 rcu_read_lock();
192 hlist_for_each_entry_rcu(softif_neigh, node,
193 &bat_priv->softif_neigh_list, list)
194 buf_size += 30;
195 rcu_read_unlock();
196
197 buff = kmalloc(buf_size, GFP_ATOMIC);
198 if (!buff)
199 return -ENOMEM;
200
201 buff[0] = '\0';
202 pos = 0;
203
204 rcu_read_lock();
205 hlist_for_each_entry_rcu(softif_neigh, node,
206 &bat_priv->softif_neigh_list, list) {
207 pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n",
208 bat_priv->softif_neigh == softif_neigh
209 ? "=>" : " ", softif_neigh->addr,
210 softif_neigh->vid);
211 }
212 rcu_read_unlock();
213
214 seq_printf(seq, "%s", buff);
215 kfree(buff);
216 return 0;
217}
218
219static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
220 short vid)
221{
222 struct bat_priv *bat_priv = netdev_priv(dev);
223 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
224 struct batman_packet *batman_packet;
225 struct softif_neigh *softif_neigh, *softif_neigh_tmp;
226
227 if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
228 batman_packet = (struct batman_packet *)
229 (skb->data + ETH_HLEN + VLAN_HLEN);
230 else
231 batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN);
232
233 if (batman_packet->version != COMPAT_VERSION)
234 goto err;
235
236 if (batman_packet->packet_type != BAT_PACKET)
237 goto err;
238
239 if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
240 goto err;
241
242 if (is_my_mac(batman_packet->orig))
243 goto err;
244
245 softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid);
246
247 if (!softif_neigh)
248 goto err;
249
250 if (bat_priv->softif_neigh == softif_neigh)
251 goto out;
252
253 /* we got a neighbor but its mac is 'bigger' than ours */
254 if (memcmp(bat_priv->primary_if->net_dev->dev_addr,
255 softif_neigh->addr, ETH_ALEN) < 0)
256 goto out;
257
258 /* switch to new 'smallest neighbor' */
259 if ((bat_priv->softif_neigh) &&
260 (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr,
261 ETH_ALEN) < 0)) {
262 bat_dbg(DBG_ROUTES, bat_priv,
263 "Changing mesh exit point from %pM (vid: %d) "
264 "to %pM (vid: %d).\n",
265 bat_priv->softif_neigh->addr,
266 bat_priv->softif_neigh->vid,
267 softif_neigh->addr, softif_neigh->vid);
268 softif_neigh_tmp = bat_priv->softif_neigh;
269 bat_priv->softif_neigh = softif_neigh;
270 kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref);
271 /* we need to hold the additional reference */
272 goto err;
273 }
274
275 /* close own batX device and use softif_neigh as exit node */
276 if ((!bat_priv->softif_neigh) &&
277 (memcmp(softif_neigh->addr,
278 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) {
279 bat_dbg(DBG_ROUTES, bat_priv,
280 "Setting mesh exit point to %pM (vid: %d).\n",
281 softif_neigh->addr, softif_neigh->vid);
282 bat_priv->softif_neigh = softif_neigh;
283 /* we need to hold the additional reference */
284 goto err;
285 }
286
287out:
288 kref_put(&softif_neigh->refcount, softif_neigh_free_ref);
289err:
290 kfree_skb(skb);
291 return;
292}
293
294static int interface_open(struct net_device *dev)
295{
296 netif_start_queue(dev);
297 return 0;
298}
299
300static int interface_release(struct net_device *dev)
301{
302 netif_stop_queue(dev);
303 return 0;
304}
305
306static struct net_device_stats *interface_stats(struct net_device *dev)
307{
308 struct bat_priv *bat_priv = netdev_priv(dev);
309 return &bat_priv->stats;
310}
311
312static int interface_set_mac_addr(struct net_device *dev, void *p)
313{
314 struct bat_priv *bat_priv = netdev_priv(dev);
315 struct sockaddr *addr = p;
316
317 if (!is_valid_ether_addr(addr->sa_data))
318 return -EADDRNOTAVAIL;
319
320 /* only modify hna-table if it has been initialised before */
321 if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
322 hna_local_remove(bat_priv, dev->dev_addr,
323 "mac address changed");
324 hna_local_add(dev, addr->sa_data);
325 }
326
327 memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
328 return 0;
329}
330
331static int interface_change_mtu(struct net_device *dev, int new_mtu)
332{
333 /* check ranges */
334 if ((new_mtu < 68) || (new_mtu > hardif_min_mtu(dev)))
335 return -EINVAL;
336
337 dev->mtu = new_mtu;
338
339 return 0;
340}
341
342int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
343{
344 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
345 struct bat_priv *bat_priv = netdev_priv(soft_iface);
346 struct bcast_packet *bcast_packet;
347 struct vlan_ethhdr *vhdr;
348 int data_len = skb->len, ret;
349 short vid = -1;
350 bool do_bcast = false;
351
352 if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
353 goto dropped;
354
355 soft_iface->trans_start = jiffies;
356
357 switch (ntohs(ethhdr->h_proto)) {
358 case ETH_P_8021Q:
359 vhdr = (struct vlan_ethhdr *)skb->data;
360 vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
361
362 if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN)
363 break;
364
365 /* fall through */
366 case ETH_P_BATMAN:
367 softif_batman_recv(skb, soft_iface, vid);
368 goto end;
369 }
370
371 /**
372 * if we have a another chosen mesh exit node in range
373 * it will transport the packets to the mesh
374 */
375 if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid))
376 goto dropped;
377
378 /* TODO: check this for locks */
379 hna_local_add(soft_iface, ethhdr->h_source);
380
381 if (is_multicast_ether_addr(ethhdr->h_dest)) {
382 ret = gw_is_target(bat_priv, skb);
383
384 if (ret < 0)
385 goto dropped;
386
387 if (ret == 0)
388 do_bcast = true;
389 }
390
391 /* ethernet packet should be broadcasted */
392 if (do_bcast) {
393 if (!bat_priv->primary_if)
394 goto dropped;
395
396 if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
397 goto dropped;
398
399 bcast_packet = (struct bcast_packet *)skb->data;
400 bcast_packet->version = COMPAT_VERSION;
401 bcast_packet->ttl = TTL;
402
403 /* batman packet type: broadcast */
404 bcast_packet->packet_type = BAT_BCAST;
405
406 /* hw address of first interface is the orig mac because only
407 * this mac is known throughout the mesh */
408 memcpy(bcast_packet->orig,
409 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
410
411 /* set broadcast sequence number */
412 bcast_packet->seqno =
413 htonl(atomic_inc_return(&bat_priv->bcast_seqno));
414
415 add_bcast_packet_to_list(bat_priv, skb);
416
417 /* a copy is stored in the bcast list, therefore removing
418 * the original skb. */
419 kfree_skb(skb);
420
421 /* unicast packet */
422 } else {
423 ret = unicast_send_skb(skb, bat_priv);
424 if (ret != 0)
425 goto dropped_freed;
426 }
427
428 bat_priv->stats.tx_packets++;
429 bat_priv->stats.tx_bytes += data_len;
430 goto end;
431
432dropped:
433 kfree_skb(skb);
434dropped_freed:
435 bat_priv->stats.tx_dropped++;
436end:
437 return NETDEV_TX_OK;
438}
439
440void interface_rx(struct net_device *soft_iface,
441 struct sk_buff *skb, struct batman_if *recv_if,
442 int hdr_size)
443{
444 struct bat_priv *bat_priv = netdev_priv(soft_iface);
445 struct unicast_packet *unicast_packet;
446 struct ethhdr *ethhdr;
447 struct vlan_ethhdr *vhdr;
448 short vid = -1;
449 int ret;
450
451 /* check if enough space is available for pulling, and pull */
452 if (!pskb_may_pull(skb, hdr_size))
453 goto dropped;
454
455 skb_pull_rcsum(skb, hdr_size);
456 skb_reset_mac_header(skb);
457
458 ethhdr = (struct ethhdr *)skb_mac_header(skb);
459
460 switch (ntohs(ethhdr->h_proto)) {
461 case ETH_P_8021Q:
462 vhdr = (struct vlan_ethhdr *)skb->data;
463 vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
464
465 if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN)
466 break;
467
468 /* fall through */
469 case ETH_P_BATMAN:
470 goto dropped;
471 }
472
473 /**
474 * if we have a another chosen mesh exit node in range
475 * it will transport the packets to the non-mesh network
476 */
477 if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) {
478 skb_push(skb, hdr_size);
479 unicast_packet = (struct unicast_packet *)skb->data;
480
481 if ((unicast_packet->packet_type != BAT_UNICAST) &&
482 (unicast_packet->packet_type != BAT_UNICAST_FRAG))
483 goto dropped;
484
485 skb_reset_mac_header(skb);
486
487 memcpy(unicast_packet->dest,
488 bat_priv->softif_neigh->addr, ETH_ALEN);
489 ret = route_unicast_packet(skb, recv_if, hdr_size);
490 if (ret == NET_RX_DROP)
491 goto dropped;
492
493 goto out;
494 }
495
496 /* skb->dev & skb->pkt_type are set here */
497 if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
498 goto dropped;
499 skb->protocol = eth_type_trans(skb, soft_iface);
500
501 /* should not be neccesary anymore as we use skb_pull_rcsum()
502 * TODO: please verify this and remove this TODO
503 * -- Dec 21st 2009, Simon Wunderlich */
504
505/* skb->ip_summed = CHECKSUM_UNNECESSARY;*/
506
507 bat_priv->stats.rx_packets++;
508 bat_priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr);
509
510 soft_iface->last_rx = jiffies;
511
512 netif_rx(skb);
513 return;
514
515dropped:
516 kfree_skb(skb);
517out:
518 return;
519}
520
521#ifdef HAVE_NET_DEVICE_OPS
522static const struct net_device_ops bat_netdev_ops = {
523 .ndo_open = interface_open,
524 .ndo_stop = interface_release,
525 .ndo_get_stats = interface_stats,
526 .ndo_set_mac_address = interface_set_mac_addr,
527 .ndo_change_mtu = interface_change_mtu,
528 .ndo_start_xmit = interface_tx,
529 .ndo_validate_addr = eth_validate_addr
530};
531#endif
532
533static void interface_setup(struct net_device *dev)
534{
535 struct bat_priv *priv = netdev_priv(dev);
536 char dev_addr[ETH_ALEN];
537
538 ether_setup(dev);
539
540#ifdef HAVE_NET_DEVICE_OPS
541 dev->netdev_ops = &bat_netdev_ops;
542#else
543 dev->open = interface_open;
544 dev->stop = interface_release;
545 dev->get_stats = interface_stats;
546 dev->set_mac_address = interface_set_mac_addr;
547 dev->change_mtu = interface_change_mtu;
548 dev->hard_start_xmit = interface_tx;
549#endif
550 dev->destructor = free_netdev;
551
552 /**
553 * can't call min_mtu, because the needed variables
554 * have not been initialized yet
555 */
556 dev->mtu = ETH_DATA_LEN;
557 dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the
558 * skbuff for our header */
559
560 /* generate random address */
561 random_ether_addr(dev_addr);
562 memcpy(dev->dev_addr, dev_addr, ETH_ALEN);
563
564 SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
565
566 memset(priv, 0, sizeof(struct bat_priv));
567}
568
569struct net_device *softif_create(char *name)
570{
571 struct net_device *soft_iface;
572 struct bat_priv *bat_priv;
573 int ret;
574
575 soft_iface = alloc_netdev(sizeof(struct bat_priv) , name,
576 interface_setup);
577
578 if (!soft_iface) {
579 pr_err("Unable to allocate the batman interface: %s\n", name);
580 goto out;
581 }
582
583 ret = register_netdev(soft_iface);
584 if (ret < 0) {
585 pr_err("Unable to register the batman interface '%s': %i\n",
586 name, ret);
587 goto free_soft_iface;
588 }
589
590 bat_priv = netdev_priv(soft_iface);
591
592 atomic_set(&bat_priv->aggregated_ogms, 1);
593 atomic_set(&bat_priv->bonding, 0);
594 atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
595 atomic_set(&bat_priv->gw_mode, GW_MODE_OFF);
596 atomic_set(&bat_priv->gw_sel_class, 20);
597 atomic_set(&bat_priv->gw_bandwidth, 41);
598 atomic_set(&bat_priv->orig_interval, 1000);
599 atomic_set(&bat_priv->hop_penalty, 10);
600 atomic_set(&bat_priv->log_level, 0);
601 atomic_set(&bat_priv->fragmentation, 1);
602 atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN);
603 atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN);
604
605 atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
606 atomic_set(&bat_priv->bcast_seqno, 1);
607 atomic_set(&bat_priv->hna_local_changed, 0);
608
609 bat_priv->primary_if = NULL;
610 bat_priv->num_ifaces = 0;
611 bat_priv->softif_neigh = NULL;
612
613 ret = sysfs_add_meshif(soft_iface);
614 if (ret < 0)
615 goto unreg_soft_iface;
616
617 ret = debugfs_add_meshif(soft_iface);
618 if (ret < 0)
619 goto unreg_sysfs;
620
621 ret = mesh_init(soft_iface);
622 if (ret < 0)
623 goto unreg_debugfs;
624
625 return soft_iface;
626
627unreg_debugfs:
628 debugfs_del_meshif(soft_iface);
629unreg_sysfs:
630 sysfs_del_meshif(soft_iface);
631unreg_soft_iface:
632 unregister_netdev(soft_iface);
633 return NULL;
634
635free_soft_iface:
636 free_netdev(soft_iface);
637out:
638 return NULL;
639}
640
641void softif_destroy(struct net_device *soft_iface)
642{
643 debugfs_del_meshif(soft_iface);
644 sysfs_del_meshif(soft_iface);
645 mesh_free(soft_iface);
646 unregister_netdevice(soft_iface);
647}
648
649/* ethtool */
650static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
651{
652 cmd->supported = 0;
653 cmd->advertising = 0;
654 cmd->speed = SPEED_10;
655 cmd->duplex = DUPLEX_FULL;
656 cmd->port = PORT_TP;
657 cmd->phy_address = 0;
658 cmd->transceiver = XCVR_INTERNAL;
659 cmd->autoneg = AUTONEG_DISABLE;
660 cmd->maxtxpkt = 0;
661 cmd->maxrxpkt = 0;
662
663 return 0;
664}
665
666static void bat_get_drvinfo(struct net_device *dev,
667 struct ethtool_drvinfo *info)
668{
669 strcpy(info->driver, "B.A.T.M.A.N. advanced");
670 strcpy(info->version, SOURCE_VERSION);
671 strcpy(info->fw_version, "N/A");
672 strcpy(info->bus_info, "batman");
673}
674
675static u32 bat_get_msglevel(struct net_device *dev)
676{
677 return -EOPNOTSUPP;
678}
679
680static void bat_set_msglevel(struct net_device *dev, u32 value)
681{
682}
683
684static u32 bat_get_link(struct net_device *dev)
685{
686 return 1;
687}
688
689static u32 bat_get_rx_csum(struct net_device *dev)
690{
691 return 0;
692}
693
694static int bat_set_rx_csum(struct net_device *dev, u32 data)
695{
696 return -EOPNOTSUPP;
697}
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h
new file mode 100644
index 000000000000..02b77334d10d
--- /dev/null
+++ b/net/batman-adv/soft-interface.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_
23#define _NET_BATMAN_ADV_SOFT_INTERFACE_H_
24
25int my_skb_head_push(struct sk_buff *skb, unsigned int len);
26int softif_neigh_seq_print_text(struct seq_file *seq, void *offset);
27void softif_neigh_purge(struct bat_priv *bat_priv);
28int interface_tx(struct sk_buff *skb, struct net_device *soft_iface);
29void interface_rx(struct net_device *soft_iface,
30 struct sk_buff *skb, struct batman_if *recv_if,
31 int hdr_size);
32struct net_device *softif_create(char *name);
33void softif_destroy(struct net_device *soft_iface);
34
35#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
new file mode 100644
index 000000000000..a19e16c94da5
--- /dev/null
+++ b/net/batman-adv/translation-table.c
@@ -0,0 +1,534 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "translation-table.h"
24#include "soft-interface.h"
25#include "types.h"
26#include "hash.h"
27#include "originator.h"
28
29static void hna_local_purge(struct work_struct *work);
30static void _hna_global_del_orig(struct bat_priv *bat_priv,
31 struct hna_global_entry *hna_global_entry,
32 char *message);
33
34static void hna_local_start_timer(struct bat_priv *bat_priv)
35{
36 INIT_DELAYED_WORK(&bat_priv->hna_work, hna_local_purge);
37 queue_delayed_work(bat_event_workqueue, &bat_priv->hna_work, 10 * HZ);
38}
39
40int hna_local_init(struct bat_priv *bat_priv)
41{
42 if (bat_priv->hna_local_hash)
43 return 1;
44
45 bat_priv->hna_local_hash = hash_new(1024);
46
47 if (!bat_priv->hna_local_hash)
48 return 0;
49
50 atomic_set(&bat_priv->hna_local_changed, 0);
51 hna_local_start_timer(bat_priv);
52
53 return 1;
54}
55
56void hna_local_add(struct net_device *soft_iface, uint8_t *addr)
57{
58 struct bat_priv *bat_priv = netdev_priv(soft_iface);
59 struct hna_local_entry *hna_local_entry;
60 struct hna_global_entry *hna_global_entry;
61 int required_bytes;
62
63 spin_lock_bh(&bat_priv->hna_lhash_lock);
64 hna_local_entry =
65 ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash,
66 compare_orig, choose_orig,
67 addr));
68 spin_unlock_bh(&bat_priv->hna_lhash_lock);
69
70 if (hna_local_entry) {
71 hna_local_entry->last_seen = jiffies;
72 return;
73 }
74
75 /* only announce as many hosts as possible in the batman-packet and
76 space in batman_packet->num_hna That also should give a limit to
77 MAC-flooding. */
78 required_bytes = (bat_priv->num_local_hna + 1) * ETH_ALEN;
79 required_bytes += BAT_PACKET_LEN;
80
81 if ((required_bytes > ETH_DATA_LEN) ||
82 (atomic_read(&bat_priv->aggregated_ogms) &&
83 required_bytes > MAX_AGGREGATION_BYTES) ||
84 (bat_priv->num_local_hna + 1 > 255)) {
85 bat_dbg(DBG_ROUTES, bat_priv,
86 "Can't add new local hna entry (%pM): "
87 "number of local hna entries exceeds packet size\n",
88 addr);
89 return;
90 }
91
92 bat_dbg(DBG_ROUTES, bat_priv,
93 "Creating new local hna entry: %pM\n", addr);
94
95 hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
96 if (!hna_local_entry)
97 return;
98
99 memcpy(hna_local_entry->addr, addr, ETH_ALEN);
100 hna_local_entry->last_seen = jiffies;
101
102 /* the batman interface mac address should never be purged */
103 if (compare_orig(addr, soft_iface->dev_addr))
104 hna_local_entry->never_purge = 1;
105 else
106 hna_local_entry->never_purge = 0;
107
108 spin_lock_bh(&bat_priv->hna_lhash_lock);
109
110 hash_add(bat_priv->hna_local_hash, compare_orig, choose_orig,
111 hna_local_entry);
112 bat_priv->num_local_hna++;
113 atomic_set(&bat_priv->hna_local_changed, 1);
114
115 spin_unlock_bh(&bat_priv->hna_lhash_lock);
116
117 /* remove address from global hash if present */
118 spin_lock_bh(&bat_priv->hna_ghash_lock);
119
120 hna_global_entry = ((struct hna_global_entry *)
121 hash_find(bat_priv->hna_global_hash,
122 compare_orig, choose_orig, addr));
123
124 if (hna_global_entry)
125 _hna_global_del_orig(bat_priv, hna_global_entry,
126 "local hna received");
127
128 spin_unlock_bh(&bat_priv->hna_ghash_lock);
129}
130
131int hna_local_fill_buffer(struct bat_priv *bat_priv,
132 unsigned char *buff, int buff_len)
133{
134 struct hashtable_t *hash = bat_priv->hna_local_hash;
135 struct hna_local_entry *hna_local_entry;
136 struct element_t *bucket;
137 int i;
138 struct hlist_node *walk;
139 struct hlist_head *head;
140 int count = 0;
141
142 spin_lock_bh(&bat_priv->hna_lhash_lock);
143
144 for (i = 0; i < hash->size; i++) {
145 head = &hash->table[i];
146
147 hlist_for_each_entry(bucket, walk, head, hlist) {
148
149 if (buff_len < (count + 1) * ETH_ALEN)
150 break;
151
152 hna_local_entry = bucket->data;
153 memcpy(buff + (count * ETH_ALEN), hna_local_entry->addr,
154 ETH_ALEN);
155
156 count++;
157 }
158 }
159
160 /* if we did not get all new local hnas see you next time ;-) */
161 if (count == bat_priv->num_local_hna)
162 atomic_set(&bat_priv->hna_local_changed, 0);
163
164 spin_unlock_bh(&bat_priv->hna_lhash_lock);
165 return i;
166}
167
168int hna_local_seq_print_text(struct seq_file *seq, void *offset)
169{
170 struct net_device *net_dev = (struct net_device *)seq->private;
171 struct bat_priv *bat_priv = netdev_priv(net_dev);
172 struct hashtable_t *hash = bat_priv->hna_local_hash;
173 struct hna_local_entry *hna_local_entry;
174 int i;
175 struct hlist_node *walk;
176 struct hlist_head *head;
177 struct element_t *bucket;
178 size_t buf_size, pos;
179 char *buff;
180
181 if (!bat_priv->primary_if) {
182 return seq_printf(seq, "BATMAN mesh %s disabled - "
183 "please specify interfaces to enable it\n",
184 net_dev->name);
185 }
186
187 seq_printf(seq, "Locally retrieved addresses (from %s) "
188 "announced via HNA:\n",
189 net_dev->name);
190
191 spin_lock_bh(&bat_priv->hna_lhash_lock);
192
193 buf_size = 1;
194 /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
195 for (i = 0; i < hash->size; i++) {
196 head = &hash->table[i];
197
198 hlist_for_each(walk, head)
199 buf_size += 21;
200 }
201
202 buff = kmalloc(buf_size, GFP_ATOMIC);
203 if (!buff) {
204 spin_unlock_bh(&bat_priv->hna_lhash_lock);
205 return -ENOMEM;
206 }
207 buff[0] = '\0';
208 pos = 0;
209
210 for (i = 0; i < hash->size; i++) {
211 head = &hash->table[i];
212
213 hlist_for_each_entry(bucket, walk, head, hlist) {
214 hna_local_entry = bucket->data;
215
216 pos += snprintf(buff + pos, 22, " * %pM\n",
217 hna_local_entry->addr);
218 }
219 }
220
221 spin_unlock_bh(&bat_priv->hna_lhash_lock);
222
223 seq_printf(seq, "%s", buff);
224 kfree(buff);
225 return 0;
226}
227
228static void _hna_local_del(void *data, void *arg)
229{
230 struct bat_priv *bat_priv = (struct bat_priv *)arg;
231
232 kfree(data);
233 bat_priv->num_local_hna--;
234 atomic_set(&bat_priv->hna_local_changed, 1);
235}
236
237static void hna_local_del(struct bat_priv *bat_priv,
238 struct hna_local_entry *hna_local_entry,
239 char *message)
240{
241 bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n",
242 hna_local_entry->addr, message);
243
244 hash_remove(bat_priv->hna_local_hash, compare_orig, choose_orig,
245 hna_local_entry->addr);
246 _hna_local_del(hna_local_entry, bat_priv);
247}
248
249void hna_local_remove(struct bat_priv *bat_priv,
250 uint8_t *addr, char *message)
251{
252 struct hna_local_entry *hna_local_entry;
253
254 spin_lock_bh(&bat_priv->hna_lhash_lock);
255
256 hna_local_entry = (struct hna_local_entry *)
257 hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig,
258 addr);
259
260 if (hna_local_entry)
261 hna_local_del(bat_priv, hna_local_entry, message);
262
263 spin_unlock_bh(&bat_priv->hna_lhash_lock);
264}
265
266static void hna_local_purge(struct work_struct *work)
267{
268 struct delayed_work *delayed_work =
269 container_of(work, struct delayed_work, work);
270 struct bat_priv *bat_priv =
271 container_of(delayed_work, struct bat_priv, hna_work);
272 struct hashtable_t *hash = bat_priv->hna_local_hash;
273 struct hna_local_entry *hna_local_entry;
274 int i;
275 struct hlist_node *walk, *safe;
276 struct hlist_head *head;
277 struct element_t *bucket;
278 unsigned long timeout;
279
280 spin_lock_bh(&bat_priv->hna_lhash_lock);
281
282 for (i = 0; i < hash->size; i++) {
283 head = &hash->table[i];
284
285 hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
286 hna_local_entry = bucket->data;
287
288 timeout = hna_local_entry->last_seen;
289 timeout += LOCAL_HNA_TIMEOUT * HZ;
290
291 if ((!hna_local_entry->never_purge) &&
292 time_after(jiffies, timeout))
293 hna_local_del(bat_priv, hna_local_entry,
294 "address timed out");
295 }
296 }
297
298 spin_unlock_bh(&bat_priv->hna_lhash_lock);
299 hna_local_start_timer(bat_priv);
300}
301
302void hna_local_free(struct bat_priv *bat_priv)
303{
304 if (!bat_priv->hna_local_hash)
305 return;
306
307 cancel_delayed_work_sync(&bat_priv->hna_work);
308 hash_delete(bat_priv->hna_local_hash, _hna_local_del, bat_priv);
309 bat_priv->hna_local_hash = NULL;
310}
311
312int hna_global_init(struct bat_priv *bat_priv)
313{
314 if (bat_priv->hna_global_hash)
315 return 1;
316
317 bat_priv->hna_global_hash = hash_new(1024);
318
319 if (!bat_priv->hna_global_hash)
320 return 0;
321
322 return 1;
323}
324
325void hna_global_add_orig(struct bat_priv *bat_priv,
326 struct orig_node *orig_node,
327 unsigned char *hna_buff, int hna_buff_len)
328{
329 struct hna_global_entry *hna_global_entry;
330 struct hna_local_entry *hna_local_entry;
331 int hna_buff_count = 0;
332 unsigned char *hna_ptr;
333
334 while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
335 spin_lock_bh(&bat_priv->hna_ghash_lock);
336
337 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
338 hna_global_entry = (struct hna_global_entry *)
339 hash_find(bat_priv->hna_global_hash, compare_orig,
340 choose_orig, hna_ptr);
341
342 if (!hna_global_entry) {
343 spin_unlock_bh(&bat_priv->hna_ghash_lock);
344
345 hna_global_entry =
346 kmalloc(sizeof(struct hna_global_entry),
347 GFP_ATOMIC);
348
349 if (!hna_global_entry)
350 break;
351
352 memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
353
354 bat_dbg(DBG_ROUTES, bat_priv,
355 "Creating new global hna entry: "
356 "%pM (via %pM)\n",
357 hna_global_entry->addr, orig_node->orig);
358
359 spin_lock_bh(&bat_priv->hna_ghash_lock);
360 hash_add(bat_priv->hna_global_hash, compare_orig,
361 choose_orig, hna_global_entry);
362
363 }
364
365 hna_global_entry->orig_node = orig_node;
366 spin_unlock_bh(&bat_priv->hna_ghash_lock);
367
368 /* remove address from local hash if present */
369 spin_lock_bh(&bat_priv->hna_lhash_lock);
370
371 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
372 hna_local_entry = (struct hna_local_entry *)
373 hash_find(bat_priv->hna_local_hash, compare_orig,
374 choose_orig, hna_ptr);
375
376 if (hna_local_entry)
377 hna_local_del(bat_priv, hna_local_entry,
378 "global hna received");
379
380 spin_unlock_bh(&bat_priv->hna_lhash_lock);
381
382 hna_buff_count++;
383 }
384
385 /* initialize, and overwrite if malloc succeeds */
386 orig_node->hna_buff = NULL;
387 orig_node->hna_buff_len = 0;
388
389 if (hna_buff_len > 0) {
390 orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC);
391 if (orig_node->hna_buff) {
392 memcpy(orig_node->hna_buff, hna_buff, hna_buff_len);
393 orig_node->hna_buff_len = hna_buff_len;
394 }
395 }
396}
397
398int hna_global_seq_print_text(struct seq_file *seq, void *offset)
399{
400 struct net_device *net_dev = (struct net_device *)seq->private;
401 struct bat_priv *bat_priv = netdev_priv(net_dev);
402 struct hashtable_t *hash = bat_priv->hna_global_hash;
403 struct hna_global_entry *hna_global_entry;
404 int i;
405 struct hlist_node *walk;
406 struct hlist_head *head;
407 struct element_t *bucket;
408 size_t buf_size, pos;
409 char *buff;
410
411 if (!bat_priv->primary_if) {
412 return seq_printf(seq, "BATMAN mesh %s disabled - "
413 "please specify interfaces to enable it\n",
414 net_dev->name);
415 }
416
417 seq_printf(seq, "Globally announced HNAs received via the mesh %s\n",
418 net_dev->name);
419
420 spin_lock_bh(&bat_priv->hna_ghash_lock);
421
422 buf_size = 1;
423 /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
424 for (i = 0; i < hash->size; i++) {
425 head = &hash->table[i];
426
427 hlist_for_each(walk, head)
428 buf_size += 43;
429 }
430
431 buff = kmalloc(buf_size, GFP_ATOMIC);
432 if (!buff) {
433 spin_unlock_bh(&bat_priv->hna_ghash_lock);
434 return -ENOMEM;
435 }
436 buff[0] = '\0';
437 pos = 0;
438
439 for (i = 0; i < hash->size; i++) {
440 head = &hash->table[i];
441
442 hlist_for_each_entry(bucket, walk, head, hlist) {
443 hna_global_entry = bucket->data;
444
445 pos += snprintf(buff + pos, 44,
446 " * %pM via %pM\n",
447 hna_global_entry->addr,
448 hna_global_entry->orig_node->orig);
449 }
450 }
451
452 spin_unlock_bh(&bat_priv->hna_ghash_lock);
453
454 seq_printf(seq, "%s", buff);
455 kfree(buff);
456 return 0;
457}
458
459static void _hna_global_del_orig(struct bat_priv *bat_priv,
460 struct hna_global_entry *hna_global_entry,
461 char *message)
462{
463 bat_dbg(DBG_ROUTES, bat_priv,
464 "Deleting global hna entry %pM (via %pM): %s\n",
465 hna_global_entry->addr, hna_global_entry->orig_node->orig,
466 message);
467
468 hash_remove(bat_priv->hna_global_hash, compare_orig, choose_orig,
469 hna_global_entry->addr);
470 kfree(hna_global_entry);
471}
472
473void hna_global_del_orig(struct bat_priv *bat_priv,
474 struct orig_node *orig_node, char *message)
475{
476 struct hna_global_entry *hna_global_entry;
477 int hna_buff_count = 0;
478 unsigned char *hna_ptr;
479
480 if (orig_node->hna_buff_len == 0)
481 return;
482
483 spin_lock_bh(&bat_priv->hna_ghash_lock);
484
485 while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) {
486 hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN);
487 hna_global_entry = (struct hna_global_entry *)
488 hash_find(bat_priv->hna_global_hash, compare_orig,
489 choose_orig, hna_ptr);
490
491 if ((hna_global_entry) &&
492 (hna_global_entry->orig_node == orig_node))
493 _hna_global_del_orig(bat_priv, hna_global_entry,
494 message);
495
496 hna_buff_count++;
497 }
498
499 spin_unlock_bh(&bat_priv->hna_ghash_lock);
500
501 orig_node->hna_buff_len = 0;
502 kfree(orig_node->hna_buff);
503 orig_node->hna_buff = NULL;
504}
505
506static void hna_global_del(void *data, void *arg)
507{
508 kfree(data);
509}
510
511void hna_global_free(struct bat_priv *bat_priv)
512{
513 if (!bat_priv->hna_global_hash)
514 return;
515
516 hash_delete(bat_priv->hna_global_hash, hna_global_del, NULL);
517 bat_priv->hna_global_hash = NULL;
518}
519
520struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr)
521{
522 struct hna_global_entry *hna_global_entry;
523
524 spin_lock_bh(&bat_priv->hna_ghash_lock);
525 hna_global_entry = (struct hna_global_entry *)
526 hash_find(bat_priv->hna_global_hash,
527 compare_orig, choose_orig, addr);
528 spin_unlock_bh(&bat_priv->hna_ghash_lock);
529
530 if (!hna_global_entry)
531 return NULL;
532
533 return hna_global_entry->orig_node;
534}
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
new file mode 100644
index 000000000000..10c4c5c319b6
--- /dev/null
+++ b/net/batman-adv/translation-table.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
23#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
24
25#include "types.h"
26
27int hna_local_init(struct bat_priv *bat_priv);
28void hna_local_add(struct net_device *soft_iface, uint8_t *addr);
29void hna_local_remove(struct bat_priv *bat_priv,
30 uint8_t *addr, char *message);
31int hna_local_fill_buffer(struct bat_priv *bat_priv,
32 unsigned char *buff, int buff_len);
33int hna_local_seq_print_text(struct seq_file *seq, void *offset);
34void hna_local_free(struct bat_priv *bat_priv);
35int hna_global_init(struct bat_priv *bat_priv);
36void hna_global_add_orig(struct bat_priv *bat_priv,
37 struct orig_node *orig_node,
38 unsigned char *hna_buff, int hna_buff_len);
39int hna_global_seq_print_text(struct seq_file *seq, void *offset);
40void hna_global_del_orig(struct bat_priv *bat_priv,
41 struct orig_node *orig_node, char *message);
42void hna_global_free(struct bat_priv *bat_priv);
43struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr);
44
45#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
new file mode 100644
index 000000000000..97cb23dd3e69
--- /dev/null
+++ b/net/batman-adv/types.h
@@ -0,0 +1,271 @@
1/*
2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner, Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22
23
24#ifndef _NET_BATMAN_ADV_TYPES_H_
25#define _NET_BATMAN_ADV_TYPES_H_
26
27#include "packet.h"
28#include "bitarray.h"
29
30#define BAT_HEADER_LEN (sizeof(struct ethhdr) + \
31 ((sizeof(struct unicast_packet) > sizeof(struct bcast_packet) ? \
32 sizeof(struct unicast_packet) : \
33 sizeof(struct bcast_packet))))
34
35
36struct batman_if {
37 struct list_head list;
38 int16_t if_num;
39 char if_status;
40 struct net_device *net_dev;
41 atomic_t seqno;
42 atomic_t frag_seqno;
43 unsigned char *packet_buff;
44 int packet_len;
45 struct kobject *hardif_obj;
46 struct kref refcount;
47 struct packet_type batman_adv_ptype;
48 struct net_device *soft_iface;
49 struct rcu_head rcu;
50};
51
52/**
53 * orig_node - structure for orig_list maintaining nodes of mesh
54 * @primary_addr: hosts primary interface address
55 * @last_valid: when last packet from this node was received
56 * @bcast_seqno_reset: time when the broadcast seqno window was reset
57 * @batman_seqno_reset: time when the batman seqno window was reset
58 * @gw_flags: flags related to gateway class
59 * @flags: for now only VIS_SERVER flag
60 * @last_real_seqno: last and best known squence number
61 * @last_ttl: ttl of last received packet
62 * @last_bcast_seqno: last broadcast sequence number received by this host
63 *
64 * @candidates: how many candidates are available
65 * @selected: next bonding candidate
66 */
67struct orig_node {
68 uint8_t orig[ETH_ALEN];
69 uint8_t primary_addr[ETH_ALEN];
70 struct neigh_node *router;
71 unsigned long *bcast_own;
72 uint8_t *bcast_own_sum;
73 uint8_t tq_own;
74 int tq_asym_penalty;
75 unsigned long last_valid;
76 unsigned long bcast_seqno_reset;
77 unsigned long batman_seqno_reset;
78 uint8_t gw_flags;
79 uint8_t flags;
80 unsigned char *hna_buff;
81 int16_t hna_buff_len;
82 uint32_t last_real_seqno;
83 uint8_t last_ttl;
84 unsigned long bcast_bits[NUM_WORDS];
85 uint32_t last_bcast_seqno;
86 struct list_head neigh_list;
87 struct list_head frag_list;
88 unsigned long last_frag_packet;
89 struct {
90 uint8_t candidates;
91 struct neigh_node *selected;
92 } bond;
93};
94
95struct gw_node {
96 struct hlist_node list;
97 struct orig_node *orig_node;
98 unsigned long deleted;
99 struct kref refcount;
100 struct rcu_head rcu;
101};
102
103/**
104 * neigh_node
105 * @last_valid: when last packet via this neighbor was received
106 */
107struct neigh_node {
108 struct list_head list;
109 uint8_t addr[ETH_ALEN];
110 uint8_t real_packet_count;
111 uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE];
112 uint8_t tq_index;
113 uint8_t tq_avg;
114 uint8_t last_ttl;
115 struct neigh_node *next_bond_candidate;
116 unsigned long last_valid;
117 unsigned long real_bits[NUM_WORDS];
118 struct orig_node *orig_node;
119 struct batman_if *if_incoming;
120};
121
122
123struct bat_priv {
124 atomic_t mesh_state;
125 struct net_device_stats stats;
126 atomic_t aggregated_ogms; /* boolean */
127 atomic_t bonding; /* boolean */
128 atomic_t fragmentation; /* boolean */
129 atomic_t vis_mode; /* VIS_TYPE_* */
130 atomic_t gw_mode; /* GW_MODE_* */
131 atomic_t gw_sel_class; /* uint */
132 atomic_t gw_bandwidth; /* gw bandwidth */
133 atomic_t orig_interval; /* uint */
134 atomic_t hop_penalty; /* uint */
135 atomic_t log_level; /* uint */
136 atomic_t bcast_seqno;
137 atomic_t bcast_queue_left;
138 atomic_t batman_queue_left;
139 char num_ifaces;
140 struct hlist_head softif_neigh_list;
141 struct softif_neigh *softif_neigh;
142 struct debug_log *debug_log;
143 struct batman_if *primary_if;
144 struct kobject *mesh_obj;
145 struct dentry *debug_dir;
146 struct hlist_head forw_bat_list;
147 struct hlist_head forw_bcast_list;
148 struct hlist_head gw_list;
149 struct list_head vis_send_list;
150 struct hashtable_t *orig_hash;
151 struct hashtable_t *hna_local_hash;
152 struct hashtable_t *hna_global_hash;
153 struct hashtable_t *vis_hash;
154 spinlock_t orig_hash_lock; /* protects orig_hash */
155 spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
156 spinlock_t forw_bcast_list_lock; /* protects */
157 spinlock_t hna_lhash_lock; /* protects hna_local_hash */
158 spinlock_t hna_ghash_lock; /* protects hna_global_hash */
159 spinlock_t gw_list_lock; /* protects gw_list */
160 spinlock_t vis_hash_lock; /* protects vis_hash */
161 spinlock_t vis_list_lock; /* protects vis_info::recv_list */
162 spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */
163 int16_t num_local_hna;
164 atomic_t hna_local_changed;
165 struct delayed_work hna_work;
166 struct delayed_work orig_work;
167 struct delayed_work vis_work;
168 struct gw_node *curr_gw;
169 struct vis_info *my_vis_info;
170};
171
172struct socket_client {
173 struct list_head queue_list;
174 unsigned int queue_len;
175 unsigned char index;
176 spinlock_t lock; /* protects queue_list, queue_len, index */
177 wait_queue_head_t queue_wait;
178 struct bat_priv *bat_priv;
179};
180
181struct socket_packet {
182 struct list_head list;
183 size_t icmp_len;
184 struct icmp_packet_rr icmp_packet;
185};
186
187struct hna_local_entry {
188 uint8_t addr[ETH_ALEN];
189 unsigned long last_seen;
190 char never_purge;
191};
192
193struct hna_global_entry {
194 uint8_t addr[ETH_ALEN];
195 struct orig_node *orig_node;
196};
197
198/**
199 * forw_packet - structure for forw_list maintaining packets to be
200 * send/forwarded
201 */
202struct forw_packet {
203 struct hlist_node list;
204 unsigned long send_time;
205 uint8_t own;
206 struct sk_buff *skb;
207 uint16_t packet_len;
208 uint32_t direct_link_flags;
209 uint8_t num_packets;
210 struct delayed_work delayed_work;
211 struct batman_if *if_incoming;
212};
213
214/* While scanning for vis-entries of a particular vis-originator
215 * this list collects its interfaces to create a subgraph/cluster
216 * out of them later
217 */
218struct if_list_entry {
219 uint8_t addr[ETH_ALEN];
220 bool primary;
221 struct hlist_node list;
222};
223
224struct debug_log {
225 char log_buff[LOG_BUF_LEN];
226 unsigned long log_start;
227 unsigned long log_end;
228 spinlock_t lock; /* protects log_buff, log_start and log_end */
229 wait_queue_head_t queue_wait;
230};
231
232struct frag_packet_list_entry {
233 struct list_head list;
234 uint16_t seqno;
235 struct sk_buff *skb;
236};
237
238struct vis_info {
239 unsigned long first_seen;
240 struct list_head recv_list;
241 /* list of server-neighbors we received a vis-packet
242 * from. we should not reply to them. */
243 struct list_head send_list;
244 struct kref refcount;
245 struct bat_priv *bat_priv;
246 /* this packet might be part of the vis send queue. */
247 struct sk_buff *skb_packet;
248 /* vis_info may follow here*/
249} __attribute__((packed));
250
251struct vis_info_entry {
252 uint8_t src[ETH_ALEN];
253 uint8_t dest[ETH_ALEN];
254 uint8_t quality; /* quality = 0 means HNA */
255} __attribute__((packed));
256
257struct recvlist_node {
258 struct list_head list;
259 uint8_t mac[ETH_ALEN];
260};
261
262struct softif_neigh {
263 struct hlist_node list;
264 uint8_t addr[ETH_ALEN];
265 unsigned long last_seen;
266 short vid;
267 struct kref refcount;
268 struct rcu_head rcu;
269};
270
271#endif /* _NET_BATMAN_ADV_TYPES_H_ */
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
new file mode 100644
index 000000000000..dc2e28bed844
--- /dev/null
+++ b/net/batman-adv/unicast.c
@@ -0,0 +1,343 @@
1/*
2 * Copyright (C) 2010 B.A.T.M.A.N. contributors:
3 *
4 * Andreas Langer
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "unicast.h"
24#include "send.h"
25#include "soft-interface.h"
26#include "gateway_client.h"
27#include "originator.h"
28#include "hash.h"
29#include "translation-table.h"
30#include "routing.h"
31#include "hard-interface.h"
32
33
34static struct sk_buff *frag_merge_packet(struct list_head *head,
35 struct frag_packet_list_entry *tfp,
36 struct sk_buff *skb)
37{
38 struct unicast_frag_packet *up =
39 (struct unicast_frag_packet *)skb->data;
40 struct sk_buff *tmp_skb;
41 struct unicast_packet *unicast_packet;
42 int hdr_len = sizeof(struct unicast_packet),
43 uni_diff = sizeof(struct unicast_frag_packet) - hdr_len;
44
45 /* set skb to the first part and tmp_skb to the second part */
46 if (up->flags & UNI_FRAG_HEAD) {
47 tmp_skb = tfp->skb;
48 } else {
49 tmp_skb = skb;
50 skb = tfp->skb;
51 }
52
53 skb_pull(tmp_skb, sizeof(struct unicast_frag_packet));
54 if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0) {
55 /* free buffered skb, skb will be freed later */
56 kfree_skb(tfp->skb);
57 return NULL;
58 }
59
60 /* move free entry to end */
61 tfp->skb = NULL;
62 tfp->seqno = 0;
63 list_move_tail(&tfp->list, head);
64
65 memcpy(skb_put(skb, tmp_skb->len), tmp_skb->data, tmp_skb->len);
66 kfree_skb(tmp_skb);
67
68 memmove(skb->data + uni_diff, skb->data, hdr_len);
69 unicast_packet = (struct unicast_packet *) skb_pull(skb, uni_diff);
70 unicast_packet->packet_type = BAT_UNICAST;
71
72 return skb;
73}
74
75static void frag_create_entry(struct list_head *head, struct sk_buff *skb)
76{
77 struct frag_packet_list_entry *tfp;
78 struct unicast_frag_packet *up =
79 (struct unicast_frag_packet *)skb->data;
80
81 /* free and oldest packets stand at the end */
82 tfp = list_entry((head)->prev, typeof(*tfp), list);
83 kfree_skb(tfp->skb);
84
85 tfp->seqno = ntohs(up->seqno);
86 tfp->skb = skb;
87 list_move(&tfp->list, head);
88 return;
89}
90
91static int frag_create_buffer(struct list_head *head)
92{
93 int i;
94 struct frag_packet_list_entry *tfp;
95
96 for (i = 0; i < FRAG_BUFFER_SIZE; i++) {
97 tfp = kmalloc(sizeof(struct frag_packet_list_entry),
98 GFP_ATOMIC);
99 if (!tfp) {
100 frag_list_free(head);
101 return -ENOMEM;
102 }
103 tfp->skb = NULL;
104 tfp->seqno = 0;
105 INIT_LIST_HEAD(&tfp->list);
106 list_add(&tfp->list, head);
107 }
108
109 return 0;
110}
111
112static struct frag_packet_list_entry *frag_search_packet(struct list_head *head,
113 struct unicast_frag_packet *up)
114{
115 struct frag_packet_list_entry *tfp;
116 struct unicast_frag_packet *tmp_up = NULL;
117 uint16_t search_seqno;
118
119 if (up->flags & UNI_FRAG_HEAD)
120 search_seqno = ntohs(up->seqno)+1;
121 else
122 search_seqno = ntohs(up->seqno)-1;
123
124 list_for_each_entry(tfp, head, list) {
125
126 if (!tfp->skb)
127 continue;
128
129 if (tfp->seqno == ntohs(up->seqno))
130 goto mov_tail;
131
132 tmp_up = (struct unicast_frag_packet *)tfp->skb->data;
133
134 if (tfp->seqno == search_seqno) {
135
136 if ((tmp_up->flags & UNI_FRAG_HEAD) !=
137 (up->flags & UNI_FRAG_HEAD))
138 return tfp;
139 else
140 goto mov_tail;
141 }
142 }
143 return NULL;
144
145mov_tail:
146 list_move_tail(&tfp->list, head);
147 return NULL;
148}
149
150void frag_list_free(struct list_head *head)
151{
152 struct frag_packet_list_entry *pf, *tmp_pf;
153
154 if (!list_empty(head)) {
155
156 list_for_each_entry_safe(pf, tmp_pf, head, list) {
157 kfree_skb(pf->skb);
158 list_del(&pf->list);
159 kfree(pf);
160 }
161 }
162 return;
163}
164
165/* frag_reassemble_skb():
166 * returns NET_RX_DROP if the operation failed - skb is left intact
167 * returns NET_RX_SUCCESS if the fragment was buffered (skb_new will be NULL)
168 * or the skb could be reassembled (skb_new will point to the new packet and
169 * skb was freed)
170 */
171int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
172 struct sk_buff **new_skb)
173{
174 struct orig_node *orig_node;
175 struct frag_packet_list_entry *tmp_frag_entry;
176 int ret = NET_RX_DROP;
177 struct unicast_frag_packet *unicast_packet =
178 (struct unicast_frag_packet *)skb->data;
179
180 *new_skb = NULL;
181 spin_lock_bh(&bat_priv->orig_hash_lock);
182 orig_node = ((struct orig_node *)
183 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
184 unicast_packet->orig));
185
186 if (!orig_node) {
187 pr_debug("couldn't find originator in orig_hash\n");
188 goto out;
189 }
190
191 orig_node->last_frag_packet = jiffies;
192
193 if (list_empty(&orig_node->frag_list) &&
194 frag_create_buffer(&orig_node->frag_list)) {
195 pr_debug("couldn't create frag buffer\n");
196 goto out;
197 }
198
199 tmp_frag_entry = frag_search_packet(&orig_node->frag_list,
200 unicast_packet);
201
202 if (!tmp_frag_entry) {
203 frag_create_entry(&orig_node->frag_list, skb);
204 ret = NET_RX_SUCCESS;
205 goto out;
206 }
207
208 *new_skb = frag_merge_packet(&orig_node->frag_list, tmp_frag_entry,
209 skb);
210 /* if not, merge failed */
211 if (*new_skb)
212 ret = NET_RX_SUCCESS;
213out:
214 spin_unlock_bh(&bat_priv->orig_hash_lock);
215
216 return ret;
217}
218
219int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
220 struct batman_if *batman_if, uint8_t dstaddr[])
221{
222 struct unicast_packet tmp_uc, *unicast_packet;
223 struct sk_buff *frag_skb;
224 struct unicast_frag_packet *frag1, *frag2;
225 int uc_hdr_len = sizeof(struct unicast_packet);
226 int ucf_hdr_len = sizeof(struct unicast_frag_packet);
227 int data_len = skb->len;
228
229 if (!bat_priv->primary_if)
230 goto dropped;
231
232 unicast_packet = (struct unicast_packet *) skb->data;
233
234 memcpy(&tmp_uc, unicast_packet, uc_hdr_len);
235 frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len);
236 skb_split(skb, frag_skb, data_len / 2);
237
238 if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 ||
239 my_skb_head_push(frag_skb, ucf_hdr_len) < 0)
240 goto drop_frag;
241
242 frag1 = (struct unicast_frag_packet *)skb->data;
243 frag2 = (struct unicast_frag_packet *)frag_skb->data;
244
245 memcpy(frag1, &tmp_uc, sizeof(struct unicast_packet));
246
247 frag1->ttl--;
248 frag1->version = COMPAT_VERSION;
249 frag1->packet_type = BAT_UNICAST_FRAG;
250
251 memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
252 memcpy(frag2, frag1, sizeof(struct unicast_frag_packet));
253
254 frag1->flags |= UNI_FRAG_HEAD;
255 frag2->flags &= ~UNI_FRAG_HEAD;
256
257 frag1->seqno = htons((uint16_t)atomic_inc_return(
258 &batman_if->frag_seqno));
259 frag2->seqno = htons((uint16_t)atomic_inc_return(
260 &batman_if->frag_seqno));
261
262 send_skb_packet(skb, batman_if, dstaddr);
263 send_skb_packet(frag_skb, batman_if, dstaddr);
264 return NET_RX_SUCCESS;
265
266drop_frag:
267 kfree_skb(frag_skb);
268dropped:
269 kfree_skb(skb);
270 return NET_RX_DROP;
271}
272
273int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
274{
275 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
276 struct unicast_packet *unicast_packet;
277 struct orig_node *orig_node;
278 struct batman_if *batman_if;
279 struct neigh_node *router;
280 int data_len = skb->len;
281 uint8_t dstaddr[6];
282
283 spin_lock_bh(&bat_priv->orig_hash_lock);
284
285 /* get routing information */
286 if (is_multicast_ether_addr(ethhdr->h_dest))
287 orig_node = (struct orig_node *)gw_get_selected(bat_priv);
288 else
289 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
290 compare_orig,
291 choose_orig,
292 ethhdr->h_dest));
293
294 /* check for hna host */
295 if (!orig_node)
296 orig_node = transtable_search(bat_priv, ethhdr->h_dest);
297
298 router = find_router(bat_priv, orig_node, NULL);
299
300 if (!router)
301 goto unlock;
302
303 /* don't lock while sending the packets ... we therefore
304 * copy the required data before sending */
305
306 batman_if = router->if_incoming;
307 memcpy(dstaddr, router->addr, ETH_ALEN);
308
309 spin_unlock_bh(&bat_priv->orig_hash_lock);
310
311 if (batman_if->if_status != IF_ACTIVE)
312 goto dropped;
313
314 if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0)
315 goto dropped;
316
317 unicast_packet = (struct unicast_packet *)skb->data;
318
319 unicast_packet->version = COMPAT_VERSION;
320 /* batman packet type: unicast */
321 unicast_packet->packet_type = BAT_UNICAST;
322 /* set unicast ttl */
323 unicast_packet->ttl = TTL;
324 /* copy the destination for faster routing */
325 memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
326
327 if (atomic_read(&bat_priv->fragmentation) &&
328 data_len + sizeof(struct unicast_packet) >
329 batman_if->net_dev->mtu) {
330 /* send frag skb decreases ttl */
331 unicast_packet->ttl++;
332 return frag_send_skb(skb, bat_priv, batman_if,
333 dstaddr);
334 }
335 send_skb_packet(skb, batman_if, dstaddr);
336 return 0;
337
338unlock:
339 spin_unlock_bh(&bat_priv->orig_hash_lock);
340dropped:
341 kfree_skb(skb);
342 return 1;
343}
diff --git a/net/batman-adv/unicast.h b/net/batman-adv/unicast.h
new file mode 100644
index 000000000000..e32b7867a9a4
--- /dev/null
+++ b/net/batman-adv/unicast.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2010 B.A.T.M.A.N. contributors:
3 *
4 * Andreas Langer
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_UNICAST_H_
23#define _NET_BATMAN_ADV_UNICAST_H_
24
25#define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */
26#define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */
27
28int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
29 struct sk_buff **new_skb);
30void frag_list_free(struct list_head *head);
31int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv);
32int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
33 struct batman_if *batman_if, uint8_t dstaddr[]);
34
35#endif /* _NET_BATMAN_ADV_UNICAST_H_ */
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
new file mode 100644
index 000000000000..cd4c4231fa48
--- /dev/null
+++ b/net/batman-adv/vis.c
@@ -0,0 +1,949 @@
1/*
2 * Copyright (C) 2008-2010 B.A.T.M.A.N. contributors:
3 *
4 * Simon Wunderlich
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23#include "send.h"
24#include "translation-table.h"
25#include "vis.h"
26#include "soft-interface.h"
27#include "hard-interface.h"
28#include "hash.h"
29#include "originator.h"
30
31#define MAX_VIS_PACKET_SIZE 1000
32
33/* Returns the smallest signed integer in two's complement with the sizeof x */
34#define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u)))
35
36/* Checks if a sequence number x is a predecessor/successor of y.
37 * they handle overflows/underflows and can correctly check for a
38 * predecessor/successor unless the variable sequence number has grown by
39 * more then 2**(bitwidth(x)-1)-1.
40 * This means that for a uint8_t with the maximum value 255, it would think:
41 * - when adding nothing - it is neither a predecessor nor a successor
42 * - before adding more than 127 to the starting value - it is a predecessor,
43 * - when adding 128 - it is neither a predecessor nor a successor,
44 * - after adding more than 127 to the starting value - it is a successor */
45#define seq_before(x, y) ({typeof(x) _dummy = (x - y); \
46 _dummy > smallest_signed_int(_dummy); })
47#define seq_after(x, y) seq_before(y, x)
48
49static void start_vis_timer(struct bat_priv *bat_priv);
50
51/* free the info */
52static void free_info(struct kref *ref)
53{
54 struct vis_info *info = container_of(ref, struct vis_info, refcount);
55 struct bat_priv *bat_priv = info->bat_priv;
56 struct recvlist_node *entry, *tmp;
57
58 list_del_init(&info->send_list);
59 spin_lock_bh(&bat_priv->vis_list_lock);
60 list_for_each_entry_safe(entry, tmp, &info->recv_list, list) {
61 list_del(&entry->list);
62 kfree(entry);
63 }
64
65 spin_unlock_bh(&bat_priv->vis_list_lock);
66 kfree_skb(info->skb_packet);
67}
68
69/* Compare two vis packets, used by the hashing algorithm */
70static int vis_info_cmp(void *data1, void *data2)
71{
72 struct vis_info *d1, *d2;
73 struct vis_packet *p1, *p2;
74 d1 = data1;
75 d2 = data2;
76 p1 = (struct vis_packet *)d1->skb_packet->data;
77 p2 = (struct vis_packet *)d2->skb_packet->data;
78 return compare_orig(p1->vis_orig, p2->vis_orig);
79}
80
81/* hash function to choose an entry in a hash table of given size */
82/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
83static int vis_info_choose(void *data, int size)
84{
85 struct vis_info *vis_info = data;
86 struct vis_packet *packet;
87 unsigned char *key;
88 uint32_t hash = 0;
89 size_t i;
90
91 packet = (struct vis_packet *)vis_info->skb_packet->data;
92 key = packet->vis_orig;
93 for (i = 0; i < ETH_ALEN; i++) {
94 hash += key[i];
95 hash += (hash << 10);
96 hash ^= (hash >> 6);
97 }
98
99 hash += (hash << 3);
100 hash ^= (hash >> 11);
101 hash += (hash << 15);
102
103 return hash % size;
104}
105
106/* insert interface to the list of interfaces of one originator, if it
107 * does not already exist in the list */
108static void vis_data_insert_interface(const uint8_t *interface,
109 struct hlist_head *if_list,
110 bool primary)
111{
112 struct if_list_entry *entry;
113 struct hlist_node *pos;
114
115 hlist_for_each_entry(entry, pos, if_list, list) {
116 if (compare_orig(entry->addr, (void *)interface))
117 return;
118 }
119
120 /* its a new address, add it to the list */
121 entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
122 if (!entry)
123 return;
124 memcpy(entry->addr, interface, ETH_ALEN);
125 entry->primary = primary;
126 hlist_add_head(&entry->list, if_list);
127}
128
129static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list)
130{
131 struct if_list_entry *entry;
132 struct hlist_node *pos;
133 size_t len = 0;
134
135 hlist_for_each_entry(entry, pos, if_list, list) {
136 if (entry->primary)
137 len += sprintf(buff + len, "PRIMARY, ");
138 else
139 len += sprintf(buff + len, "SEC %pM, ", entry->addr);
140 }
141
142 return len;
143}
144
145static size_t vis_data_count_prim_sec(struct hlist_head *if_list)
146{
147 struct if_list_entry *entry;
148 struct hlist_node *pos;
149 size_t count = 0;
150
151 hlist_for_each_entry(entry, pos, if_list, list) {
152 if (entry->primary)
153 count += 9;
154 else
155 count += 23;
156 }
157
158 return count;
159}
160
161/* read an entry */
162static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry,
163 uint8_t *src, bool primary)
164{
165 /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */
166 if (primary && entry->quality == 0)
167 return sprintf(buff, "HNA %pM, ", entry->dest);
168 else if (compare_orig(entry->src, src))
169 return sprintf(buff, "TQ %pM %d, ", entry->dest,
170 entry->quality);
171
172 return 0;
173}
174
175int vis_seq_print_text(struct seq_file *seq, void *offset)
176{
177 struct hlist_node *walk;
178 struct hlist_head *head;
179 struct element_t *bucket;
180 struct vis_info *info;
181 struct vis_packet *packet;
182 struct vis_info_entry *entries;
183 struct net_device *net_dev = (struct net_device *)seq->private;
184 struct bat_priv *bat_priv = netdev_priv(net_dev);
185 struct hashtable_t *hash = bat_priv->vis_hash;
186 HLIST_HEAD(vis_if_list);
187 struct if_list_entry *entry;
188 struct hlist_node *pos, *n;
189 int i, j;
190 int vis_server = atomic_read(&bat_priv->vis_mode);
191 size_t buff_pos, buf_size;
192 char *buff;
193 int compare;
194
195 if ((!bat_priv->primary_if) ||
196 (vis_server == VIS_TYPE_CLIENT_UPDATE))
197 return 0;
198
199 buf_size = 1;
200 /* Estimate length */
201 spin_lock_bh(&bat_priv->vis_hash_lock);
202 for (i = 0; i < hash->size; i++) {
203 head = &hash->table[i];
204
205 hlist_for_each_entry(bucket, walk, head, hlist) {
206 info = bucket->data;
207 packet = (struct vis_packet *)info->skb_packet->data;
208 entries = (struct vis_info_entry *)
209 ((char *)packet + sizeof(struct vis_packet));
210
211 for (j = 0; j < packet->entries; j++) {
212 if (entries[j].quality == 0)
213 continue;
214 compare =
215 compare_orig(entries[j].src, packet->vis_orig);
216 vis_data_insert_interface(entries[j].src,
217 &vis_if_list,
218 compare);
219 }
220
221 hlist_for_each_entry(entry, pos, &vis_if_list, list) {
222 buf_size += 18 + 26 * packet->entries;
223
224 /* add primary/secondary records */
225 if (compare_orig(entry->addr, packet->vis_orig))
226 buf_size +=
227 vis_data_count_prim_sec(&vis_if_list);
228
229 buf_size += 1;
230 }
231
232 hlist_for_each_entry_safe(entry, pos, n, &vis_if_list,
233 list) {
234 hlist_del(&entry->list);
235 kfree(entry);
236 }
237 }
238 }
239
240 buff = kmalloc(buf_size, GFP_ATOMIC);
241 if (!buff) {
242 spin_unlock_bh(&bat_priv->vis_hash_lock);
243 return -ENOMEM;
244 }
245 buff[0] = '\0';
246 buff_pos = 0;
247
248 for (i = 0; i < hash->size; i++) {
249 head = &hash->table[i];
250
251 hlist_for_each_entry(bucket, walk, head, hlist) {
252 info = bucket->data;
253 packet = (struct vis_packet *)info->skb_packet->data;
254 entries = (struct vis_info_entry *)
255 ((char *)packet + sizeof(struct vis_packet));
256
257 for (j = 0; j < packet->entries; j++) {
258 if (entries[j].quality == 0)
259 continue;
260 compare =
261 compare_orig(entries[j].src, packet->vis_orig);
262 vis_data_insert_interface(entries[j].src,
263 &vis_if_list,
264 compare);
265 }
266
267 hlist_for_each_entry(entry, pos, &vis_if_list, list) {
268 buff_pos += sprintf(buff + buff_pos, "%pM,",
269 entry->addr);
270
271 for (i = 0; i < packet->entries; i++)
272 buff_pos += vis_data_read_entry(
273 buff + buff_pos,
274 &entries[i],
275 entry->addr,
276 entry->primary);
277
278 /* add primary/secondary records */
279 if (compare_orig(entry->addr, packet->vis_orig))
280 buff_pos +=
281 vis_data_read_prim_sec(buff + buff_pos,
282 &vis_if_list);
283
284 buff_pos += sprintf(buff + buff_pos, "\n");
285 }
286
287 hlist_for_each_entry_safe(entry, pos, n, &vis_if_list,
288 list) {
289 hlist_del(&entry->list);
290 kfree(entry);
291 }
292 }
293 }
294
295 spin_unlock_bh(&bat_priv->vis_hash_lock);
296
297 seq_printf(seq, "%s", buff);
298 kfree(buff);
299
300 return 0;
301}
302
303/* add the info packet to the send list, if it was not
304 * already linked in. */
305static void send_list_add(struct bat_priv *bat_priv, struct vis_info *info)
306{
307 if (list_empty(&info->send_list)) {
308 kref_get(&info->refcount);
309 list_add_tail(&info->send_list, &bat_priv->vis_send_list);
310 }
311}
312
313/* delete the info packet from the send list, if it was
314 * linked in. */
315static void send_list_del(struct vis_info *info)
316{
317 if (!list_empty(&info->send_list)) {
318 list_del_init(&info->send_list);
319 kref_put(&info->refcount, free_info);
320 }
321}
322
323/* tries to add one entry to the receive list. */
324static void recv_list_add(struct bat_priv *bat_priv,
325 struct list_head *recv_list, char *mac)
326{
327 struct recvlist_node *entry;
328
329 entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC);
330 if (!entry)
331 return;
332
333 memcpy(entry->mac, mac, ETH_ALEN);
334 spin_lock_bh(&bat_priv->vis_list_lock);
335 list_add_tail(&entry->list, recv_list);
336 spin_unlock_bh(&bat_priv->vis_list_lock);
337}
338
339/* returns 1 if this mac is in the recv_list */
340static int recv_list_is_in(struct bat_priv *bat_priv,
341 struct list_head *recv_list, char *mac)
342{
343 struct recvlist_node *entry;
344
345 spin_lock_bh(&bat_priv->vis_list_lock);
346 list_for_each_entry(entry, recv_list, list) {
347 if (memcmp(entry->mac, mac, ETH_ALEN) == 0) {
348 spin_unlock_bh(&bat_priv->vis_list_lock);
349 return 1;
350 }
351 }
352 spin_unlock_bh(&bat_priv->vis_list_lock);
353 return 0;
354}
355
356/* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old,
357 * broken.. ). vis hash must be locked outside. is_new is set when the packet
358 * is newer than old entries in the hash. */
359static struct vis_info *add_packet(struct bat_priv *bat_priv,
360 struct vis_packet *vis_packet,
361 int vis_info_len, int *is_new,
362 int make_broadcast)
363{
364 struct vis_info *info, *old_info;
365 struct vis_packet *search_packet, *old_packet;
366 struct vis_info search_elem;
367 struct vis_packet *packet;
368 int hash_added;
369
370 *is_new = 0;
371 /* sanity check */
372 if (!bat_priv->vis_hash)
373 return NULL;
374
375 /* see if the packet is already in vis_hash */
376 search_elem.skb_packet = dev_alloc_skb(sizeof(struct vis_packet));
377 if (!search_elem.skb_packet)
378 return NULL;
379 search_packet = (struct vis_packet *)skb_put(search_elem.skb_packet,
380 sizeof(struct vis_packet));
381
382 memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN);
383 old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
384 &search_elem);
385 kfree_skb(search_elem.skb_packet);
386
387 if (old_info) {
388 old_packet = (struct vis_packet *)old_info->skb_packet->data;
389 if (!seq_after(ntohl(vis_packet->seqno),
390 ntohl(old_packet->seqno))) {
391 if (old_packet->seqno == vis_packet->seqno) {
392 recv_list_add(bat_priv, &old_info->recv_list,
393 vis_packet->sender_orig);
394 return old_info;
395 } else {
396 /* newer packet is already in hash. */
397 return NULL;
398 }
399 }
400 /* remove old entry */
401 hash_remove(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
402 old_info);
403 send_list_del(old_info);
404 kref_put(&old_info->refcount, free_info);
405 }
406
407 info = kmalloc(sizeof(struct vis_info), GFP_ATOMIC);
408 if (!info)
409 return NULL;
410
411 info->skb_packet = dev_alloc_skb(sizeof(struct vis_packet) +
412 vis_info_len + sizeof(struct ethhdr));
413 if (!info->skb_packet) {
414 kfree(info);
415 return NULL;
416 }
417 skb_reserve(info->skb_packet, sizeof(struct ethhdr));
418 packet = (struct vis_packet *)skb_put(info->skb_packet,
419 sizeof(struct vis_packet) +
420 vis_info_len);
421
422 kref_init(&info->refcount);
423 INIT_LIST_HEAD(&info->send_list);
424 INIT_LIST_HEAD(&info->recv_list);
425 info->first_seen = jiffies;
426 info->bat_priv = bat_priv;
427 memcpy(packet, vis_packet, sizeof(struct vis_packet) + vis_info_len);
428
429 /* initialize and add new packet. */
430 *is_new = 1;
431
432 /* Make it a broadcast packet, if required */
433 if (make_broadcast)
434 memcpy(packet->target_orig, broadcast_addr, ETH_ALEN);
435
436 /* repair if entries is longer than packet. */
437 if (packet->entries * sizeof(struct vis_info_entry) > vis_info_len)
438 packet->entries = vis_info_len / sizeof(struct vis_info_entry);
439
440 recv_list_add(bat_priv, &info->recv_list, packet->sender_orig);
441
442 /* try to add it */
443 hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
444 info);
445 if (hash_added < 0) {
446 /* did not work (for some reason) */
447 kref_put(&old_info->refcount, free_info);
448 info = NULL;
449 }
450
451 return info;
452}
453
454/* handle the server sync packet, forward if needed. */
455void receive_server_sync_packet(struct bat_priv *bat_priv,
456 struct vis_packet *vis_packet,
457 int vis_info_len)
458{
459 struct vis_info *info;
460 int is_new, make_broadcast;
461 int vis_server = atomic_read(&bat_priv->vis_mode);
462
463 make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC);
464
465 spin_lock_bh(&bat_priv->vis_hash_lock);
466 info = add_packet(bat_priv, vis_packet, vis_info_len,
467 &is_new, make_broadcast);
468 if (!info)
469 goto end;
470
471 /* only if we are server ourselves and packet is newer than the one in
472 * hash.*/
473 if (vis_server == VIS_TYPE_SERVER_SYNC && is_new)
474 send_list_add(bat_priv, info);
475end:
476 spin_unlock_bh(&bat_priv->vis_hash_lock);
477}
478
479/* handle an incoming client update packet and schedule forward if needed. */
480void receive_client_update_packet(struct bat_priv *bat_priv,
481 struct vis_packet *vis_packet,
482 int vis_info_len)
483{
484 struct vis_info *info;
485 struct vis_packet *packet;
486 int is_new;
487 int vis_server = atomic_read(&bat_priv->vis_mode);
488 int are_target = 0;
489
490 /* clients shall not broadcast. */
491 if (is_broadcast_ether_addr(vis_packet->target_orig))
492 return;
493
494 /* Are we the target for this VIS packet? */
495 if (vis_server == VIS_TYPE_SERVER_SYNC &&
496 is_my_mac(vis_packet->target_orig))
497 are_target = 1;
498
499 spin_lock_bh(&bat_priv->vis_hash_lock);
500 info = add_packet(bat_priv, vis_packet, vis_info_len,
501 &is_new, are_target);
502
503 if (!info)
504 goto end;
505 /* note that outdated packets will be dropped at this point. */
506
507 packet = (struct vis_packet *)info->skb_packet->data;
508
509 /* send only if we're the target server or ... */
510 if (are_target && is_new) {
511 packet->vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */
512 send_list_add(bat_priv, info);
513
514 /* ... we're not the recipient (and thus need to forward). */
515 } else if (!is_my_mac(packet->target_orig)) {
516 send_list_add(bat_priv, info);
517 }
518
519end:
520 spin_unlock_bh(&bat_priv->vis_hash_lock);
521}
522
523/* Walk the originators and find the VIS server with the best tq. Set the packet
524 * address to its address and return the best_tq.
525 *
526 * Must be called with the originator hash locked */
527static int find_best_vis_server(struct bat_priv *bat_priv,
528 struct vis_info *info)
529{
530 struct hashtable_t *hash = bat_priv->orig_hash;
531 struct hlist_node *walk;
532 struct hlist_head *head;
533 struct element_t *bucket;
534 struct orig_node *orig_node;
535 struct vis_packet *packet;
536 int best_tq = -1, i;
537
538 packet = (struct vis_packet *)info->skb_packet->data;
539
540 for (i = 0; i < hash->size; i++) {
541 head = &hash->table[i];
542
543 hlist_for_each_entry(bucket, walk, head, hlist) {
544 orig_node = bucket->data;
545 if ((orig_node) && (orig_node->router) &&
546 (orig_node->flags & VIS_SERVER) &&
547 (orig_node->router->tq_avg > best_tq)) {
548 best_tq = orig_node->router->tq_avg;
549 memcpy(packet->target_orig, orig_node->orig,
550 ETH_ALEN);
551 }
552 }
553 }
554
555 return best_tq;
556}
557
558/* Return true if the vis packet is full. */
559static bool vis_packet_full(struct vis_info *info)
560{
561 struct vis_packet *packet;
562 packet = (struct vis_packet *)info->skb_packet->data;
563
564 if (MAX_VIS_PACKET_SIZE / sizeof(struct vis_info_entry)
565 < packet->entries + 1)
566 return true;
567 return false;
568}
569
570/* generates a packet of own vis data,
571 * returns 0 on success, -1 if no packet could be generated */
572static int generate_vis_packet(struct bat_priv *bat_priv)
573{
574 struct hashtable_t *hash = bat_priv->orig_hash;
575 struct hlist_node *walk;
576 struct hlist_head *head;
577 struct element_t *bucket;
578 struct orig_node *orig_node;
579 struct neigh_node *neigh_node;
580 struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info;
581 struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
582 struct vis_info_entry *entry;
583 struct hna_local_entry *hna_local_entry;
584 int best_tq = -1, i;
585
586 info->first_seen = jiffies;
587 packet->vis_type = atomic_read(&bat_priv->vis_mode);
588
589 spin_lock_bh(&bat_priv->orig_hash_lock);
590 memcpy(packet->target_orig, broadcast_addr, ETH_ALEN);
591 packet->ttl = TTL;
592 packet->seqno = htonl(ntohl(packet->seqno) + 1);
593 packet->entries = 0;
594 skb_trim(info->skb_packet, sizeof(struct vis_packet));
595
596 if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) {
597 best_tq = find_best_vis_server(bat_priv, info);
598
599 if (best_tq < 0) {
600 spin_unlock_bh(&bat_priv->orig_hash_lock);
601 return -1;
602 }
603 }
604
605 for (i = 0; i < hash->size; i++) {
606 head = &hash->table[i];
607
608 hlist_for_each_entry(bucket, walk, head, hlist) {
609 orig_node = bucket->data;
610 neigh_node = orig_node->router;
611
612 if (!neigh_node)
613 continue;
614
615 if (!compare_orig(neigh_node->addr, orig_node->orig))
616 continue;
617
618 if (neigh_node->if_incoming->if_status != IF_ACTIVE)
619 continue;
620
621 if (neigh_node->tq_avg < 1)
622 continue;
623
624 /* fill one entry into buffer. */
625 entry = (struct vis_info_entry *)
626 skb_put(info->skb_packet, sizeof(*entry));
627 memcpy(entry->src,
628 neigh_node->if_incoming->net_dev->dev_addr,
629 ETH_ALEN);
630 memcpy(entry->dest, orig_node->orig, ETH_ALEN);
631 entry->quality = neigh_node->tq_avg;
632 packet->entries++;
633
634 if (vis_packet_full(info)) {
635 spin_unlock_bh(&bat_priv->orig_hash_lock);
636 return 0;
637 }
638 }
639 }
640
641 spin_unlock_bh(&bat_priv->orig_hash_lock);
642
643 hash = bat_priv->hna_local_hash;
644
645 spin_lock_bh(&bat_priv->hna_lhash_lock);
646 for (i = 0; i < hash->size; i++) {
647 head = &hash->table[i];
648
649 hlist_for_each_entry(bucket, walk, head, hlist) {
650 hna_local_entry = bucket->data;
651 entry = (struct vis_info_entry *)
652 skb_put(info->skb_packet,
653 sizeof(*entry));
654 memset(entry->src, 0, ETH_ALEN);
655 memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN);
656 entry->quality = 0; /* 0 means HNA */
657 packet->entries++;
658
659 if (vis_packet_full(info)) {
660 spin_unlock_bh(&bat_priv->hna_lhash_lock);
661 return 0;
662 }
663 }
664 }
665
666 spin_unlock_bh(&bat_priv->hna_lhash_lock);
667 return 0;
668}
669
670/* free old vis packets. Must be called with this vis_hash_lock
671 * held */
672static void purge_vis_packets(struct bat_priv *bat_priv)
673{
674 int i;
675 struct hashtable_t *hash = bat_priv->vis_hash;
676 struct hlist_node *walk, *safe;
677 struct hlist_head *head;
678 struct element_t *bucket;
679 struct vis_info *info;
680
681 for (i = 0; i < hash->size; i++) {
682 head = &hash->table[i];
683
684 hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
685 info = bucket->data;
686
687 /* never purge own data. */
688 if (info == bat_priv->my_vis_info)
689 continue;
690
691 if (time_after(jiffies,
692 info->first_seen + VIS_TIMEOUT * HZ)) {
693 hlist_del(walk);
694 kfree(bucket);
695 send_list_del(info);
696 kref_put(&info->refcount, free_info);
697 }
698 }
699 }
700}
701
702static void broadcast_vis_packet(struct bat_priv *bat_priv,
703 struct vis_info *info)
704{
705 struct hashtable_t *hash = bat_priv->orig_hash;
706 struct hlist_node *walk;
707 struct hlist_head *head;
708 struct element_t *bucket;
709 struct orig_node *orig_node;
710 struct vis_packet *packet;
711 struct sk_buff *skb;
712 struct batman_if *batman_if;
713 uint8_t dstaddr[ETH_ALEN];
714 int i;
715
716
717 spin_lock_bh(&bat_priv->orig_hash_lock);
718 packet = (struct vis_packet *)info->skb_packet->data;
719
720 /* send to all routers in range. */
721 for (i = 0; i < hash->size; i++) {
722 head = &hash->table[i];
723
724 hlist_for_each_entry(bucket, walk, head, hlist) {
725 orig_node = bucket->data;
726
727 /* if it's a vis server and reachable, send it. */
728 if ((!orig_node) || (!orig_node->router))
729 continue;
730 if (!(orig_node->flags & VIS_SERVER))
731 continue;
732 /* don't send it if we already received the packet from
733 * this node. */
734 if (recv_list_is_in(bat_priv, &info->recv_list,
735 orig_node->orig))
736 continue;
737
738 memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
739 batman_if = orig_node->router->if_incoming;
740 memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
741 spin_unlock_bh(&bat_priv->orig_hash_lock);
742
743 skb = skb_clone(info->skb_packet, GFP_ATOMIC);
744 if (skb)
745 send_skb_packet(skb, batman_if, dstaddr);
746
747 spin_lock_bh(&bat_priv->orig_hash_lock);
748 }
749
750 }
751
752 spin_unlock_bh(&bat_priv->orig_hash_lock);
753}
754
755static void unicast_vis_packet(struct bat_priv *bat_priv,
756 struct vis_info *info)
757{
758 struct orig_node *orig_node;
759 struct sk_buff *skb;
760 struct vis_packet *packet;
761 struct batman_if *batman_if;
762 uint8_t dstaddr[ETH_ALEN];
763
764 spin_lock_bh(&bat_priv->orig_hash_lock);
765 packet = (struct vis_packet *)info->skb_packet->data;
766 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
767 compare_orig, choose_orig,
768 packet->target_orig));
769
770 if ((!orig_node) || (!orig_node->router))
771 goto out;
772
773 /* don't lock while sending the packets ... we therefore
774 * copy the required data before sending */
775 batman_if = orig_node->router->if_incoming;
776 memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
777 spin_unlock_bh(&bat_priv->orig_hash_lock);
778
779 skb = skb_clone(info->skb_packet, GFP_ATOMIC);
780 if (skb)
781 send_skb_packet(skb, batman_if, dstaddr);
782
783 return;
784
785out:
786 spin_unlock_bh(&bat_priv->orig_hash_lock);
787}
788
789/* only send one vis packet. called from send_vis_packets() */
790static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
791{
792 struct vis_packet *packet;
793
794 packet = (struct vis_packet *)info->skb_packet->data;
795 if (packet->ttl < 2) {
796 pr_debug("Error - can't send vis packet: ttl exceeded\n");
797 return;
798 }
799
800 memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr,
801 ETH_ALEN);
802 packet->ttl--;
803
804 if (is_broadcast_ether_addr(packet->target_orig))
805 broadcast_vis_packet(bat_priv, info);
806 else
807 unicast_vis_packet(bat_priv, info);
808 packet->ttl++; /* restore TTL */
809}
810
811/* called from timer; send (and maybe generate) vis packet. */
812static void send_vis_packets(struct work_struct *work)
813{
814 struct delayed_work *delayed_work =
815 container_of(work, struct delayed_work, work);
816 struct bat_priv *bat_priv =
817 container_of(delayed_work, struct bat_priv, vis_work);
818 struct vis_info *info, *temp;
819
820 spin_lock_bh(&bat_priv->vis_hash_lock);
821 purge_vis_packets(bat_priv);
822
823 if (generate_vis_packet(bat_priv) == 0) {
824 /* schedule if generation was successful */
825 send_list_add(bat_priv, bat_priv->my_vis_info);
826 }
827
828 list_for_each_entry_safe(info, temp, &bat_priv->vis_send_list,
829 send_list) {
830
831 kref_get(&info->refcount);
832 spin_unlock_bh(&bat_priv->vis_hash_lock);
833
834 if (bat_priv->primary_if)
835 send_vis_packet(bat_priv, info);
836
837 spin_lock_bh(&bat_priv->vis_hash_lock);
838 send_list_del(info);
839 kref_put(&info->refcount, free_info);
840 }
841 spin_unlock_bh(&bat_priv->vis_hash_lock);
842 start_vis_timer(bat_priv);
843}
844
845/* init the vis server. this may only be called when if_list is already
846 * initialized (e.g. bat0 is initialized, interfaces have been added) */
847int vis_init(struct bat_priv *bat_priv)
848{
849 struct vis_packet *packet;
850 int hash_added;
851
852 if (bat_priv->vis_hash)
853 return 1;
854
855 spin_lock_bh(&bat_priv->vis_hash_lock);
856
857 bat_priv->vis_hash = hash_new(256);
858 if (!bat_priv->vis_hash) {
859 pr_err("Can't initialize vis_hash\n");
860 goto err;
861 }
862
863 bat_priv->my_vis_info = kmalloc(MAX_VIS_PACKET_SIZE, GFP_ATOMIC);
864 if (!bat_priv->my_vis_info) {
865 pr_err("Can't initialize vis packet\n");
866 goto err;
867 }
868
869 bat_priv->my_vis_info->skb_packet = dev_alloc_skb(
870 sizeof(struct vis_packet) +
871 MAX_VIS_PACKET_SIZE +
872 sizeof(struct ethhdr));
873 if (!bat_priv->my_vis_info->skb_packet)
874 goto free_info;
875
876 skb_reserve(bat_priv->my_vis_info->skb_packet, sizeof(struct ethhdr));
877 packet = (struct vis_packet *)skb_put(
878 bat_priv->my_vis_info->skb_packet,
879 sizeof(struct vis_packet));
880
881 /* prefill the vis info */
882 bat_priv->my_vis_info->first_seen = jiffies -
883 msecs_to_jiffies(VIS_INTERVAL);
884 INIT_LIST_HEAD(&bat_priv->my_vis_info->recv_list);
885 INIT_LIST_HEAD(&bat_priv->my_vis_info->send_list);
886 kref_init(&bat_priv->my_vis_info->refcount);
887 bat_priv->my_vis_info->bat_priv = bat_priv;
888 packet->version = COMPAT_VERSION;
889 packet->packet_type = BAT_VIS;
890 packet->ttl = TTL;
891 packet->seqno = 0;
892 packet->entries = 0;
893
894 INIT_LIST_HEAD(&bat_priv->vis_send_list);
895
896 hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
897 bat_priv->my_vis_info);
898 if (hash_added < 0) {
899 pr_err("Can't add own vis packet into hash\n");
900 /* not in hash, need to remove it manually. */
901 kref_put(&bat_priv->my_vis_info->refcount, free_info);
902 goto err;
903 }
904
905 spin_unlock_bh(&bat_priv->vis_hash_lock);
906 start_vis_timer(bat_priv);
907 return 1;
908
909free_info:
910 kfree(bat_priv->my_vis_info);
911 bat_priv->my_vis_info = NULL;
912err:
913 spin_unlock_bh(&bat_priv->vis_hash_lock);
914 vis_quit(bat_priv);
915 return 0;
916}
917
918/* Decrease the reference count on a hash item info */
919static void free_info_ref(void *data, void *arg)
920{
921 struct vis_info *info = data;
922
923 send_list_del(info);
924 kref_put(&info->refcount, free_info);
925}
926
927/* shutdown vis-server */
928void vis_quit(struct bat_priv *bat_priv)
929{
930 if (!bat_priv->vis_hash)
931 return;
932
933 cancel_delayed_work_sync(&bat_priv->vis_work);
934
935 spin_lock_bh(&bat_priv->vis_hash_lock);
936 /* properly remove, kill timers ... */
937 hash_delete(bat_priv->vis_hash, free_info_ref, NULL);
938 bat_priv->vis_hash = NULL;
939 bat_priv->my_vis_info = NULL;
940 spin_unlock_bh(&bat_priv->vis_hash_lock);
941}
942
943/* schedule packets for (re)transmission */
944static void start_vis_timer(struct bat_priv *bat_priv)
945{
946 INIT_DELAYED_WORK(&bat_priv->vis_work, send_vis_packets);
947 queue_delayed_work(bat_event_workqueue, &bat_priv->vis_work,
948 msecs_to_jiffies(VIS_INTERVAL));
949}
diff --git a/net/batman-adv/vis.h b/net/batman-adv/vis.h
new file mode 100644
index 000000000000..2c3b33089a9b
--- /dev/null
+++ b/net/batman-adv/vis.h
@@ -0,0 +1,37 @@
1/*
2 * Copyright (C) 2008-2010 B.A.T.M.A.N. contributors:
3 *
4 * Simon Wunderlich, Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#ifndef _NET_BATMAN_ADV_VIS_H_
23#define _NET_BATMAN_ADV_VIS_H_
24
25#define VIS_TIMEOUT 200 /* timeout of vis packets in seconds */
26
27int vis_seq_print_text(struct seq_file *seq, void *offset);
28void receive_server_sync_packet(struct bat_priv *bat_priv,
29 struct vis_packet *vis_packet,
30 int vis_info_len);
31void receive_client_update_packet(struct bat_priv *bat_priv,
32 struct vis_packet *vis_packet,
33 int vis_info_len);
34int vis_init(struct bat_priv *bat_priv);
35void vis_quit(struct bat_priv *bat_priv);
36
37#endif /* _NET_BATMAN_ADV_VIS_H_ */