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