aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Lunn <andrew@lunn.ch>2009-11-09 15:20:10 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 15:23:22 -0500
commit5beef3c9bf7f967a4a70ddb0108fd3e459fed133 (patch)
treeef6e8f8e9b7a7febef2e478139b38f92b93e4ef2
parent6638db58dbb831fa66ac583644d34ae3cf662431 (diff)
staging: 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. This is the first submission for inclusion in staging. Signed-off-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/batman-adv/CHANGELOG37
-rw-r--r--drivers/staging/batman-adv/Kconfig25
-rw-r--r--drivers/staging/batman-adv/Makefile22
-rw-r--r--drivers/staging/batman-adv/README125
-rw-r--r--drivers/staging/batman-adv/TODO51
-rw-r--r--drivers/staging/batman-adv/aggregation.c232
-rw-r--r--drivers/staging/batman-adv/aggregation.h37
-rw-r--r--drivers/staging/batman-adv/bitarray.c177
-rw-r--r--drivers/staging/batman-adv/bitarray.h45
-rw-r--r--drivers/staging/batman-adv/compat.h75
-rw-r--r--drivers/staging/batman-adv/device.c337
-rw-r--r--drivers/staging/batman-adv/device.h36
-rw-r--r--drivers/staging/batman-adv/hard-interface.c451
-rw-r--r--drivers/staging/batman-adv/hard-interface.h36
-rw-r--r--drivers/staging/batman-adv/hash.c313
-rw-r--r--drivers/staging/batman-adv/hash.h99
-rw-r--r--drivers/staging/batman-adv/log.c179
-rw-r--r--drivers/staging/batman-adv/log.h32
-rw-r--r--drivers/staging/batman-adv/main.c286
-rw-r--r--drivers/staging/batman-adv/main.h151
-rw-r--r--drivers/staging/batman-adv/packet.h96
-rw-r--r--drivers/staging/batman-adv/proc.c950
-rw-r--r--drivers/staging/batman-adv/proc.h49
-rw-r--r--drivers/staging/batman-adv/ring_buffer.c52
-rw-r--r--drivers/staging/batman-adv/ring_buffer.h23
-rw-r--r--drivers/staging/batman-adv/routing.c1010
-rw-r--r--drivers/staging/batman-adv/routing.h34
-rw-r--r--drivers/staging/batman-adv/send.c473
-rw-r--r--drivers/staging/batman-adv/send.h36
-rw-r--r--drivers/staging/batman-adv/soft-interface.c349
-rw-r--r--drivers/staging/batman-adv/soft-interface.h33
-rw-r--r--drivers/staging/batman-adv/translation-table.c454
-rw-r--r--drivers/staging/batman-adv/translation-table.h42
-rw-r--r--drivers/staging/batman-adv/types.h124
-rw-r--r--drivers/staging/batman-adv/vis.c564
-rw-r--r--drivers/staging/batman-adv/vis.h63
38 files changed, 7101 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 6fbbedbc7fe7..d30fa451e6f3 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -129,6 +129,8 @@ source "drivers/staging/wlags49_h2/Kconfig"
129 129
130source "drivers/staging/wlags49_h25/Kconfig" 130source "drivers/staging/wlags49_h25/Kconfig"
131 131
132source "drivers/staging/batman-adv/Kconfig"
133
132source "drivers/staging/strip/Kconfig" 134source "drivers/staging/strip/Kconfig"
133 135
134source "drivers/staging/arlan/Kconfig" 136source "drivers/staging/arlan/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 61a81c148c9f..910e55dd7914 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_IIO) += iio/
46obj-$(CONFIG_RAMZSWAP) += ramzswap/ 46obj-$(CONFIG_RAMZSWAP) += ramzswap/
47obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ 47obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
48obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ 48obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
49obj-$(CONFIG_BATMAN_ADV) += batman-adv/
49obj-$(CONFIG_STRIP) += strip/ 50obj-$(CONFIG_STRIP) += strip/
50obj-$(CONFIG_ARLAN) += arlan/ 51obj-$(CONFIG_ARLAN) += arlan/
51obj-$(CONFIG_WAVELAN) += wavelan/ 52obj-$(CONFIG_WAVELAN) += wavelan/
diff --git a/drivers/staging/batman-adv/CHANGELOG b/drivers/staging/batman-adv/CHANGELOG
new file mode 100644
index 000000000000..8a181639ceaa
--- /dev/null
+++ b/drivers/staging/batman-adv/CHANGELOG
@@ -0,0 +1,37 @@
1batman-adv 0.2:
2
3* support latest kernels (2.6.20 - 2.6.31)
4* temporary routing loops / TTL code bug / ghost entries in originator table fixed
5* internal packet queue for packet aggregation & transmission retry (ARQ)
6 for payload broadcasts added
7* interface detection converted to event based handling to avoid timers
8* major linux coding style adjustments applied
9* all kernel version compatibility functions has been moved to compat.h
10* use random ethernet address generator from the kernel
11* /sys/module/batman_adv/version to export kernel module version
12* vis: secondary interface export for dot draw format + JSON output format added
13* many bugs (alignment issues, race conditions, deadlocks, etc) squashed
14
15 -- Sat, 07 Nov 2009 15:44:31 +0100
16
17batman-adv 0.1:
18
19* support latest kernels (2.6.20 - 2.6.28)
20* LOTS of cleanup: locking, stack usage, memory leaks
21* Change Ethertype from 0x0842 to 0x4305
22 unregistered at IEEE, if you want to sponsor an official Ethertype ($2500)
23 please contact us
24
25 -- Sun, 28 Dec 2008 00:44:31 +0100
26
27batman-adv 0.1-beta:
28
29* layer 2 meshing based on BATMAN TQ algorithm in kernelland
30* operates on any ethernet like interface
31* supports IPv4, IPv6, DHCP, etc
32* is controlled via /proc/net/batman-adv/
33* bridging via brctl is supported
34* interface watchdog (interfaces can be (de)activated dynamically)
35* offers integrated vis server which meshes/syncs with other vis servers in range
36
37 -- Mon, 05 May 2008 14:10:04 +0200
diff --git a/drivers/staging/batman-adv/Kconfig b/drivers/staging/batman-adv/Kconfig
new file mode 100644
index 000000000000..b9742e7c7d9e
--- /dev/null
+++ b/drivers/staging/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 default n
8 ---help---
9
10 B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
11 a routing protocol for multi-hop ad-hoc mesh networks. The
12 networks may be wired or wireless. See
13 http://www.open-mesh.org/ for more information and user space
14 tools.
15
16config BATMAN_DEBUG
17 bool "B.A.T.M.A.N. debugging"
18 depends on BATMAN != n
19 help
20
21 This is an option for use by developers; most people should
22 say N here. This enables compilation of support for
23 outputting debugging information to the kernel log. The
24 output is controlled via the module parameter debug.
25
diff --git a/drivers/staging/batman-adv/Makefile b/drivers/staging/batman-adv/Makefile
new file mode 100644
index 000000000000..02da87134fce
--- /dev/null
+++ b/drivers/staging/batman-adv/Makefile
@@ -0,0 +1,22 @@
1#
2# Copyright (C) 2007-2009 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-m += batman-adv.o
22batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o log.o
diff --git a/drivers/staging/batman-adv/README b/drivers/staging/batman-adv/README
new file mode 100644
index 000000000000..3aaf393ebaa7
--- /dev/null
+++ b/drivers/staging/batman-adv/README
@@ -0,0 +1,125 @@
1[state: 07-11-2009]
2
3BATMAN-ADV
4----------
5
6Batman-advanced is a new approach to wireless networking which does no longer
7operate on the IP basis. Unlike B.A.T.M.A.N, which exchanges information
8using UDP packets and sets routing tables, batman-advanced operates on ISO/OSI
9Layer 2 only and uses and routes (or better: bridges) Ethernet Frames. It
10emulates a virtual network switch of all nodes participating. Therefore all
11nodes appear to be link local, thus all higher operating protocols won't be
12affected by any changes within the network. You can run almost any protocol
13above B.A.T.M.A.N. Advanced, prominent examples are: IPv4, IPv6, DHCP, IPX.
14
15This is batman-advanced implemented as Linux kernel driver. It does not depend
16on any network (other) driver, and can be used on wifi as well as ethernet,
17vpn, etc ... (anything with ethernet-style layer 2).
18It compiles against and should work with Linux 2.6.20 - 2.6.31. Supporting older
19versions is not planned, but it's probably easy to backport it. If you work on a
20backport, feel free to contact us. :-)
21
22COMPILE
23-------
24To compile against your currently installed kernel, just type:
25
26# make
27
28if you want to compile against some other kernel, use:
29
30# make KERNELPATH=/path/to/kernel
31
32USAGE
33-----
34
35insmod the batman-adv.ko in your kernel:
36
37# insmod batman-adv.ko
38
39the module is now waiting for activation. You must add some interfaces
40on which batman can operate. Each interface must be added separately:
41
42# echo wlan0 > /proc/net/batman-adv/interfaces
43
44( # echo wlan1 > /proc/net/batman-adv/interfaces )
45( # echo eth0 > /proc/net/batman-adv/interfaces )
46( ... )
47
48Now batman starts broadcasting on this interface.
49You can now view the table of originators (mesh participants) with:
50
51# cat /proc/net/batman-adv/originators
52
53The module will create a new interface "bat0", which can be used as a
54regular interface:
55
56# ifconfig bat0 inet 192.168.0.1 up
57# ping 192.168.0.2
58...
59
60If you want topology visualization, your meshnode must be configured
61as VIS-server:
62
63# echo "server" > /proc/net/batman-adv/vis
64
65Each node is either configured as "server" or as "client" (default:
66"client"). Clients send their topology data to the server next to them,
67and server synchronize with other servers. If there is no server
68configured (default) within the mesh, no topology information will be
69transmitted. With these "synchronizing servers", there can be 1 or
70more vis servers sharing the same (or at least very similar) data.
71
72When configured as server, you can get a topology snapshot of your mesh:
73
74# cat /proc/net/batman-adv/vis
75
76This output format is a graphviz formatted text file which can be
77processed with graphviz-tools like dot.
78The labels are similar/compatible to the ETX metric, 1.0 means perfect
79connection (100%), 2.0 means 50%, 3.0 means 33% and so on.
80
81Alternatively, a JSON output format is available. The format can be set
82using by writing either "dot_draw" or "json" into the vis_format file.
83"dot_draw" is selected by default.
84
85echo "json" > /proc/net/batman-adv/vis_format
86
87In very mobile scenarios, you might want to adjust the originator
88interval to a lower value. This will make the mesh more responsive to
89topology changes, but will also increase the overhead. Please make sure
90that all nodes in your mesh use the same interval. The default value
91is 1000 ms (1 second).
92
93# echo 1000 > /proc/net/batman-adv/orig_interval
94
95To deactivate batman, do:
96
97# echo "" > /proc/net/batman-adv/interfaces
98
99BATCTL
100------
101
102B.A.T.M.A.N. advanced operates on layer 2 and thus all hosts partici-
103pating in the virtual switch are completely transparent for all proto-
104cols above layer 2. Therefore the common diagnosis tools do not work as
105expected. To overcome these problems batctl was created. At the moment
106the batctl contains ping, traceroute, tcpdump and interfaces to the
107kernel module settings.
108
109For more information, please see the manpage (man batctl).
110
111batctl is available on http://www.open-mesh.net/
112
113CONTACT
114-------
115
116Please send us comments, experiences, questions, anything :)
117
118IRC: #batman on irc.freenode.org
119Mailing-list: b.a.t.m.a.n@open-mesh.net
120(subscription at https://list.open-mesh.net/mm/listinfo/b.a.t.m.a.n )
121
122You can also contact the Authors:
123
124Marek Lindner <lindner_marek@yahoo.de>
125Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO
new file mode 100644
index 000000000000..ea6dcf94d661
--- /dev/null
+++ b/drivers/staging/batman-adv/TODO
@@ -0,0 +1,51 @@
1=> proc interface
2* implement new interface to add/delete interfaces and setting options
3* /proc/sys/net/batman-adv/ as main folder
4* in interfaces/ list every available interface of the host
5* each interfaces/$iface/ contains the following files:
6-> enable (def: 0) [add/remove this interface to batman-adv]
7-> ogm_interval (def: 1000) [ogm interval of that interface]
8-> context (def: bat0) [later we want to support multiple mesh instances via
9-> bat0/bat1/bat2/..]
10-> status (read-only) [outputs the interface status from batman's
11-> perspective]
12* in mesh/batX/ list every available mesh subnet
13-> vis_server (def: 0) [enable/disable vis server for that mesh]
14-> vis_data (read-only) [outputs the vis data in a raw format]
15-> aggregate_ogm (def: 1) [enable/disable ogm aggregation for that mesh]
16-> originators (read-only) [outputs the originator table]
17-> transtable_global (read-only) [outputs the global translation table]
18-> transtable_local (read-only) [outputs the local translation table]
19
20=> vis "raw" data output
21* the raw format shall replace dot draw / json to offer a neutral that can
22* be converted
23* the format (comma seperated entries):
24-> "mac" -> mac address of an originator (each line begins with it)
25-> "TQ mac value" -> src mac's link quality towards mac address
26-> "HNA mac" -> HNA announced by source mac
27-> "PRIMARY" -> this is a primary interface
28-> "SEC mac" -> secondary mac address of source (requires preceeding
29-> PRIMARY)
30
31=> logging
32* the log level LOG_TYPE_CRIT, LOG_TYPE_WARN & LOG_TYPE_NOTICE will be
33* unified to use printk
34* LOG_TYPE_BATMAN & LOG_TYPE_ROUTES will also use printk but only after the
35* internal debug level has been raised
36* the internal debug level can be modified using a module parameter (debug)
37* or at run time via /sys/module/batman-adv/parameters/debug
38* make use of printk %pM support instead of converting mac addresses
39* manually
40
41=> strip out all backward compatibility support to older kernels
42 (only found in compat.h)
43
44=> fix checkpatch.pl errors
45
46Please send all patches to:
47 Marek Lindner <lindner_marek@yahoo.de>
48 Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
49 Andrew Lunn <andrew@lunn.ch>
50 b.a.t.m.a.n@lists.open-mesh.net
51 Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/batman-adv/aggregation.c b/drivers/staging/batman-adv/aggregation.c
new file mode 100644
index 000000000000..9c6e681f6fb6
--- /dev/null
+++ b/drivers/staging/batman-adv/aggregation.c
@@ -0,0 +1,232 @@
1/*
2 * Copyright (C) 2007-2009 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->packet_buff;
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 (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
56
57 /**
58 * check aggregation compatibility
59 * -> direct link packets are broadcasted on
60 * their interface only
61 * -> aggregate packet if the current packet is
62 * a "global" packet as well as the base
63 * packet
64 */
65
66 /* packets without direct link flag and high TTL
67 * are flooded through the net */
68 if ((!directlink) &&
69 (!(batman_packet->flags & DIRECTLINK)) &&
70 (batman_packet->ttl != 1) &&
71
72 /* own packets originating non-primary
73 * interfaces leave only that interface */
74 ((!forw_packet->own) ||
75 (forw_packet->if_incoming->if_num == 0)))
76 return true;
77
78 /* if the incoming packet is sent via this one
79 * interface only - we still can aggregate */
80 if ((directlink) &&
81 (new_batman_packet->ttl == 1) &&
82 (forw_packet->if_incoming == if_incoming))
83 return true;
84
85 }
86
87 return false;
88}
89
90/* create a new aggregated packet and add this packet to it */
91static void new_aggregated_packet(unsigned char *packet_buff,
92 int packet_len,
93 unsigned long send_time,
94 bool direct_link,
95 struct batman_if *if_incoming,
96 int own_packet)
97{
98 struct forw_packet *forw_packet_aggr;
99
100 forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
101 if (!forw_packet_aggr)
102 return;
103
104 forw_packet_aggr->packet_buff = kmalloc(MAX_AGGREGATION_BYTES,
105 GFP_ATOMIC);
106 if (!forw_packet_aggr->packet_buff) {
107 kfree(forw_packet_aggr);
108 return;
109 }
110
111 INIT_HLIST_NODE(&forw_packet_aggr->list);
112
113 forw_packet_aggr->packet_len = packet_len;
114 memcpy(forw_packet_aggr->packet_buff,
115 packet_buff,
116 forw_packet_aggr->packet_len);
117
118 forw_packet_aggr->own = own_packet;
119 forw_packet_aggr->if_incoming = if_incoming;
120 forw_packet_aggr->num_packets = 0;
121 forw_packet_aggr->direct_link_flags = 0;
122 forw_packet_aggr->send_time = send_time;
123
124 /* save packet direct link flag status */
125 if (direct_link)
126 forw_packet_aggr->direct_link_flags |= 1;
127
128 /* add new packet to packet list */
129 spin_lock(&forw_bat_list_lock);
130 hlist_add_head(&forw_packet_aggr->list, &forw_bat_list);
131 spin_unlock(&forw_bat_list_lock);
132
133 /* start timer for this packet */
134 INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
135 send_outstanding_bat_packet);
136 queue_delayed_work(bat_event_workqueue,
137 &forw_packet_aggr->delayed_work,
138 send_time - jiffies);
139}
140
141/* aggregate a new packet into the existing aggregation */
142static void aggregate(struct forw_packet *forw_packet_aggr,
143 unsigned char *packet_buff,
144 int packet_len,
145 bool direct_link)
146{
147 memcpy((forw_packet_aggr->packet_buff + forw_packet_aggr->packet_len),
148 packet_buff, packet_len);
149 forw_packet_aggr->packet_len += packet_len;
150 forw_packet_aggr->num_packets++;
151
152 /* save packet direct link flag status */
153 if (direct_link)
154 forw_packet_aggr->direct_link_flags |=
155 (1 << forw_packet_aggr->num_packets);
156}
157
158void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len,
159 struct batman_if *if_incoming, char own_packet,
160 unsigned long send_time)
161{
162 /**
163 * _aggr -> pointer to the packet we want to aggregate with
164 * _pos -> pointer to the position in the queue
165 */
166 struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
167 struct hlist_node *tmp_node;
168 struct batman_packet *batman_packet =
169 (struct batman_packet *)packet_buff;
170 bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
171
172 /* find position for the packet in the forward queue */
173 spin_lock(&forw_bat_list_lock);
174 /* own packets are not to be aggregated */
175 if ((atomic_read(&aggregation_enabled)) && (!own_packet)) {
176 hlist_for_each_entry(forw_packet_pos, tmp_node, &forw_bat_list,
177 list) {
178 if (can_aggregate_with(batman_packet,
179 packet_len,
180 send_time,
181 direct_link,
182 if_incoming,
183 forw_packet_pos)) {
184 forw_packet_aggr = forw_packet_pos;
185 break;
186 }
187 }
188 }
189
190 /* nothing to aggregate with - either aggregation disabled or no
191 * suitable aggregation packet found */
192 if (forw_packet_aggr == NULL) {
193 /* the following section can run without the lock */
194 spin_unlock(&forw_bat_list_lock);
195 new_aggregated_packet(packet_buff, packet_len,
196 send_time, direct_link,
197 if_incoming, own_packet);
198 } else {
199 aggregate(forw_packet_aggr,
200 packet_buff, packet_len,
201 direct_link);
202 spin_unlock(&forw_bat_list_lock);
203 }
204}
205
206/* unpack the aggregated packets and process them one by one */
207void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
208 int packet_len, struct batman_if *if_incoming)
209{
210 struct batman_packet *batman_packet;
211 int buff_pos = 0;
212 unsigned char *hna_buff;
213
214 batman_packet = (struct batman_packet *)packet_buff;
215
216 while (aggregated_packet(buff_pos, packet_len,
217 batman_packet->num_hna)) {
218
219 /* network to host order for our 16bit seqno, and the
220 orig_interval. */
221 batman_packet->seqno = ntohs(batman_packet->seqno);
222
223 hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
224 receive_bat_packet(ethhdr, batman_packet,
225 hna_buff, hna_len(batman_packet),
226 if_incoming);
227
228 buff_pos += BAT_PACKET_LEN + hna_len(batman_packet);
229 batman_packet = (struct batman_packet *)
230 (packet_buff + buff_pos);
231 }
232}
diff --git a/drivers/staging/batman-adv/aggregation.h b/drivers/staging/batman-adv/aggregation.h
new file mode 100644
index 000000000000..6da8df9f99b7
--- /dev/null
+++ b/drivers/staging/batman-adv/aggregation.h
@@ -0,0 +1,37 @@
1/*
2 * Copyright (C) 2007-2009 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
24/* is there another aggregated packet here? */
25static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna)
26{
27 int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN);
28
29 return (next_buff_pos <= packet_len) &&
30 (next_buff_pos <= MAX_AGGREGATION_BYTES);
31}
32
33void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len,
34 struct batman_if *if_outgoing, char own_packet,
35 unsigned long send_time);
36void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
37 int packet_len, struct batman_if *if_incoming);
diff --git a/drivers/staging/batman-adv/bitarray.c b/drivers/staging/batman-adv/bitarray.c
new file mode 100644
index 000000000000..3c67f5f42b2b
--- /dev/null
+++ b/drivers/staging/batman-adv/bitarray.c
@@ -0,0 +1,177 @@
1/*
2 * Copyright (C) 2006-2009 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#include "log.h"
25
26/* returns true if the corresponding bit in the given seq_bits indicates true
27 * and curr_seqno is within range of last_seqno */
28uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint16_t last_seqno,
29 uint16_t curr_seqno)
30{
31 int16_t diff, word_offset, word_num;
32
33 diff = last_seqno - curr_seqno;
34 if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) {
35 return 0;
36 } else {
37 /* which word */
38 word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE;
39 /* which position in the selected word */
40 word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE;
41
42 if (seq_bits[word_num] & 1 << word_offset)
43 return 1;
44 else
45 return 0;
46 }
47}
48
49/* turn corresponding bit on, so we can remember that we got the packet */
50void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n)
51{
52 int32_t word_offset, word_num;
53
54 /* if too old, just drop it */
55 if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE)
56 return;
57
58 /* which word */
59 word_num = n / WORD_BIT_SIZE;
60 /* which position in the selected word */
61 word_offset = n % WORD_BIT_SIZE;
62
63 seq_bits[word_num] |= 1 << word_offset; /* turn the position on */
64}
65
66/* shift the packet array by n places. */
67void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n)
68{
69 int32_t word_offset, word_num;
70 int32_t i;
71
72 if (n <= 0)
73 return;
74
75 word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */
76 word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */
77
78 for (i = NUM_WORDS - 1; i > word_num; i--) {
79 /* going from old to new, so we don't overwrite the data we copy
80 * from.
81 *
82 * left is high, right is low: FEDC BA98 7654 3210
83 * ^^ ^^
84 * vvvv
85 * ^^^^ = from, vvvvv =to, we'd have word_num==1 and
86 * word_offset==WORD_BIT_SIZE/2 ????? in this example.
87 * (=24 bits)
88 *
89 * our desired output would be: 9876 5432 1000 0000
90 * */
91
92 seq_bits[i] =
93 (seq_bits[i - word_num] << word_offset) +
94 /* take the lower port from the left half, shift it left
95 * to its final position */
96 (seq_bits[i - word_num - 1] >>
97 (WORD_BIT_SIZE-word_offset));
98 /* and the upper part of the right half and shift it left to
99 * it's position */
100 /* for our example that would be: word[0] = 9800 + 0076 =
101 * 9876 */
102 }
103 /* now for our last word, i==word_num, we only have the it's "left"
104 * half. that's the 1000 word in our example.*/
105
106 seq_bits[i] = (seq_bits[i - word_num] << word_offset);
107
108 /* pad the rest with 0, if there is anything */
109 i--;
110
111 for (; i >= 0; i--)
112 seq_bits[i] = 0;
113}
114
115
116/* receive and process one packet, returns 1 if received seq_num is considered
117 * new, 0 if old */
118char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
119 int8_t set_mark)
120{
121 int i;
122
123 /* we already got a sequence number higher than this one, so we just
124 * mark it. this should wrap around the integer just fine */
125 if ((seq_num_diff < 0) && (seq_num_diff >= -TQ_LOCAL_WINDOW_SIZE)) {
126 if (set_mark)
127 bit_mark(seq_bits, -seq_num_diff);
128 return 0;
129 }
130
131 /* it seems we missed a lot of packets or the other host restarted */
132 if ((seq_num_diff > TQ_LOCAL_WINDOW_SIZE) ||
133 (seq_num_diff < -TQ_LOCAL_WINDOW_SIZE)) {
134
135 if (seq_num_diff > TQ_LOCAL_WINDOW_SIZE)
136 debug_log(LOG_TYPE_BATMAN,
137 "We missed a lot of packets (%i) !\n",
138 seq_num_diff-1);
139
140 if (-seq_num_diff > TQ_LOCAL_WINDOW_SIZE)
141 debug_log(LOG_TYPE_BATMAN,
142 "Other host probably restarted !\n");
143
144 for (i = 0; i < NUM_WORDS; i++)
145 seq_bits[i] = 0;
146
147 if (set_mark)
148 seq_bits[0] = 1; /* we only have the latest packet */
149 } else {
150 bit_shift(seq_bits, seq_num_diff);
151
152 if (set_mark)
153 bit_mark(seq_bits, 0);
154 }
155
156 return 1;
157}
158
159/* count the hamming weight, how many good packets did we receive? just count
160 * the 1's. The inner loop uses the Kernighan algorithm, see
161 * http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
162 */
163int bit_packet_count(TYPE_OF_WORD *seq_bits)
164{
165 int i, hamming = 0;
166 TYPE_OF_WORD word;
167
168 for (i = 0; i < NUM_WORDS; i++) {
169 word = seq_bits[i];
170
171 while (word) {
172 word &= word-1;
173 hamming++;
174 }
175 }
176 return hamming;
177}
diff --git a/drivers/staging/batman-adv/bitarray.h b/drivers/staging/batman-adv/bitarray.h
new file mode 100644
index 000000000000..ec72dd784362
--- /dev/null
+++ b/drivers/staging/batman-adv/bitarray.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2006-2009 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
23/* you should choose something big, if you don't want to waste cpu */
24#define TYPE_OF_WORD unsigned long
25#define WORD_BIT_SIZE (sizeof(TYPE_OF_WORD) * 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(TYPE_OF_WORD *seq_bits, uint16_t last_seqno,
30 uint16_t curr_seqno);
31
32/* turn corresponding bit on, so we can remember that we got the packet */
33void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n);
34
35/* shift the packet array by n places. */
36void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n);
37
38
39/* receive and process one packet, returns 1 if received seq_num is considered
40 * new, 0 if old */
41char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
42 int8_t set_mark);
43
44/* count the hamming weight, how many good packets did we receive? */
45int bit_packet_count(TYPE_OF_WORD *seq_bits);
diff --git a/drivers/staging/batman-adv/compat.h b/drivers/staging/batman-adv/compat.h
new file mode 100644
index 000000000000..f4e0a4564ba7
--- /dev/null
+++ b/drivers/staging/batman-adv/compat.h
@@ -0,0 +1,75 @@
1/*
2 * Copyright (C) 2007-2009 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 * This file contains macros for maintaining compatibility with older versions
22 * of the Linux kernel.
23 */
24
25#include <linux/version.h> /* LINUX_VERSION_CODE */
26
27#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
28
29#define skb_set_network_header(_skb, _offset) \
30 do { (_skb)->nh.raw = (_skb)->data + (_offset); } while (0)
31
32#define skb_reset_mac_header(_skb) \
33 do { (_skb)->mac.raw = (_skb)->data; } while (0)
34
35#define list_first_entry(ptr, type, member) \
36 list_entry((ptr)->next, type, member)
37
38#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */
39
40
41#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
42
43#define device_create(_cls, _parent, _devt, _device, _fmt) \
44 class_device_create(_cls, _parent, _devt, _device, _fmt)
45
46#define device_destroy(_cls, _device) \
47 class_device_destroy(_cls, _device)
48
49#else
50
51#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
52
53#define device_create(_cls, _parent, _devt, _device, _fmt) \
54 device_create_drvdata(_cls, _parent, _devt, _device, _fmt)
55
56#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) */
57
58#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) */
59
60#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
61
62#define cancel_delayed_work_sync(wq) cancel_rearming_delayed_work(wq)
63
64#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) */
65#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
66#define strict_strtoul(cp, base, res) \
67 ({ \
68 int ret = 0; \
69 char *endp; \
70 *res = simple_strtoul(cp, &endp, base); \
71 if (cp == endp) \
72 ret = -EINVAL; \
73 ret; \
74})
75#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) */
diff --git a/drivers/staging/batman-adv/device.c b/drivers/staging/batman-adv/device.c
new file mode 100644
index 000000000000..1e7d1f88674f
--- /dev/null
+++ b/drivers/staging/batman-adv/device.c
@@ -0,0 +1,337 @@
1/*
2 * Copyright (C) 2007-2009 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 "device.h"
24#include "log.h"
25#include "send.h"
26#include "types.h"
27#include "hash.h"
28
29#include "compat.h"
30
31static struct class *batman_class;
32
33static int Major; /* Major number assigned to our device driver */
34
35static const struct file_operations fops = {
36 .open = bat_device_open,
37 .release = bat_device_release,
38 .read = bat_device_read,
39 .write = bat_device_write,
40 .poll = bat_device_poll,
41};
42
43static struct device_client *device_client_hash[256];
44
45void bat_device_init(void)
46{
47 int i;
48
49 for (i = 0; i < 256; i++)
50 device_client_hash[i] = NULL;
51}
52
53int bat_device_setup(void)
54{
55 int tmp_major;
56
57 if (Major)
58 return 1;
59
60 /* register our device - kernel assigns a free major number */
61 tmp_major = register_chrdev(0, DRIVER_DEVICE, &fops);
62 if (tmp_major < 0) {
63 debug_log(LOG_TYPE_WARN, "Registering the character device failed with %d\n",
64 tmp_major);
65 return 0;
66 }
67
68 batman_class = class_create(THIS_MODULE, "batman-adv");
69
70 if (IS_ERR(batman_class)) {
71 debug_log(LOG_TYPE_WARN, "Could not register class 'batman-adv' \n");
72 return 0;
73 }
74
75 device_create(batman_class, NULL, MKDEV(tmp_major, 0), NULL,
76 "batman-adv");
77
78 Major = tmp_major;
79 return 1;
80}
81
82void bat_device_destroy(void)
83{
84 if (!Major)
85 return;
86
87 device_destroy(batman_class, MKDEV(Major, 0));
88 class_destroy(batman_class);
89
90 /* Unregister the device */
91 unregister_chrdev(Major, DRIVER_DEVICE);
92
93 Major = 0;
94}
95
96int bat_device_open(struct inode *inode, struct file *file)
97{
98 unsigned int i;
99 struct device_client *device_client;
100
101 device_client = kmalloc(sizeof(struct device_client), GFP_KERNEL);
102
103 if (!device_client)
104 return -ENOMEM;
105
106 for (i = 0; i < 256; i++) {
107 if (!device_client_hash[i]) {
108 device_client_hash[i] = device_client;
109 break;
110 }
111 }
112
113 if (device_client_hash[i] != device_client) {
114 debug_log(LOG_TYPE_WARN, "Error - can't add another packet client: maximum number of clients reached \n");
115 kfree(device_client);
116 return -EXFULL;
117 }
118
119 INIT_LIST_HEAD(&device_client->queue_list);
120 device_client->queue_len = 0;
121 device_client->index = i;
122 device_client->lock = __SPIN_LOCK_UNLOCKED(device_client->lock);
123 init_waitqueue_head(&device_client->queue_wait);
124
125 file->private_data = device_client;
126
127 inc_module_count();
128 return 0;
129}
130
131int bat_device_release(struct inode *inode, struct file *file)
132{
133 struct device_client *device_client =
134 (struct device_client *)file->private_data;
135 struct device_packet *device_packet;
136 struct list_head *list_pos, *list_pos_tmp;
137
138 spin_lock(&device_client->lock);
139
140 /* for all packets in the queue ... */
141 list_for_each_safe(list_pos, list_pos_tmp, &device_client->queue_list) {
142 device_packet = list_entry(list_pos,
143 struct device_packet, list);
144
145 list_del(list_pos);
146 kfree(device_packet);
147 }
148
149 device_client_hash[device_client->index] = NULL;
150 spin_unlock(&device_client->lock);
151
152 kfree(device_client);
153 dec_module_count();
154
155 return 0;
156}
157
158ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
159 loff_t *ppos)
160{
161 struct device_client *device_client =
162 (struct device_client *)file->private_data;
163 struct device_packet *device_packet;
164 int error;
165
166 if ((file->f_flags & O_NONBLOCK) && (device_client->queue_len == 0))
167 return -EAGAIN;
168
169 if ((!buf) || (count < sizeof(struct icmp_packet)))
170 return -EINVAL;
171
172 if (!access_ok(VERIFY_WRITE, buf, count))
173 return -EFAULT;
174
175 error = wait_event_interruptible(device_client->queue_wait,
176 device_client->queue_len);
177
178 if (error)
179 return error;
180
181 spin_lock(&device_client->lock);
182
183 device_packet = list_first_entry(&device_client->queue_list,
184 struct device_packet, list);
185 list_del(&device_packet->list);
186 device_client->queue_len--;
187
188 spin_unlock(&device_client->lock);
189
190 error = __copy_to_user(buf, &device_packet->icmp_packet,
191 sizeof(struct icmp_packet));
192
193 kfree(device_packet);
194
195 if (error)
196 return error;
197
198 return sizeof(struct icmp_packet);
199}
200
201ssize_t bat_device_write(struct file *file, const char __user *buff,
202 size_t len, loff_t *off)
203{
204 struct device_client *device_client =
205 (struct device_client *)file->private_data;
206 struct icmp_packet icmp_packet;
207 struct orig_node *orig_node;
208 struct batman_if *batman_if;
209
210 if (len < sizeof(struct icmp_packet)) {
211 debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: invalid packet size\n");
212 return -EINVAL;
213 }
214
215 if (!access_ok(VERIFY_READ, buff, sizeof(struct icmp_packet)))
216 return -EFAULT;
217
218 if (__copy_from_user(&icmp_packet, buff, sizeof(icmp_packet)))
219 return -EFAULT;
220
221 if (icmp_packet.packet_type != BAT_ICMP) {
222 debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n");
223 return -EINVAL;
224 }
225
226 if (icmp_packet.msg_type != ECHO_REQUEST) {
227 debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n");
228 return -EINVAL;
229 }
230
231 icmp_packet.uid = device_client->index;
232
233 if (icmp_packet.version != COMPAT_VERSION) {
234 icmp_packet.msg_type = PARAMETER_PROBLEM;
235 icmp_packet.ttl = COMPAT_VERSION;
236 bat_device_add_packet(device_client, &icmp_packet);
237 goto out;
238 }
239
240 if (atomic_read(&module_state) != MODULE_ACTIVE)
241 goto dst_unreach;
242
243 spin_lock(&orig_hash_lock);
244 orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet.dst));
245
246 if (!orig_node)
247 goto unlock;
248
249 if (!orig_node->router)
250 goto unlock;
251
252 batman_if = orig_node->batman_if;
253
254 if (!batman_if)
255 goto unlock;
256
257 memcpy(icmp_packet.orig,
258 batman_if->net_dev->dev_addr,
259 ETH_ALEN);
260
261 send_raw_packet((unsigned char *)&icmp_packet,
262 sizeof(struct icmp_packet),
263 batman_if, orig_node->router->addr);
264
265 spin_unlock(&orig_hash_lock);
266 goto out;
267
268unlock:
269 spin_unlock(&orig_hash_lock);
270dst_unreach:
271 icmp_packet.msg_type = DESTINATION_UNREACHABLE;
272 bat_device_add_packet(device_client, &icmp_packet);
273out:
274 return len;
275}
276
277unsigned int bat_device_poll(struct file *file, poll_table *wait)
278{
279 struct device_client *device_client =
280 (struct device_client *)file->private_data;
281
282 poll_wait(file, &device_client->queue_wait, wait);
283
284 if (device_client->queue_len > 0)
285 return POLLIN | POLLRDNORM;
286
287 return 0;
288}
289
290void bat_device_add_packet(struct device_client *device_client,
291 struct icmp_packet *icmp_packet)
292{
293 struct device_packet *device_packet;
294
295 device_packet = kmalloc(sizeof(struct device_packet), GFP_KERNEL);
296
297 if (!device_packet)
298 return;
299
300 INIT_LIST_HEAD(&device_packet->list);
301 memcpy(&device_packet->icmp_packet, icmp_packet,
302 sizeof(struct icmp_packet));
303
304 spin_lock(&device_client->lock);
305
306 /* while waiting for the lock the device_client could have been
307 * deleted */
308 if (!device_client_hash[icmp_packet->uid]) {
309 spin_unlock(&device_client->lock);
310 kfree(device_packet);
311 return;
312 }
313
314 list_add_tail(&device_packet->list, &device_client->queue_list);
315 device_client->queue_len++;
316
317 if (device_client->queue_len > 100) {
318 device_packet = list_first_entry(&device_client->queue_list,
319 struct device_packet, list);
320
321 list_del(&device_packet->list);
322 kfree(device_packet);
323 device_client->queue_len--;
324 }
325
326 spin_unlock(&device_client->lock);
327
328 wake_up(&device_client->queue_wait);
329}
330
331void bat_device_receive_packet(struct icmp_packet *icmp_packet)
332{
333 struct device_client *hash = device_client_hash[icmp_packet->uid];
334
335 if (hash)
336 bat_device_add_packet(hash, icmp_packet);
337}
diff --git a/drivers/staging/batman-adv/device.h b/drivers/staging/batman-adv/device.h
new file mode 100644
index 000000000000..46c0f4496527
--- /dev/null
+++ b/drivers/staging/batman-adv/device.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2007-2009 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 "types.h"
23
24void bat_device_init(void);
25int bat_device_setup(void);
26void bat_device_destroy(void);
27int bat_device_open(struct inode *inode, struct file *file);
28int bat_device_release(struct inode *inode, struct file *file);
29ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
30 loff_t *ppos);
31ssize_t bat_device_write(struct file *file, const char __user *buff,
32 size_t len, loff_t *off);
33unsigned int bat_device_poll(struct file *file, poll_table *wait);
34void bat_device_add_packet(struct device_client *device_client,
35 struct icmp_packet *icmp_packet);
36void bat_device_receive_packet(struct icmp_packet *icmp_packet);
diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c
new file mode 100644
index 000000000000..5ea35da5ee7a
--- /dev/null
+++ b/drivers/staging/batman-adv/hard-interface.c
@@ -0,0 +1,451 @@
1/*
2 * Copyright (C) 2007-2009 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 "log.h"
25#include "soft-interface.h"
26#include "send.h"
27#include "translation-table.h"
28#include "routing.h"
29#include "hash.h"
30#include "compat.h"
31
32#define MIN(x, y) ((x) < (y) ? (x) : (y))
33
34static char avail_ifs;
35static char active_ifs;
36
37static void hardif_free_interface(struct rcu_head *rcu);
38
39static struct batman_if *get_batman_if_by_name(char *name)
40{
41 struct batman_if *batman_if;
42
43 rcu_read_lock();
44 list_for_each_entry_rcu(batman_if, &if_list, list) {
45 if (strncmp(batman_if->dev, name, IFNAMSIZ) == 0)
46 goto out;
47 }
48
49 batman_if = NULL;
50
51out:
52 rcu_read_unlock();
53 return batman_if;
54}
55
56int hardif_min_mtu(void)
57{
58 struct batman_if *batman_if;
59 /* allow big frames if all devices are capable to do so
60 * (have MTU > 1500 + BAT_HEADER_LEN) */
61 int min_mtu = ETH_DATA_LEN;
62
63 rcu_read_lock();
64 list_for_each_entry_rcu(batman_if, &if_list, list) {
65 if ((batman_if->if_active == IF_ACTIVE) ||
66 (batman_if->if_active == IF_TO_BE_ACTIVATED))
67 min_mtu = MIN(batman_if->net_dev->mtu - BAT_HEADER_LEN,
68 min_mtu);
69 }
70 rcu_read_unlock();
71
72 return min_mtu;
73}
74
75static void check_known_mac_addr(uint8_t *addr)
76{
77 struct batman_if *batman_if;
78 char mac_string[ETH_STR_LEN];
79
80 rcu_read_lock();
81 list_for_each_entry_rcu(batman_if, &if_list, list) {
82 if ((batman_if->if_active != IF_ACTIVE) &&
83 (batman_if->if_active != IF_TO_BE_ACTIVATED))
84 continue;
85
86 if (!compare_orig(batman_if->net_dev->dev_addr, addr))
87 continue;
88
89 addr_to_string(mac_string, addr);
90 debug_log(LOG_TYPE_WARN, "The newly added mac address (%s) already exists on: %s\n",
91 mac_string, batman_if->dev);
92 debug_log(LOG_TYPE_WARN, "It is strongly recommended to keep mac addresses unique to avoid problems!\n");
93 }
94 rcu_read_unlock();
95}
96
97/* adjusts the MTU if a new interface with a smaller MTU appeared. */
98void update_min_mtu(void)
99{
100 int min_mtu;
101
102 min_mtu = hardif_min_mtu();
103 if (soft_device->mtu != min_mtu)
104 soft_device->mtu = min_mtu;
105}
106
107/* checks if the interface is up. (returns 1 if it is) */
108static int hardif_is_interface_up(char *dev)
109{
110 struct net_device *net_dev;
111
112 /**
113 * if we already have an interface in our interface list and
114 * the current interface is not the primary interface and
115 * the primary interface is not up and
116 * the primary interface has never been up - don't activate any
117 * secondary interface !
118 */
119
120 rcu_read_lock();
121 if ((!list_empty(&if_list)) &&
122 strncmp(((struct batman_if *)if_list.next)->dev, dev, IFNAMSIZ) &&
123 !(((struct batman_if *)if_list.next)->if_active == IF_ACTIVE) &&
124 !(((struct batman_if *)if_list.next)->if_active == IF_TO_BE_ACTIVATED) &&
125 (!main_if_was_up())) {
126 rcu_read_unlock();
127 goto end;
128 }
129 rcu_read_unlock();
130
131#ifdef __NET_NET_NAMESPACE_H
132 net_dev = dev_get_by_name(&init_net, dev);
133#else
134 net_dev = dev_get_by_name(dev);
135#endif
136 if (!net_dev)
137 goto end;
138
139 if (!(net_dev->flags & IFF_UP))
140 goto failure;
141
142 dev_put(net_dev);
143 return 1;
144
145failure:
146 dev_put(net_dev);
147end:
148 return 0;
149}
150
151/* deactivates the interface. */
152void hardif_deactivate_interface(struct batman_if *batman_if)
153{
154 if (batman_if->if_active != IF_ACTIVE)
155 return;
156
157 if (batman_if->raw_sock)
158 sock_release(batman_if->raw_sock);
159
160 /**
161 * batman_if->net_dev has been acquired by dev_get_by_name() in
162 * proc_interfaces_write() and has to be unreferenced.
163 */
164
165 if (batman_if->net_dev)
166 dev_put(batman_if->net_dev);
167
168 batman_if->raw_sock = NULL;
169 batman_if->net_dev = NULL;
170
171 batman_if->if_active = IF_INACTIVE;
172 active_ifs--;
173
174 debug_log(LOG_TYPE_NOTICE, "Interface deactivated: %s\n",
175 batman_if->dev);
176}
177
178/* (re)activate given interface. */
179static void hardif_activate_interface(struct batman_if *batman_if)
180{
181 struct sockaddr_ll bind_addr;
182 int retval;
183
184 if (batman_if->if_active != IF_INACTIVE)
185 return;
186
187#ifdef __NET_NET_NAMESPACE_H
188 batman_if->net_dev = dev_get_by_name(&init_net, batman_if->dev);
189#else
190 batman_if->net_dev = dev_get_by_name(batman_if->dev);
191#endif
192 if (!batman_if->net_dev)
193 goto dev_err;
194
195 retval = sock_create_kern(PF_PACKET, SOCK_RAW,
196 __constant_htons(ETH_P_BATMAN),
197 &batman_if->raw_sock);
198
199 if (retval < 0) {
200 debug_log(LOG_TYPE_WARN, "Can't create raw socket: %i\n",
201 retval);
202 goto sock_err;
203 }
204
205 bind_addr.sll_family = AF_PACKET;
206 bind_addr.sll_ifindex = batman_if->net_dev->ifindex;
207 bind_addr.sll_protocol = 0; /* is set by the kernel */
208
209 retval = kernel_bind(batman_if->raw_sock,
210 (struct sockaddr *)&bind_addr, sizeof(bind_addr));
211
212 if (retval < 0) {
213 debug_log(LOG_TYPE_WARN, "Can't create bind raw socket: %i\n",
214 retval);
215 goto bind_err;
216 }
217
218 check_known_mac_addr(batman_if->net_dev->dev_addr);
219
220 batman_if->raw_sock->sk->sk_user_data =
221 batman_if->raw_sock->sk->sk_data_ready;
222 batman_if->raw_sock->sk->sk_data_ready = batman_data_ready;
223
224 addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr);
225
226 memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig,
227 batman_if->net_dev->dev_addr, ETH_ALEN);
228 memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender,
229 batman_if->net_dev->dev_addr, ETH_ALEN);
230
231 batman_if->if_active = IF_TO_BE_ACTIVATED;
232 active_ifs++;
233
234 /* save the mac address if it is our primary interface */
235 if (batman_if->if_num == 0)
236 set_main_if_addr(batman_if->net_dev->dev_addr);
237
238 debug_log(LOG_TYPE_NOTICE, "Interface activated: %s\n",
239 batman_if->dev);
240
241 return;
242
243bind_err:
244 sock_release(batman_if->raw_sock);
245sock_err:
246 dev_put(batman_if->net_dev);
247dev_err:
248 batman_if->raw_sock = NULL;
249 batman_if->net_dev = NULL;
250}
251
252static void hardif_free_interface(struct rcu_head *rcu)
253{
254 struct batman_if *batman_if = container_of(rcu, struct batman_if, rcu);
255
256 kfree(batman_if->packet_buff);
257 kfree(batman_if->dev);
258 kfree(batman_if);
259}
260
261/**
262 * called by
263 * - echo '' > /proc/.../interfaces
264 * - modprobe -r batman-adv-core
265 */
266/* removes and frees all interfaces */
267void hardif_remove_interfaces(void)
268{
269 struct batman_if *batman_if = NULL;
270
271 avail_ifs = 0;
272
273 /* no lock needed - we don't delete somewhere else */
274 list_for_each_entry(batman_if, &if_list, list) {
275
276 list_del_rcu(&batman_if->list);
277
278 /* first deactivate interface */
279 if (batman_if->if_active != IF_INACTIVE)
280 hardif_deactivate_interface(batman_if);
281
282 call_rcu(&batman_if->rcu, hardif_free_interface);
283 }
284}
285
286static int resize_orig(struct orig_node *orig_node, int if_num)
287{
288 void *data_ptr;
289
290 data_ptr = kmalloc((if_num + 1) * sizeof(TYPE_OF_WORD) * NUM_WORDS,
291 GFP_ATOMIC);
292 if (!data_ptr) {
293 debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n");
294 return -1;
295 }
296
297 memcpy(data_ptr, orig_node->bcast_own,
298 if_num * sizeof(TYPE_OF_WORD) * NUM_WORDS);
299 kfree(orig_node->bcast_own);
300 orig_node->bcast_own = data_ptr;
301
302 data_ptr = kmalloc((if_num + 1) * sizeof(uint8_t), GFP_ATOMIC);
303 if (!data_ptr) {
304 debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n");
305 return -1;
306 }
307
308 memcpy(data_ptr, orig_node->bcast_own_sum, if_num * sizeof(uint8_t));
309 kfree(orig_node->bcast_own_sum);
310 orig_node->bcast_own_sum = data_ptr;
311
312 return 0;
313}
314
315
316/* adds an interface the interface list and activate it, if possible */
317int hardif_add_interface(char *dev, int if_num)
318{
319 struct batman_if *batman_if;
320 struct batman_packet *batman_packet;
321 struct orig_node *orig_node;
322 struct hash_it_t *hashit = NULL;
323
324 batman_if = kmalloc(sizeof(struct batman_if), GFP_KERNEL);
325
326 if (!batman_if) {
327 debug_log(LOG_TYPE_WARN, "Can't add interface (%s): out of memory\n", dev);
328 return -1;
329 }
330
331 batman_if->raw_sock = NULL;
332 batman_if->net_dev = NULL;
333
334 if ((if_num == 0) && (num_hna > 0))
335 batman_if->packet_len = BAT_PACKET_LEN + num_hna * ETH_ALEN;
336 else
337 batman_if->packet_len = BAT_PACKET_LEN;
338
339 batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_KERNEL);
340
341 if (!batman_if->packet_buff) {
342 debug_log(LOG_TYPE_WARN, "Can't add interface packet (%s): out of memory\n", dev);
343 goto out;
344 }
345
346 batman_if->if_num = if_num;
347 batman_if->dev = dev;
348 batman_if->if_active = IF_INACTIVE;
349 INIT_RCU_HEAD(&batman_if->rcu);
350
351 debug_log(LOG_TYPE_NOTICE, "Adding interface: %s\n", dev);
352 avail_ifs++;
353
354 INIT_LIST_HEAD(&batman_if->list);
355
356 batman_packet = (struct batman_packet *)(batman_if->packet_buff);
357 batman_packet->packet_type = BAT_PACKET;
358 batman_packet->version = COMPAT_VERSION;
359 batman_packet->flags = 0x00;
360 batman_packet->ttl = (batman_if->if_num > 0 ? 2 : TTL);
361 batman_packet->flags = 0;
362 batman_packet->tq = TQ_MAX_VALUE;
363 batman_packet->num_hna = 0;
364
365 if (batman_if->packet_len != BAT_PACKET_LEN) {
366 unsigned char *hna_buff;
367 int hna_len;
368
369 hna_buff = batman_if->packet_buff + BAT_PACKET_LEN;
370 hna_len = batman_if->packet_len - BAT_PACKET_LEN;
371 batman_packet->num_hna = hna_local_fill_buffer(hna_buff,
372 hna_len);
373 }
374
375 atomic_set(&batman_if->seqno, 1);
376
377 /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
378 * if_num */
379 spin_lock(&orig_hash_lock);
380
381 while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
382 orig_node = hashit->bucket->data;
383 if (resize_orig(orig_node, if_num) == -1) {
384 spin_unlock(&orig_hash_lock);
385 goto out;
386 }
387 }
388
389 spin_unlock(&orig_hash_lock);
390
391 if (!hardif_is_interface_up(batman_if->dev))
392 debug_log(LOG_TYPE_WARN, "Not using interface %s (retrying later): interface not active\n", batman_if->dev);
393 else
394 hardif_activate_interface(batman_if);
395
396 list_add_tail_rcu(&batman_if->list, &if_list);
397
398 /* begin sending originator messages on that interface */
399 schedule_own_packet(batman_if);
400 return 1;
401
402out:
403 if (batman_if->packet_buff)
404 kfree(batman_if->packet_buff);
405 kfree(batman_if);
406 kfree(dev);
407 return -1;
408}
409
410char hardif_get_active_if_num(void)
411{
412 return active_ifs;
413}
414
415static int hard_if_event(struct notifier_block *this,
416 unsigned long event, void *ptr)
417{
418 struct net_device *dev = (struct net_device *)ptr;
419 struct batman_if *batman_if = get_batman_if_by_name(dev->name);
420
421 if (!batman_if)
422 goto out;
423
424 switch (event) {
425 case NETDEV_GOING_DOWN:
426 case NETDEV_DOWN:
427 case NETDEV_UNREGISTER:
428 hardif_deactivate_interface(batman_if);
429 break;
430 case NETDEV_UP:
431 hardif_activate_interface(batman_if);
432 if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
433 (hardif_get_active_if_num() > 0)) {
434 activate_module();
435 }
436 break;
437 /* NETDEV_CHANGEADDR - mac address change - what are we doing here ? */
438 default:
439 /* debug_log(LOG_TYPE_CRIT, "hard_if_event: %s %i\n", dev->name, event); */
440 break;
441 };
442
443 update_min_mtu();
444
445out:
446 return NOTIFY_DONE;
447}
448
449struct notifier_block hard_if_notifier = {
450 .notifier_call = hard_if_event,
451};
diff --git a/drivers/staging/batman-adv/hard-interface.h b/drivers/staging/batman-adv/hard-interface.h
new file mode 100644
index 000000000000..742358c00c0e
--- /dev/null
+++ b/drivers/staging/batman-adv/hard-interface.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2007-2009 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#define IF_INACTIVE 0
23#define IF_ACTIVE 1
24/* #define IF_TO_BE_DEACTIVATED 2 - not needed anymore */
25#define IF_TO_BE_ACTIVATED 3
26
27extern struct notifier_block hard_if_notifier;
28
29void hardif_remove_interfaces(void);
30int hardif_add_interface(char *dev, int if_num);
31void hardif_deactivate_interface(struct batman_if *batman_if);
32char hardif_get_active_if_num(void);
33void hardif_check_interfaces_status(void);
34void hardif_check_interfaces_status_wq(struct work_struct *work);
35int hardif_min_mtu(void);
36void update_min_mtu(void);
diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c
new file mode 100644
index 000000000000..61cb4a20ebca
--- /dev/null
+++ b/drivers/staging/batman-adv/hash.c
@@ -0,0 +1,313 @@
1/*
2 * Copyright (C) 2006-2009 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 */
26void hash_init(struct hashtable_t *hash)
27{
28 int i;
29
30 hash->elements = 0;
31
32 for (i = 0 ; i < hash->size; i++)
33 hash->table[i] = NULL;
34}
35
36/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
37 * called to remove the elements inside of the hash. if you don't remove the
38 * elements, memory might be leaked. */
39void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb)
40{
41 struct element_t *bucket, *last_bucket;
42 int i;
43
44 for (i = 0; i < hash->size; i++) {
45 bucket = hash->table[i];
46
47 while (bucket != NULL) {
48 if (free_cb != NULL)
49 free_cb(bucket->data);
50
51 last_bucket = bucket;
52 bucket = bucket->next;
53 kfree(last_bucket);
54 }
55 }
56
57 hash_destroy(hash);
58}
59
60/* free only the hashtable and the hash itself. */
61void hash_destroy(struct hashtable_t *hash)
62{
63 kfree(hash->table);
64 kfree(hash);
65}
66
67/* iterate though the hash. first element is selected with iter_in NULL. use
68 * the returned iterator to access the elements until hash_it_t returns NULL. */
69struct hash_it_t *hash_iterate(struct hashtable_t *hash,
70 struct hash_it_t *iter_in)
71{
72 struct hash_it_t *iter;
73
74 if (!hash)
75 return NULL;
76
77 if (iter_in == NULL) {
78 iter = kmalloc(sizeof(struct hash_it_t), GFP_ATOMIC);
79 iter->index = -1;
80 iter->bucket = NULL;
81 iter->prev_bucket = NULL;
82 } else {
83 iter = iter_in;
84 }
85
86 /* sanity checks first (if our bucket got deleted in the last
87 * iteration): */
88 if (iter->bucket != NULL) {
89 if (iter->first_bucket != NULL) {
90 /* we're on the first element and it got removed after
91 * the last iteration. */
92 if ((*iter->first_bucket) != iter->bucket) {
93 /* there are still other elements in the list */
94 if ((*iter->first_bucket) != NULL) {
95 iter->prev_bucket = NULL;
96 iter->bucket = (*iter->first_bucket);
97 iter->first_bucket =
98 &hash->table[iter->index];
99 return iter;
100 } else {
101 iter->bucket = NULL;
102 }
103 }
104 } else if (iter->prev_bucket != NULL) {
105 /*
106 * we're not on the first element, and the bucket got
107 * removed after the last iteration. the last bucket's
108 * next pointer is not pointing to our actual bucket
109 * anymore. select the next.
110 */
111 if (iter->prev_bucket->next != iter->bucket)
112 iter->bucket = iter->prev_bucket;
113 }
114 }
115
116 /* now as we are sane, select the next one if there is some */
117 if (iter->bucket != NULL) {
118 if (iter->bucket->next != NULL) {
119 iter->prev_bucket = iter->bucket;
120 iter->bucket = iter->bucket->next;
121 iter->first_bucket = NULL;
122 return iter;
123 }
124 }
125
126 /* if not returned yet, we've reached the last one on the index and have
127 * to search forward */
128 iter->index++;
129 /* go through the entries of the hash table */
130 while (iter->index < hash->size) {
131 if ((hash->table[iter->index]) != NULL) {
132 iter->prev_bucket = NULL;
133 iter->bucket = hash->table[iter->index];
134 iter->first_bucket = &hash->table[iter->index];
135 return iter;
136 } else {
137 iter->index++;
138 }
139 }
140
141 /* nothing to iterate over anymore */
142 kfree(iter);
143 return NULL;
144}
145
146/* allocates and clears the hash */
147struct hashtable_t *hash_new(int size, hashdata_compare_cb compare,
148 hashdata_choose_cb choose)
149{
150 struct hashtable_t *hash;
151
152 hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC);
153
154 if (hash == NULL)
155 return NULL;
156
157 hash->size = size;
158 hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC);
159
160 if (hash->table == NULL) {
161 kfree(hash);
162 return NULL;
163 }
164
165 hash_init(hash);
166
167 hash->compare = compare;
168 hash->choose = choose;
169
170 return hash;
171}
172
173/* adds data to the hashtable. returns 0 on success, -1 on error */
174int hash_add(struct hashtable_t *hash, void *data)
175{
176 int index;
177 struct element_t *bucket, *prev_bucket = NULL;
178
179 if (!hash)
180 return -1;
181
182 index = hash->choose(data, hash->size);
183 bucket = hash->table[index];
184
185 while (bucket != NULL) {
186 if (hash->compare(bucket->data, data))
187 return -1;
188
189 prev_bucket = bucket;
190 bucket = bucket->next;
191 }
192
193 /* found the tail of the list, add new element */
194 bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC);
195
196 if (bucket == NULL)
197 return -1;
198
199 bucket->data = data;
200 bucket->next = NULL;
201
202 /* and link it */
203 if (prev_bucket == NULL)
204 hash->table[index] = bucket;
205 else
206 prev_bucket->next = bucket;
207
208 hash->elements++;
209 return 0;
210}
211
212/* finds data, based on the key in keydata. returns the found data on success,
213 * or NULL on error */
214void *hash_find(struct hashtable_t *hash, void *keydata)
215{
216 int index;
217 struct element_t *bucket;
218
219 if (!hash)
220 return NULL;
221
222 index = hash->choose(keydata , hash->size);
223 bucket = hash->table[index];
224
225 while (bucket != NULL) {
226 if (hash->compare(bucket->data, keydata))
227 return bucket->data;
228
229 bucket = bucket->next;
230 }
231
232 return NULL;
233}
234
235/* remove bucket (this might be used in hash_iterate() if you already found the
236 * bucket you want to delete and don't need the overhead to find it again with
237 * hash_remove(). But usually, you don't want to use this function, as it
238 * fiddles with hash-internals. */
239void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t)
240{
241 void *data_save;
242
243 data_save = hash_it_t->bucket->data;
244
245 if (hash_it_t->prev_bucket != NULL)
246 hash_it_t->prev_bucket->next = hash_it_t->bucket->next;
247 else if (hash_it_t->first_bucket != NULL)
248 (*hash_it_t->first_bucket) = hash_it_t->bucket->next;
249
250 kfree(hash_it_t->bucket);
251 hash->elements--;
252
253 return data_save;
254}
255
256/* removes data from hash, if found. returns pointer do data on success, so you
257 * can remove the used structure yourself, or NULL on error . data could be the
258 * structure you use with just the key filled, we just need the key for
259 * comparing. */
260void *hash_remove(struct hashtable_t *hash, void *data)
261{
262 struct hash_it_t hash_it_t;
263
264 hash_it_t.index = hash->choose(data, hash->size);
265 hash_it_t.bucket = hash->table[hash_it_t.index];
266 hash_it_t.prev_bucket = NULL;
267
268 while (hash_it_t.bucket != NULL) {
269 if (hash->compare(hash_it_t.bucket->data, data)) {
270 hash_it_t.first_bucket =
271 (hash_it_t.bucket ==
272 hash->table[hash_it_t.index] ?
273 &hash->table[hash_it_t.index] : NULL);
274 return hash_remove_bucket(hash, &hash_it_t);
275 }
276
277 hash_it_t.prev_bucket = hash_it_t.bucket;
278 hash_it_t.bucket = hash_it_t.bucket->next;
279 }
280
281 return NULL;
282}
283
284/* resize the hash, returns the pointer to the new hash or NULL on
285 * error. removes the old hash on success. */
286struct hashtable_t *hash_resize(struct hashtable_t *hash, int size)
287{
288 struct hashtable_t *new_hash;
289 struct element_t *bucket;
290 int i;
291
292 /* initialize a new hash with the new size */
293 new_hash = hash_new(size, hash->compare, hash->choose);
294
295 if (new_hash == NULL)
296 return NULL;
297
298 /* copy the elements */
299 for (i = 0; i < hash->size; i++) {
300 bucket = hash->table[i];
301
302 while (bucket != NULL) {
303 hash_add(new_hash, bucket->data);
304 bucket = bucket->next;
305 }
306 }
307
308 /* remove hash and eventual overflow buckets but not the content
309 * itself. */
310 hash_delete(hash, NULL);
311
312 return new_hash;
313}
diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h
new file mode 100644
index 000000000000..bb60f082be6a
--- /dev/null
+++ b/drivers/staging/batman-adv/hash.h
@@ -0,0 +1,99 @@
1/*
2 * Copyright (C) 2006-2009 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 _BATMAN_HASH_H
23#define _BATMAN_HASH_H
24
25typedef int (*hashdata_compare_cb)(void *, void *);
26typedef int (*hashdata_choose_cb)(void *, int);
27typedef void (*hashdata_free_cb)(void *);
28
29struct element_t {
30 void *data; /* pointer to the data */
31 struct element_t *next; /* overflow bucket pointer */
32};
33
34struct hash_it_t {
35 int index;
36 struct element_t *bucket;
37 struct element_t *prev_bucket;
38 struct element_t **first_bucket;
39};
40
41struct hashtable_t {
42 struct element_t **table; /* the hashtable itself, with the buckets */
43 int elements; /* number of elements registered */
44 int size; /* size of hashtable */
45 hashdata_compare_cb compare;/* callback to a compare function. should
46 * compare 2 element datas for their keys,
47 * return 0 if same and not 0 if not
48 * same */
49 hashdata_choose_cb choose; /* the hashfunction, should return an index
50 * based on the key in the data of the first
51 * argument and the size the second */
52};
53
54/* clears the hash */
55void hash_init(struct hashtable_t *hash);
56
57/* allocates and clears the hash */
58struct hashtable_t *hash_new(int size, hashdata_compare_cb compare,
59 hashdata_choose_cb choose);
60
61/* remove bucket (this might be used in hash_iterate() if you already found the
62 * bucket you want to delete and don't need the overhead to find it again with
63 * hash_remove(). But usually, you don't want to use this function, as it
64 * fiddles with hash-internals. */
65void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t);
66
67/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
68 * called to remove the elements inside of the hash. if you don't remove the
69 * elements, memory might be leaked. */
70void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb);
71
72/* free only the hashtable and the hash itself. */
73void hash_destroy(struct hashtable_t *hash);
74
75/* adds data to the hashtable. returns 0 on success, -1 on error */
76int hash_add(struct hashtable_t *hash, void *data);
77
78/* removes data from hash, if found. returns pointer do data on success, so you
79 * can remove the used structure yourself, or NULL on error . data could be the
80 * structure you use with just the key filled, we just need the key for
81 * comparing. */
82void *hash_remove(struct hashtable_t *hash, void *data);
83
84/* finds data, based on the key in keydata. returns the found data on success,
85 * or NULL on error */
86void *hash_find(struct hashtable_t *hash, void *keydata);
87
88/* resize the hash, returns the pointer to the new hash or NULL on
89 * error. removes the old hash on success */
90struct hashtable_t *hash_resize(struct hashtable_t *hash, int size);
91
92/* iterate though the hash. first element is selected with iter_in NULL. use
93 * the returned iterator to access the elements until hash_it_t returns NULL. */
94struct hash_it_t *hash_iterate(struct hashtable_t *hash,
95 struct hash_it_t *iter_in);
96
97/* print the hash table for debugging */
98void hash_debug(struct hashtable_t *hash);
99#endif
diff --git a/drivers/staging/batman-adv/log.c b/drivers/staging/batman-adv/log.c
new file mode 100644
index 000000000000..f37c7f01a9f5
--- /dev/null
+++ b/drivers/staging/batman-adv/log.c
@@ -0,0 +1,179 @@
1/*
2 * Copyright (C) 2007-2009 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 "log.h"
24
25#define LOG_BUF_MASK (log_buf_len-1)
26#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
27
28static char log_buf[LOG_BUF_LEN];
29static int log_buf_len = LOG_BUF_LEN;
30static unsigned long log_start;
31static unsigned long log_end;
32uint8_t log_level;
33
34static DEFINE_SPINLOCK(logbuf_lock);
35
36const struct file_operations proc_log_operations = {
37 .open = log_open,
38 .release = log_release,
39 .read = log_read,
40 .write = log_write,
41 .poll = log_poll,
42};
43
44static DECLARE_WAIT_QUEUE_HEAD(log_wait);
45
46static void emit_log_char(char c)
47{
48 LOG_BUF(log_end) = c;
49 log_end++;
50
51 if (log_end - log_start > log_buf_len)
52 log_start = log_end - log_buf_len;
53}
54
55static int fdebug_log(char *fmt, ...)
56{
57 int printed_len;
58 char *p;
59 va_list args;
60 static char debug_log_buf[256];
61 unsigned long flags;
62
63 spin_lock_irqsave(&logbuf_lock, flags);
64 va_start(args, fmt);
65 printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt,
66 args);
67 va_end(args);
68
69 for (p = debug_log_buf; *p != 0; p++)
70 emit_log_char(*p);
71
72 spin_unlock_irqrestore(&logbuf_lock, flags);
73
74 wake_up(&log_wait);
75
76 return 0;
77}
78
79int debug_log(int type, char *fmt, ...)
80{
81 va_list args;
82 int retval = 0;
83 char tmp_log_buf[256];
84
85 /* only critical information get into the official kernel log */
86 if (type == LOG_TYPE_CRIT) {
87 va_start(args, fmt);
88 vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
89 printk(KERN_ERR "batman-adv: %s", tmp_log_buf);
90 va_end(args);
91 }
92
93 if ((type == LOG_TYPE_CRIT) || (log_level & type)) {
94 va_start(args, fmt);
95 vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
96 fdebug_log("[%10u] %s", (jiffies / HZ), tmp_log_buf);
97 va_end(args);
98 }
99
100 return retval;
101}
102
103int log_open(struct inode *inode, struct file *file)
104{
105 inc_module_count();
106 return 0;
107}
108
109int log_release(struct inode *inode, struct file *file)
110{
111 dec_module_count();
112 return 0;
113}
114
115ssize_t log_read(struct file *file, char __user *buf, size_t count,
116 loff_t *ppos)
117{
118 int error, i = 0;
119 char c;
120 unsigned long flags;
121
122 if ((file->f_flags & O_NONBLOCK) && !(log_end - log_start))
123 return -EAGAIN;
124
125 if ((!buf) || (count < 0))
126 return -EINVAL;
127
128 if (count == 0)
129 return 0;
130
131 if (!access_ok(VERIFY_WRITE, buf, count))
132 return -EFAULT;
133
134 error = wait_event_interruptible(log_wait, (log_start - log_end));
135
136 if (error)
137 return error;
138
139 spin_lock_irqsave(&logbuf_lock, flags);
140
141 while ((!error) && (log_start != log_end) && (i < count)) {
142 c = LOG_BUF(log_start);
143
144 log_start++;
145
146 spin_unlock_irqrestore(&logbuf_lock, flags);
147
148 error = __put_user(c, buf);
149
150 spin_lock_irqsave(&logbuf_lock, flags);
151
152 buf++;
153 i++;
154
155 }
156
157 spin_unlock_irqrestore(&logbuf_lock, flags);
158
159 if (!error)
160 return i;
161
162 return error;
163}
164
165ssize_t log_write(struct file *file, const char __user *buf, size_t count,
166 loff_t *ppos)
167{
168 return count;
169}
170
171unsigned int log_poll(struct file *file, poll_table *wait)
172{
173 poll_wait(file, &log_wait, wait);
174
175 if (log_end - log_start)
176 return POLLIN | POLLRDNORM;
177
178 return 0;
179}
diff --git a/drivers/staging/batman-adv/log.h b/drivers/staging/batman-adv/log.h
new file mode 100644
index 000000000000..780e3abb48f9
--- /dev/null
+++ b/drivers/staging/batman-adv/log.h
@@ -0,0 +1,32 @@
1/*
2 * Copyright (C) 2007-2009 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
22extern const struct file_operations proc_log_operations;
23extern uint8_t log_level;
24
25int debug_log(int type, char *fmt, ...);
26int log_open(struct inode *inode, struct file *file);
27int log_release(struct inode *inode, struct file *file);
28ssize_t log_read(struct file *file, char __user *buf, size_t count,
29 loff_t *ppos);
30ssize_t log_write(struct file *file, const char __user *buf, size_t count,
31 loff_t *ppos);
32unsigned int log_poll(struct file *file, poll_table *wait);
diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c
new file mode 100644
index 000000000000..bb89bfc5dda6
--- /dev/null
+++ b/drivers/staging/batman-adv/main.c
@@ -0,0 +1,286 @@
1/*
2 * Copyright (C) 2007-2009 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 "proc.h"
24#include "log.h"
25#include "routing.h"
26#include "send.h"
27#include "soft-interface.h"
28#include "device.h"
29#include "translation-table.h"
30#include "hard-interface.h"
31#include "types.h"
32#include "vis.h"
33#include "hash.h"
34#include "compat.h"
35
36struct list_head if_list;
37struct hlist_head forw_bat_list;
38struct hlist_head forw_bcast_list;
39struct hashtable_t *orig_hash;
40
41DEFINE_SPINLOCK(orig_hash_lock);
42DEFINE_SPINLOCK(forw_bat_list_lock);
43DEFINE_SPINLOCK(forw_bcast_list_lock);
44
45atomic_t originator_interval;
46atomic_t vis_interval;
47atomic_t aggregation_enabled;
48int16_t num_hna;
49int16_t num_ifs;
50
51struct net_device *soft_device;
52
53static struct task_struct *kthread_task;
54
55unsigned char broadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
56atomic_t module_state;
57
58struct workqueue_struct *bat_event_workqueue;
59
60int init_module(void)
61{
62 int retval;
63
64 INIT_LIST_HEAD(&if_list);
65 INIT_HLIST_HEAD(&forw_bat_list);
66 INIT_HLIST_HEAD(&forw_bcast_list);
67
68 atomic_set(&module_state, MODULE_INACTIVE);
69
70 atomic_set(&originator_interval, 1000);
71 atomic_set(&vis_interval, 1000);/* TODO: raise this later, this is only
72 * for debugging now. */
73 atomic_set(&aggregation_enabled, 1);
74
75 /* the name should not be longer than 10 chars - see
76 * http://lwn.net/Articles/23634/ */
77 bat_event_workqueue = create_singlethread_workqueue("bat_events");
78
79 if (!bat_event_workqueue)
80 return -ENOMEM;
81
82 retval = setup_procfs();
83 if (retval < 0)
84 return retval;
85
86 bat_device_init();
87
88 /* initialize layer 2 interface */
89 soft_device = alloc_netdev(sizeof(struct bat_priv) , "bat%d",
90 interface_setup);
91
92 if (!soft_device) {
93 debug_log(LOG_TYPE_CRIT, "Unable to allocate the batman interface\n");
94 goto end;
95 }
96
97 retval = register_netdev(soft_device);
98
99 if (retval < 0) {
100 debug_log(LOG_TYPE_CRIT, "Unable to register the batman interface: %i\n", retval);
101 goto free_soft_device;
102 }
103
104 register_netdevice_notifier(&hard_if_notifier);
105
106 debug_log(LOG_TYPE_CRIT, "B.A.T.M.A.N. advanced %s%s (compatibility version %i) loaded \n",
107 SOURCE_VERSION, REVISION_VERSION_STR, COMPAT_VERSION);
108
109 return 0;
110
111free_soft_device:
112 free_netdev(soft_device);
113 soft_device = NULL;
114end:
115 return -ENOMEM;
116}
117
118void cleanup_module(void)
119{
120 shutdown_module();
121
122 if (soft_device) {
123 unregister_netdev(soft_device);
124 soft_device = NULL;
125 }
126
127 unregister_netdevice_notifier(&hard_if_notifier);
128 cleanup_procfs();
129
130 destroy_workqueue(bat_event_workqueue);
131 bat_event_workqueue = NULL;
132}
133
134/* activates the module, creates bat device, starts timer ... */
135void activate_module(void)
136{
137 if (originator_init() < 1)
138 goto err;
139
140 if (hna_local_init() < 1)
141 goto err;
142
143 if (hna_global_init() < 1)
144 goto err;
145
146 hna_local_add(soft_device->dev_addr);
147
148 if (bat_device_setup() < 1)
149 goto end;
150
151 if (vis_init() < 1)
152 goto err;
153
154 /* (re)start kernel thread for packet processing */
155 if (!kthread_task) {
156 kthread_task = kthread_run(packet_recv_thread, NULL, "batman-adv");
157
158 if (IS_ERR(kthread_task)) {
159 debug_log(LOG_TYPE_CRIT, "Unable to start packet receive thread\n");
160 kthread_task = NULL;
161 }
162 }
163
164 update_min_mtu();
165 atomic_set(&module_state, MODULE_ACTIVE);
166 goto end;
167
168err:
169 debug_log(LOG_TYPE_CRIT, "Unable to allocate memory for mesh information structures: out of mem ?\n");
170 shutdown_module();
171end:
172 return;
173}
174
175/* shuts down the whole module.*/
176void shutdown_module(void)
177{
178 atomic_set(&module_state, MODULE_DEACTIVATING);
179
180 purge_outstanding_packets();
181 flush_workqueue(bat_event_workqueue);
182
183 vis_quit();
184
185 /* deactivate kernel thread for packet processing (if running) */
186 if (kthread_task) {
187 atomic_set(&exit_cond, 1);
188 wake_up_interruptible(&thread_wait);
189 kthread_stop(kthread_task);
190
191 kthread_task = NULL;
192 }
193
194 originator_free();
195
196 hna_local_free();
197 hna_global_free();
198
199 synchronize_net();
200 bat_device_destroy();
201
202 hardif_remove_interfaces();
203 synchronize_rcu();
204 atomic_set(&module_state, MODULE_INACTIVE);
205}
206
207void inc_module_count(void)
208{
209 try_module_get(THIS_MODULE);
210}
211
212void dec_module_count(void)
213{
214 module_put(THIS_MODULE);
215}
216
217int addr_to_string(char *buff, uint8_t *addr)
218{
219 return sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x",
220 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
221}
222
223/* returns 1 if they are the same originator */
224
225int compare_orig(void *data1, void *data2)
226{
227 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
228}
229
230/* hashfunction to choose an entry in a hash table of given size */
231/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
232int choose_orig(void *data, int32_t size)
233{
234 unsigned char *key = data;
235 uint32_t hash = 0;
236 size_t i;
237
238 for (i = 0; i < 6; i++) {
239 hash += key[i];
240 hash += (hash << 10);
241 hash ^= (hash >> 6);
242 }
243
244 hash += (hash << 3);
245 hash ^= (hash >> 11);
246 hash += (hash << 15);
247
248 return hash % size;
249}
250
251int is_my_mac(uint8_t *addr)
252{
253 struct batman_if *batman_if;
254 rcu_read_lock();
255 list_for_each_entry_rcu(batman_if, &if_list, list) {
256 if ((batman_if->net_dev) &&
257 (compare_orig(batman_if->net_dev->dev_addr, addr))) {
258 rcu_read_unlock();
259 return 1;
260 }
261 }
262 rcu_read_unlock();
263 return 0;
264
265}
266
267int is_bcast(uint8_t *addr)
268{
269 return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff);
270}
271
272int is_mcast(uint8_t *addr)
273{
274 return *addr & 0x01;
275}
276
277MODULE_LICENSE("GPL");
278
279MODULE_AUTHOR(DRIVER_AUTHOR);
280MODULE_DESCRIPTION(DRIVER_DESC);
281MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE);
282#ifdef REVISION_VERSION
283MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION);
284#else
285MODULE_VERSION(SOURCE_VERSION);
286#endif
diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h
new file mode 100644
index 000000000000..facb6b79ee52
--- /dev/null
+++ b/drivers/staging/batman-adv/main.h
@@ -0,0 +1,151 @@
1/*
2 * Copyright (C) 2007-2009 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/* Kernel Programming */
23#define LINUX
24
25#define DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, Simon Wunderlich <siwu@hrz.tu-chemnitz.de>"
26#define DRIVER_DESC "B.A.T.M.A.N. advanced"
27#define DRIVER_DEVICE "batman-adv"
28
29#define SOURCE_VERSION "0.2.1-beta"
30
31
32/* B.A.T.M.A.N. parameters */
33
34#define TQ_MAX_VALUE 255
35#define JITTER 20
36#define TTL 50 /* Time To Live of broadcast messages */
37#define MAX_ADDR 16 /* number of interfaces which can be added to
38 * batman. */
39
40#define PURGE_TIMEOUT 200000 /* purge originators after time in ms if no
41 * valid packet comes in -> TODO: check
42 * influence on TQ_LOCAL_WINDOW_SIZE */
43#define LOCAL_HNA_TIMEOUT 3600000
44
45#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator
46 * messages in squence numbers (should be a
47 * multiple of our word size) */
48#define TQ_GLOBAL_WINDOW_SIZE 5
49#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
50#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
51#define TQ_TOTAL_BIDRECT_LIMIT 1
52
53#define TQ_HOP_PENALTY 10
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#define ETH_STR_LEN 20
60
61#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or
62 * change the size of
63 * forw_packet->direct_link_flags */
64#define MAX_AGGREGATION_MS 100
65
66#define MODULE_INACTIVE 0
67#define MODULE_ACTIVE 1
68#define MODULE_DEACTIVATING 2
69
70
71/*
72 * Logging
73 */
74
75#define LOG_TYPE_CRIT 0 /* highest priority for fatal errors such as
76 * blocked sockets / failed packet delivery /
77 * programming errors */
78#define LOG_TYPE_WARN 1 /* warnings for small errors like wrong user
79 * input / damaged packets / etc */
80#define LOG_TYPE_NOTICE 2 /* notice information for new interfaces /
81 * changed settings / new originators / etc */
82#define LOG_TYPE_BATMAN 4 /* all messages related to routing / flooding /
83 * broadcasting / etc */
84#define LOG_TYPE_ROUTES 8 /* route or hna added / changed / deleted */
85#define LOG_TYPE_CRIT_NAME "critical"
86#define LOG_TYPE_WARN_NAME "warnings"
87#define LOG_TYPE_NOTICE_NAME "notices"
88#define LOG_TYPE_BATMAN_NAME "batman"
89#define LOG_TYPE_ROUTES_NAME "routes"
90
91/*
92 * Vis
93 */
94
95/* #define VIS_SUBCLUSTERS_DISABLED */
96
97/*
98 * Kernel headers
99 */
100
101#include <linux/mutex.h> /* mutex */
102#include <linux/module.h> /* needed by all modules */
103#include <linux/netdevice.h> /* netdevice */
104#include <linux/if_ether.h> /* ethernet header */
105#include <linux/poll.h> /* poll_table */
106#include <linux/kthread.h> /* kernel threads */
107#include <linux/pkt_sched.h> /* schedule types */
108#include <linux/workqueue.h> /* workqueue */
109#include <net/sock.h> /* struct sock */
110#include <linux/jiffies.h>
111#include "types.h"
112
113#ifndef REVISION_VERSION
114#define REVISION_VERSION_STR ""
115#else
116#define REVISION_VERSION_STR " "REVISION_VERSION
117#endif
118
119extern struct list_head if_list;
120extern struct hlist_head forw_bat_list;
121extern struct hlist_head forw_bcast_list;
122extern struct hashtable_t *orig_hash;
123
124extern spinlock_t orig_hash_lock;
125extern spinlock_t forw_bat_list_lock;
126extern spinlock_t forw_bcast_list_lock;
127
128extern atomic_t originator_interval;
129extern atomic_t vis_interval;
130extern atomic_t aggregation_enabled;
131extern int16_t num_hna;
132extern int16_t num_ifs;
133
134extern struct net_device *soft_device;
135
136extern unsigned char broadcastAddr[];
137extern atomic_t module_state;
138extern struct workqueue_struct *bat_event_workqueue;
139
140void activate_module(void);
141void shutdown_module(void);
142void inc_module_count(void);
143void dec_module_count(void);
144int addr_to_string(char *buff, uint8_t *addr);
145int compare_orig(void *data1, void *data2);
146int choose_orig(void *data, int32_t size);
147int is_my_mac(uint8_t *addr);
148int is_bcast(uint8_t *addr);
149int is_mcast(uint8_t *addr);
150
151
diff --git a/drivers/staging/batman-adv/packet.h b/drivers/staging/batman-adv/packet.h
new file mode 100644
index 000000000000..5627ca326018
--- /dev/null
+++ b/drivers/staging/batman-adv/packet.h
@@ -0,0 +1,96 @@
1/*
2 * Copyright (C) 2007-2009 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#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
23
24#define BAT_PACKET 0x01
25#define BAT_ICMP 0x02
26#define BAT_UNICAST 0x03
27#define BAT_BCAST 0x04
28#define BAT_VIS 0x05
29
30/* this file is included by batctl which needs these defines */
31#define COMPAT_VERSION 8
32#define DIRECTLINK 0x40
33#define VIS_SERVER 0x20
34
35/* ICMP message types */
36#define ECHO_REPLY 0
37#define DESTINATION_UNREACHABLE 3
38#define ECHO_REQUEST 8
39#define TTL_EXCEEDED 11
40#define PARAMETER_PROBLEM 12
41
42/* vis defines */
43#define VIS_TYPE_SERVER_SYNC 0
44#define VIS_TYPE_CLIENT_UPDATE 1
45
46struct batman_packet {
47 uint8_t packet_type;
48 uint8_t version; /* batman version field */
49 uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
50 uint8_t tq;
51 uint16_t seqno;
52 uint8_t orig[6];
53 uint8_t prev_sender[6];
54 uint8_t ttl;
55 uint8_t num_hna;
56} __attribute__((packed));
57
58#define BAT_PACKET_LEN sizeof(struct batman_packet)
59
60struct icmp_packet {
61 uint8_t packet_type;
62 uint8_t version; /* batman version field */
63 uint8_t msg_type; /* see ICMP message types above */
64 uint8_t ttl;
65 uint8_t dst[6];
66 uint8_t orig[6];
67 uint16_t seqno;
68 uint8_t uid;
69} __attribute__((packed));
70
71struct unicast_packet {
72 uint8_t packet_type;
73 uint8_t version; /* batman version field */
74 uint8_t dest[6];
75 uint8_t ttl;
76} __attribute__((packed));
77
78struct bcast_packet {
79 uint8_t packet_type;
80 uint8_t version; /* batman version field */
81 uint8_t orig[6];
82 uint16_t seqno;
83} __attribute__((packed));
84
85struct vis_packet {
86 uint8_t packet_type;
87 uint8_t version; /* batman version field */
88 uint8_t vis_type; /* which type of vis-participant sent this? */
89 uint8_t seqno; /* sequence number */
90 uint8_t entries; /* number of entries behind this struct */
91 uint8_t ttl; /* TTL */
92 uint8_t vis_orig[6]; /* originator that informs about its
93 * neighbours */
94 uint8_t target_orig[6]; /* who should receive this packet */
95 uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
96} __attribute__((packed));
diff --git a/drivers/staging/batman-adv/proc.c b/drivers/staging/batman-adv/proc.c
new file mode 100644
index 000000000000..aac3df7f13fb
--- /dev/null
+++ b/drivers/staging/batman-adv/proc.c
@@ -0,0 +1,950 @@
1/*
2 * Copyright (C) 2007-2009 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 "proc.h"
24#include "log.h"
25#include "routing.h"
26#include "translation-table.h"
27#include "hard-interface.h"
28#include "types.h"
29#include "hash.h"
30#include "vis.h"
31#include "compat.h"
32
33static uint8_t vis_format = DOT_DRAW;
34
35static struct proc_dir_entry *proc_batman_dir, *proc_interface_file;
36static struct proc_dir_entry *proc_orig_interval_file, *proc_originators_file;
37static struct proc_dir_entry *proc_log_file, *proc_log_level_file;
38static struct proc_dir_entry *proc_transt_local_file;
39static struct proc_dir_entry *proc_transt_global_file;
40static struct proc_dir_entry *proc_vis_file, *proc_vis_format_file;
41static struct proc_dir_entry *proc_aggr_file;
42
43static int proc_interfaces_read(struct seq_file *seq, void *offset)
44{
45 struct batman_if *batman_if;
46
47 rcu_read_lock();
48 list_for_each_entry_rcu(batman_if, &if_list, list) {
49 seq_printf(seq, "[%8s] %s %s \n",
50 (batman_if->if_active == IF_ACTIVE ?
51 "active" : "inactive"),
52 batman_if->dev,
53 (batman_if->if_active == IF_ACTIVE ?
54 batman_if->addr_str : " "));
55 }
56 rcu_read_unlock();
57
58 return 0;
59}
60
61static int proc_interfaces_open(struct inode *inode, struct file *file)
62{
63 return single_open(file, proc_interfaces_read, NULL);
64}
65
66static ssize_t proc_interfaces_write(struct file *instance,
67 const char __user *userbuffer,
68 size_t count, loff_t *data)
69{
70 char *if_string, *colon_ptr = NULL, *cr_ptr = NULL;
71 int not_copied = 0, if_num = 0;
72 struct batman_if *batman_if = NULL;
73
74 if_string = kmalloc(count, GFP_KERNEL);
75
76 if (!if_string)
77 return -ENOMEM;
78
79 if (count > IFNAMSIZ - 1) {
80 debug_log(LOG_TYPE_WARN,
81 "Can't add interface: device name is too long\n");
82 goto end;
83 }
84
85 not_copied = copy_from_user(if_string, userbuffer, count);
86 if_string[count - not_copied - 1] = 0;
87
88 colon_ptr = strchr(if_string, ':');
89 if (colon_ptr)
90 *colon_ptr = 0;
91
92 if (!colon_ptr) {
93 cr_ptr = strchr(if_string, '\n');
94 if (cr_ptr)
95 *cr_ptr = 0;
96 }
97
98 if (strlen(if_string) == 0) {
99 shutdown_module();
100 num_ifs = 0;
101 goto end;
102 }
103
104 /* add interface */
105 rcu_read_lock();
106 list_for_each_entry_rcu(batman_if, &if_list, list) {
107 if (strncmp(batman_if->dev, if_string, count) == 0) {
108 debug_log(LOG_TYPE_WARN, "Given interface is already active: %s\n", if_string);
109 rcu_read_unlock();
110 goto end;
111
112 }
113
114 if_num++;
115 }
116 rcu_read_unlock();
117
118 hardif_add_interface(if_string, if_num);
119
120 if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
121 (hardif_get_active_if_num() > 0))
122 activate_module();
123
124 rcu_read_lock();
125 if (list_empty(&if_list)) {
126 rcu_read_unlock();
127 goto end;
128 }
129 rcu_read_unlock();
130
131 num_ifs = if_num + 1;
132 return count;
133
134end:
135 kfree(if_string);
136 return count;
137}
138
139static int proc_orig_interval_read(struct seq_file *seq, void *offset)
140{
141 seq_printf(seq, "%i\n", atomic_read(&originator_interval));
142
143 return 0;
144}
145
146static ssize_t proc_orig_interval_write(struct file *file,
147 const char __user *buffer,
148 size_t count, loff_t *ppos)
149{
150 char *interval_string;
151 int not_copied = 0;
152 unsigned long originator_interval_tmp;
153 int retval;
154
155 interval_string = kmalloc(count, GFP_KERNEL);
156
157 if (!interval_string)
158 return -ENOMEM;
159
160 not_copied = copy_from_user(interval_string, buffer, count);
161 interval_string[count - not_copied - 1] = 0;
162
163 retval = strict_strtoul(interval_string, 10, &originator_interval_tmp);
164 if (retval) {
165 debug_log(LOG_TYPE_WARN, "New originator interval invalid\n");
166 goto end;
167 }
168
169 if (originator_interval_tmp <= JITTER * 2) {
170 debug_log(LOG_TYPE_WARN,
171 "New originator interval too small: %i (min: %i)\n",
172 originator_interval_tmp, JITTER * 2);
173 goto end;
174 }
175
176 debug_log(LOG_TYPE_NOTICE,
177 "Changing originator interval from: %i to: %i\n",
178 atomic_read(&originator_interval), originator_interval_tmp);
179
180 atomic_set(&originator_interval, originator_interval_tmp);
181
182end:
183 kfree(interval_string);
184 return count;
185}
186
187static int proc_orig_interval_open(struct inode *inode, struct file *file)
188{
189 return single_open(file, proc_orig_interval_read, NULL);
190}
191
192static int proc_originators_read(struct seq_file *seq, void *offset)
193{
194 struct hash_it_t *hashit = NULL;
195 struct orig_node *orig_node;
196 struct neigh_node *neigh_node;
197 int batman_count = 0;
198 char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
199
200 rcu_read_lock();
201 if (list_empty(&if_list)) {
202 rcu_read_unlock();
203 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
204 goto end;
205 }
206
207 if (((struct batman_if *)if_list.next)->if_active != IF_ACTIVE) {
208 rcu_read_unlock();
209 seq_printf(seq, "BATMAN disabled - primary interface not active \n");
210 goto end;
211 }
212
213 seq_printf(seq,
214 " %-14s (%s/%i) %17s [%10s]: %20s ... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s] \n",
215 "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF",
216 "Potential nexthops", SOURCE_VERSION, REVISION_VERSION_STR,
217 ((struct batman_if *)if_list.next)->dev,
218 ((struct batman_if *)if_list.next)->addr_str);
219
220 rcu_read_unlock();
221 spin_lock(&orig_hash_lock);
222
223 while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
224
225 orig_node = hashit->bucket->data;
226
227 if (!orig_node->router)
228 continue;
229
230 if (orig_node->router->tq_avg == 0)
231 continue;
232
233 batman_count++;
234
235 addr_to_string(orig_str, orig_node->orig);
236 addr_to_string(router_str, orig_node->router->addr);
237
238 seq_printf(seq, "%-17s (%3i) %17s [%10s]:",
239 orig_str, orig_node->router->tq_avg,
240 router_str, orig_node->router->if_incoming->dev);
241
242 list_for_each_entry(neigh_node, &orig_node->neigh_list, list) {
243 addr_to_string(orig_str, neigh_node->addr);
244 seq_printf(seq, " %17s (%3i)",
245 orig_str, neigh_node->tq_avg);
246 }
247
248 seq_printf(seq, "\n");
249
250 }
251
252 spin_unlock(&orig_hash_lock);
253
254 if (batman_count == 0)
255 seq_printf(seq, "No batman nodes in range ... \n");
256
257end:
258 return 0;
259}
260
261static int proc_originators_open(struct inode *inode, struct file *file)
262{
263 return single_open(file, proc_originators_read, NULL);
264}
265
266static int proc_log_level_read(struct seq_file *seq, void *offset)
267{
268
269 seq_printf(seq, "[x] %s (%d)\n", LOG_TYPE_CRIT_NAME, LOG_TYPE_CRIT);
270 seq_printf(seq, "[%c] %s (%d)\n",
271 (LOG_TYPE_WARN & log_level) ? 'x' : ' ',
272 LOG_TYPE_WARN_NAME, LOG_TYPE_WARN);
273 seq_printf(seq, "[%c] %s (%d)\n",
274 (LOG_TYPE_NOTICE & log_level) ? 'x' : ' ',
275 LOG_TYPE_NOTICE_NAME, LOG_TYPE_NOTICE);
276 seq_printf(seq, "[%c] %s (%d)\n",
277 (LOG_TYPE_BATMAN & log_level) ? 'x' : ' ',
278 LOG_TYPE_BATMAN_NAME, LOG_TYPE_BATMAN);
279 seq_printf(seq, "[%c] %s (%d)\n",
280 (LOG_TYPE_ROUTES & log_level) ? 'x' : ' ',
281 LOG_TYPE_ROUTES_NAME, LOG_TYPE_ROUTES);
282 return 0;
283}
284
285static int proc_log_level_open(struct inode *inode, struct file *file)
286{
287 return single_open(file, proc_log_level_read, NULL);
288}
289
290static ssize_t proc_log_level_write(struct file *instance,
291 const char __user *userbuffer,
292 size_t count, loff_t *data)
293{
294 char *log_level_string, *tokptr, *cp;
295 int finished, not_copied = 0;
296 unsigned long log_level_tmp = 0;
297
298 log_level_string = kmalloc(count, GFP_KERNEL);
299
300 if (!log_level_string)
301 return -ENOMEM;
302
303 not_copied = copy_from_user(log_level_string, userbuffer, count);
304 log_level_string[count - not_copied - 1] = 0;
305
306 if (strict_strtoul(log_level_string, 10, &log_level_tmp) < 0) {
307 /* was not a number, doing textual parsing */
308 log_level_tmp = 0;
309 tokptr = log_level_string;
310
311 for (cp = log_level_string, finished = 0; !finished; cp++) {
312 switch (*cp) {
313 case 0:
314 finished = 1;
315 case ' ':
316 case '\n':
317 case '\t':
318 *cp = 0;
319 /* compare */
320 if (strcmp(tokptr, LOG_TYPE_WARN_NAME) == 0)
321 log_level_tmp |= LOG_TYPE_WARN;
322 if (strcmp(tokptr, LOG_TYPE_NOTICE_NAME) == 0)
323 log_level_tmp |= LOG_TYPE_NOTICE;
324 if (strcmp(tokptr, LOG_TYPE_BATMAN_NAME) == 0)
325 log_level_tmp |= LOG_TYPE_BATMAN;
326 if (strcmp(tokptr, LOG_TYPE_ROUTES_NAME) == 0)
327 log_level_tmp |= LOG_TYPE_ROUTES;
328 tokptr = cp + 1;
329 break;
330 default:
331 ;
332 }
333 }
334 }
335
336 debug_log(LOG_TYPE_CRIT, "Changing log_level from: %i to: %i\n",
337 log_level, log_level_tmp);
338 log_level = log_level_tmp;
339
340 kfree(log_level_string);
341 return count;
342}
343
344static int proc_transt_local_read(struct seq_file *seq, void *offset)
345{
346 char *buf;
347
348 buf = kmalloc(4096, GFP_KERNEL);
349 if (!buf)
350 return 0;
351
352 rcu_read_lock();
353 if (list_empty(&if_list)) {
354 rcu_read_unlock();
355 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
356 goto end;
357 }
358
359 rcu_read_unlock();
360
361 seq_printf(seq, "Locally retrieved addresses (from %s) announced via HNA:\n", soft_device->name);
362
363 hna_local_fill_buffer_text(buf, 4096);
364 seq_printf(seq, "%s", buf);
365
366end:
367 kfree(buf);
368 return 0;
369}
370
371static int proc_transt_local_open(struct inode *inode, struct file *file)
372{
373 return single_open(file, proc_transt_local_read, NULL);
374}
375
376static int proc_transt_global_read(struct seq_file *seq, void *offset)
377{
378 char *buf;
379
380 buf = kmalloc(4096, GFP_KERNEL);
381 if (!buf)
382 return 0;
383
384 rcu_read_lock();
385 if (list_empty(&if_list)) {
386 rcu_read_unlock();
387 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
388 goto end;
389 }
390 rcu_read_unlock();
391
392
393 seq_printf(seq, "Globally announced HNAs received via the mesh (translation table):\n");
394
395 hna_global_fill_buffer_text(buf, 4096);
396 seq_printf(seq, "%s", buf);
397
398end:
399 kfree(buf);
400 return 0;
401}
402
403static int proc_transt_global_open(struct inode *inode, struct file *file)
404{
405 return single_open(file, proc_transt_global_read, NULL);
406}
407
408/* insert interface to the list of interfaces of one originator */
409
410static void proc_vis_insert_interface(const uint8_t *interface,
411 struct vis_if_list **if_entry,
412 bool primary)
413{
414 /* Did we get an empty list? (then insert imediately) */
415 if(*if_entry == NULL) {
416 *if_entry = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
417 if (*if_entry == NULL)
418 return;
419
420 (*if_entry)->primary = primary;
421 (*if_entry)->next = NULL;
422 memcpy((*if_entry)->addr, interface, ETH_ALEN);
423 } else {
424 struct vis_if_list *head_if_entry = *if_entry;
425 /* Do we already have this interface in our list? */
426 while (!compare_orig((*if_entry)->addr, (void *)interface)) {
427
428 /* Or did we reach the end (then append the interface) */
429 if ((*if_entry)->next == NULL) {
430 (*if_entry)->next = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
431 if ((*if_entry)->next == NULL)
432 return;
433
434 memcpy((*if_entry)->next->addr, interface, ETH_ALEN);
435 (*if_entry)->next->primary = primary;
436 (*if_entry)->next->next = NULL;
437 break;
438 }
439 *if_entry = (*if_entry)->next;
440 }
441 /* Rewind the list to its head */
442 *if_entry = head_if_entry;
443 }
444}
445/* read an entry */
446
447static void proc_vis_read_entry(struct seq_file *seq,
448 struct vis_info_entry *entry,
449 struct vis_if_list **if_entry,
450 uint8_t *vis_orig,
451 uint8_t current_format,
452 uint8_t first_line)
453{
454 char from[40];
455 char to[40];
456 int int_part, frac_part;
457
458 addr_to_string(to, entry->dest);
459 if (entry->quality == 0) {
460#ifndef VIS_SUBCLUSTERS_DISABLED
461 proc_vis_insert_interface(vis_orig, if_entry, true);
462#endif /* VIS_SUBCLUSTERS_DISABLED */
463 addr_to_string(from, vis_orig);
464 if (current_format == DOT_DRAW) {
465 seq_printf(seq, "\t\"%s\" -> \"%s\" [label=\"HNA\"]\n",
466 from, to);
467 } else {
468 seq_printf(seq,
469 "%s\t{ router : \"%s\", gateway : \"%s\", label : \"HNA\" }",
470 (first_line ? "" : ",\n"), from, to);
471 }
472 } else {
473#ifndef VIS_SUBCLUSTERS_DISABLED
474 proc_vis_insert_interface(entry->src, if_entry, compare_orig(entry->src, vis_orig));
475#endif /* VIS_SUBCLUSTERS_DISABLED */
476 addr_to_string(from, entry->src);
477
478 /* kernel has no printf-support for %f? it'd be better to return
479 * this in float. */
480
481 int_part = TQ_MAX_VALUE / entry->quality;
482 frac_part = 1000 * TQ_MAX_VALUE / entry->quality - int_part * 1000;
483
484 if (current_format == DOT_DRAW) {
485 seq_printf(seq,
486 "\t\"%s\" -> \"%s\" [label=\"%d.%d\"]\n",
487 from, to, int_part, frac_part);
488 } else {
489 seq_printf(seq,
490 "%s\t{ router : \"%s\", neighbour : \"%s\", label : %d.%d }",
491 (first_line ? "" : ",\n"), from, to, int_part, frac_part);
492 }
493 }
494}
495
496
497static int proc_vis_read(struct seq_file *seq, void *offset)
498{
499 struct hash_it_t *hashit = NULL;
500 struct vis_info *info;
501 struct vis_info_entry *entries;
502 struct vis_if_list *if_entries = NULL;
503 int i;
504 uint8_t current_format, first_line = 1;
505#ifndef VIS_SUBCLUSTERS_DISABLED
506 char tmp_addr_str[ETH_STR_LEN];
507 struct vis_if_list *tmp_if_next;
508#endif /* VIS_SUBCLUSTERS_DISABLED */
509
510 current_format = vis_format;
511
512 rcu_read_lock();
513 if (list_empty(&if_list) || (!is_vis_server())) {
514 rcu_read_unlock();
515 if (current_format == DOT_DRAW)
516 seq_printf(seq, "digraph {\n}\n");
517 goto end;
518 }
519
520 rcu_read_unlock();
521
522 if (current_format == DOT_DRAW)
523 seq_printf(seq, "digraph {\n");
524
525 spin_lock(&vis_hash_lock);
526 while (NULL != (hashit = hash_iterate(vis_hash, hashit))) {
527 info = hashit->bucket->data;
528 entries = (struct vis_info_entry *)
529 ((char *)info + sizeof(struct vis_info));
530
531 for (i = 0; i < info->packet.entries; i++) {
532 proc_vis_read_entry(seq, &entries[i], &if_entries,
533 info->packet.vis_orig,
534 current_format, first_line);
535 if (first_line)
536 first_line = 0;
537 }
538
539#ifndef VIS_SUBCLUSTERS_DISABLED
540 /* Generate subgraphs from the collected items */
541 if (current_format == DOT_DRAW) {
542
543 addr_to_string(tmp_addr_str, info->packet.vis_orig);
544 seq_printf(seq, "\tsubgraph \"cluster_%s\" {\n", tmp_addr_str);
545 while (if_entries != NULL) {
546
547 addr_to_string(tmp_addr_str, if_entries->addr);
548 if (if_entries->primary)
549 seq_printf(seq, "\t\t\"%s\" [peripheries=2]\n", tmp_addr_str);
550 else
551 seq_printf(seq, "\t\t\"%s\"\n", tmp_addr_str);
552
553 /* ... and empty the list while doing this */
554 tmp_if_next = if_entries->next;
555 kfree(if_entries);
556 if_entries = tmp_if_next;
557 }
558 seq_printf(seq, "\t}\n");
559 }
560#endif /* VIS_SUBCLUSTERS_DISABLED */
561 }
562 spin_unlock(&vis_hash_lock);
563
564 if (current_format == DOT_DRAW)
565 seq_printf(seq, "}\n");
566 else
567 seq_printf(seq, "\n");
568end:
569 return 0;
570}
571
572/* setting the mode of the vis server by the user */
573static ssize_t proc_vis_write(struct file *file, const char __user * buffer,
574 size_t count, loff_t *ppos)
575{
576 char *vis_mode_string;
577 int not_copied = 0;
578
579 vis_mode_string = kmalloc(count, GFP_KERNEL);
580
581 if (!vis_mode_string)
582 return -ENOMEM;
583
584 not_copied = copy_from_user(vis_mode_string, buffer, count);
585 vis_mode_string[count - not_copied - 1] = 0;
586
587 if (strcmp(vis_mode_string, "client") == 0) {
588 debug_log(LOG_TYPE_NOTICE, "Setting VIS mode to client\n");
589 vis_set_mode(VIS_TYPE_CLIENT_UPDATE);
590 } else if (strcmp(vis_mode_string, "server") == 0) {
591 debug_log(LOG_TYPE_NOTICE, "Setting VIS mode to server\n");
592 vis_set_mode(VIS_TYPE_SERVER_SYNC);
593 } else
594 debug_log(LOG_TYPE_WARN, "Unknown VIS mode: %s\n",
595 vis_mode_string);
596
597 kfree(vis_mode_string);
598 return count;
599}
600
601static int proc_vis_open(struct inode *inode, struct file *file)
602{
603 return single_open(file, proc_vis_read, NULL);
604}
605
606static int proc_vis_format_read(struct seq_file *seq, void *offset)
607{
608 uint8_t current_format = vis_format;
609
610 seq_printf(seq, "[%c] %s\n",
611 (current_format == DOT_DRAW) ? 'x' : ' ',
612 VIS_FORMAT_DD_NAME);
613 seq_printf(seq, "[%c] %s\n",
614 (current_format == JSON) ? 'x' : ' ',
615 VIS_FORMAT_JSON_NAME);
616 return 0;
617}
618
619static int proc_vis_format_open(struct inode *inode, struct file *file)
620{
621 return single_open(file, proc_vis_format_read, NULL);
622}
623
624static ssize_t proc_vis_format_write(struct file *file,
625 const char __user *buffer,
626 size_t count, loff_t *ppos)
627{
628 char *vis_format_string;
629 int not_copied = 0;
630
631 vis_format_string = kmalloc(count, GFP_KERNEL);
632
633 if (!vis_format_string)
634 return -ENOMEM;
635
636 not_copied = copy_from_user(vis_format_string, buffer, count);
637 vis_format_string[count - not_copied - 1] = 0;
638
639 if (strcmp(vis_format_string, VIS_FORMAT_DD_NAME) == 0) {
640 debug_log(LOG_TYPE_NOTICE, "Setting VIS output format to: %s\n",
641 VIS_FORMAT_DD_NAME);
642 vis_format = DOT_DRAW;
643 } else if (strcmp(vis_format_string, VIS_FORMAT_JSON_NAME) == 0) {
644 debug_log(LOG_TYPE_NOTICE, "Setting VIS output format to: %s\n",
645 VIS_FORMAT_JSON_NAME);
646 vis_format = JSON;
647 } else
648 debug_log(LOG_TYPE_WARN, "Unknown VIS output format: %s\n",
649 vis_format_string);
650
651 kfree(vis_format_string);
652 return count;
653}
654
655static int proc_aggr_read(struct seq_file *seq, void *offset)
656{
657 seq_printf(seq, "%i\n", atomic_read(&aggregation_enabled));
658
659 return 0;
660}
661
662static ssize_t proc_aggr_write(struct file *file, const char __user *buffer,
663 size_t count, loff_t *ppos)
664{
665 char *aggr_string;
666 int not_copied = 0;
667 unsigned long aggregation_enabled_tmp;
668
669 aggr_string = kmalloc(count, GFP_KERNEL);
670
671 if (!aggr_string)
672 return -ENOMEM;
673
674 not_copied = copy_from_user(aggr_string, buffer, count);
675 aggr_string[count - not_copied - 1] = 0;
676
677 strict_strtoul(aggr_string, 10, &aggregation_enabled_tmp);
678
679 if ((aggregation_enabled_tmp != 0) && (aggregation_enabled_tmp != 1)) {
680 debug_log(LOG_TYPE_WARN, "Aggregation can only be enabled (1) or disabled (0), given value: %li\n", aggregation_enabled_tmp);
681 goto end;
682 }
683
684 debug_log(LOG_TYPE_NOTICE, "Changing aggregation from: %s (%i) to: %s (%li)\n",
685 (atomic_read(&aggregation_enabled) == 1 ?
686 "enabled" : "disabled"),
687 atomic_read(&aggregation_enabled),
688 (aggregation_enabled_tmp == 1 ? "enabled" : "disabled"),
689 aggregation_enabled_tmp);
690
691 atomic_set(&aggregation_enabled, (unsigned)aggregation_enabled_tmp);
692end:
693 kfree(aggr_string);
694 return count;
695}
696
697static int proc_aggr_open(struct inode *inode, struct file *file)
698{
699 return single_open(file, proc_aggr_read, NULL);
700}
701
702/* satisfying different prototypes ... */
703static ssize_t proc_dummy_write(struct file *file, const char __user *buffer,
704 size_t count, loff_t *ppos)
705{
706 return count;
707}
708
709static const struct file_operations proc_aggr_fops = {
710 .owner = THIS_MODULE,
711 .open = proc_aggr_open,
712 .read = seq_read,
713 .write = proc_aggr_write,
714 .llseek = seq_lseek,
715 .release = single_release,
716};
717
718static const struct file_operations proc_vis_format_fops = {
719 .owner = THIS_MODULE,
720 .open = proc_vis_format_open,
721 .read = seq_read,
722 .write = proc_vis_format_write,
723 .llseek = seq_lseek,
724 .release = single_release,
725};
726
727static const struct file_operations proc_vis_fops = {
728 .owner = THIS_MODULE,
729 .open = proc_vis_open,
730 .read = seq_read,
731 .write = proc_vis_write,
732 .llseek = seq_lseek,
733 .release = single_release,
734};
735
736static const struct file_operations proc_originators_fops = {
737 .owner = THIS_MODULE,
738 .open = proc_originators_open,
739 .read = seq_read,
740 .write = proc_dummy_write,
741 .llseek = seq_lseek,
742 .release = single_release,
743};
744
745static const struct file_operations proc_transt_local_fops = {
746 .owner = THIS_MODULE,
747 .open = proc_transt_local_open,
748 .read = seq_read,
749 .write = proc_dummy_write,
750 .llseek = seq_lseek,
751 .release = single_release,
752};
753
754static const struct file_operations proc_transt_global_fops = {
755 .owner = THIS_MODULE,
756 .open = proc_transt_global_open,
757 .read = seq_read,
758 .write = proc_dummy_write,
759 .llseek = seq_lseek,
760 .release = single_release,
761};
762
763static const struct file_operations proc_log_level_fops = {
764 .owner = THIS_MODULE,
765 .open = proc_log_level_open,
766 .read = seq_read,
767 .write = proc_log_level_write,
768 .llseek = seq_lseek,
769 .release = single_release,
770};
771
772static const struct file_operations proc_interfaces_fops = {
773 .owner = THIS_MODULE,
774 .open = proc_interfaces_open,
775 .read = seq_read,
776 .write = proc_interfaces_write,
777 .llseek = seq_lseek,
778 .release = single_release,
779};
780
781static const struct file_operations proc_orig_interval_fops = {
782 .owner = THIS_MODULE,
783 .open = proc_orig_interval_open,
784 .read = seq_read,
785 .write = proc_orig_interval_write,
786 .llseek = seq_lseek,
787 .release = single_release,
788};
789
790void cleanup_procfs(void)
791{
792 if (proc_transt_global_file)
793 remove_proc_entry(PROC_FILE_TRANST_GLOBAL, proc_batman_dir);
794
795 if (proc_transt_local_file)
796 remove_proc_entry(PROC_FILE_TRANST_LOCAL, proc_batman_dir);
797
798 if (proc_log_file)
799 remove_proc_entry(PROC_FILE_LOG, proc_batman_dir);
800
801 if (proc_log_level_file)
802 remove_proc_entry(PROC_FILE_LOG_LEVEL, proc_batman_dir);
803
804 if (proc_originators_file)
805 remove_proc_entry(PROC_FILE_ORIGINATORS, proc_batman_dir);
806
807 if (proc_orig_interval_file)
808 remove_proc_entry(PROC_FILE_ORIG_INTERVAL, proc_batman_dir);
809
810 if (proc_interface_file)
811 remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir);
812
813 if (proc_vis_file)
814 remove_proc_entry(PROC_FILE_VIS, proc_batman_dir);
815
816 if (proc_vis_format_file)
817 remove_proc_entry(PROC_FILE_VIS_FORMAT, proc_batman_dir);
818
819 if (proc_aggr_file)
820 remove_proc_entry(PROC_FILE_AGGR, proc_batman_dir);
821
822 if (proc_batman_dir)
823#ifdef __NET_NET_NAMESPACE_H
824 remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net);
825#else
826 remove_proc_entry(PROC_ROOT_DIR, proc_net);
827#endif
828}
829
830int setup_procfs(void)
831{
832#ifdef __NET_NET_NAMESPACE_H
833 proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net);
834#else
835 proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, proc_net);
836#endif
837
838 if (!proc_batman_dir) {
839 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR);
840 return -EFAULT;
841 }
842
843 proc_interface_file = create_proc_entry(PROC_FILE_INTERFACES,
844 S_IWUSR | S_IRUGO,
845 proc_batman_dir);
846 if (proc_interface_file) {
847 proc_interface_file->proc_fops = &proc_interfaces_fops;
848 } else {
849 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_INTERFACES);
850 cleanup_procfs();
851 return -EFAULT;
852 }
853
854 proc_orig_interval_file = create_proc_entry(PROC_FILE_ORIG_INTERVAL,
855 S_IWUSR | S_IRUGO,
856 proc_batman_dir);
857 if (proc_orig_interval_file) {
858 proc_orig_interval_file->proc_fops = &proc_orig_interval_fops;
859 } else {
860 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIG_INTERVAL);
861 cleanup_procfs();
862 return -EFAULT;
863 }
864
865 proc_log_level_file = create_proc_entry(PROC_FILE_LOG_LEVEL,
866 S_IWUSR | S_IRUGO,
867 proc_batman_dir);
868 if (proc_log_level_file) {
869 proc_log_level_file->proc_fops = &proc_log_level_fops;
870 } else {
871 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_LOG_LEVEL);
872 cleanup_procfs();
873 return -EFAULT;
874 }
875
876 proc_originators_file = create_proc_entry(PROC_FILE_ORIGINATORS,
877 S_IRUGO, proc_batman_dir);
878 if (proc_originators_file) {
879 proc_originators_file->proc_fops = &proc_originators_fops;
880 } else {
881 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIGINATORS);
882 cleanup_procfs();
883 return -EFAULT;
884 }
885
886 proc_log_file = create_proc_entry(PROC_FILE_LOG,
887 S_IRUGO, proc_batman_dir);
888 if (proc_log_file) {
889 proc_log_file->proc_fops = &proc_log_operations;
890 } else {
891 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_FILE_LOG, PROC_FILE_GATEWAYS);
892 cleanup_procfs();
893 return -EFAULT;
894 }
895
896 proc_transt_local_file = create_proc_entry(PROC_FILE_TRANST_LOCAL,
897 S_IRUGO, proc_batman_dir);
898 if (proc_transt_local_file) {
899 proc_transt_local_file->proc_fops = &proc_transt_local_fops;
900 } else {
901 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_LOCAL);
902 cleanup_procfs();
903 return -EFAULT;
904 }
905
906 proc_transt_global_file = create_proc_entry(PROC_FILE_TRANST_GLOBAL,
907 S_IRUGO, proc_batman_dir);
908 if (proc_transt_global_file) {
909 proc_transt_global_file->proc_fops = &proc_transt_global_fops;
910 } else {
911 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_GLOBAL);
912 cleanup_procfs();
913 return -EFAULT;
914 }
915
916 proc_vis_file = create_proc_entry(PROC_FILE_VIS, S_IWUSR | S_IRUGO,
917 proc_batman_dir);
918 if (proc_vis_file) {
919 proc_vis_file->proc_fops = &proc_vis_fops;
920 } else {
921 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS);
922 cleanup_procfs();
923 return -EFAULT;
924 }
925
926 proc_vis_format_file = create_proc_entry(PROC_FILE_VIS_FORMAT,
927 S_IWUSR | S_IRUGO,
928 proc_batman_dir);
929 if (proc_vis_format_file) {
930 proc_vis_format_file->proc_fops = &proc_vis_format_fops;
931 } else {
932 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_FORMAT);
933 cleanup_procfs();
934 return -EFAULT;
935 }
936
937 proc_aggr_file = create_proc_entry(PROC_FILE_AGGR, S_IWUSR | S_IRUGO,
938 proc_batman_dir);
939 if (proc_aggr_file) {
940 proc_aggr_file->proc_fops = &proc_aggr_fops;
941 } else {
942 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_AGGR);
943 cleanup_procfs();
944 return -EFAULT;
945 }
946
947 return 0;
948}
949
950
diff --git a/drivers/staging/batman-adv/proc.h b/drivers/staging/batman-adv/proc.h
new file mode 100644
index 000000000000..16d3efdebe52
--- /dev/null
+++ b/drivers/staging/batman-adv/proc.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2007-2009 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 <linux/proc_fs.h>
23#include <linux/seq_file.h>
24
25#define PROC_ROOT_DIR "batman-adv"
26#define PROC_FILE_INTERFACES "interfaces"
27#define PROC_FILE_ORIG_INTERVAL "orig_interval"
28#define PROC_FILE_ORIGINATORS "originators"
29#define PROC_FILE_GATEWAYS "gateways"
30#define PROC_FILE_LOG "log"
31#define PROC_FILE_LOG_LEVEL "log_level"
32#define PROC_FILE_TRANST_LOCAL "transtable_local"
33#define PROC_FILE_TRANST_GLOBAL "transtable_global"
34#define PROC_FILE_VIS "vis"
35#define PROC_FILE_VIS_FORMAT "vis_format"
36#define PROC_FILE_AGGR "aggregate_ogm"
37
38void cleanup_procfs(void);
39int setup_procfs(void);
40
41/* While scanning for vis-entries of a particular vis-originator
42 * this list collects its interfaces to create a subgraph/cluster
43 * out of them later
44 */
45struct vis_if_list {
46 uint8_t addr[ETH_ALEN];
47 bool primary;
48 struct vis_if_list *next;
49};
diff --git a/drivers/staging/batman-adv/ring_buffer.c b/drivers/staging/batman-adv/ring_buffer.c
new file mode 100644
index 000000000000..751c899f54c5
--- /dev/null
+++ b/drivers/staging/batman-adv/ring_buffer.c
@@ -0,0 +1,52 @@
1/*
2 * Copyright (C) 2007-2009 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/drivers/staging/batman-adv/ring_buffer.h b/drivers/staging/batman-adv/ring_buffer.h
new file mode 100644
index 000000000000..6839ba97eeb3
--- /dev/null
+++ b/drivers/staging/batman-adv/ring_buffer.h
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2007-2009 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
22void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value);
23uint8_t ring_buffer_avg(uint8_t lq_recv[]);
diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c
new file mode 100644
index 000000000000..4a14c363ac2b
--- /dev/null
+++ b/drivers/staging/batman-adv/routing.c
@@ -0,0 +1,1010 @@
1/*
2 * Copyright (C) 2007-2009 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
25
26#include "main.h"
27#include "routing.h"
28#include "log.h"
29#include "send.h"
30#include "soft-interface.h"
31#include "hard-interface.h"
32#include "device.h"
33#include "translation-table.h"
34#include "types.h"
35#include "hash.h"
36#include "ring_buffer.h"
37#include "vis.h"
38#include "aggregation.h"
39#include "compat.h"
40
41
42
43DECLARE_WAIT_QUEUE_HEAD(thread_wait);
44static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig);
45
46static atomic_t data_ready_cond;
47atomic_t exit_cond;
48
49static void start_purge_timer(void)
50{
51 queue_delayed_work(bat_event_workqueue, &purge_orig_wq, 1 * HZ);
52}
53
54int originator_init(void)
55{
56 if (orig_hash)
57 return 1;
58
59 spin_lock(&orig_hash_lock);
60 orig_hash = hash_new(128, compare_orig, choose_orig);
61
62 if (!orig_hash)
63 goto err;
64
65 spin_unlock(&orig_hash_lock);
66 start_purge_timer();
67 return 1;
68
69err:
70 spin_unlock(&orig_hash_lock);
71 return 0;
72}
73
74void originator_free(void)
75{
76 if (!orig_hash)
77 return;
78
79 cancel_delayed_work_sync(&purge_orig_wq);
80
81 spin_lock(&orig_hash_lock);
82 hash_delete(orig_hash, free_orig_node);
83 orig_hash = NULL;
84 spin_unlock(&orig_hash_lock);
85}
86
87static struct neigh_node *create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint8_t *neigh, struct batman_if *if_incoming)
88{
89 struct neigh_node *neigh_node;
90
91 debug_log(LOG_TYPE_BATMAN, "Creating new last-hop neighbour of originator\n");
92
93 neigh_node = kmalloc(sizeof(struct neigh_node), GFP_ATOMIC);
94 memset(neigh_node, 0, sizeof(struct neigh_node));
95 INIT_LIST_HEAD(&neigh_node->list);
96
97 memcpy(neigh_node->addr, neigh, ETH_ALEN);
98 neigh_node->orig_node = orig_neigh_node;
99 neigh_node->if_incoming = if_incoming;
100
101 list_add_tail(&neigh_node->list, &orig_node->neigh_list);
102 return neigh_node;
103}
104
105void free_orig_node(void *data)
106{
107 struct list_head *list_pos, *list_pos_tmp;
108 struct neigh_node *neigh_node;
109 struct orig_node *orig_node = (struct orig_node *)data;
110
111 /* for all neighbours towards this originator ... */
112 list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
113 neigh_node = list_entry(list_pos, struct neigh_node, list);
114
115 list_del(list_pos);
116 kfree(neigh_node);
117 }
118
119 hna_global_del_orig(orig_node, "originator timed out");
120
121 kfree(orig_node->bcast_own);
122 kfree(orig_node->bcast_own_sum);
123 kfree(orig_node);
124}
125
126/* this function finds or creates an originator entry for the given address if it does not exits */
127static struct orig_node *get_orig_node(uint8_t *addr)
128{
129 struct orig_node *orig_node;
130 struct hashtable_t *swaphash;
131 char orig_str[ETH_STR_LEN];
132
133 orig_node = ((struct orig_node *)hash_find(orig_hash, addr));
134
135 if (orig_node != NULL)
136 return orig_node;
137
138 addr_to_string(orig_str, addr);
139 debug_log(LOG_TYPE_BATMAN, "Creating new originator: %s \n", orig_str);
140
141 orig_node = kmalloc(sizeof(struct orig_node), GFP_ATOMIC);
142 memset(orig_node, 0, sizeof(struct orig_node));
143 INIT_LIST_HEAD(&orig_node->neigh_list);
144
145 memcpy(orig_node->orig, addr, ETH_ALEN);
146 orig_node->router = NULL;
147 orig_node->batman_if = NULL;
148 orig_node->hna_buff = NULL;
149
150 orig_node->bcast_own = kmalloc(num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS, GFP_ATOMIC);
151 memset(orig_node->bcast_own, 0, num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS);
152
153 orig_node->bcast_own_sum = kmalloc(num_ifs * sizeof(uint8_t), GFP_ATOMIC);
154 memset(orig_node->bcast_own_sum, 0, num_ifs * sizeof(uint8_t));
155
156 hash_add(orig_hash, orig_node);
157
158 if (orig_hash->elements * 4 > orig_hash->size) {
159 swaphash = hash_resize(orig_hash, orig_hash->size * 2);
160
161 if (swaphash == NULL)
162 debug_log(LOG_TYPE_CRIT, "Couldn't resize orig hash table \n");
163 else
164 orig_hash = swaphash;
165 }
166
167 return orig_node;
168}
169
170void slide_own_bcast_window(struct batman_if *batman_if)
171{
172 struct hash_it_t *hashit = NULL;
173 struct orig_node *orig_node;
174
175 spin_lock(&orig_hash_lock);
176
177 while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
178 orig_node = hashit->bucket->data;
179
180 bit_get_packet((TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]), 1, 0);
181 orig_node->bcast_own_sum[batman_if->if_num] = bit_packet_count((TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]));
182 }
183
184 spin_unlock(&orig_hash_lock);
185}
186
187static void update_routes(struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len)
188{
189 char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
190
191 if (orig_node == NULL)
192 return;
193
194 if (orig_node->router != neigh_node) {
195 addr_to_string(orig_str, orig_node->orig);
196
197 /* route deleted */
198 if ((orig_node->router != NULL) && (neigh_node == NULL)) {
199
200 debug_log(LOG_TYPE_ROUTES, "Deleting route towards: %s\n", orig_str);
201 hna_global_del_orig(orig_node, "originator timed out");
202
203 /* route added */
204 } else if ((orig_node->router == NULL) && (neigh_node != NULL)) {
205
206 addr_to_string(neigh_str, neigh_node->addr);
207 debug_log(LOG_TYPE_ROUTES, "Adding route towards: %s (via %s)\n", orig_str, neigh_str);
208 hna_global_add_orig(orig_node, hna_buff, hna_buff_len);
209
210 /* route changed */
211 } else {
212
213 addr_to_string(neigh_str, neigh_node->addr);
214 addr_to_string(router_str, orig_node->router->addr);
215 debug_log(LOG_TYPE_ROUTES, "Changing route towards: %s (now via %s - was via %s)\n", orig_str, neigh_str, router_str);
216
217 }
218
219 if (neigh_node != NULL)
220 orig_node->batman_if = neigh_node->if_incoming;
221 else
222 orig_node->batman_if = NULL;
223
224 orig_node->router = neigh_node;
225
226 /* may be just HNA changed */
227 } else {
228
229 if ((hna_buff_len != orig_node->hna_buff_len) || ((hna_buff_len > 0) && (orig_node->hna_buff_len > 0) && (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) {
230
231 if (orig_node->hna_buff_len > 0)
232 hna_global_del_orig(orig_node, "originator changed hna");
233
234 if ((hna_buff_len > 0) && (hna_buff != NULL))
235 hna_global_add_orig(orig_node, hna_buff, hna_buff_len);
236
237 }
238
239 }
240}
241
242static int isBidirectionalNeigh(struct orig_node *orig_node, struct orig_node *orig_neigh_node, struct batman_packet *batman_packet, struct batman_if *if_incoming)
243{
244 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
245 char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN];
246 unsigned char total_count;
247
248 addr_to_string(orig_str, orig_node->orig);
249 addr_to_string(neigh_str, orig_neigh_node->orig);
250
251 if (orig_node == orig_neigh_node) {
252 list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
253
254 if (compare_orig(tmp_neigh_node->addr, orig_neigh_node->orig) && (tmp_neigh_node->if_incoming == if_incoming))
255 neigh_node = tmp_neigh_node;
256 }
257
258 if (neigh_node == NULL)
259 neigh_node = create_neighbor(orig_node, orig_neigh_node, orig_neigh_node->orig, if_incoming);
260
261 neigh_node->last_valid = jiffies;
262 } else {
263 /* find packet count of corresponding one hop neighbor */
264 list_for_each_entry(tmp_neigh_node, &orig_neigh_node->neigh_list, list) {
265
266 if (compare_orig(tmp_neigh_node->addr, orig_neigh_node->orig) && (tmp_neigh_node->if_incoming == if_incoming))
267 neigh_node = tmp_neigh_node;
268 }
269
270 if (neigh_node == NULL)
271 neigh_node = create_neighbor(orig_neigh_node, orig_neigh_node, orig_neigh_node->orig, if_incoming);
272 }
273
274 orig_node->last_valid = jiffies;
275
276 /* pay attention to not get a value bigger than 100 % */
277 total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > neigh_node->real_packet_count ? neigh_node->real_packet_count : orig_neigh_node->bcast_own_sum[if_incoming->if_num]);
278
279 /* if we have too few packets (too less data) we set tq_own to zero */
280 /* if we receive too few packets it is not considered bidirectional */
281 if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
282 orig_neigh_node->tq_own = 0;
283 else
284 /* neigh_node->real_packet_count is never zero as we only purge old information when getting new information */
285 orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / neigh_node->real_packet_count;
286
287 /*
288 * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE
289 * this does affect the nearly-symmetric links only a little,
290 * but punishes asymmetric links more.
291 * this will give a value between 0 and TQ_MAX_VALUE
292 */
293 orig_neigh_node->tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE *
294 (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
295 (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
296 (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) /
297 (TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE);
298
299 batman_packet->tq = ((batman_packet->tq * orig_neigh_node->tq_own * orig_neigh_node->tq_asym_penalty) / (TQ_MAX_VALUE * TQ_MAX_VALUE));
300
301 debug_log(LOG_TYPE_BATMAN, "bidirectional: orig = %-15s neigh = %-15s => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i \n",
302 orig_str, neigh_str, total_count, neigh_node->real_packet_count, orig_neigh_node->tq_own, orig_neigh_node->tq_asym_penalty, batman_packet->tq);
303
304 /* if link has the minimum required transmission quality consider it bidirectional */
305 if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
306 return 1;
307
308 return 0;
309}
310
311static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, struct batman_packet *batman_packet, struct batman_if *if_incoming, unsigned char *hna_buff, int hna_buff_len, char is_duplicate)
312{
313 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
314 int tmp_hna_buff_len;
315
316 debug_log(LOG_TYPE_BATMAN, "update_originator(): Searching and updating originator entry of received packet \n");
317
318 list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
319 if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming)) {
320 neigh_node = tmp_neigh_node;
321 continue;
322 }
323
324 if (is_duplicate)
325 continue;
326
327 ring_buffer_set(tmp_neigh_node->tq_recv, &tmp_neigh_node->tq_index, 0);
328 tmp_neigh_node->tq_avg = ring_buffer_avg(tmp_neigh_node->tq_recv);
329 }
330
331 if (neigh_node == NULL)
332 neigh_node = create_neighbor(orig_node, get_orig_node(ethhdr->h_source), ethhdr->h_source, if_incoming);
333 else
334 debug_log(LOG_TYPE_BATMAN, "Updating existing last-hop neighbour of originator\n");
335
336 orig_node->flags = batman_packet->flags;
337 neigh_node->last_valid = jiffies;
338
339 ring_buffer_set(neigh_node->tq_recv, &neigh_node->tq_index, batman_packet->tq);
340 neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
341
342 if (!is_duplicate) {
343 orig_node->last_ttl = batman_packet->ttl;
344 neigh_node->last_ttl = batman_packet->ttl;
345 }
346
347 tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? batman_packet->num_hna * ETH_ALEN : hna_buff_len);
348
349 /* if this neighbor already is our next hop there is nothing to change */
350 if (orig_node->router == neigh_node)
351 goto update_hna;
352
353 /* if this neighbor does not offer a better TQ we won't consider it */
354 if ((orig_node->router) &&
355 (orig_node->router->tq_avg > neigh_node->tq_avg))
356 goto update_hna;
357
358 /* if the TQ is the same and the link not more symetric we won't consider it either */
359 if ((orig_node->router) &&
360 ((neigh_node->tq_avg == orig_node->router->tq_avg) &&
361 (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num] >=
362 neigh_node->orig_node->bcast_own_sum[if_incoming->if_num])))
363 goto update_hna;
364
365 update_routes(orig_node, neigh_node, hna_buff, tmp_hna_buff_len);
366 return;
367
368update_hna:
369 update_routes(orig_node, orig_node->router, hna_buff, tmp_hna_buff_len);
370 return;
371}
372
373static char count_real_packets(struct ethhdr *ethhdr, struct batman_packet *batman_packet, struct batman_if *if_incoming)
374{
375 struct orig_node *orig_node;
376 struct neigh_node *tmp_neigh_node;
377 char is_duplicate = 0;
378
379
380 orig_node = get_orig_node(batman_packet->orig);
381 if (orig_node == NULL)
382 return 0;
383
384
385 list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
386
387 if (!is_duplicate)
388 is_duplicate = get_bit_status(tmp_neigh_node->real_bits, orig_node->last_real_seqno, batman_packet->seqno);
389
390 if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming))
391 bit_get_packet(tmp_neigh_node->real_bits, batman_packet->seqno - orig_node->last_real_seqno, 1);
392 else
393 bit_get_packet(tmp_neigh_node->real_bits, batman_packet->seqno - orig_node->last_real_seqno, 0);
394
395 tmp_neigh_node->real_packet_count = bit_packet_count(tmp_neigh_node->real_bits);
396 }
397
398 if (!is_duplicate) {
399 debug_log(LOG_TYPE_BATMAN, "updating last_seqno: old %d, new %d \n", orig_node->last_real_seqno, batman_packet->seqno);
400 orig_node->last_real_seqno = batman_packet->seqno;
401 }
402
403 return is_duplicate;
404}
405
406void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_packet, unsigned char *hna_buff, int hna_buff_len, struct batman_if *if_incoming)
407{
408 struct batman_if *batman_if;
409 struct orig_node *orig_neigh_node, *orig_node;
410 char orig_str[ETH_STR_LEN], prev_sender_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN];
411 char has_directlink_flag;
412 char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0, is_broadcast = 0, is_bidirectional, is_single_hop_neigh, is_duplicate;
413 unsigned short if_incoming_seqno;
414
415 /* Silently drop when the batman packet is actually not a correct packet.
416 *
417 * This might happen if a packet is padded (e.g. Ethernet has a
418 * minimum frame length of 64 byte) and the aggregation interprets
419 * it as an additional length.
420 *
421 * TODO: A more sane solution would be to have a bit in the batman_packet
422 * to detect whether the packet is the last packet in an aggregation.
423 * Here we expect that the padding is always zero (or not 0x01)
424 */
425 if (batman_packet->packet_type != BAT_PACKET)
426 return;
427
428 /* could be changed by schedule_own_packet() */
429 if_incoming_seqno = atomic_read(&if_incoming->seqno);
430
431 addr_to_string(orig_str, batman_packet->orig);
432 addr_to_string(prev_sender_str, batman_packet->prev_sender);
433 addr_to_string(neigh_str, ethhdr->h_source);
434
435 has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0);
436
437 is_single_hop_neigh = (compare_orig(ethhdr->h_source, batman_packet->orig) ? 1 : 0);
438
439 debug_log(LOG_TYPE_BATMAN, "Received BATMAN packet via NB: %s, IF: %s [%s] (from OG: %s, via prev OG: %s, seqno %d, tq %d, TTL %d, V %d, IDF %d) \n", neigh_str, if_incoming->dev, if_incoming->addr_str, orig_str, prev_sender_str, batman_packet->seqno, batman_packet->tq, batman_packet->ttl, batman_packet->version, has_directlink_flag);
440
441 list_for_each_entry_rcu(batman_if, &if_list, list) {
442 if (batman_if->if_active != IF_ACTIVE)
443 continue;
444
445 if (compare_orig(ethhdr->h_source, batman_if->net_dev->dev_addr))
446 is_my_addr = 1;
447
448 if (compare_orig(batman_packet->orig, batman_if->net_dev->dev_addr))
449 is_my_orig = 1;
450
451 if (compare_orig(batman_packet->prev_sender, batman_if->net_dev->dev_addr))
452 is_my_oldorig = 1;
453
454 if (compare_orig(ethhdr->h_source, broadcastAddr))
455 is_broadcast = 1;
456 }
457
458 if (batman_packet->version != COMPAT_VERSION) {
459 debug_log(LOG_TYPE_BATMAN, "Drop packet: incompatible batman version (%i) \n", batman_packet->version);
460 return;
461 }
462
463 if (is_my_addr) {
464 debug_log(LOG_TYPE_BATMAN, "Drop packet: received my own broadcast (sender: %s) \n", neigh_str);
465 return;
466 }
467
468 if (is_broadcast) {
469 debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all packets with broadcast source addr (sender: %s) \n", neigh_str);
470 return;
471 }
472
473 if (is_my_orig) {
474 orig_neigh_node = get_orig_node(ethhdr->h_source);
475
476 /* neighbour has to indicate direct link and it has to come via the corresponding interface */
477 /* if received seqno equals last send seqno save new seqno for bidirectional check */
478 if (has_directlink_flag && compare_orig(if_incoming->net_dev->dev_addr, batman_packet->orig) &&
479 (batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
480 bit_mark((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * NUM_WORDS]), 0);
481 orig_neigh_node->bcast_own_sum[if_incoming->if_num] = bit_packet_count((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * NUM_WORDS]));
482 }
483
484 debug_log(LOG_TYPE_BATMAN, "Drop packet: originator packet from myself (via neighbour) \n");
485 return;
486 }
487
488 if (batman_packet->tq == 0) {
489 count_real_packets(ethhdr, batman_packet, if_incoming);
490
491 debug_log(LOG_TYPE_BATMAN, "Drop packet: originator packet with tq equal 0 \n");
492 return;
493 }
494
495 if (is_my_oldorig) {
496 debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all rebroadcast echos (sender: %s) \n", neigh_str);
497 return;
498 }
499
500 is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming);
501
502 orig_node = get_orig_node(batman_packet->orig);
503 if (orig_node == NULL)
504 return;
505
506 /* avoid temporary routing loops */
507 if ((orig_node->router) && (orig_node->router->orig_node->router) &&
508 (compare_orig(orig_node->router->addr, batman_packet->prev_sender)) &&
509 !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) &&
510 (compare_orig(orig_node->router->addr, orig_node->router->orig_node->router->addr))) {
511 debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %s) \n", neigh_str);
512 return;
513 }
514
515 /* if sender is a direct neighbor the sender mac equals originator mac */
516 orig_neigh_node = (is_single_hop_neigh ? orig_node : get_orig_node(ethhdr->h_source));
517 if (orig_neigh_node == NULL)
518 return;
519
520 /* drop packet if sender is not a direct neighbor and if we don't route towards it */
521 if (!is_single_hop_neigh && (orig_neigh_node->router == NULL)) {
522 debug_log(LOG_TYPE_BATMAN, "Drop packet: OGM via unknown neighbor! \n");
523 return;
524 }
525
526 is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node, batman_packet, if_incoming);
527
528 /* update ranking if it is not a duplicate or has the same seqno and similar ttl as the non-duplicate */
529 if (is_bidirectional && (!is_duplicate ||
530 ((orig_node->last_real_seqno == batman_packet->seqno) &&
531 (orig_node->last_ttl - 3 <= batman_packet->ttl))))
532 update_orig(orig_node, ethhdr, batman_packet, if_incoming, hna_buff, hna_buff_len, is_duplicate);
533
534 /* is single hop (direct) neighbour */
535 if (is_single_hop_neigh) {
536
537 /* mark direct link on incoming interface */
538 schedule_forward_packet(orig_node, ethhdr, batman_packet, 1, hna_buff_len, if_incoming);
539
540 debug_log(LOG_TYPE_BATMAN, "Forwarding packet: rebroadcast neighbour packet with direct link flag \n");
541 return;
542 }
543
544 /* multihop originator */
545 if (!is_bidirectional) {
546 debug_log(LOG_TYPE_BATMAN, "Drop packet: not received via bidirectional link\n");
547 return;
548 }
549
550 if (is_duplicate) {
551 debug_log(LOG_TYPE_BATMAN, "Drop packet: duplicate packet received\n");
552 return;
553 }
554
555 debug_log(LOG_TYPE_BATMAN, "Forwarding packet: rebroadcast originator packet \n");
556 schedule_forward_packet(orig_node, ethhdr, batman_packet, 0, hna_buff_len, if_incoming);
557}
558
559void purge_orig(struct work_struct *work)
560{
561 struct list_head *list_pos, *list_pos_tmp;
562 struct hash_it_t *hashit = NULL;
563 struct orig_node *orig_node;
564 struct neigh_node *neigh_node, *best_neigh_node;
565 char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN], neigh_purged;
566
567 spin_lock(&orig_hash_lock);
568
569 /* for all origins... */
570 while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
571
572 orig_node = hashit->bucket->data;
573 addr_to_string(orig_str, orig_node->orig);
574
575 if (time_after(jiffies, orig_node->last_valid + ((2 * PURGE_TIMEOUT * HZ) / 1000))) {
576
577 debug_log(LOG_TYPE_BATMAN, "Originator timeout: originator %s, last_valid %u \n", orig_str, (orig_node->last_valid / HZ));
578
579 hash_remove_bucket(orig_hash, hashit);
580 free_orig_node(orig_node);
581
582 } else {
583
584 best_neigh_node = NULL;
585 neigh_purged = 0;
586
587 /* for all neighbours towards this originator ... */
588 list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
589 neigh_node = list_entry(list_pos, struct neigh_node, list);
590
591 if (time_after(jiffies, neigh_node->last_valid + ((PURGE_TIMEOUT * HZ) / 1000))) {
592
593 addr_to_string(neigh_str, neigh_node->addr);
594 debug_log(LOG_TYPE_BATMAN, "Neighbour timeout: originator %s, neighbour: %s, last_valid %u \n", orig_str, neigh_str, (neigh_node->last_valid / HZ));
595
596 neigh_purged = 1;
597 list_del(list_pos);
598 kfree(neigh_node);
599
600 } else {
601
602 if ((best_neigh_node == NULL) || (neigh_node->tq_avg > best_neigh_node->tq_avg))
603 best_neigh_node = neigh_node;
604
605 }
606
607 }
608
609 if (neigh_purged)
610 update_routes(orig_node, best_neigh_node, orig_node->hna_buff, orig_node->hna_buff_len);
611
612 }
613
614 }
615
616 spin_unlock(&orig_hash_lock);
617
618 start_purge_timer();
619}
620
621static int receive_raw_packet(struct socket *raw_sock, unsigned char *packet_buff, int packet_buff_len)
622{
623 struct kvec iov;
624 struct msghdr msg;
625
626 iov.iov_base = packet_buff;
627 iov.iov_len = packet_buff_len;
628
629 msg.msg_flags = MSG_DONTWAIT; /* non-blocking */
630 msg.msg_name = NULL;
631 msg.msg_namelen = 0;
632 msg.msg_control = NULL;
633
634 return kernel_recvmsg(raw_sock, &msg, &iov, 1, packet_buff_len, MSG_DONTWAIT);
635}
636
637int packet_recv_thread(void *data)
638{
639 struct batman_if *batman_if;
640 struct ethhdr *ethhdr;
641 struct batman_packet *batman_packet;
642 struct unicast_packet *unicast_packet;
643 struct bcast_packet *bcast_packet;
644 struct icmp_packet *icmp_packet;
645 struct vis_packet *vis_packet;
646 struct orig_node *orig_node;
647 unsigned char *packet_buff, src_str[ETH_STR_LEN], dst_str[ETH_STR_LEN];
648 int vis_info_len;
649 int result;
650
651 atomic_set(&data_ready_cond, 0);
652 atomic_set(&exit_cond, 0);
653 packet_buff = kmalloc(PACKBUFF_SIZE, GFP_KERNEL);
654 if (!packet_buff) {
655 debug_log(LOG_TYPE_CRIT, "Could allocate memory for the packet buffer. :(\n");
656 return -1;
657 }
658
659 while ((!kthread_should_stop()) && (!atomic_read(&exit_cond))) {
660
661 wait_event_interruptible(thread_wait, (atomic_read(&data_ready_cond) || atomic_read(&exit_cond)));
662
663 atomic_set(&data_ready_cond, 0);
664
665 if (kthread_should_stop() || atomic_read(&exit_cond))
666 break;
667
668 /* we only want to safely traverse the list, hard-interfaces
669 * won't be deleted anyway as long as this thread runs. */
670
671 rcu_read_lock();
672 list_for_each_entry_rcu(batman_if, &if_list, list) {
673 rcu_read_unlock();
674
675 result = -1;
676
677 while (1) {
678 if (batman_if->if_active != IF_ACTIVE) {
679 if (batman_if->if_active != IF_TO_BE_ACTIVATED)
680 debug_log(LOG_TYPE_NOTICE,
681 "Could not read from deactivated interface %s!\n",
682 batman_if->dev);
683
684 if (batman_if->raw_sock)
685 receive_raw_packet(batman_if->raw_sock, packet_buff, PACKBUFF_SIZE);
686 result = 0;
687 break;
688 }
689
690 result = receive_raw_packet(batman_if->raw_sock, packet_buff, PACKBUFF_SIZE);
691 if (result <= 0)
692 break;
693
694 if (result < sizeof(struct ethhdr) + 2)
695 continue;
696
697 ethhdr = (struct ethhdr *)packet_buff;
698 batman_packet = (struct batman_packet *)(packet_buff + sizeof(struct ethhdr));
699
700 if (batman_packet->version != COMPAT_VERSION) {
701 debug_log(LOG_TYPE_BATMAN, "Drop packet: incompatible batman version (%i) \n", batman_packet->version);
702 continue;
703 }
704
705 switch (batman_packet->packet_type) {
706 /* batman originator packet */
707 case BAT_PACKET:
708 /* packet with broadcast indication but unicast recipient */
709 if (!is_bcast(ethhdr->h_dest))
710 continue;
711
712 /* packet with broadcast sender address */
713 if (is_bcast(ethhdr->h_source))
714 continue;
715
716 /* drop packet if it has not at least one batman packet as payload */
717 if (result < sizeof(struct ethhdr) + sizeof(struct batman_packet))
718 continue;
719
720 spin_lock(&orig_hash_lock);
721 receive_aggr_bat_packet(ethhdr,
722 packet_buff + sizeof(struct ethhdr),
723 result - sizeof(struct ethhdr),
724 batman_if);
725 spin_unlock(&orig_hash_lock);
726
727 break;
728
729 /* batman icmp packet */
730 case BAT_ICMP:
731 /* packet with unicast indication but broadcast recipient */
732 if (is_bcast(ethhdr->h_dest))
733 continue;
734
735 /* packet with broadcast sender address */
736 if (is_bcast(ethhdr->h_source))
737 continue;
738
739 /* not for me */
740 if (!is_my_mac(ethhdr->h_dest))
741 continue;
742
743 /* drop packet if it has not necessary minimum size */
744 if (result < sizeof(struct ethhdr) + sizeof(struct icmp_packet))
745 continue;
746
747 icmp_packet = (struct icmp_packet *)(packet_buff + sizeof(struct ethhdr));
748
749 /* packet for me */
750 if (is_my_mac(icmp_packet->dst)) {
751
752 /* add data to device queue */
753 if (icmp_packet->msg_type != ECHO_REQUEST) {
754 bat_device_receive_packet(icmp_packet);
755 continue;
756 }
757
758 /* answer echo request (ping) */
759 /* get routing information */
760 spin_lock(&orig_hash_lock);
761 orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->orig));
762
763 if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
764
765 memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
766 memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
767 icmp_packet->msg_type = ECHO_REPLY;
768 icmp_packet->ttl = TTL;
769
770 send_raw_packet(packet_buff + sizeof(struct ethhdr),
771 result - sizeof(struct ethhdr),
772 orig_node->batman_if,
773 orig_node->router->addr);
774
775 }
776
777 spin_unlock(&orig_hash_lock);
778 continue;
779
780 }
781
782 /* TTL exceeded */
783 if (icmp_packet->ttl < 2) {
784
785 addr_to_string(src_str, icmp_packet->orig);
786 addr_to_string(dst_str, icmp_packet->dst);
787
788 debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str);
789
790 /* send TTL exceeded if packet is an echo request (traceroute) */
791 if (icmp_packet->msg_type != ECHO_REQUEST)
792 continue;
793
794 /* get routing information */
795 spin_lock(&orig_hash_lock);
796 orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->orig));
797
798 if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
799
800 memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
801 memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
802 icmp_packet->msg_type = TTL_EXCEEDED;
803 icmp_packet->ttl = TTL;
804
805 send_raw_packet(packet_buff + sizeof(struct ethhdr),
806 result - sizeof(struct ethhdr),
807 orig_node->batman_if,
808 orig_node->router->addr);
809
810 }
811
812 spin_unlock(&orig_hash_lock);
813 continue;
814
815 }
816
817 /* get routing information */
818 spin_lock(&orig_hash_lock);
819 orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->dst));
820
821 if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
822
823 /* decrement ttl */
824 icmp_packet->ttl--;
825
826 /* route it */
827 send_raw_packet(packet_buff + sizeof(struct ethhdr),
828 result - sizeof(struct ethhdr),
829 orig_node->batman_if,
830 orig_node->router->addr);
831 }
832
833 spin_unlock(&orig_hash_lock);
834 break;
835
836 /* unicast packet */
837 case BAT_UNICAST:
838 /* packet with unicast indication but broadcast recipient */
839 if (is_bcast(ethhdr->h_dest))
840 continue;
841
842 /* packet with broadcast sender address */
843 if (is_bcast(ethhdr->h_source))
844 continue;
845
846 /* not for me */
847 if (!is_my_mac(ethhdr->h_dest))
848 continue;
849
850 /* drop packet if it has not necessary minimum size */
851 if (result < sizeof(struct ethhdr) + sizeof(struct unicast_packet))
852 continue;
853
854 unicast_packet = (struct unicast_packet *)(packet_buff + sizeof(struct ethhdr));
855
856 /* packet for me */
857 if (is_my_mac(unicast_packet->dest)) {
858
859 interface_rx(soft_device, packet_buff + sizeof(struct ethhdr) + sizeof(struct unicast_packet), result - sizeof(struct ethhdr) - sizeof(struct unicast_packet));
860 continue;
861
862 }
863
864 /* TTL exceeded */
865 if (unicast_packet->ttl < 2) {
866 addr_to_string(src_str, ((struct ethhdr *)(unicast_packet + 1))->h_source);
867 addr_to_string(dst_str, unicast_packet->dest);
868
869 debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str);
870 continue;
871 }
872
873 /* get routing information */
874 spin_lock(&orig_hash_lock);
875 orig_node = ((struct orig_node *)hash_find(orig_hash, unicast_packet->dest));
876
877 if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
878 /* decrement ttl */
879 unicast_packet->ttl--;
880
881 /* route it */
882 send_raw_packet(packet_buff + sizeof(struct ethhdr),
883 result - sizeof(struct ethhdr),
884 orig_node->batman_if,
885 orig_node->router->addr);
886 }
887
888 spin_unlock(&orig_hash_lock);
889 break;
890
891 /* broadcast packet */
892 case BAT_BCAST:
893 /* packet with broadcast indication but unicast recipient */
894 if (!is_bcast(ethhdr->h_dest))
895 continue;
896
897 /* packet with broadcast sender address */
898 if (is_bcast(ethhdr->h_source))
899 continue;
900
901 /* drop packet if it has not necessary minimum size */
902 if (result < sizeof(struct ethhdr) + sizeof(struct bcast_packet))
903 continue;
904
905 /* ignore broadcasts sent by myself */
906 if (is_my_mac(ethhdr->h_source))
907 continue;
908
909 bcast_packet = (struct bcast_packet *)(packet_buff + sizeof(struct ethhdr));
910
911 /* ignore broadcasts originated by myself */
912 if (is_my_mac(bcast_packet->orig))
913 continue;
914
915 spin_lock(&orig_hash_lock);
916 orig_node = ((struct orig_node *)hash_find(orig_hash, bcast_packet->orig));
917
918 if (orig_node == NULL) {
919 spin_unlock(&orig_hash_lock);
920 continue;
921 }
922
923 /* check flood history */
924 if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno, ntohs(bcast_packet->seqno))) {
925 spin_unlock(&orig_hash_lock);
926 continue;
927 }
928
929 /* mark broadcast in flood history */
930 if (bit_get_packet(orig_node->bcast_bits, ntohs(bcast_packet->seqno) - orig_node->last_bcast_seqno, 1))
931 orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno);
932
933 spin_unlock(&orig_hash_lock);
934
935 /* broadcast for me */
936 interface_rx(soft_device, packet_buff + sizeof(struct ethhdr) + sizeof(struct bcast_packet), result - sizeof(struct ethhdr) - sizeof(struct bcast_packet));
937
938 /* rebroadcast packet */
939 add_bcast_packet_to_list(packet_buff + sizeof(struct ethhdr),
940 result - sizeof(struct ethhdr));
941
942 break;
943
944 /* vis packet */
945 case BAT_VIS:
946 /* drop if too short. */
947 if (result < sizeof(struct ethhdr) + sizeof(struct vis_packet))
948 continue;
949
950 /* not for me */
951 if (!is_my_mac(ethhdr->h_dest))
952 continue;
953
954 vis_packet = (struct vis_packet *)(packet_buff + sizeof(struct ethhdr));
955 vis_info_len = result - sizeof(struct ethhdr) - sizeof(struct vis_packet);
956
957 /* ignore own packets */
958 if (is_my_mac(vis_packet->vis_orig))
959 continue;
960
961 if (is_my_mac(vis_packet->sender_orig))
962 continue;
963
964 switch (vis_packet->vis_type) {
965 case VIS_TYPE_SERVER_SYNC:
966 receive_server_sync_packet(vis_packet, vis_info_len);
967 break;
968
969 case VIS_TYPE_CLIENT_UPDATE:
970 receive_client_update_packet(vis_packet, vis_info_len);
971 break;
972
973 default: /* ignore unknown packet */
974 break;
975 }
976
977 break;
978 }
979
980 }
981
982 if ((result < 0) && (result != -EAGAIN))
983 debug_log(LOG_TYPE_CRIT, "Could not receive packet from interface %s: %i\n", batman_if->dev, result);
984
985 /* lock for the next iteration */
986 rcu_read_lock();
987 }
988 rcu_read_unlock();
989
990 }
991 kfree(packet_buff);
992
993 /* do not exit until kthread_stop() is actually called, otherwise it will wait for us
994 * forever. */
995 while (!kthread_should_stop())
996 schedule();
997
998 return 0;
999}
1000
1001void batman_data_ready(struct sock *sk, int len)
1002{
1003 void (*data_ready)(struct sock *, int) = sk->sk_user_data;
1004
1005 data_ready(sk, len);
1006
1007 atomic_set(&data_ready_cond, 1);
1008 wake_up_interruptible(&thread_wait);
1009}
1010
diff --git a/drivers/staging/batman-adv/routing.h b/drivers/staging/batman-adv/routing.h
new file mode 100644
index 000000000000..0123ea86debb
--- /dev/null
+++ b/drivers/staging/batman-adv/routing.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2007-2009 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 "types.h"
23
24extern wait_queue_head_t thread_wait;
25extern atomic_t exit_cond;
26
27int originator_init(void);
28void free_orig_node(void *data);
29void originator_free(void);
30void slide_own_bcast_window(struct batman_if *batman_if);
31void batman_data_ready(struct sock *sk, int len);
32void purge_orig(struct work_struct *work);
33int packet_recv_thread(void *data);
34void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_packet, unsigned char *hna_buff, int hna_buff_len, struct batman_if *if_incoming);
diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c
new file mode 100644
index 000000000000..d724798278d6
--- /dev/null
+++ b/drivers/staging/batman-adv/send.c
@@ -0,0 +1,473 @@
1/*
2 * Copyright (C) 2007-2009 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 "log.h"
25#include "routing.h"
26#include "translation-table.h"
27#include "hard-interface.h"
28#include "types.h"
29#include "vis.h"
30#include "aggregation.h"
31
32#include "compat.h"
33
34/* apply hop penalty for a normal link */
35static uint8_t hop_penalty(const uint8_t tq)
36{
37 return (tq * (TQ_MAX_VALUE - TQ_HOP_PENALTY)) / (TQ_MAX_VALUE);
38}
39
40/* when do we schedule our own packet to be sent */
41static unsigned long own_send_time(void)
42{
43 return jiffies +
44 (((atomic_read(&originator_interval) - JITTER +
45 (random32() % 2*JITTER)) * HZ) / 1000);
46}
47
48/* when do we schedule a forwarded packet to be sent */
49static unsigned long forward_send_time(void)
50{
51 unsigned long send_time = jiffies; /* Starting now plus... */
52
53 if (atomic_read(&aggregation_enabled))
54 send_time += (((MAX_AGGREGATION_MS - (JITTER/2) +
55 (random32() % JITTER)) * HZ) / 1000);
56 else
57 send_time += (((random32() % (JITTER/2)) * HZ) / 1000);
58
59 return send_time;
60}
61
62/* sends a raw packet. */
63void send_raw_packet(unsigned char *pack_buff, int pack_buff_len,
64 struct batman_if *batman_if, uint8_t *dst_addr)
65{
66 struct ethhdr *ethhdr;
67 struct sk_buff *skb;
68 int retval;
69 char *data;
70
71 if (batman_if->if_active != IF_ACTIVE)
72 return;
73
74 if (!(batman_if->net_dev->flags & IFF_UP)) {
75 debug_log(LOG_TYPE_WARN,
76 "Interface %s is not up - can't send packet via that interface (IF_TO_BE_DEACTIVATED was here) !\n",
77 batman_if->dev);
78 return;
79 }
80
81 skb = dev_alloc_skb(pack_buff_len + sizeof(struct ethhdr));
82 if (!skb)
83 return;
84 data = skb_put(skb, pack_buff_len + sizeof(struct ethhdr));
85
86 memcpy(data + sizeof(struct ethhdr), pack_buff, pack_buff_len);
87
88 ethhdr = (struct ethhdr *) data;
89 memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN);
90 memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
91 ethhdr->h_proto = __constant_htons(ETH_P_BATMAN);
92
93 skb_reset_mac_header(skb);
94 skb_set_network_header(skb, ETH_HLEN);
95 skb->priority = TC_PRIO_CONTROL;
96 skb->protocol = __constant_htons(ETH_P_BATMAN);
97 skb->dev = batman_if->net_dev;
98
99 /* dev_queue_xmit() returns a negative result on error. However on
100 * congestion and traffic shaping, it drops and returns NET_XMIT_DROP
101 * (which is > 0). This will not be treated as an error. */
102 retval = dev_queue_xmit(skb);
103 if (retval < 0)
104 debug_log(LOG_TYPE_CRIT,
105 "Can't write to raw socket (IF_TO_BE_DEACTIVATED was here): %i\n",
106 retval);
107}
108
109/* Send a packet to a given interface */
110static void send_packet_to_if(struct forw_packet *forw_packet,
111 struct batman_if *batman_if)
112{
113 char *fwd_str;
114 uint8_t packet_num;
115 int16_t buff_pos;
116 struct batman_packet *batman_packet;
117 char orig_str[ETH_STR_LEN];
118
119 if (batman_if->if_active != IF_ACTIVE)
120 return;
121
122 packet_num = buff_pos = 0;
123 batman_packet = (struct batman_packet *)
124 (forw_packet->packet_buff);
125
126 /* adjust all flags and log packets */
127 while (aggregated_packet(buff_pos,
128 forw_packet->packet_len,
129 batman_packet->num_hna)) {
130
131 /* we might have aggregated direct link packets with an
132 * ordinary base packet */
133 if ((forw_packet->direct_link_flags & (1 << packet_num)) &&
134 (forw_packet->if_incoming == batman_if))
135 batman_packet->flags |= DIRECTLINK;
136 else
137 batman_packet->flags &= ~DIRECTLINK;
138
139 addr_to_string(orig_str, batman_packet->orig);
140 fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
141 "Sending own" :
142 "Forwarding"));
143 debug_log(LOG_TYPE_BATMAN,
144 "%s %spacket (originator %s, seqno %d, TQ %d, TTL %d, IDF %s) on interface %s [%s]\n",
145 fwd_str,
146 (packet_num > 0 ? "aggregated " : ""),
147 orig_str, ntohs(batman_packet->seqno),
148 batman_packet->tq, batman_packet->ttl,
149 (batman_packet->flags & DIRECTLINK ?
150 "on" : "off"),
151 batman_if->dev, batman_if->addr_str);
152
153 buff_pos += sizeof(struct batman_packet) +
154 (batman_packet->num_hna * ETH_ALEN);
155 packet_num++;
156 batman_packet = (struct batman_packet *)
157 (forw_packet->packet_buff + buff_pos);
158 }
159
160 send_raw_packet(forw_packet->packet_buff,
161 forw_packet->packet_len,
162 batman_if, broadcastAddr);
163}
164
165/* send a batman packet */
166static void send_packet(struct forw_packet *forw_packet)
167{
168 struct batman_if *batman_if;
169 struct batman_packet *batman_packet =
170 (struct batman_packet *)(forw_packet->packet_buff);
171 char orig_str[ETH_STR_LEN];
172 unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
173
174 if (!forw_packet->if_incoming) {
175 debug_log(LOG_TYPE_CRIT,
176 "Error - can't forward packet: incoming iface not specified\n");
177 return;
178 }
179
180 if (forw_packet->if_incoming->if_active != IF_ACTIVE)
181 return;
182
183 addr_to_string(orig_str, batman_packet->orig);
184
185 /* multihomed peer assumed */
186 /* non-primary OGMs are only broadcasted on their interface */
187 if ((directlink && (batman_packet->ttl == 1)) ||
188 (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
189
190 /* FIXME: what about aggregated packets ? */
191 debug_log(LOG_TYPE_BATMAN,
192 "%s packet (originator %s, seqno %d, TTL %d) on interface %s [%s]\n",
193 (forw_packet->own ? "Sending own" : "Forwarding"),
194 orig_str, ntohs(batman_packet->seqno),
195 batman_packet->ttl, forw_packet->if_incoming->dev,
196 forw_packet->if_incoming->addr_str);
197
198 send_raw_packet(forw_packet->packet_buff,
199 forw_packet->packet_len,
200 forw_packet->if_incoming,
201 broadcastAddr);
202 return;
203 }
204
205 /* broadcast on every interface */
206 rcu_read_lock();
207 list_for_each_entry_rcu(batman_if, &if_list, list)
208 send_packet_to_if(forw_packet, batman_if);
209 rcu_read_unlock();
210}
211
212static void rebuild_batman_packet(struct batman_if *batman_if)
213{
214 int new_len;
215 unsigned char *new_buff;
216 struct batman_packet *batman_packet;
217
218 new_len = sizeof(struct batman_packet) + (num_hna * ETH_ALEN);
219 new_buff = kmalloc(new_len, GFP_ATOMIC);
220
221 /* keep old buffer if kmalloc should fail */
222 if (new_buff) {
223 memcpy(new_buff, batman_if->packet_buff,
224 sizeof(struct batman_packet));
225 batman_packet = (struct batman_packet *)new_buff;
226
227 batman_packet->num_hna = hna_local_fill_buffer(
228 new_buff + sizeof(struct batman_packet),
229 new_len - sizeof(struct batman_packet));
230
231 kfree(batman_if->packet_buff);
232 batman_if->packet_buff = new_buff;
233 batman_if->packet_len = new_len;
234 }
235}
236
237void schedule_own_packet(struct batman_if *batman_if)
238{
239 unsigned long send_time;
240 struct batman_packet *batman_packet;
241
242 /**
243 * the interface gets activated here to avoid race conditions between
244 * the moment of activating the interface in
245 * hardif_activate_interface() where the originator mac is set and
246 * outdated packets (especially uninitialized mac addresses) in the
247 * packet queue
248 */
249 if (batman_if->if_active == IF_TO_BE_ACTIVATED)
250 batman_if->if_active = IF_ACTIVE;
251
252 /* if local hna has changed and interface is a primary interface */
253 if ((atomic_read(&hna_local_changed)) && (batman_if->if_num == 0))
254 rebuild_batman_packet(batman_if);
255
256 /**
257 * NOTE: packet_buff might just have been re-allocated in
258 * rebuild_batman_packet()
259 */
260 batman_packet = (struct batman_packet *)batman_if->packet_buff;
261
262 /* change sequence number to network order */
263 batman_packet->seqno = htons((uint16_t)atomic_read(&batman_if->seqno));
264
265 if (is_vis_server())
266 batman_packet->flags = VIS_SERVER;
267 else
268 batman_packet->flags = 0;
269
270 /* could be read by receive_bat_packet() */
271 atomic_inc(&batman_if->seqno);
272
273 slide_own_bcast_window(batman_if);
274 send_time = own_send_time();
275 add_bat_packet_to_list(batman_if->packet_buff,
276 batman_if->packet_len, batman_if, 1, send_time);
277}
278
279void schedule_forward_packet(struct orig_node *orig_node,
280 struct ethhdr *ethhdr,
281 struct batman_packet *batman_packet,
282 uint8_t directlink, int hna_buff_len,
283 struct batman_if *if_incoming)
284{
285 unsigned char in_tq, in_ttl, tq_avg = 0;
286 unsigned long send_time;
287
288 if (batman_packet->ttl <= 1) {
289 debug_log(LOG_TYPE_BATMAN, "ttl exceeded \n");
290 return;
291 }
292
293 in_tq = batman_packet->tq;
294 in_ttl = batman_packet->ttl;
295
296 batman_packet->ttl--;
297 memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
298
299 /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
300 * of our best tq value */
301 if ((orig_node->router) && (orig_node->router->tq_avg != 0)) {
302
303 /* rebroadcast ogm of best ranking neighbor as is */
304 if (!compare_orig(orig_node->router->addr, ethhdr->h_source)) {
305 batman_packet->tq = orig_node->router->tq_avg;
306
307 if (orig_node->router->last_ttl)
308 batman_packet->ttl = orig_node->router->last_ttl - 1;
309 }
310
311 tq_avg = orig_node->router->tq_avg;
312 }
313
314 /* apply hop penalty */
315 batman_packet->tq = hop_penalty(batman_packet->tq);
316
317 debug_log(LOG_TYPE_BATMAN, "Forwarding packet: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i \n",
318 in_tq, tq_avg, batman_packet->tq, in_ttl - 1,
319 batman_packet->ttl);
320
321 batman_packet->seqno = htons(batman_packet->seqno);
322
323 if (directlink)
324 batman_packet->flags |= DIRECTLINK;
325 else
326 batman_packet->flags &= ~DIRECTLINK;
327
328 send_time = forward_send_time();
329 add_bat_packet_to_list((unsigned char *)batman_packet,
330 sizeof(struct batman_packet) + hna_buff_len,
331 if_incoming, 0, send_time);
332}
333
334static void forw_packet_free(struct forw_packet *forw_packet)
335{
336 kfree(forw_packet->packet_buff);
337 kfree(forw_packet);
338}
339
340static void _add_bcast_packet_to_list(struct forw_packet *forw_packet,
341 unsigned long send_time)
342{
343 INIT_HLIST_NODE(&forw_packet->list);
344
345 /* add new packet to packet list */
346 spin_lock(&forw_bcast_list_lock);
347 hlist_add_head(&forw_packet->list, &forw_bcast_list);
348 spin_unlock(&forw_bcast_list_lock);
349
350 /* start timer for this packet */
351 INIT_DELAYED_WORK(&forw_packet->delayed_work,
352 send_outstanding_bcast_packet);
353 queue_delayed_work(bat_event_workqueue, &forw_packet->delayed_work,
354 send_time);
355}
356
357void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len)
358{
359 struct forw_packet *forw_packet;
360
361 forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
362 if (!forw_packet)
363 return;
364
365 forw_packet->packet_buff = kmalloc(packet_len, GFP_ATOMIC);
366 if (!forw_packet->packet_buff)
367 return;
368
369 forw_packet->packet_len = packet_len;
370 memcpy(forw_packet->packet_buff, packet_buff, forw_packet->packet_len);
371
372 /* how often did we send the bcast packet ? */
373 forw_packet->num_packets = 0;
374
375 _add_bcast_packet_to_list(forw_packet, 1);
376}
377
378void send_outstanding_bcast_packet(struct work_struct *work)
379{
380 struct batman_if *batman_if;
381 struct delayed_work *delayed_work =
382 container_of(work, struct delayed_work, work);
383 struct forw_packet *forw_packet =
384 container_of(delayed_work, struct forw_packet, delayed_work);
385
386 spin_lock(&forw_bcast_list_lock);
387 hlist_del(&forw_packet->list);
388 spin_unlock(&forw_bcast_list_lock);
389
390 /* rebroadcast packet */
391 rcu_read_lock();
392 list_for_each_entry_rcu(batman_if, &if_list, list) {
393 send_raw_packet(forw_packet->packet_buff,
394 forw_packet->packet_len,
395 batman_if, broadcastAddr);
396 }
397 rcu_read_unlock();
398
399 forw_packet->num_packets++;
400
401 /* if we still have some more bcasts to send and we are not shutting
402 * down */
403 if ((forw_packet->num_packets < 3) &&
404 (atomic_read(&module_state) != MODULE_DEACTIVATING))
405 _add_bcast_packet_to_list(forw_packet, ((5 * HZ) / 1000));
406 else
407 forw_packet_free(forw_packet);
408}
409
410void send_outstanding_bat_packet(struct work_struct *work)
411{
412 struct delayed_work *delayed_work =
413 container_of(work, struct delayed_work, work);
414 struct forw_packet *forw_packet =
415 container_of(delayed_work, struct forw_packet, delayed_work);
416
417 spin_lock(&forw_bat_list_lock);
418 hlist_del(&forw_packet->list);
419 spin_unlock(&forw_bat_list_lock);
420
421 send_packet(forw_packet);
422
423 /**
424 * we have to have at least one packet in the queue
425 * to determine the queues wake up time unless we are
426 * shutting down
427 */
428 if ((forw_packet->own) &&
429 (atomic_read(&module_state) != MODULE_DEACTIVATING))
430 schedule_own_packet(forw_packet->if_incoming);
431
432 forw_packet_free(forw_packet);
433}
434
435void purge_outstanding_packets(void)
436{
437 struct forw_packet *forw_packet;
438 struct hlist_node *tmp_node, *safe_tmp_node;
439
440 debug_log(LOG_TYPE_BATMAN, "purge_outstanding_packets()\n");
441
442 /* free bcast list */
443 spin_lock(&forw_bcast_list_lock);
444 hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
445 &forw_bcast_list, list) {
446
447 spin_unlock(&forw_bcast_list_lock);
448
449 /**
450 * send_outstanding_bcast_packet() will lock the list to
451 * delete the item from the list
452 */
453 cancel_delayed_work_sync(&forw_packet->delayed_work);
454 spin_lock(&forw_bcast_list_lock);
455 }
456 spin_unlock(&forw_bcast_list_lock);
457
458 /* free batman packet list */
459 spin_lock(&forw_bat_list_lock);
460 hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
461 &forw_bat_list, list) {
462
463 spin_unlock(&forw_bat_list_lock);
464
465 /**
466 * send_outstanding_bat_packet() will lock the list to
467 * delete the item from the list
468 */
469 cancel_delayed_work_sync(&forw_packet->delayed_work);
470 spin_lock(&forw_bat_list_lock);
471 }
472 spin_unlock(&forw_bat_list_lock);
473}
diff --git a/drivers/staging/batman-adv/send.h b/drivers/staging/batman-adv/send.h
new file mode 100644
index 000000000000..59d500917a35
--- /dev/null
+++ b/drivers/staging/batman-adv/send.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2007-2009 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 "types.h"
23
24void send_own_packet_work(struct work_struct *work);
25void send_raw_packet(unsigned char *pack_buff, int pack_buff_len,
26 struct batman_if *batman_if, uint8_t *dst_addr);
27void schedule_own_packet(struct batman_if *batman_if);
28void schedule_forward_packet(struct orig_node *orig_node,
29 struct ethhdr *ethhdr,
30 struct batman_packet *batman_packet,
31 uint8_t directlink, int hna_buff_len,
32 struct batman_if *if_outgoing);
33void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len);
34void send_outstanding_bcast_packet(struct work_struct *work);
35void send_outstanding_bat_packet(struct work_struct *work);
36void purge_outstanding_packets(void);
diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c
new file mode 100644
index 000000000000..d543f50b647f
--- /dev/null
+++ b/drivers/staging/batman-adv/soft-interface.c
@@ -0,0 +1,349 @@
1/*
2 * Copyright (C) 2007-2009 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 "send.h"
26#include "translation-table.h"
27#include "log.h"
28#include "types.h"
29#include "hash.h"
30#include <linux/ethtool.h>
31#include <linux/etherdevice.h>
32#include "compat.h"
33
34static uint16_t bcast_seqno = 1; /* give own bcast messages seq numbers to avoid
35 * broadcast storms */
36static int32_t skb_packets;
37static int32_t skb_bad_packets;
38static int32_t lock_dropped;
39
40unsigned char mainIfAddr[ETH_ALEN];
41static unsigned char mainIfAddr_default[ETH_ALEN];
42static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
43static void bat_get_drvinfo(struct net_device *dev,
44 struct ethtool_drvinfo *info);
45static u32 bat_get_msglevel(struct net_device *dev);
46static void bat_set_msglevel(struct net_device *dev, u32 value);
47static u32 bat_get_link(struct net_device *dev);
48static u32 bat_get_rx_csum(struct net_device *dev);
49static int bat_set_rx_csum(struct net_device *dev, u32 data);
50
51static const struct ethtool_ops bat_ethtool_ops = {
52 .get_settings = bat_get_settings,
53 .get_drvinfo = bat_get_drvinfo,
54 .get_msglevel = bat_get_msglevel,
55 .set_msglevel = bat_set_msglevel,
56 .get_link = bat_get_link,
57 .get_rx_csum = bat_get_rx_csum,
58 .set_rx_csum = bat_set_rx_csum
59};
60
61void set_main_if_addr(uint8_t *addr)
62{
63 memcpy(mainIfAddr, addr, ETH_ALEN);
64}
65
66int main_if_was_up(void)
67{
68 return (memcmp(mainIfAddr, mainIfAddr_default, ETH_ALEN) != 0 ? 1 : 0);
69}
70
71static int my_skb_push(struct sk_buff *skb, unsigned int len)
72{
73 int result = 0;
74
75 skb_packets++;
76 if (skb->data - len < skb->head) {
77 skb_bad_packets++;
78 result = pskb_expand_head(skb, len, 0, GFP_ATOMIC);
79
80 if (result < 0)
81 return result;
82 }
83
84 skb_push(skb, len);
85 return 0;
86}
87
88#ifdef HAVE_NET_DEVICE_OPS
89static const struct net_device_ops bat_netdev_ops = {
90 .ndo_open = interface_open,
91 .ndo_stop = interface_release,
92 .ndo_get_stats = interface_stats,
93 .ndo_set_mac_address = interface_set_mac_addr,
94 .ndo_change_mtu = interface_change_mtu,
95 .ndo_start_xmit = interface_tx,
96 .ndo_validate_addr = eth_validate_addr
97};
98#endif
99
100void interface_setup(struct net_device *dev)
101{
102 struct bat_priv *priv = netdev_priv(dev);
103 char dev_addr[ETH_ALEN];
104
105 ether_setup(dev);
106
107#ifdef HAVE_NET_DEVICE_OPS
108 dev->netdev_ops = &bat_netdev_ops;
109#else
110 dev->open = interface_open;
111 dev->stop = interface_release;
112 dev->get_stats = interface_stats;
113 dev->set_mac_address = interface_set_mac_addr;
114 dev->change_mtu = interface_change_mtu;
115 dev->hard_start_xmit = interface_tx;
116#endif
117 dev->destructor = free_netdev;
118
119 dev->mtu = hardif_min_mtu();
120 dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the
121 * skbuff for our header */
122
123 /* generate random address */
124 random_ether_addr(dev_addr);
125 memcpy(dev->dev_addr, dev_addr, sizeof(dev->dev_addr));
126
127 SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
128
129 memset(priv, 0, sizeof(struct bat_priv));
130}
131
132int interface_open(struct net_device *dev)
133{
134 netif_start_queue(dev);
135 return 0;
136}
137
138int interface_release(struct net_device *dev)
139{
140 netif_stop_queue(dev);
141 return 0;
142}
143
144struct net_device_stats *interface_stats(struct net_device *dev)
145{
146 struct bat_priv *priv = netdev_priv(dev);
147 return &priv->stats;
148}
149
150int interface_set_mac_addr(struct net_device *dev, void *addr)
151{
152 return -EBUSY;
153}
154
155int interface_change_mtu(struct net_device *dev, int new_mtu)
156{
157 /* check ranges */
158 if ((new_mtu < 68) || (new_mtu > hardif_min_mtu()))
159 return -EINVAL;
160
161 dev->mtu = new_mtu;
162
163 return 0;
164}
165
166int interface_tx(struct sk_buff *skb, struct net_device *dev)
167{
168 struct unicast_packet *unicast_packet;
169 struct bcast_packet *bcast_packet;
170 struct orig_node *orig_node;
171 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
172 struct bat_priv *priv = netdev_priv(dev);
173 int data_len = skb->len;
174
175 if (atomic_read(&module_state) != MODULE_ACTIVE)
176 goto dropped;
177
178 dev->trans_start = jiffies;
179 /* TODO: check this for locks */
180 hna_local_add(ethhdr->h_source);
181
182 /* ethernet packet should be broadcasted */
183 if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) {
184
185 if (my_skb_push(skb, sizeof(struct bcast_packet)) < 0)
186 goto dropped;
187
188 bcast_packet = (struct bcast_packet *)skb->data;
189
190 bcast_packet->version = COMPAT_VERSION;
191
192 /* batman packet type: broadcast */
193 bcast_packet->packet_type = BAT_BCAST;
194
195 /* hw address of first interface is the orig mac because only
196 * this mac is known throughout the mesh */
197 memcpy(bcast_packet->orig, mainIfAddr, ETH_ALEN);
198 /* set broadcast sequence number */
199 bcast_packet->seqno = htons(bcast_seqno);
200
201 bcast_seqno++;
202
203 /* broadcast packet */
204 add_bcast_packet_to_list(skb->data, skb->len);
205
206 /* unicast packet */
207 } else {
208
209 /* simply spin_lock()ing can deadlock when the lock is already
210 * hold. */
211 /* TODO: defer the work in a working queue instead of
212 * dropping */
213 if (!spin_trylock(&orig_hash_lock)) {
214 lock_dropped++;
215 debug_log(LOG_TYPE_NOTICE, "%d packets dropped because lock was hold\n", lock_dropped);
216 goto dropped;
217 }
218
219 /* get routing information */
220 orig_node = ((struct orig_node *)hash_find(orig_hash,
221 ethhdr->h_dest));
222
223 /* check for hna host */
224 if (!orig_node)
225 orig_node = transtable_search(ethhdr->h_dest);
226
227 if ((orig_node) &&
228 (orig_node->batman_if) &&
229 (orig_node->router)) {
230 if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0)
231 goto unlock;
232
233 unicast_packet = (struct unicast_packet *)skb->data;
234
235 unicast_packet->version = COMPAT_VERSION;
236 /* batman packet type: unicast */
237 unicast_packet->packet_type = BAT_UNICAST;
238 /* set unicast ttl */
239 unicast_packet->ttl = TTL;
240 /* copy the destination for faster routing */
241 memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
242
243 /* net_dev won't be available when not active */
244 if (orig_node->batman_if->if_active != IF_ACTIVE)
245 goto unlock;
246
247 send_raw_packet(skb->data, skb->len,
248 orig_node->batman_if,
249 orig_node->router->addr);
250 } else {
251 goto unlock;
252 }
253
254 spin_unlock(&orig_hash_lock);
255 }
256
257 priv->stats.tx_packets++;
258 priv->stats.tx_bytes += data_len;
259 goto end;
260
261unlock:
262 spin_unlock(&orig_hash_lock);
263dropped:
264 priv->stats.tx_dropped++;
265end:
266 kfree_skb(skb);
267 return 0;
268}
269
270void interface_rx(struct net_device *dev, void *packet, int packet_len)
271{
272 struct sk_buff *skb;
273 struct bat_priv *priv = netdev_priv(dev);
274
275 skb = dev_alloc_skb(packet_len);
276
277 if (!skb) {
278 priv->stats.rx_dropped++;
279 goto out;
280 }
281
282 memcpy(skb_put(skb, packet_len), packet, packet_len);
283
284 /* Write metadata, and then pass to the receive level */
285 skb->dev = dev;
286 skb->protocol = eth_type_trans(skb, dev);
287 skb->ip_summed = CHECKSUM_UNNECESSARY;
288
289 priv->stats.rx_packets++;
290 priv->stats.rx_bytes += packet_len;
291
292 dev->last_rx = jiffies;
293
294 netif_rx(skb);
295
296out:
297 return;
298}
299
300/* ethtool */
301static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
302{
303 cmd->supported = 0;
304 cmd->advertising = 0;
305 cmd->speed = SPEED_10;
306 cmd->duplex = DUPLEX_FULL;
307 cmd->port = PORT_TP;
308 cmd->phy_address = 0;
309 cmd->transceiver = XCVR_INTERNAL;
310 cmd->autoneg = AUTONEG_DISABLE;
311 cmd->maxtxpkt = 0;
312 cmd->maxrxpkt = 0;
313
314 return 0;
315}
316
317static void bat_get_drvinfo(struct net_device *dev,
318 struct ethtool_drvinfo *info)
319{
320 strcpy(info->driver, "B.A.T.M.A.N. advanced");
321 strcpy(info->version, SOURCE_VERSION);
322 strcpy(info->fw_version, "N/A");
323 strcpy(info->bus_info, "batman");
324}
325
326static u32 bat_get_msglevel(struct net_device *dev)
327{
328 return -EOPNOTSUPP;
329}
330
331static void bat_set_msglevel(struct net_device *dev, u32 value)
332{
333 return;
334}
335
336static u32 bat_get_link(struct net_device *dev)
337{
338 return 1;
339}
340
341static u32 bat_get_rx_csum(struct net_device *dev)
342{
343 return 0;
344}
345
346static int bat_set_rx_csum(struct net_device *dev, u32 data)
347{
348 return -EOPNOTSUPP;
349}
diff --git a/drivers/staging/batman-adv/soft-interface.h b/drivers/staging/batman-adv/soft-interface.h
new file mode 100644
index 000000000000..515e276ef53d
--- /dev/null
+++ b/drivers/staging/batman-adv/soft-interface.h
@@ -0,0 +1,33 @@
1/*
2 * Copyright (C) 2007-2009 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
22void set_main_if_addr(uint8_t *addr);
23int main_if_was_up(void);
24void interface_setup(struct net_device *dev);
25int interface_open(struct net_device *dev);
26int interface_release(struct net_device *dev);
27struct net_device_stats *interface_stats(struct net_device *dev);
28int interface_set_mac_addr(struct net_device *dev, void *addr);
29int interface_change_mtu(struct net_device *dev, int new_mtu);
30int interface_tx(struct sk_buff *skb, struct net_device *dev);
31void interface_rx(struct net_device *dev, void *packet, int packet_len);
32
33extern unsigned char mainIfAddr[];
diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c
new file mode 100644
index 000000000000..c2190e177c56
--- /dev/null
+++ b/drivers/staging/batman-adv/translation-table.c
@@ -0,0 +1,454 @@
1/*
2 * Copyright (C) 2007-2009 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 "log.h"
25#include "soft-interface.h"
26#include "types.h"
27#include "hash.h"
28#include "compat.h"
29
30struct hashtable_t *hna_local_hash;
31static struct hashtable_t *hna_global_hash;
32atomic_t hna_local_changed;
33
34DEFINE_SPINLOCK(hna_local_hash_lock);
35static DEFINE_SPINLOCK(hna_global_hash_lock);
36
37static DECLARE_DELAYED_WORK(hna_local_purge_wq, hna_local_purge);
38
39static void hna_local_start_timer(void)
40{
41 queue_delayed_work(bat_event_workqueue, &hna_local_purge_wq, 10 * HZ);
42}
43
44int hna_local_init(void)
45{
46 if (hna_local_hash)
47 return 1;
48
49 hna_local_hash = hash_new(128, compare_orig, choose_orig);
50
51 if (!hna_local_hash)
52 return 0;
53
54 atomic_set(&hna_local_changed, 0);
55 hna_local_start_timer();
56
57 return 1;
58}
59
60void hna_local_add(uint8_t *addr)
61{
62 struct hna_local_entry *hna_local_entry;
63 struct hna_global_entry *hna_global_entry;
64 struct hashtable_t *swaphash;
65 char hna_str[ETH_STR_LEN];
66 unsigned long flags;
67
68 spin_lock_irqsave(&hna_local_hash_lock, flags);
69 hna_local_entry =
70 ((struct hna_local_entry *)hash_find(hna_local_hash, addr));
71 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
72
73 if (hna_local_entry != NULL) {
74 hna_local_entry->last_seen = jiffies;
75 return;
76 }
77
78 addr_to_string(hna_str, addr);
79
80 /* only announce as many hosts as possible in the batman-packet and
81 space in batman_packet->num_hna That also should give a limit to
82 MAC-flooding. */
83 if ((num_hna + 1 > (ETH_DATA_LEN - BAT_PACKET_LEN) / ETH_ALEN) ||
84 (num_hna + 1 > 255)) {
85 debug_log(LOG_TYPE_ROUTES, "Can't add new local hna entry (%s): number of local hna entries exceeds packet size \n", hna_str);
86 return;
87 }
88
89 debug_log(LOG_TYPE_ROUTES, "Creating new local hna entry: %s \n",
90 hna_str);
91
92 hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
93 if (!hna_local_entry)
94 return;
95
96 memcpy(hna_local_entry->addr, addr, ETH_ALEN);
97 hna_local_entry->last_seen = jiffies;
98
99 /* the batman interface mac address should never be purged */
100 if (compare_orig(addr, soft_device->dev_addr))
101 hna_local_entry->never_purge = 1;
102 else
103 hna_local_entry->never_purge = 0;
104
105 spin_lock_irqsave(&hna_local_hash_lock, flags);
106
107 hash_add(hna_local_hash, hna_local_entry);
108 num_hna++;
109 atomic_set(&hna_local_changed, 1);
110
111 if (hna_local_hash->elements * 4 > hna_local_hash->size) {
112 swaphash = hash_resize(hna_local_hash,
113 hna_local_hash->size * 2);
114
115 if (swaphash == NULL)
116 debug_log(LOG_TYPE_CRIT, "Couldn't resize local hna hash table \n");
117 else
118 hna_local_hash = swaphash;
119 }
120
121 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
122
123 /* remove address from global hash if present */
124 spin_lock_irqsave(&hna_global_hash_lock, flags);
125
126 hna_global_entry =
127 ((struct hna_global_entry *)hash_find(hna_global_hash, addr));
128
129 if (hna_global_entry != NULL)
130 _hna_global_del_orig(hna_global_entry, "local hna received");
131
132 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
133}
134
135int hna_local_fill_buffer(unsigned char *buff, int buff_len)
136{
137 struct hna_local_entry *hna_local_entry;
138 struct hash_it_t *hashit = NULL;
139 int i = 0;
140 unsigned long flags;
141
142 spin_lock_irqsave(&hna_local_hash_lock, flags);
143
144 while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
145
146 if (buff_len < (i + 1) * ETH_ALEN)
147 break;
148
149 hna_local_entry = hashit->bucket->data;
150 memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN);
151
152 i++;
153 }
154
155 /* if we did not get all new local hnas see you next time ;-) */
156 if (i == num_hna)
157 atomic_set(&hna_local_changed, 0);
158
159 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
160
161 return i;
162}
163
164int hna_local_fill_buffer_text(unsigned char *buff, int buff_len)
165{
166 struct hna_local_entry *hna_local_entry;
167 struct hash_it_t *hashit = NULL;
168 int bytes_written = 0;
169 unsigned long flags;
170
171 spin_lock_irqsave(&hna_local_hash_lock, flags);
172
173 while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
174
175 if (buff_len < bytes_written + ETH_STR_LEN + 4)
176 break;
177
178 hna_local_entry = hashit->bucket->data;
179
180 bytes_written += snprintf(buff + bytes_written, ETH_STR_LEN + 4,
181 " * %02x:%02x:%02x:%02x:%02x:%02x\n",
182 hna_local_entry->addr[0],
183 hna_local_entry->addr[1],
184 hna_local_entry->addr[2],
185 hna_local_entry->addr[3],
186 hna_local_entry->addr[4],
187 hna_local_entry->addr[5]);
188 }
189
190 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
191
192 return bytes_written;
193}
194
195static void _hna_local_del(void *data)
196{
197 kfree(data);
198 num_hna--;
199 atomic_set(&hna_local_changed, 1);
200}
201
202static void hna_local_del(struct hna_local_entry *hna_local_entry,
203 char *message)
204{
205 char hna_str[ETH_STR_LEN];
206
207 addr_to_string(hna_str, hna_local_entry->addr);
208 debug_log(LOG_TYPE_ROUTES, "Deleting local hna entry (%s): %s \n",
209 hna_str, message);
210
211 hash_remove(hna_local_hash, hna_local_entry->addr);
212 _hna_local_del(hna_local_entry);
213}
214
215void hna_local_purge(struct work_struct *work)
216{
217 struct hna_local_entry *hna_local_entry;
218 struct hash_it_t *hashit = NULL;
219 unsigned long flags;
220 unsigned long timeout;
221
222 spin_lock_irqsave(&hna_local_hash_lock, flags);
223
224 while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
225 hna_local_entry = hashit->bucket->data;
226
227 timeout = hna_local_entry->last_seen +
228 ((LOCAL_HNA_TIMEOUT / 1000) * HZ);
229 if ((!hna_local_entry->never_purge) &&
230 time_after(jiffies, timeout))
231 hna_local_del(hna_local_entry, "address timed out");
232 }
233
234 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
235 hna_local_start_timer();
236}
237
238void hna_local_free(void)
239{
240 if (!hna_local_hash)
241 return;
242
243 cancel_delayed_work_sync(&hna_local_purge_wq);
244 hash_delete(hna_local_hash, _hna_local_del);
245 hna_local_hash = NULL;
246}
247
248int hna_global_init(void)
249{
250 if (hna_global_hash)
251 return 1;
252
253 hna_global_hash = hash_new(128, compare_orig, choose_orig);
254
255 if (!hna_global_hash)
256 return 0;
257
258 return 1;
259}
260
261void hna_global_add_orig(struct orig_node *orig_node,
262 unsigned char *hna_buff, int hna_buff_len)
263{
264 struct hna_global_entry *hna_global_entry;
265 struct hna_local_entry *hna_local_entry;
266 struct hashtable_t *swaphash;
267 char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN];
268 int hna_buff_count = 0;
269 unsigned long flags;
270 unsigned char *hna_ptr;
271
272 addr_to_string(orig_str, orig_node->orig);
273
274 while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
275 spin_lock_irqsave(&hna_global_hash_lock, flags);
276
277 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
278 hna_global_entry = (struct hna_global_entry *)
279 hash_find(hna_global_hash, hna_ptr);
280
281 if (hna_global_entry == NULL) {
282 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
283
284 hna_global_entry =
285 kmalloc(sizeof(struct hna_global_entry),
286 GFP_ATOMIC);
287
288 if (!hna_global_entry)
289 break;
290
291 memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
292
293 addr_to_string(hna_str, hna_global_entry->addr);
294 debug_log(LOG_TYPE_ROUTES, "Creating new global hna entry: %s (via %s)\n", hna_str, orig_str);
295
296 spin_lock_irqsave(&hna_global_hash_lock, flags);
297 hash_add(hna_global_hash, hna_global_entry);
298
299 }
300
301 hna_global_entry->orig_node = orig_node;
302 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
303
304 /* remove address from local hash if present */
305 spin_lock_irqsave(&hna_local_hash_lock, flags);
306
307 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
308 hna_local_entry = (struct hna_local_entry *)
309 hash_find(hna_local_hash, hna_ptr);
310
311 if (hna_local_entry != NULL)
312 hna_local_del(hna_local_entry, "global hna received");
313
314 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
315
316 hna_buff_count++;
317 }
318
319 orig_node->hna_buff_len = hna_buff_len;
320
321 if (orig_node->hna_buff_len > 0) {
322 orig_node->hna_buff = kmalloc(orig_node->hna_buff_len,
323 GFP_ATOMIC);
324 memcpy(orig_node->hna_buff, hna_buff, orig_node->hna_buff_len);
325 } else {
326 orig_node->hna_buff = NULL;
327 }
328
329 spin_lock_irqsave(&hna_global_hash_lock, flags);
330
331 if (hna_global_hash->elements * 4 > hna_global_hash->size) {
332 swaphash = hash_resize(hna_global_hash,
333 hna_global_hash->size * 2);
334
335 if (swaphash == NULL)
336 debug_log(LOG_TYPE_CRIT, "Couldn't resize global hna hash table \n");
337 else
338 hna_global_hash = swaphash;
339 }
340
341 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
342}
343
344int hna_global_fill_buffer_text(unsigned char *buff, int buff_len)
345{
346 struct hna_global_entry *hna_global_entry;
347 struct hash_it_t *hashit = NULL;
348 int bytes_written = 0;
349 unsigned long flags;
350
351 spin_lock_irqsave(&hna_global_hash_lock, flags);
352
353 while (NULL != (hashit = hash_iterate(hna_global_hash, hashit))) {
354 if (buff_len < bytes_written + (2 * ETH_STR_LEN) + 10)
355 break;
356
357 hna_global_entry = hashit->bucket->data;
358
359 bytes_written += snprintf(buff + bytes_written,
360 (2 * ETH_STR_LEN) + 10,
361 " * %02x:%02x:%02x:%02x:%02x:%02x via %02x:%02x:%02x:%02x:%02x:%02x \n",
362 hna_global_entry->addr[0],
363 hna_global_entry->addr[1],
364 hna_global_entry->addr[2],
365 hna_global_entry->addr[3],
366 hna_global_entry->addr[4],
367 hna_global_entry->addr[5],
368 hna_global_entry->orig_node->orig[0],
369 hna_global_entry->orig_node->orig[1],
370 hna_global_entry->orig_node->orig[2],
371 hna_global_entry->orig_node->orig[3],
372 hna_global_entry->orig_node->orig[4],
373 hna_global_entry->orig_node->orig[5]);
374 }
375
376 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
377
378 return bytes_written;
379}
380
381void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
382 char *message)
383{
384 char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN];
385
386 addr_to_string(orig_str, hna_global_entry->orig_node->orig);
387 addr_to_string(hna_str, hna_global_entry->addr);
388
389 debug_log(LOG_TYPE_ROUTES, "Deleting global hna entry %s (via %s): %s \n", hna_str, orig_str, message);
390
391 hash_remove(hna_global_hash, hna_global_entry->addr);
392 kfree(hna_global_entry);
393}
394
395void hna_global_del_orig(struct orig_node *orig_node, char *message)
396{
397 struct hna_global_entry *hna_global_entry;
398 int hna_buff_count = 0;
399 unsigned long flags;
400 unsigned char *hna_ptr;
401
402 if (orig_node->hna_buff_len == 0)
403 return;
404
405 spin_lock_irqsave(&hna_global_hash_lock, flags);
406
407 while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) {
408 hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN);
409 hna_global_entry = (struct hna_global_entry *)
410 hash_find(hna_global_hash, hna_ptr);
411
412 if ((hna_global_entry != NULL) &&
413 (hna_global_entry->orig_node == orig_node))
414 _hna_global_del_orig(hna_global_entry, message);
415
416 hna_buff_count++;
417 }
418
419 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
420
421 orig_node->hna_buff_len = 0;
422 kfree(orig_node->hna_buff);
423 orig_node->hna_buff = NULL;
424}
425
426static void hna_global_del(void *data)
427{
428 kfree(data);
429}
430
431void hna_global_free(void)
432{
433 if (!hna_global_hash)
434 return;
435
436 hash_delete(hna_global_hash, hna_global_del);
437 hna_global_hash = NULL;
438}
439
440struct orig_node *transtable_search(uint8_t *addr)
441{
442 struct hna_global_entry *hna_global_entry;
443 unsigned long flags;
444
445 spin_lock_irqsave(&hna_global_hash_lock, flags);
446 hna_global_entry = (struct hna_global_entry *)
447 hash_find(hna_global_hash, addr);
448 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
449
450 if (hna_global_entry == NULL)
451 return NULL;
452
453 return hna_global_entry->orig_node;
454}
diff --git a/drivers/staging/batman-adv/translation-table.h b/drivers/staging/batman-adv/translation-table.h
new file mode 100644
index 000000000000..f7da81129318
--- /dev/null
+++ b/drivers/staging/batman-adv/translation-table.h
@@ -0,0 +1,42 @@
1/*
2 * Copyright (C) 2007-2009 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 "types.h"
23
24int hna_local_init(void);
25void hna_local_add(uint8_t *addr);
26int hna_local_fill_buffer(unsigned char *buff, int buff_len);
27int hna_local_fill_buffer_text(unsigned char *buff, int buff_len);
28void hna_local_purge(struct work_struct *work);
29void hna_local_free(void);
30int hna_global_init(void);
31void hna_global_add_orig(struct orig_node *orig_node, unsigned char *hna_buff,
32 int hna_buff_len);
33int hna_global_fill_buffer_text(unsigned char *buff, int buff_len);
34void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
35 char *orig_str);
36void hna_global_del_orig(struct orig_node *orig_node, char *message);
37void hna_global_free(void);
38struct orig_node *transtable_search(uint8_t *addr);
39
40extern spinlock_t hna_local_hash_lock;
41extern struct hashtable_t *hna_local_hash;
42extern atomic_t hna_local_changed;
diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h
new file mode 100644
index 000000000000..3a0ef0c38c93
--- /dev/null
+++ b/drivers/staging/batman-adv/types.h
@@ -0,0 +1,124 @@
1/*
2 * Copyright (C) 2007-2009 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
25
26#ifndef TYPES_H
27#define TYPES_H
28
29#include "packet.h"
30#include "bitarray.h"
31
32#define BAT_HEADER_LEN (sizeof(struct ethhdr) + ((sizeof(struct unicast_packet) > sizeof(struct bcast_packet) ? sizeof(struct unicast_packet) : sizeof(struct bcast_packet))))
33
34
35struct batman_if {
36 struct list_head list;
37 int16_t if_num;
38 char *dev;
39 char if_active;
40 char addr_str[ETH_STR_LEN];
41 struct net_device *net_dev;
42 struct socket *raw_sock;
43 atomic_t seqno;
44 unsigned char *packet_buff;
45 int packet_len;
46 struct rcu_head rcu;
47
48};
49
50struct orig_node { /* structure for orig_list maintaining nodes of mesh */
51 uint8_t orig[ETH_ALEN];
52 struct neigh_node *router;
53 struct batman_if *batman_if;
54 TYPE_OF_WORD *bcast_own;
55 uint8_t *bcast_own_sum;
56 uint8_t tq_own;
57 int tq_asym_penalty;
58 unsigned long last_valid; /* when last packet from this node was received */
59/* uint8_t gwflags; * flags related to gateway functions: gateway class */
60 uint8_t flags; /* for now only VIS_SERVER flag. */
61 unsigned char *hna_buff;
62 int16_t hna_buff_len;
63 uint16_t last_real_seqno; /* last and best known squence number */
64 uint8_t last_ttl; /* ttl of last received packet */
65 TYPE_OF_WORD bcast_bits[NUM_WORDS];
66 uint16_t last_bcast_seqno; /* last broadcast sequence number received by this host */
67 struct list_head neigh_list;
68};
69
70struct neigh_node {
71 struct list_head list;
72 uint8_t addr[ETH_ALEN];
73 uint8_t real_packet_count;
74 uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE];
75 uint8_t tq_index;
76 uint8_t tq_avg;
77 uint8_t last_ttl;
78 unsigned long last_valid; /* when last packet via this neighbour was received */
79 TYPE_OF_WORD real_bits[NUM_WORDS];
80 struct orig_node *orig_node;
81 struct batman_if *if_incoming;
82};
83
84struct bat_priv {
85 struct net_device_stats stats;
86};
87
88struct device_client {
89 struct list_head queue_list;
90 unsigned int queue_len;
91 unsigned char index;
92 spinlock_t lock;
93 wait_queue_head_t queue_wait;
94};
95
96struct device_packet {
97 struct list_head list;
98 struct icmp_packet icmp_packet;
99};
100
101struct hna_local_entry {
102 uint8_t addr[ETH_ALEN];
103 unsigned long last_seen;
104 char never_purge;
105};
106
107struct hna_global_entry {
108 uint8_t addr[ETH_ALEN];
109 struct orig_node *orig_node;
110};
111
112struct forw_packet { /* structure for forw_list maintaining packets to be send/forwarded */
113 struct hlist_node list;
114 unsigned long send_time;
115 uint8_t own;
116 unsigned char *packet_buff;
117 uint16_t packet_len;
118 uint32_t direct_link_flags;
119 uint8_t num_packets;
120 struct delayed_work delayed_work;
121 struct batman_if *if_incoming;
122};
123
124#endif
diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c
new file mode 100644
index 000000000000..f6c9acb289ed
--- /dev/null
+++ b/drivers/staging/batman-adv/vis.c
@@ -0,0 +1,564 @@
1/*
2 * Copyright (C) 2008-2009 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 "log.h"
27#include "soft-interface.h"
28#include "hard-interface.h"
29#include "hash.h"
30#include "compat.h"
31
32struct hashtable_t *vis_hash;
33DEFINE_SPINLOCK(vis_hash_lock);
34static struct vis_info *my_vis_info;
35static struct list_head send_list; /* always locked with vis_hash_lock */
36
37static void start_vis_timer(void);
38
39/* free the info */
40static void free_info(void *data)
41{
42 struct vis_info *info = data;
43 struct recvlist_node *entry, *tmp;
44
45 list_del_init(&info->send_list);
46 list_for_each_entry_safe(entry, tmp, &info->recv_list, list) {
47 list_del(&entry->list);
48 kfree(entry);
49 }
50 kfree(info);
51}
52
53/* set the mode of the visualization to client or server */
54void vis_set_mode(int mode)
55{
56 spin_lock(&vis_hash_lock);
57
58 if (my_vis_info != NULL)
59 my_vis_info->packet.vis_type = mode;
60
61 spin_unlock(&vis_hash_lock);
62}
63
64/* is_vis_server(), locked outside */
65static int is_vis_server_locked(void)
66{
67 if (my_vis_info != NULL)
68 if (my_vis_info->packet.vis_type == VIS_TYPE_SERVER_SYNC)
69 return 1;
70
71 return 0;
72}
73
74/* get the current set mode */
75int is_vis_server(void)
76{
77 int ret = 0;
78
79 spin_lock(&vis_hash_lock);
80 ret = is_vis_server_locked();
81 spin_unlock(&vis_hash_lock);
82
83 return ret;
84}
85
86/* Compare two vis packets, used by the hashing algorithm */
87static int vis_info_cmp(void *data1, void *data2)
88{
89 struct vis_info *d1, *d2;
90 d1 = data1;
91 d2 = data2;
92 return compare_orig(d1->packet.vis_orig, d2->packet.vis_orig);
93}
94
95/* hash function to choose an entry in a hash table of given size */
96/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
97static int vis_info_choose(void *data, int size)
98{
99 struct vis_info *vis_info = data;
100 unsigned char *key;
101 uint32_t hash = 0;
102 size_t i;
103
104 key = vis_info->packet.vis_orig;
105 for (i = 0; i < ETH_ALEN; i++) {
106 hash += key[i];
107 hash += (hash << 10);
108 hash ^= (hash >> 6);
109 }
110
111 hash += (hash << 3);
112 hash ^= (hash >> 11);
113 hash += (hash << 15);
114
115 return hash % size;
116}
117
118/* tries to add one entry to the receive list. */
119static void recv_list_add(struct list_head *recv_list, char *mac)
120{
121 struct recvlist_node *entry;
122 entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC);
123 if (!entry)
124 return;
125
126 memcpy(entry->mac, mac, ETH_ALEN);
127 list_add_tail(&entry->list, recv_list);
128}
129
130/* returns 1 if this mac is in the recv_list */
131static int recv_list_is_in(struct list_head *recv_list, char *mac)
132{
133 struct recvlist_node *entry;
134
135 list_for_each_entry(entry, recv_list, list) {
136 if (memcmp(entry->mac, mac, ETH_ALEN) == 0)
137 return 1;
138 }
139
140 return 0;
141}
142
143/* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old,
144 * broken.. ). vis hash must be locked outside. is_new is set when the packet
145 * is newer than old entries in the hash. */
146static struct vis_info *add_packet(struct vis_packet *vis_packet,
147 int vis_info_len, int *is_new)
148{
149 struct vis_info *info, *old_info;
150 struct vis_info search_elem;
151
152 *is_new = 0;
153 /* sanity check */
154 if (vis_hash == NULL)
155 return NULL;
156
157 /* see if the packet is already in vis_hash */
158 memcpy(search_elem.packet.vis_orig, vis_packet->vis_orig, ETH_ALEN);
159 old_info = hash_find(vis_hash, &search_elem);
160
161 if (old_info != NULL) {
162 if (vis_packet->seqno - old_info->packet.seqno <= 0) {
163 if (old_info->packet.seqno == vis_packet->seqno) {
164 recv_list_add(&old_info->recv_list,
165 vis_packet->sender_orig);
166 return old_info;
167 } else {
168 /* newer packet is already in hash. */
169 return NULL;
170 }
171 }
172 /* remove old entry */
173 hash_remove(vis_hash, old_info);
174 free_info(old_info);
175 }
176
177 info = kmalloc(sizeof(struct vis_info) + vis_info_len, GFP_ATOMIC);
178 if (info == NULL)
179 return NULL;
180
181 INIT_LIST_HEAD(&info->send_list);
182 INIT_LIST_HEAD(&info->recv_list);
183 info->first_seen = jiffies;
184 memcpy(&info->packet, vis_packet,
185 sizeof(struct vis_packet) + vis_info_len);
186
187 /* initialize and add new packet. */
188 *is_new = 1;
189
190 /* repair if entries is longer than packet. */
191 if (info->packet.entries * sizeof(struct vis_info_entry) > vis_info_len)
192 info->packet.entries = vis_info_len / sizeof(struct vis_info_entry);
193
194 recv_list_add(&info->recv_list, info->packet.sender_orig);
195
196 /* try to add it */
197 if (hash_add(vis_hash, info) < 0) {
198 /* did not work (for some reason) */
199 free_info(info);
200 info = NULL;
201 }
202
203 return info;
204}
205
206/* handle the server sync packet, forward if needed. */
207void receive_server_sync_packet(struct vis_packet *vis_packet, int vis_info_len)
208{
209 struct vis_info *info;
210 int is_new;
211
212 spin_lock(&vis_hash_lock);
213 info = add_packet(vis_packet, vis_info_len, &is_new);
214 if (info == NULL)
215 goto end;
216
217 /* only if we are server ourselves and packet is newer than the one in
218 * hash.*/
219 if (is_vis_server_locked() && is_new) {
220 memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
221 if (list_empty(&info->send_list))
222 list_add_tail(&info->send_list, &send_list);
223 }
224end:
225 spin_unlock(&vis_hash_lock);
226}
227
228/* handle an incoming client update packet and schedule forward if needed. */
229void receive_client_update_packet(struct vis_packet *vis_packet,
230 int vis_info_len)
231{
232 struct vis_info *info;
233 int is_new;
234
235 /* clients shall not broadcast. */
236 if (is_bcast(vis_packet->target_orig))
237 return;
238
239 spin_lock(&vis_hash_lock);
240 info = add_packet(vis_packet, vis_info_len, &is_new);
241 if (info == NULL)
242 goto end;
243 /* note that outdated packets will be dropped at this point. */
244
245
246 /* send only if we're the target server or ... */
247 if (is_vis_server_locked() &&
248 is_my_mac(info->packet.target_orig) &&
249 is_new) {
250 info->packet.vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */
251 memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
252 if (list_empty(&info->send_list))
253 list_add_tail(&info->send_list, &send_list);
254
255 /* ... we're not the recipient (and thus need to forward). */
256 } else if (!is_my_mac(info->packet.target_orig)) {
257 if (list_empty(&info->send_list))
258 list_add_tail(&info->send_list, &send_list);
259 }
260end:
261 spin_unlock(&vis_hash_lock);
262}
263
264/* Walk the originators and find the VIS server with the best tq. Set the packet
265 * address to its address and return the best_tq.
266 *
267 * Must be called with the originator hash locked */
268static int find_best_vis_server(struct vis_info *info)
269{
270 struct hash_it_t *hashit = NULL;
271 struct orig_node *orig_node;
272 int best_tq = -1;
273
274 while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
275 orig_node = hashit->bucket->data;
276 if ((orig_node != NULL) &&
277 (orig_node->router != NULL) &&
278 (orig_node->flags & VIS_SERVER) &&
279 (orig_node->router->tq_avg > best_tq)) {
280 best_tq = orig_node->router->tq_avg;
281 memcpy(info->packet.target_orig, orig_node->orig,
282 ETH_ALEN);
283 }
284 }
285 return best_tq;
286}
287
288/* Return true if the vis packet is full. */
289static bool vis_packet_full(struct vis_info *info)
290{
291 if (info->packet.entries + 1 >
292 (1000 - sizeof(struct vis_info)) / sizeof(struct vis_info_entry))
293 return true;
294 return false;
295}
296
297/* generates a packet of own vis data,
298 * returns 0 on success, -1 if no packet could be generated */
299static int generate_vis_packet(void)
300{
301 struct hash_it_t *hashit = NULL;
302 struct orig_node *orig_node;
303 struct vis_info *info = (struct vis_info *)my_vis_info;
304 struct vis_info_entry *entry, *entry_array;
305 struct hna_local_entry *hna_local_entry;
306 int best_tq = -1;
307 unsigned long flags;
308
309 info->first_seen = jiffies;
310
311 spin_lock(&orig_hash_lock);
312 memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
313 info->packet.ttl = TTL;
314 info->packet.seqno++;
315 info->packet.entries = 0;
316
317 if (!is_vis_server_locked()) {
318 best_tq = find_best_vis_server(info);
319 if (best_tq < 0) {
320 spin_unlock(&orig_hash_lock);
321 return -1;
322 }
323 }
324 hashit = NULL;
325
326 entry_array = (struct vis_info_entry *)
327 ((char *)info + sizeof(struct vis_info));
328
329 while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
330 orig_node = hashit->bucket->data;
331 if (orig_node->router != NULL
332 && compare_orig(orig_node->router->addr, orig_node->orig)
333 && orig_node->batman_if
334 && (orig_node->batman_if->if_active == IF_ACTIVE)
335 && orig_node->router->tq_avg > 0) {
336
337 /* fill one entry into buffer. */
338 entry = &entry_array[info->packet.entries];
339 memcpy(entry->src, orig_node->batman_if->net_dev->dev_addr, ETH_ALEN);
340 memcpy(entry->dest, orig_node->orig, ETH_ALEN);
341 entry->quality = orig_node->router->tq_avg;
342 info->packet.entries++;
343
344 if (vis_packet_full(info)) {
345 spin_unlock(&orig_hash_lock);
346 return 0;
347 }
348 }
349 }
350
351 spin_unlock(&orig_hash_lock);
352
353 hashit = NULL;
354 spin_lock_irqsave(&hna_local_hash_lock, flags);
355 while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
356 hna_local_entry = hashit->bucket->data;
357 entry = &entry_array[info->packet.entries];
358 memset(entry->src, 0, ETH_ALEN);
359 memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN);
360 entry->quality = 0; /* 0 means HNA */
361 info->packet.entries++;
362
363 if (vis_packet_full(info)) {
364 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
365 return 0;
366 }
367 }
368 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
369 return 0;
370}
371
372static void purge_vis_packets(void)
373{
374 struct hash_it_t *hashit = NULL;
375 struct vis_info *info;
376
377 while (NULL != (hashit = hash_iterate(vis_hash, hashit))) {
378 info = hashit->bucket->data;
379 if (info == my_vis_info) /* never purge own data. */
380 continue;
381 if (time_after(jiffies,
382 info->first_seen + (VIS_TIMEOUT/1000)*HZ)) {
383 hash_remove_bucket(vis_hash, hashit);
384 free_info(info);
385 }
386 }
387}
388
389static void broadcast_vis_packet(struct vis_info *info, int packet_length)
390{
391 struct hash_it_t *hashit = NULL;
392 struct orig_node *orig_node;
393
394 spin_lock(&orig_hash_lock);
395
396 /* send to all routers in range. */
397 while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
398 orig_node = hashit->bucket->data;
399
400 /* if it's a vis server and reachable, send it. */
401 if (orig_node &&
402 (orig_node->flags & VIS_SERVER) &&
403 orig_node->batman_if &&
404 orig_node->router) {
405
406 /* don't send it if we already received the packet from
407 * this node. */
408 if (recv_list_is_in(&info->recv_list, orig_node->orig))
409 continue;
410
411 memcpy(info->packet.target_orig,
412 orig_node->orig, ETH_ALEN);
413
414 send_raw_packet((unsigned char *) &info->packet,
415 packet_length,
416 orig_node->batman_if,
417 orig_node->router->addr);
418 }
419 }
420 memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
421 spin_unlock(&orig_hash_lock);
422}
423
424static void unicast_vis_packet(struct vis_info *info, int packet_length)
425{
426 struct orig_node *orig_node;
427
428 spin_lock(&orig_hash_lock);
429 orig_node = ((struct orig_node *)
430 hash_find(orig_hash, info->packet.target_orig));
431
432 if ((orig_node != NULL) &&
433 (orig_node->batman_if != NULL) &&
434 (orig_node->router != NULL)) {
435 send_raw_packet((unsigned char *) &info->packet, packet_length,
436 orig_node->batman_if,
437 orig_node->router->addr);
438 }
439 spin_unlock(&orig_hash_lock);
440}
441
442/* only send one vis packet. called from send_vis_packets() */
443static void send_vis_packet(struct vis_info *info)
444{
445 int packet_length;
446
447 if (info->packet.ttl < 2) {
448 debug_log(LOG_TYPE_NOTICE,
449 "Error - can't send vis packet: ttl exceeded\n");
450 return;
451 }
452
453 memcpy(info->packet.sender_orig, mainIfAddr, ETH_ALEN);
454 info->packet.ttl--;
455
456 packet_length = sizeof(struct vis_packet) +
457 info->packet.entries * sizeof(struct vis_info_entry);
458
459 if (is_bcast(info->packet.target_orig))
460 broadcast_vis_packet(info, packet_length);
461 else
462 unicast_vis_packet(info, packet_length);
463 info->packet.ttl++; /* restore TTL */
464}
465
466/* called from timer; send (and maybe generate) vis packet. */
467static void send_vis_packets(struct work_struct *work)
468{
469 struct vis_info *info, *temp;
470
471 spin_lock(&vis_hash_lock);
472 purge_vis_packets();
473
474 if (generate_vis_packet() == 0)
475 /* schedule if generation was successful */
476 list_add_tail(&my_vis_info->send_list, &send_list);
477
478 list_for_each_entry_safe(info, temp, &send_list, send_list) {
479 list_del_init(&info->send_list);
480 send_vis_packet(info);
481 }
482 spin_unlock(&vis_hash_lock);
483 start_vis_timer();
484}
485static DECLARE_DELAYED_WORK(vis_timer_wq, send_vis_packets);
486
487/* init the vis server. this may only be called when if_list is already
488 * initialized (e.g. bat0 is initialized, interfaces have been added) */
489int vis_init(void)
490{
491 if (vis_hash)
492 return 1;
493
494 spin_lock(&vis_hash_lock);
495
496 vis_hash = hash_new(256, vis_info_cmp, vis_info_choose);
497 if (!vis_hash) {
498 debug_log(LOG_TYPE_CRIT, "Can't initialize vis_hash\n");
499 goto err;
500 }
501
502 my_vis_info = kmalloc(1000, GFP_ATOMIC);
503 if (!my_vis_info) {
504 debug_log(LOG_TYPE_CRIT, "Can't initialize vis packet\n");
505 goto err;
506 }
507
508 /* prefill the vis info */
509 my_vis_info->first_seen = jiffies - atomic_read(&vis_interval);
510 INIT_LIST_HEAD(&my_vis_info->recv_list);
511 INIT_LIST_HEAD(&my_vis_info->send_list);
512 my_vis_info->packet.version = COMPAT_VERSION;
513 my_vis_info->packet.packet_type = BAT_VIS;
514 my_vis_info->packet.vis_type = VIS_TYPE_CLIENT_UPDATE;
515 my_vis_info->packet.ttl = TTL;
516 my_vis_info->packet.seqno = 0;
517 my_vis_info->packet.entries = 0;
518
519 INIT_LIST_HEAD(&send_list);
520
521 memcpy(my_vis_info->packet.vis_orig, mainIfAddr, ETH_ALEN);
522 memcpy(my_vis_info->packet.sender_orig, mainIfAddr, ETH_ALEN);
523
524 if (hash_add(vis_hash, my_vis_info) < 0) {
525 debug_log(LOG_TYPE_CRIT,
526 "Can't add own vis packet into hash\n");
527 free_info(my_vis_info); /* not in hash, need to remove it
528 * manually. */
529 goto err;
530 }
531
532 spin_unlock(&vis_hash_lock);
533 start_vis_timer();
534 return 1;
535
536err:
537 spin_unlock(&vis_hash_lock);
538 vis_quit();
539 return 0;
540}
541
542/* shutdown vis-server */
543void vis_quit(void)
544{
545 if (!vis_hash)
546 return;
547
548 cancel_delayed_work_sync(&vis_timer_wq);
549
550 spin_lock(&vis_hash_lock);
551 /* properly remove, kill timers ... */
552 hash_delete(vis_hash, free_info);
553 vis_hash = NULL;
554 my_vis_info = NULL;
555 spin_unlock(&vis_hash_lock);
556}
557
558/* schedule packets for (re)transmission */
559static void start_vis_timer(void)
560{
561 queue_delayed_work(bat_event_workqueue, &vis_timer_wq,
562 (atomic_read(&vis_interval)/1000) * HZ);
563}
564
diff --git a/drivers/staging/batman-adv/vis.h b/drivers/staging/batman-adv/vis.h
new file mode 100644
index 000000000000..276fabab4e88
--- /dev/null
+++ b/drivers/staging/batman-adv/vis.h
@@ -0,0 +1,63 @@
1/*
2 * Copyright (C) 2008-2009 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#define VIS_TIMEOUT 200000
23#define VIS_FORMAT_DD_NAME "dot_draw"
24#define VIS_FORMAT_JSON_NAME "json"
25
26struct vis_info {
27 unsigned long first_seen;
28 struct list_head recv_list;
29 /* list of server-neighbors we received a vis-packet
30 * from. we should not reply to them. */
31 struct list_head send_list;
32 /* this packet might be part of the vis send queue. */
33 struct vis_packet packet;
34 /* vis_info may follow here*/
35} __attribute__((packed));
36
37struct vis_info_entry {
38 uint8_t src[ETH_ALEN];
39 uint8_t dest[ETH_ALEN];
40 uint8_t quality; /* quality = 0 means HNA */
41} __attribute__((packed));
42
43struct recvlist_node {
44 struct list_head list;
45 uint8_t mac[ETH_ALEN];
46};
47
48enum vis_formats {
49 DOT_DRAW,
50 JSON,
51};
52
53extern struct hashtable_t *vis_hash;
54extern spinlock_t vis_hash_lock;
55
56void vis_set_mode(int mode);
57int is_vis_server(void);
58void receive_server_sync_packet(struct vis_packet *vis_packet,
59 int vis_info_len);
60void receive_client_update_packet(struct vis_packet *vis_packet,
61 int vis_info_len);
62int vis_init(void);
63void vis_quit(void);