Blame view

net/batman-adv/translation-table.c 51.5 KB
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1
  /*
64afe3539   Sven Eckelmann   batman-adv: Updat...
2
   * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
c6c8fea29   Sven Eckelmann   net: Add batman-a...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *
   * Marek Lindner, Simon Wunderlich
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   * 02110-1301, USA
   *
   */
  
  #include "main.h"
  #include "translation-table.h"
  #include "soft-interface.h"
32ae9b221   Marek Lindner   batman-adv: Make ...
25
  #include "hard-interface.h"
a73105b8d   Antonio Quartulli   batman-adv: impro...
26
  #include "send.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
27
28
  #include "hash.h"
  #include "originator.h"
a73105b8d   Antonio Quartulli   batman-adv: impro...
29
  #include "routing.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
30

a73105b8d   Antonio Quartulli   batman-adv: impro...
31
32
33
34
35
36
  #include <linux/crc16.h>
  
  static void _tt_global_del(struct bat_priv *bat_priv,
  			   struct tt_global_entry *tt_global_entry,
  			   const char *message);
  static void tt_purge(struct work_struct *work);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
37

7aadf889e   Marek Lindner   batman-adv: remov...
38
  /* returns 1 if they are the same mac addr */
48100bac8   Antonio Quartulli   batman-adv: creat...
39
  static int compare_tt(const struct hlist_node *node, const void *data2)
7aadf889e   Marek Lindner   batman-adv: remov...
40
  {
48100bac8   Antonio Quartulli   batman-adv: creat...
41
  	const void *data1 = container_of(node, struct tt_common_entry,
747e4221a   Sven Eckelmann   batman-adv: Add c...
42
  					 hash_entry);
7aadf889e   Marek Lindner   batman-adv: remov...
43
44
45
  
  	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
46
  static void tt_start_timer(struct bat_priv *bat_priv)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
47
  {
a73105b8d   Antonio Quartulli   batman-adv: impro...
48
49
50
  	INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
  	queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
  			   msecs_to_jiffies(5000));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
51
  }
48100bac8   Antonio Quartulli   batman-adv: creat...
52
53
  static struct tt_common_entry *tt_hash_find(struct hashtable_t *hash,
  					    const void *data)
7aadf889e   Marek Lindner   batman-adv: remov...
54
  {
7aadf889e   Marek Lindner   batman-adv: remov...
55
56
  	struct hlist_head *head;
  	struct hlist_node *node;
48100bac8   Antonio Quartulli   batman-adv: creat...
57
  	struct tt_common_entry *tt_common_entry, *tt_common_entry_tmp = NULL;
c90681b85   Antonio Quartulli   batman-adv: fixed...
58
  	uint32_t index;
7aadf889e   Marek Lindner   batman-adv: remov...
59
60
61
62
63
64
65
66
  
  	if (!hash)
  		return NULL;
  
  	index = choose_orig(data, hash->size);
  	head = &hash->table[index];
  
  	rcu_read_lock();
48100bac8   Antonio Quartulli   batman-adv: creat...
67
68
  	hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) {
  		if (!compare_eth(tt_common_entry, data))
7aadf889e   Marek Lindner   batman-adv: remov...
69
  			continue;
48100bac8   Antonio Quartulli   batman-adv: creat...
70
  		if (!atomic_inc_not_zero(&tt_common_entry->refcount))
7683fdc1e   Antonio Quartulli   batman-adv: prote...
71
  			continue;
48100bac8   Antonio Quartulli   batman-adv: creat...
72
  		tt_common_entry_tmp = tt_common_entry;
7aadf889e   Marek Lindner   batman-adv: remov...
73
74
75
  		break;
  	}
  	rcu_read_unlock();
48100bac8   Antonio Quartulli   batman-adv: creat...
76
  	return tt_common_entry_tmp;
7aadf889e   Marek Lindner   batman-adv: remov...
77
  }
48100bac8   Antonio Quartulli   batman-adv: creat...
78
79
  static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
  						 const void *data)
7aadf889e   Marek Lindner   batman-adv: remov...
80
  {
48100bac8   Antonio Quartulli   batman-adv: creat...
81
82
  	struct tt_common_entry *tt_common_entry;
  	struct tt_local_entry *tt_local_entry = NULL;
7aadf889e   Marek Lindner   batman-adv: remov...
83

48100bac8   Antonio Quartulli   batman-adv: creat...
84
85
86
87
88
89
  	tt_common_entry = tt_hash_find(bat_priv->tt_local_hash, data);
  	if (tt_common_entry)
  		tt_local_entry = container_of(tt_common_entry,
  					      struct tt_local_entry, common);
  	return tt_local_entry;
  }
7aadf889e   Marek Lindner   batman-adv: remov...
90

48100bac8   Antonio Quartulli   batman-adv: creat...
91
92
93
94
95
  static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
  						   const void *data)
  {
  	struct tt_common_entry *tt_common_entry;
  	struct tt_global_entry *tt_global_entry = NULL;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
96

48100bac8   Antonio Quartulli   batman-adv: creat...
97
98
99
100
101
  	tt_common_entry = tt_hash_find(bat_priv->tt_global_hash, data);
  	if (tt_common_entry)
  		tt_global_entry = container_of(tt_common_entry,
  					       struct tt_global_entry, common);
  	return tt_global_entry;
7aadf889e   Marek Lindner   batman-adv: remov...
102

7aadf889e   Marek Lindner   batman-adv: remov...
103
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
104
105
106
107
108
109
110
  static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
  {
  	unsigned long deadline;
  	deadline = starting_time + msecs_to_jiffies(timeout);
  
  	return time_after(jiffies, deadline);
  }
7683fdc1e   Antonio Quartulli   batman-adv: prote...
111
112
  static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
  {
48100bac8   Antonio Quartulli   batman-adv: creat...
113
114
  	if (atomic_dec_and_test(&tt_local_entry->common.refcount))
  		kfree_rcu(tt_local_entry, common.rcu);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
115
  }
531027fcd   Simon Wunderlich   batman-adv: remov...
116
117
  static void tt_global_entry_free_rcu(struct rcu_head *rcu)
  {
48100bac8   Antonio Quartulli   batman-adv: creat...
118
  	struct tt_common_entry *tt_common_entry;
531027fcd   Simon Wunderlich   batman-adv: remov...
119
  	struct tt_global_entry *tt_global_entry;
48100bac8   Antonio Quartulli   batman-adv: creat...
120
121
122
  	tt_common_entry = container_of(rcu, struct tt_common_entry, rcu);
  	tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
  				       common);
531027fcd   Simon Wunderlich   batman-adv: remov...
123
124
125
126
127
128
  
  	if (tt_global_entry->orig_node)
  		orig_node_free_ref(tt_global_entry->orig_node);
  
  	kfree(tt_global_entry);
  }
7683fdc1e   Antonio Quartulli   batman-adv: prote...
129
130
  static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
  {
48100bac8   Antonio Quartulli   batman-adv: creat...
131
132
133
  	if (atomic_dec_and_test(&tt_global_entry->common.refcount))
  		call_rcu(&tt_global_entry->common.rcu,
  			 tt_global_entry_free_rcu);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
134
  }
ff66c975d   Antonio Quartulli   batman-adv: pass ...
135
136
  static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
  			   uint8_t flags)
a73105b8d   Antonio Quartulli   batman-adv: impro...
137
138
139
140
141
142
143
  {
  	struct tt_change_node *tt_change_node;
  
  	tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
  
  	if (!tt_change_node)
  		return;
ff66c975d   Antonio Quartulli   batman-adv: pass ...
144
  	tt_change_node->change.flags = flags;
a73105b8d   Antonio Quartulli   batman-adv: impro...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  	memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
  
  	spin_lock_bh(&bat_priv->tt_changes_list_lock);
  	/* track the change in the OGMinterval list */
  	list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
  	atomic_inc(&bat_priv->tt_local_changes);
  	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
  
  	atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
  }
  
  int tt_len(int changes_num)
  {
  	return changes_num * sizeof(struct tt_change);
  }
  
  static int tt_local_init(struct bat_priv *bat_priv)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
162
  {
2dafb49d8   Antonio Quartulli   batman-adv: renam...
163
  	if (bat_priv->tt_local_hash)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
164
  		return 1;
2dafb49d8   Antonio Quartulli   batman-adv: renam...
165
  	bat_priv->tt_local_hash = hash_new(1024);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
166

2dafb49d8   Antonio Quartulli   batman-adv: renam...
167
  	if (!bat_priv->tt_local_hash)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
168
  		return 0;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
169
170
  	return 1;
  }
bc2790808   Antonio Quartulli   batman-adv: detec...
171
172
  void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
  		  int ifindex)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
173
174
  {
  	struct bat_priv *bat_priv = netdev_priv(soft_iface);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
175
176
  	struct tt_local_entry *tt_local_entry = NULL;
  	struct tt_global_entry *tt_global_entry = NULL;
80b3f58cf   Simon Wunderlich   batman-adv: check...
177
  	int hash_added;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
178

2dafb49d8   Antonio Quartulli   batman-adv: renam...
179
  	tt_local_entry = tt_local_hash_find(bat_priv, addr);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
180

2dafb49d8   Antonio Quartulli   batman-adv: renam...
181
182
  	if (tt_local_entry) {
  		tt_local_entry->last_seen = jiffies;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
183
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
184
  	}
704509b8d   Sven Eckelmann   batman-adv: Calcu...
185
  	tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
2dafb49d8   Antonio Quartulli   batman-adv: renam...
186
  	if (!tt_local_entry)
7683fdc1e   Antonio Quartulli   batman-adv: prote...
187
  		goto out;
a73105b8d   Antonio Quartulli   batman-adv: impro...
188

a73105b8d   Antonio Quartulli   batman-adv: impro...
189
190
191
192
  	bat_dbg(DBG_TT, bat_priv,
  		"Creating new local tt entry: %pM (ttvn: %d)
  ", addr,
  		(uint8_t)atomic_read(&bat_priv->ttvn));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
193

48100bac8   Antonio Quartulli   batman-adv: creat...
194
195
  	memcpy(tt_local_entry->common.addr, addr, ETH_ALEN);
  	tt_local_entry->common.flags = NO_FLAGS;
bc2790808   Antonio Quartulli   batman-adv: detec...
196
  	if (is_wifi_iface(ifindex))
48100bac8   Antonio Quartulli   batman-adv: creat...
197
198
199
  		tt_local_entry->common.flags |= TT_CLIENT_WIFI;
  	atomic_set(&tt_local_entry->common.refcount, 2);
  	tt_local_entry->last_seen = jiffies;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
200
201
  
  	/* the batman interface mac address should never be purged */
39901e716   Marek Lindner   batman-adv: separ...
202
  	if (compare_eth(addr, soft_iface->dev_addr))
48100bac8   Antonio Quartulli   batman-adv: creat...
203
  		tt_local_entry->common.flags |= TT_CLIENT_NOPURGE;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
204

80b3f58cf   Simon Wunderlich   batman-adv: check...
205
206
207
208
209
210
211
212
213
  	hash_added = hash_add(bat_priv->tt_local_hash, compare_tt, choose_orig,
  			 &tt_local_entry->common,
  			 &tt_local_entry->common.hash_entry);
  
  	if (unlikely(hash_added != 0)) {
  		/* remove the reference for the hash */
  		tt_local_entry_free_ref(tt_local_entry);
  		goto out;
  	}
48100bac8   Antonio Quartulli   batman-adv: creat...
214
  	tt_local_event(bat_priv, addr, tt_local_entry->common.flags);
ff66c975d   Antonio Quartulli   batman-adv: pass ...
215

058d0e269   Antonio Quartulli   batman-adv: keep ...
216
217
218
  	/* The local entry has to be marked as NEW to avoid to send it in
  	 * a full table response going out before the next ttvn increment
  	 * (consistency check) */
48100bac8   Antonio Quartulli   batman-adv: creat...
219
  	tt_local_entry->common.flags |= TT_CLIENT_NEW;
058d0e269   Antonio Quartulli   batman-adv: keep ...
220

c6c8fea29   Sven Eckelmann   net: Add batman-a...
221
  	/* remove address from global hash if present */
2dafb49d8   Antonio Quartulli   batman-adv: renam...
222
  	tt_global_entry = tt_global_hash_find(bat_priv, addr);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
223

cc47f66e6   Antonio Quartulli   batman-adv: impro...
224
225
  	/* Check whether it is a roaming! */
  	if (tt_global_entry) {
cc47f66e6   Antonio Quartulli   batman-adv: impro...
226
227
  		/* This node is probably going to update its tt table */
  		tt_global_entry->orig_node->tt_poss_change = true;
03fc30704   Antonio Quartulli   batman-adv: in ca...
228
  		/* The global entry has to be marked as ROAMING and has to be
980d55b20   Antonio Quartulli   batman-adv: keep ...
229
  		 * kept for consistency purpose */
220b07e90   David S. Miller   batman-adv: Fix m...
230
  		tt_global_entry->common.flags |= TT_CLIENT_ROAM;
03fc30704   Antonio Quartulli   batman-adv: in ca...
231
  		tt_global_entry->roam_at = jiffies;
48100bac8   Antonio Quartulli   batman-adv: creat...
232
  		send_roam_adv(bat_priv, tt_global_entry->common.addr,
7683fdc1e   Antonio Quartulli   batman-adv: prote...
233
234
235
236
237
238
239
  			      tt_global_entry->orig_node);
  	}
  out:
  	if (tt_local_entry)
  		tt_local_entry_free_ref(tt_local_entry);
  	if (tt_global_entry)
  		tt_global_entry_free_ref(tt_global_entry);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
240
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
241
242
  int tt_changes_fill_buffer(struct bat_priv *bat_priv,
  			   unsigned char *buff, int buff_len)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
243
  {
a73105b8d   Antonio Quartulli   batman-adv: impro...
244
245
  	int count = 0, tot_changes = 0;
  	struct tt_change_node *entry, *safe;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
246

a73105b8d   Antonio Quartulli   batman-adv: impro...
247
248
  	if (buff_len > 0)
  		tot_changes = buff_len / tt_len(1);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
249

a73105b8d   Antonio Quartulli   batman-adv: impro...
250
251
  	spin_lock_bh(&bat_priv->tt_changes_list_lock);
  	atomic_set(&bat_priv->tt_local_changes, 0);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
252

a73105b8d   Antonio Quartulli   batman-adv: impro...
253
254
255
256
257
  	list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
  			list) {
  		if (count < tot_changes) {
  			memcpy(buff + tt_len(count),
  			       &entry->change, sizeof(struct tt_change));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
258
259
  			count++;
  		}
a73105b8d   Antonio Quartulli   batman-adv: impro...
260
261
  		list_del(&entry->list);
  		kfree(entry);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
262
  	}
a73105b8d   Antonio Quartulli   batman-adv: impro...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
  
  	/* Keep the buffer for possible tt_request */
  	spin_lock_bh(&bat_priv->tt_buff_lock);
  	kfree(bat_priv->tt_buff);
  	bat_priv->tt_buff_len = 0;
  	bat_priv->tt_buff = NULL;
  	/* We check whether this new OGM has no changes due to size
  	 * problems */
  	if (buff_len > 0) {
  		/**
  		 * if kmalloc() fails we will reply with the full table
  		 * instead of providing the diff
  		 */
  		bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
  		if (bat_priv->tt_buff) {
  			memcpy(bat_priv->tt_buff, buff, buff_len);
  			bat_priv->tt_buff_len = buff_len;
  		}
  	}
  	spin_unlock_bh(&bat_priv->tt_buff_lock);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
284

a73105b8d   Antonio Quartulli   batman-adv: impro...
285
  	return tot_changes;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
286
  }
2dafb49d8   Antonio Quartulli   batman-adv: renam...
287
  int tt_local_seq_print_text(struct seq_file *seq, void *offset)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
288
289
290
  {
  	struct net_device *net_dev = (struct net_device *)seq->private;
  	struct bat_priv *bat_priv = netdev_priv(net_dev);
2dafb49d8   Antonio Quartulli   batman-adv: renam...
291
  	struct hashtable_t *hash = bat_priv->tt_local_hash;
48100bac8   Antonio Quartulli   batman-adv: creat...
292
  	struct tt_common_entry *tt_common_entry;
32ae9b221   Marek Lindner   batman-adv: Make ...
293
  	struct hard_iface *primary_if;
7aadf889e   Marek Lindner   batman-adv: remov...
294
  	struct hlist_node *node;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
295
  	struct hlist_head *head;
c90681b85   Antonio Quartulli   batman-adv: fixed...
296
297
  	uint32_t i;
  	int ret = 0;
32ae9b221   Marek Lindner   batman-adv: Make ...
298
299
300
301
302
303
304
305
306
  
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if) {
  		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
  				 "please specify interfaces to enable it
  ",
  				 net_dev->name);
  		goto out;
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
307

32ae9b221   Marek Lindner   batman-adv: Make ...
308
309
310
311
312
313
  	if (primary_if->if_status != IF_ACTIVE) {
  		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
  				 "primary interface not active
  ",
  				 net_dev->name);
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
314
315
316
  	}
  
  	seq_printf(seq, "Locally retrieved addresses (from %s) "
a73105b8d   Antonio Quartulli   batman-adv: impro...
317
318
319
  		   "announced via TT (TTVN: %u):
  ",
  		   net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
320

c6c8fea29   Sven Eckelmann   net: Add batman-a...
321
322
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
7aadf889e   Marek Lindner   batman-adv: remov...
323
  		rcu_read_lock();
48100bac8   Antonio Quartulli   batman-adv: creat...
324
  		hlist_for_each_entry_rcu(tt_common_entry, node,
7aadf889e   Marek Lindner   batman-adv: remov...
325
  					 head, hash_entry) {
d099c2c54   Simon Wunderlich   batman-adv: direc...
326
327
  			seq_printf(seq, " * %pM [%c%c%c%c%c]
  ",
48100bac8   Antonio Quartulli   batman-adv: creat...
328
329
  					tt_common_entry->addr,
  					(tt_common_entry->flags &
df6edb9e6   Antonio Quartulli   batman-adv: print...
330
  					 TT_CLIENT_ROAM ? 'R' : '.'),
48100bac8   Antonio Quartulli   batman-adv: creat...
331
  					(tt_common_entry->flags &
df6edb9e6   Antonio Quartulli   batman-adv: print...
332
  					 TT_CLIENT_NOPURGE ? 'P' : '.'),
48100bac8   Antonio Quartulli   batman-adv: creat...
333
  					(tt_common_entry->flags &
df6edb9e6   Antonio Quartulli   batman-adv: print...
334
  					 TT_CLIENT_NEW ? 'N' : '.'),
48100bac8   Antonio Quartulli   batman-adv: creat...
335
  					(tt_common_entry->flags &
df6edb9e6   Antonio Quartulli   batman-adv: print...
336
  					 TT_CLIENT_PENDING ? 'X' : '.'),
48100bac8   Antonio Quartulli   batman-adv: creat...
337
  					(tt_common_entry->flags &
df6edb9e6   Antonio Quartulli   batman-adv: print...
338
  					 TT_CLIENT_WIFI ? 'W' : '.'));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
339
  		}
7aadf889e   Marek Lindner   batman-adv: remov...
340
  		rcu_read_unlock();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
341
  	}
32ae9b221   Marek Lindner   batman-adv: Make ...
342
343
344
345
  out:
  	if (primary_if)
  		hardif_free_ref(primary_if);
  	return ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
346
  }
058d0e269   Antonio Quartulli   batman-adv: keep ...
347
348
349
  static void tt_local_set_pending(struct bat_priv *bat_priv,
  				 struct tt_local_entry *tt_local_entry,
  				 uint16_t flags)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
350
  {
48100bac8   Antonio Quartulli   batman-adv: creat...
351
352
  	tt_local_event(bat_priv, tt_local_entry->common.addr,
  		       tt_local_entry->common.flags | flags);
a73105b8d   Antonio Quartulli   batman-adv: impro...
353

015758d00   Antonio Quartulli   batman-adv: corre...
354
355
  	/* The local client has to be marked as "pending to be removed" but has
  	 * to be kept in the table in order to send it in a full table
058d0e269   Antonio Quartulli   batman-adv: keep ...
356
  	 * response issued before the net ttvn increment (consistency check) */
48100bac8   Antonio Quartulli   batman-adv: creat...
357
  	tt_local_entry->common.flags |= TT_CLIENT_PENDING;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
358
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
359
  void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
cc47f66e6   Antonio Quartulli   batman-adv: impro...
360
  		     const char *message, bool roaming)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
361
  {
7683fdc1e   Antonio Quartulli   batman-adv: prote...
362
  	struct tt_local_entry *tt_local_entry = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
363

2dafb49d8   Antonio Quartulli   batman-adv: renam...
364
  	tt_local_entry = tt_local_hash_find(bat_priv, addr);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
365
366
  	if (!tt_local_entry)
  		goto out;
058d0e269   Antonio Quartulli   batman-adv: keep ...
367
368
369
370
  	tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
  			     (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
  
  	bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
48100bac8   Antonio Quartulli   batman-adv: creat...
371
372
  		"%s
  ", tt_local_entry->common.addr, message);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
373
374
375
  out:
  	if (tt_local_entry)
  		tt_local_entry_free_ref(tt_local_entry);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
376
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
377
  static void tt_local_purge(struct bat_priv *bat_priv)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
378
  {
2dafb49d8   Antonio Quartulli   batman-adv: renam...
379
380
  	struct hashtable_t *hash = bat_priv->tt_local_hash;
  	struct tt_local_entry *tt_local_entry;
48100bac8   Antonio Quartulli   batman-adv: creat...
381
  	struct tt_common_entry *tt_common_entry;
7aadf889e   Marek Lindner   batman-adv: remov...
382
  	struct hlist_node *node, *node_tmp;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
383
  	struct hlist_head *head;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
384
  	spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b85   Antonio Quartulli   batman-adv: fixed...
385
  	uint32_t i;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
386

c6c8fea29   Sven Eckelmann   net: Add batman-a...
387
388
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
7683fdc1e   Antonio Quartulli   batman-adv: prote...
389
  		list_lock = &hash->list_locks[i];
c6c8fea29   Sven Eckelmann   net: Add batman-a...
390

7683fdc1e   Antonio Quartulli   batman-adv: prote...
391
  		spin_lock_bh(list_lock);
48100bac8   Antonio Quartulli   batman-adv: creat...
392
  		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
7aadf889e   Marek Lindner   batman-adv: remov...
393
  					  head, hash_entry) {
48100bac8   Antonio Quartulli   batman-adv: creat...
394
395
396
397
  			tt_local_entry = container_of(tt_common_entry,
  						      struct tt_local_entry,
  						      common);
  			if (tt_local_entry->common.flags & TT_CLIENT_NOPURGE)
7aadf889e   Marek Lindner   batman-adv: remov...
398
  				continue;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
399

058d0e269   Antonio Quartulli   batman-adv: keep ...
400
  			/* entry already marked for deletion */
48100bac8   Antonio Quartulli   batman-adv: creat...
401
  			if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
058d0e269   Antonio Quartulli   batman-adv: keep ...
402
  				continue;
a73105b8d   Antonio Quartulli   batman-adv: impro...
403
  			if (!is_out_of_time(tt_local_entry->last_seen,
7683fdc1e   Antonio Quartulli   batman-adv: prote...
404
  					    TT_LOCAL_TIMEOUT * 1000))
7aadf889e   Marek Lindner   batman-adv: remov...
405
  				continue;
058d0e269   Antonio Quartulli   batman-adv: keep ...
406
407
408
409
410
  			tt_local_set_pending(bat_priv, tt_local_entry,
  					     TT_CLIENT_DEL);
  			bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
  				"pending to be removed: timed out
  ",
48100bac8   Antonio Quartulli   batman-adv: creat...
411
  				tt_local_entry->common.addr);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
412
  		}
7683fdc1e   Antonio Quartulli   batman-adv: prote...
413
  		spin_unlock_bh(list_lock);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
414
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
415
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
416
  static void tt_local_table_free(struct bat_priv *bat_priv)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
417
  {
a73105b8d   Antonio Quartulli   batman-adv: impro...
418
  	struct hashtable_t *hash;
a73105b8d   Antonio Quartulli   batman-adv: impro...
419
  	spinlock_t *list_lock; /* protects write access to the hash lists */
48100bac8   Antonio Quartulli   batman-adv: creat...
420
  	struct tt_common_entry *tt_common_entry;
a73105b8d   Antonio Quartulli   batman-adv: impro...
421
  	struct tt_local_entry *tt_local_entry;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
422
423
  	struct hlist_node *node, *node_tmp;
  	struct hlist_head *head;
c90681b85   Antonio Quartulli   batman-adv: fixed...
424
  	uint32_t i;
a73105b8d   Antonio Quartulli   batman-adv: impro...
425

2dafb49d8   Antonio Quartulli   batman-adv: renam...
426
  	if (!bat_priv->tt_local_hash)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
427
  		return;
a73105b8d   Antonio Quartulli   batman-adv: impro...
428
429
430
431
432
433
434
  	hash = bat_priv->tt_local_hash;
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
  		list_lock = &hash->list_locks[i];
  
  		spin_lock_bh(list_lock);
48100bac8   Antonio Quartulli   batman-adv: creat...
435
  		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
a73105b8d   Antonio Quartulli   batman-adv: impro...
436
437
  					  head, hash_entry) {
  			hlist_del_rcu(node);
48100bac8   Antonio Quartulli   batman-adv: creat...
438
439
440
  			tt_local_entry = container_of(tt_common_entry,
  						      struct tt_local_entry,
  						      common);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
441
  			tt_local_entry_free_ref(tt_local_entry);
a73105b8d   Antonio Quartulli   batman-adv: impro...
442
443
444
445
446
  		}
  		spin_unlock_bh(list_lock);
  	}
  
  	hash_destroy(hash);
2dafb49d8   Antonio Quartulli   batman-adv: renam...
447
  	bat_priv->tt_local_hash = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
448
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
449
  static int tt_global_init(struct bat_priv *bat_priv)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
450
  {
2dafb49d8   Antonio Quartulli   batman-adv: renam...
451
  	if (bat_priv->tt_global_hash)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
452
  		return 1;
2dafb49d8   Antonio Quartulli   batman-adv: renam...
453
  	bat_priv->tt_global_hash = hash_new(1024);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
454

2dafb49d8   Antonio Quartulli   batman-adv: renam...
455
  	if (!bat_priv->tt_global_hash)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
456
457
458
459
  		return 0;
  
  	return 1;
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
460
  static void tt_changes_list_free(struct bat_priv *bat_priv)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
461
  {
a73105b8d   Antonio Quartulli   batman-adv: impro...
462
  	struct tt_change_node *entry, *safe;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
463

a73105b8d   Antonio Quartulli   batman-adv: impro...
464
  	spin_lock_bh(&bat_priv->tt_changes_list_lock);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
465

a73105b8d   Antonio Quartulli   batman-adv: impro...
466
467
468
469
470
  	list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
  				 list) {
  		list_del(&entry->list);
  		kfree(entry);
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
471

a73105b8d   Antonio Quartulli   batman-adv: impro...
472
473
474
  	atomic_set(&bat_priv->tt_local_changes, 0);
  	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
  }
c6c8fea29   Sven Eckelmann   net: Add batman-a...
475

a73105b8d   Antonio Quartulli   batman-adv: impro...
476
477
  /* caller must hold orig_node refcount */
  int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
bc2790808   Antonio Quartulli   batman-adv: detec...
478
479
  		  const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
  		  bool wifi)
a73105b8d   Antonio Quartulli   batman-adv: impro...
480
481
  {
  	struct tt_global_entry *tt_global_entry;
a73105b8d   Antonio Quartulli   batman-adv: impro...
482
  	struct orig_node *orig_node_tmp;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
483
  	int ret = 0;
80b3f58cf   Simon Wunderlich   batman-adv: check...
484
  	int hash_added;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
485

a73105b8d   Antonio Quartulli   batman-adv: impro...
486
487
488
489
490
491
492
  	tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
  
  	if (!tt_global_entry) {
  		tt_global_entry =
  			kmalloc(sizeof(*tt_global_entry),
  				GFP_ATOMIC);
  		if (!tt_global_entry)
7683fdc1e   Antonio Quartulli   batman-adv: prote...
493
  			goto out;
48100bac8   Antonio Quartulli   batman-adv: creat...
494
495
496
  		memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN);
  		tt_global_entry->common.flags = NO_FLAGS;
  		atomic_set(&tt_global_entry->common.refcount, 2);
a73105b8d   Antonio Quartulli   batman-adv: impro...
497
498
  		/* Assign the new orig_node */
  		atomic_inc(&orig_node->refcount);
2dafb49d8   Antonio Quartulli   batman-adv: renam...
499
  		tt_global_entry->orig_node = orig_node;
a73105b8d   Antonio Quartulli   batman-adv: impro...
500
  		tt_global_entry->ttvn = ttvn;
cc47f66e6   Antonio Quartulli   batman-adv: impro...
501
  		tt_global_entry->roam_at = 0;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
502

80b3f58cf   Simon Wunderlich   batman-adv: check...
503
504
505
506
507
508
509
510
511
  		hash_added = hash_add(bat_priv->tt_global_hash, compare_tt,
  				 choose_orig, &tt_global_entry->common,
  				 &tt_global_entry->common.hash_entry);
  
  		if (unlikely(hash_added != 0)) {
  			/* remove the reference for the hash */
  			tt_global_entry_free_ref(tt_global_entry);
  			goto out_remove;
  		}
7683fdc1e   Antonio Quartulli   batman-adv: prote...
512
  		atomic_inc(&orig_node->tt_size);
a73105b8d   Antonio Quartulli   batman-adv: impro...
513
514
515
516
517
518
  	} else {
  		if (tt_global_entry->orig_node != orig_node) {
  			atomic_dec(&tt_global_entry->orig_node->tt_size);
  			orig_node_tmp = tt_global_entry->orig_node;
  			atomic_inc(&orig_node->refcount);
  			tt_global_entry->orig_node = orig_node;
a73105b8d   Antonio Quartulli   batman-adv: impro...
519
520
521
  			orig_node_free_ref(orig_node_tmp);
  			atomic_inc(&orig_node->tt_size);
  		}
48100bac8   Antonio Quartulli   batman-adv: creat...
522
  		tt_global_entry->common.flags = NO_FLAGS;
cc47f66e6   Antonio Quartulli   batman-adv: impro...
523
  		tt_global_entry->ttvn = ttvn;
cc47f66e6   Antonio Quartulli   batman-adv: impro...
524
  		tt_global_entry->roam_at = 0;
a73105b8d   Antonio Quartulli   batman-adv: impro...
525
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
526

bc2790808   Antonio Quartulli   batman-adv: detec...
527
  	if (wifi)
48100bac8   Antonio Quartulli   batman-adv: creat...
528
  		tt_global_entry->common.flags |= TT_CLIENT_WIFI;
bc2790808   Antonio Quartulli   batman-adv: detec...
529

a73105b8d   Antonio Quartulli   batman-adv: impro...
530
531
532
  	bat_dbg(DBG_TT, bat_priv,
  		"Creating new global tt entry: %pM (via %pM)
  ",
48100bac8   Antonio Quartulli   batman-adv: creat...
533
  		tt_global_entry->common.addr, orig_node->orig);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
534

80b3f58cf   Simon Wunderlich   batman-adv: check...
535
  out_remove:
a73105b8d   Antonio Quartulli   batman-adv: impro...
536
  	/* remove address from local hash if present */
48100bac8   Antonio Quartulli   batman-adv: creat...
537
  	tt_local_remove(bat_priv, tt_global_entry->common.addr,
7683fdc1e   Antonio Quartulli   batman-adv: prote...
538
539
540
541
542
543
  			"global tt received", roaming);
  	ret = 1;
  out:
  	if (tt_global_entry)
  		tt_global_entry_free_ref(tt_global_entry);
  	return ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
544
  }
2dafb49d8   Antonio Quartulli   batman-adv: renam...
545
  int tt_global_seq_print_text(struct seq_file *seq, void *offset)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
546
547
548
  {
  	struct net_device *net_dev = (struct net_device *)seq->private;
  	struct bat_priv *bat_priv = netdev_priv(net_dev);
2dafb49d8   Antonio Quartulli   batman-adv: renam...
549
  	struct hashtable_t *hash = bat_priv->tt_global_hash;
48100bac8   Antonio Quartulli   batman-adv: creat...
550
  	struct tt_common_entry *tt_common_entry;
2dafb49d8   Antonio Quartulli   batman-adv: renam...
551
  	struct tt_global_entry *tt_global_entry;
32ae9b221   Marek Lindner   batman-adv: Make ...
552
  	struct hard_iface *primary_if;
7aadf889e   Marek Lindner   batman-adv: remov...
553
  	struct hlist_node *node;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
554
  	struct hlist_head *head;
c90681b85   Antonio Quartulli   batman-adv: fixed...
555
556
  	uint32_t i;
  	int ret = 0;
32ae9b221   Marek Lindner   batman-adv: Make ...
557
558
559
560
561
562
563
564
565
  
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if) {
  		ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
  				 "specify interfaces to enable it
  ",
  				 net_dev->name);
  		goto out;
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
566

32ae9b221   Marek Lindner   batman-adv: Make ...
567
568
569
570
571
572
  	if (primary_if->if_status != IF_ACTIVE) {
  		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
  				 "primary interface not active
  ",
  				 net_dev->name);
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
573
  	}
2dafb49d8   Antonio Quartulli   batman-adv: renam...
574
575
576
  	seq_printf(seq,
  		   "Globally announced TT entries received via the mesh %s
  ",
c6c8fea29   Sven Eckelmann   net: Add batman-a...
577
  		   net_dev->name);
df6edb9e6   Antonio Quartulli   batman-adv: print...
578
579
580
  	seq_printf(seq, "       %-13s %s       %-15s %s %s
  ",
  		   "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
c6c8fea29   Sven Eckelmann   net: Add batman-a...
581

c6c8fea29   Sven Eckelmann   net: Add batman-a...
582
583
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
7aadf889e   Marek Lindner   batman-adv: remov...
584
  		rcu_read_lock();
48100bac8   Antonio Quartulli   batman-adv: creat...
585
  		hlist_for_each_entry_rcu(tt_common_entry, node,
7aadf889e   Marek Lindner   batman-adv: remov...
586
  					 head, hash_entry) {
48100bac8   Antonio Quartulli   batman-adv: creat...
587
588
589
  			tt_global_entry = container_of(tt_common_entry,
  						       struct tt_global_entry,
  						       common);
d099c2c54   Simon Wunderlich   batman-adv: direc...
590
  			seq_printf(seq, " * %pM  (%3u) via %pM     (%3u)   "
48100bac8   Antonio Quartulli   batman-adv: creat...
591
592
593
  					"[%c%c%c]
  ",
  					tt_global_entry->common.addr,
a73105b8d   Antonio Quartulli   batman-adv: impro...
594
595
596
597
  					tt_global_entry->ttvn,
  					tt_global_entry->orig_node->orig,
  					(uint8_t) atomic_read(
  						&tt_global_entry->orig_node->
df6edb9e6   Antonio Quartulli   batman-adv: print...
598
  						last_ttvn),
48100bac8   Antonio Quartulli   batman-adv: creat...
599
  					(tt_global_entry->common.flags &
df6edb9e6   Antonio Quartulli   batman-adv: print...
600
  					 TT_CLIENT_ROAM ? 'R' : '.'),
48100bac8   Antonio Quartulli   batman-adv: creat...
601
  					(tt_global_entry->common.flags &
df6edb9e6   Antonio Quartulli   batman-adv: print...
602
  					 TT_CLIENT_PENDING ? 'X' : '.'),
48100bac8   Antonio Quartulli   batman-adv: creat...
603
  					(tt_global_entry->common.flags &
df6edb9e6   Antonio Quartulli   batman-adv: print...
604
  					 TT_CLIENT_WIFI ? 'W' : '.'));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
605
  		}
7aadf889e   Marek Lindner   batman-adv: remov...
606
  		rcu_read_unlock();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
607
  	}
32ae9b221   Marek Lindner   batman-adv: Make ...
608
609
610
611
  out:
  	if (primary_if)
  		hardif_free_ref(primary_if);
  	return ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
612
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
613
614
615
  static void _tt_global_del(struct bat_priv *bat_priv,
  			   struct tt_global_entry *tt_global_entry,
  			   const char *message)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
616
  {
a73105b8d   Antonio Quartulli   batman-adv: impro...
617
  	if (!tt_global_entry)
7683fdc1e   Antonio Quartulli   batman-adv: prote...
618
  		goto out;
a73105b8d   Antonio Quartulli   batman-adv: impro...
619
620
  
  	bat_dbg(DBG_TT, bat_priv,
2dafb49d8   Antonio Quartulli   batman-adv: renam...
621
622
  		"Deleting global tt entry %pM (via %pM): %s
  ",
48100bac8   Antonio Quartulli   batman-adv: creat...
623
  		tt_global_entry->common.addr, tt_global_entry->orig_node->orig,
c6c8fea29   Sven Eckelmann   net: Add batman-a...
624
  		message);
a73105b8d   Antonio Quartulli   batman-adv: impro...
625
  	atomic_dec(&tt_global_entry->orig_node->tt_size);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
626

48100bac8   Antonio Quartulli   batman-adv: creat...
627
628
  	hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig,
  		    tt_global_entry->common.addr);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
629
630
631
  out:
  	if (tt_global_entry)
  		tt_global_entry_free_ref(tt_global_entry);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
632
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
633
634
  void tt_global_del(struct bat_priv *bat_priv,
  		   struct orig_node *orig_node, const unsigned char *addr,
cc47f66e6   Antonio Quartulli   batman-adv: impro...
635
  		   const char *message, bool roaming)
a73105b8d   Antonio Quartulli   batman-adv: impro...
636
  {
7683fdc1e   Antonio Quartulli   batman-adv: prote...
637
  	struct tt_global_entry *tt_global_entry = NULL;
797399b41   Antonio Quartulli   batman-adv: delet...
638
  	struct tt_local_entry *tt_local_entry = NULL;
a73105b8d   Antonio Quartulli   batman-adv: impro...
639

a73105b8d   Antonio Quartulli   batman-adv: impro...
640
  	tt_global_entry = tt_global_hash_find(bat_priv, addr);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
641
642
  	if (!tt_global_entry)
  		goto out;
a73105b8d   Antonio Quartulli   batman-adv: impro...
643

7683fdc1e   Antonio Quartulli   batman-adv: prote...
644
  	if (tt_global_entry->orig_node == orig_node) {
cc47f66e6   Antonio Quartulli   batman-adv: impro...
645
  		if (roaming) {
797399b41   Antonio Quartulli   batman-adv: delet...
646
647
648
649
650
651
652
653
654
  			/* if we are deleting a global entry due to a roam
  			 * event, there are two possibilities:
  			 * 1) the client roamed from node A to node B => we mark
  			 *    it with TT_CLIENT_ROAM, we start a timer and we
  			 *    wait for node B to claim it. In case of timeout
  			 *    the entry is purged.
  			 * 2) the client roamed to us => we can directly delete
  			 *    the global entry, since it is useless now. */
  			tt_local_entry = tt_local_hash_find(bat_priv,
b26e478f8   David S. Miller   Merge git://git.k...
655
  							    tt_global_entry->common.addr);
797399b41   Antonio Quartulli   batman-adv: delet...
656
  			if (!tt_local_entry) {
b26e478f8   David S. Miller   Merge git://git.k...
657
  				tt_global_entry->common.flags |= TT_CLIENT_ROAM;
797399b41   Antonio Quartulli   batman-adv: delet...
658
659
660
  				tt_global_entry->roam_at = jiffies;
  				goto out;
  			}
cc47f66e6   Antonio Quartulli   batman-adv: impro...
661
  		}
a73105b8d   Antonio Quartulli   batman-adv: impro...
662
663
  		_tt_global_del(bat_priv, tt_global_entry, message);
  	}
cc47f66e6   Antonio Quartulli   batman-adv: impro...
664
  out:
7683fdc1e   Antonio Quartulli   batman-adv: prote...
665
666
  	if (tt_global_entry)
  		tt_global_entry_free_ref(tt_global_entry);
797399b41   Antonio Quartulli   batman-adv: delet...
667
668
  	if (tt_local_entry)
  		tt_local_entry_free_ref(tt_local_entry);
a73105b8d   Antonio Quartulli   batman-adv: impro...
669
  }
2dafb49d8   Antonio Quartulli   batman-adv: renam...
670
  void tt_global_del_orig(struct bat_priv *bat_priv,
a73105b8d   Antonio Quartulli   batman-adv: impro...
671
  			struct orig_node *orig_node, const char *message)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
672
  {
2dafb49d8   Antonio Quartulli   batman-adv: renam...
673
  	struct tt_global_entry *tt_global_entry;
48100bac8   Antonio Quartulli   batman-adv: creat...
674
  	struct tt_common_entry *tt_common_entry;
c90681b85   Antonio Quartulli   batman-adv: fixed...
675
  	uint32_t i;
a73105b8d   Antonio Quartulli   batman-adv: impro...
676
677
678
  	struct hashtable_t *hash = bat_priv->tt_global_hash;
  	struct hlist_node *node, *safe;
  	struct hlist_head *head;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
679
  	spinlock_t *list_lock; /* protects write access to the hash lists */
c6c8fea29   Sven Eckelmann   net: Add batman-a...
680

6e8014947   Simon Wunderlich   batman-adv: add s...
681
682
  	if (!hash)
  		return;
a73105b8d   Antonio Quartulli   batman-adv: impro...
683
684
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
7683fdc1e   Antonio Quartulli   batman-adv: prote...
685
  		list_lock = &hash->list_locks[i];
c6c8fea29   Sven Eckelmann   net: Add batman-a...
686

7683fdc1e   Antonio Quartulli   batman-adv: prote...
687
  		spin_lock_bh(list_lock);
48100bac8   Antonio Quartulli   batman-adv: creat...
688
  		hlist_for_each_entry_safe(tt_common_entry, node, safe,
a73105b8d   Antonio Quartulli   batman-adv: impro...
689
  					 head, hash_entry) {
48100bac8   Antonio Quartulli   batman-adv: creat...
690
691
692
  			tt_global_entry = container_of(tt_common_entry,
  						       struct tt_global_entry,
  						       common);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
693
694
695
  			if (tt_global_entry->orig_node == orig_node) {
  				bat_dbg(DBG_TT, bat_priv,
  					"Deleting global tt entry %pM "
87944973d   Antonio Quartulli   batman-adv: tt_gl...
696
697
  					"(via %pM): %s
  ",
48100bac8   Antonio Quartulli   batman-adv: creat...
698
  					tt_global_entry->common.addr,
87944973d   Antonio Quartulli   batman-adv: tt_gl...
699
700
  					tt_global_entry->orig_node->orig,
  					message);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
701
702
703
  				hlist_del_rcu(node);
  				tt_global_entry_free_ref(tt_global_entry);
  			}
a73105b8d   Antonio Quartulli   batman-adv: impro...
704
  		}
7683fdc1e   Antonio Quartulli   batman-adv: prote...
705
  		spin_unlock_bh(list_lock);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
706
  	}
a73105b8d   Antonio Quartulli   batman-adv: impro...
707
  	atomic_set(&orig_node->tt_size, 0);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
708
  }
cc47f66e6   Antonio Quartulli   batman-adv: impro...
709
710
711
  static void tt_global_roam_purge(struct bat_priv *bat_priv)
  {
  	struct hashtable_t *hash = bat_priv->tt_global_hash;
48100bac8   Antonio Quartulli   batman-adv: creat...
712
  	struct tt_common_entry *tt_common_entry;
cc47f66e6   Antonio Quartulli   batman-adv: impro...
713
714
715
  	struct tt_global_entry *tt_global_entry;
  	struct hlist_node *node, *node_tmp;
  	struct hlist_head *head;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
716
  	spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b85   Antonio Quartulli   batman-adv: fixed...
717
  	uint32_t i;
cc47f66e6   Antonio Quartulli   batman-adv: impro...
718

cc47f66e6   Antonio Quartulli   batman-adv: impro...
719
720
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
7683fdc1e   Antonio Quartulli   batman-adv: prote...
721
  		list_lock = &hash->list_locks[i];
cc47f66e6   Antonio Quartulli   batman-adv: impro...
722

7683fdc1e   Antonio Quartulli   batman-adv: prote...
723
  		spin_lock_bh(list_lock);
48100bac8   Antonio Quartulli   batman-adv: creat...
724
  		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
cc47f66e6   Antonio Quartulli   batman-adv: impro...
725
  					  head, hash_entry) {
48100bac8   Antonio Quartulli   batman-adv: creat...
726
727
728
729
  			tt_global_entry = container_of(tt_common_entry,
  						       struct tt_global_entry,
  						       common);
  			if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM))
cc47f66e6   Antonio Quartulli   batman-adv: impro...
730
731
732
733
  				continue;
  			if (!is_out_of_time(tt_global_entry->roam_at,
  					    TT_CLIENT_ROAM_TIMEOUT * 1000))
  				continue;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
734
735
736
  			bat_dbg(DBG_TT, bat_priv, "Deleting global "
  				"tt entry (%pM): Roaming timeout
  ",
48100bac8   Antonio Quartulli   batman-adv: creat...
737
  				tt_global_entry->common.addr);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
738
739
740
  			atomic_dec(&tt_global_entry->orig_node->tt_size);
  			hlist_del_rcu(node);
  			tt_global_entry_free_ref(tt_global_entry);
cc47f66e6   Antonio Quartulli   batman-adv: impro...
741
  		}
7683fdc1e   Antonio Quartulli   batman-adv: prote...
742
  		spin_unlock_bh(list_lock);
cc47f66e6   Antonio Quartulli   batman-adv: impro...
743
  	}
cc47f66e6   Antonio Quartulli   batman-adv: impro...
744
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
745
  static void tt_global_table_free(struct bat_priv *bat_priv)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
746
  {
7683fdc1e   Antonio Quartulli   batman-adv: prote...
747
748
  	struct hashtable_t *hash;
  	spinlock_t *list_lock; /* protects write access to the hash lists */
48100bac8   Antonio Quartulli   batman-adv: creat...
749
  	struct tt_common_entry *tt_common_entry;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
750
751
752
  	struct tt_global_entry *tt_global_entry;
  	struct hlist_node *node, *node_tmp;
  	struct hlist_head *head;
c90681b85   Antonio Quartulli   batman-adv: fixed...
753
  	uint32_t i;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
754

2dafb49d8   Antonio Quartulli   batman-adv: renam...
755
  	if (!bat_priv->tt_global_hash)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
756
  		return;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
757
758
759
760
761
762
763
  	hash = bat_priv->tt_global_hash;
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
  		list_lock = &hash->list_locks[i];
  
  		spin_lock_bh(list_lock);
48100bac8   Antonio Quartulli   batman-adv: creat...
764
  		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
7683fdc1e   Antonio Quartulli   batman-adv: prote...
765
766
  					  head, hash_entry) {
  			hlist_del_rcu(node);
48100bac8   Antonio Quartulli   batman-adv: creat...
767
768
769
  			tt_global_entry = container_of(tt_common_entry,
  						       struct tt_global_entry,
  						       common);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
770
771
772
773
774
775
  			tt_global_entry_free_ref(tt_global_entry);
  		}
  		spin_unlock_bh(list_lock);
  	}
  
  	hash_destroy(hash);
2dafb49d8   Antonio Quartulli   batman-adv: renam...
776
  	bat_priv->tt_global_hash = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
777
  }
59b699cde   Antonio Quartulli   batman-adv: imple...
778
779
780
781
  static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
  			    struct tt_global_entry *tt_global_entry)
  {
  	bool ret = false;
48100bac8   Antonio Quartulli   batman-adv: creat...
782
783
  	if (tt_local_entry->common.flags & TT_CLIENT_WIFI &&
  	    tt_global_entry->common.flags & TT_CLIENT_WIFI)
59b699cde   Antonio Quartulli   batman-adv: imple...
784
785
786
787
  		ret = true;
  
  	return ret;
  }
747e4221a   Sven Eckelmann   batman-adv: Add c...
788
  struct orig_node *transtable_search(struct bat_priv *bat_priv,
3d393e473   Antonio Quartulli   batman-adv: imple...
789
  				    const uint8_t *src, const uint8_t *addr)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
790
  {
3d393e473   Antonio Quartulli   batman-adv: imple...
791
792
  	struct tt_local_entry *tt_local_entry = NULL;
  	struct tt_global_entry *tt_global_entry = NULL;
7b36e8eef   Marek Lindner   batman-adv: Corre...
793
  	struct orig_node *orig_node = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
794

3d393e473   Antonio Quartulli   batman-adv: imple...
795
796
797
798
799
  	if (src && atomic_read(&bat_priv->ap_isolation)) {
  		tt_local_entry = tt_local_hash_find(bat_priv, src);
  		if (!tt_local_entry)
  			goto out;
  	}
7aadf889e   Marek Lindner   batman-adv: remov...
800

3d393e473   Antonio Quartulli   batman-adv: imple...
801
  	tt_global_entry = tt_global_hash_find(bat_priv, addr);
2dafb49d8   Antonio Quartulli   batman-adv: renam...
802
  	if (!tt_global_entry)
7b36e8eef   Marek Lindner   batman-adv: Corre...
803
  		goto out;
7aadf889e   Marek Lindner   batman-adv: remov...
804

3d393e473   Antonio Quartulli   batman-adv: imple...
805
806
807
808
  	/* check whether the clients should not communicate due to AP
  	 * isolation */
  	if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
  		goto out;
2dafb49d8   Antonio Quartulli   batman-adv: renam...
809
  	if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
3d393e473   Antonio Quartulli   batman-adv: imple...
810
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
811

980d55b20   Antonio Quartulli   batman-adv: keep ...
812
813
  	/* A global client marked as PENDING has already moved from that
  	 * originator */
48100bac8   Antonio Quartulli   batman-adv: creat...
814
  	if (tt_global_entry->common.flags & TT_CLIENT_PENDING)
3d393e473   Antonio Quartulli   batman-adv: imple...
815
  		goto out;
980d55b20   Antonio Quartulli   batman-adv: keep ...
816

2dafb49d8   Antonio Quartulli   batman-adv: renam...
817
  	orig_node = tt_global_entry->orig_node;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
818

7b36e8eef   Marek Lindner   batman-adv: Corre...
819
  out:
3d393e473   Antonio Quartulli   batman-adv: imple...
820
821
822
823
  	if (tt_global_entry)
  		tt_global_entry_free_ref(tt_global_entry);
  	if (tt_local_entry)
  		tt_local_entry_free_ref(tt_local_entry);
7b36e8eef   Marek Lindner   batman-adv: Corre...
824
  	return orig_node;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
825
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
826
827
828
829
830
831
  
  /* Calculates the checksum of the local table of a given orig_node */
  uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
  {
  	uint16_t total = 0, total_one;
  	struct hashtable_t *hash = bat_priv->tt_global_hash;
48100bac8   Antonio Quartulli   batman-adv: creat...
832
  	struct tt_common_entry *tt_common_entry;
a73105b8d   Antonio Quartulli   batman-adv: impro...
833
834
835
  	struct tt_global_entry *tt_global_entry;
  	struct hlist_node *node;
  	struct hlist_head *head;
c90681b85   Antonio Quartulli   batman-adv: fixed...
836
837
  	uint32_t i;
  	int j;
a73105b8d   Antonio Quartulli   batman-adv: impro...
838
839
840
841
842
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
  
  		rcu_read_lock();
48100bac8   Antonio Quartulli   batman-adv: creat...
843
  		hlist_for_each_entry_rcu(tt_common_entry, node,
a73105b8d   Antonio Quartulli   batman-adv: impro...
844
  					 head, hash_entry) {
48100bac8   Antonio Quartulli   batman-adv: creat...
845
846
847
  			tt_global_entry = container_of(tt_common_entry,
  						       struct tt_global_entry,
  						       common);
a73105b8d   Antonio Quartulli   batman-adv: impro...
848
849
  			if (compare_eth(tt_global_entry->orig_node,
  					orig_node)) {
cc47f66e6   Antonio Quartulli   batman-adv: impro...
850
851
852
853
  				/* Roaming clients are in the global table for
  				 * consistency only. They don't have to be
  				 * taken into account while computing the
  				 * global crc */
48100bac8   Antonio Quartulli   batman-adv: creat...
854
  				if (tt_common_entry->flags & TT_CLIENT_ROAM)
cc47f66e6   Antonio Quartulli   batman-adv: impro...
855
  					continue;
a73105b8d   Antonio Quartulli   batman-adv: impro...
856
857
858
  				total_one = 0;
  				for (j = 0; j < ETH_ALEN; j++)
  					total_one = crc16_byte(total_one,
48100bac8   Antonio Quartulli   batman-adv: creat...
859
  						tt_common_entry->addr[j]);
a73105b8d   Antonio Quartulli   batman-adv: impro...
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  				total ^= total_one;
  			}
  		}
  		rcu_read_unlock();
  	}
  
  	return total;
  }
  
  /* Calculates the checksum of the local table */
  uint16_t tt_local_crc(struct bat_priv *bat_priv)
  {
  	uint16_t total = 0, total_one;
  	struct hashtable_t *hash = bat_priv->tt_local_hash;
48100bac8   Antonio Quartulli   batman-adv: creat...
874
  	struct tt_common_entry *tt_common_entry;
a73105b8d   Antonio Quartulli   batman-adv: impro...
875
876
  	struct hlist_node *node;
  	struct hlist_head *head;
c90681b85   Antonio Quartulli   batman-adv: fixed...
877
878
  	uint32_t i;
  	int j;
a73105b8d   Antonio Quartulli   batman-adv: impro...
879
880
881
882
883
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
  
  		rcu_read_lock();
48100bac8   Antonio Quartulli   batman-adv: creat...
884
  		hlist_for_each_entry_rcu(tt_common_entry, node,
a73105b8d   Antonio Quartulli   batman-adv: impro...
885
  					 head, hash_entry) {
058d0e269   Antonio Quartulli   batman-adv: keep ...
886
887
  			/* not yet committed clients have not to be taken into
  			 * account while computing the CRC */
48100bac8   Antonio Quartulli   batman-adv: creat...
888
  			if (tt_common_entry->flags & TT_CLIENT_NEW)
058d0e269   Antonio Quartulli   batman-adv: keep ...
889
  				continue;
a73105b8d   Antonio Quartulli   batman-adv: impro...
890
891
892
  			total_one = 0;
  			for (j = 0; j < ETH_ALEN; j++)
  				total_one = crc16_byte(total_one,
48100bac8   Antonio Quartulli   batman-adv: creat...
893
  						   tt_common_entry->addr[j]);
a73105b8d   Antonio Quartulli   batman-adv: impro...
894
895
  			total ^= total_one;
  		}
a73105b8d   Antonio Quartulli   batman-adv: impro...
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
  		rcu_read_unlock();
  	}
  
  	return total;
  }
  
  static void tt_req_list_free(struct bat_priv *bat_priv)
  {
  	struct tt_req_node *node, *safe;
  
  	spin_lock_bh(&bat_priv->tt_req_list_lock);
  
  	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
  		list_del(&node->list);
  		kfree(node);
  	}
  
  	spin_unlock_bh(&bat_priv->tt_req_list_lock);
  }
  
  void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
  			 const unsigned char *tt_buff, uint8_t tt_num_changes)
  {
  	uint16_t tt_buff_len = tt_len(tt_num_changes);
  
  	/* Replace the old buffer only if I received something in the
  	 * last OGM (the OGM could carry no changes) */
  	spin_lock_bh(&orig_node->tt_buff_lock);
  	if (tt_buff_len > 0) {
  		kfree(orig_node->tt_buff);
  		orig_node->tt_buff_len = 0;
  		orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
  		if (orig_node->tt_buff) {
  			memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
  			orig_node->tt_buff_len = tt_buff_len;
  		}
  	}
  	spin_unlock_bh(&orig_node->tt_buff_lock);
  }
  
  static void tt_req_purge(struct bat_priv *bat_priv)
  {
  	struct tt_req_node *node, *safe;
  
  	spin_lock_bh(&bat_priv->tt_req_list_lock);
  	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
  		if (is_out_of_time(node->issued_at,
  		    TT_REQUEST_TIMEOUT * 1000)) {
  			list_del(&node->list);
  			kfree(node);
  		}
  	}
  	spin_unlock_bh(&bat_priv->tt_req_list_lock);
  }
  
  /* returns the pointer to the new tt_req_node struct if no request
   * has already been issued for this orig_node, NULL otherwise */
  static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
  					  struct orig_node *orig_node)
  {
  	struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
  
  	spin_lock_bh(&bat_priv->tt_req_list_lock);
  	list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
  		if (compare_eth(tt_req_node_tmp, orig_node) &&
  		    !is_out_of_time(tt_req_node_tmp->issued_at,
  				    TT_REQUEST_TIMEOUT * 1000))
  			goto unlock;
  	}
  
  	tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
  	if (!tt_req_node)
  		goto unlock;
  
  	memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
  	tt_req_node->issued_at = jiffies;
  
  	list_add(&tt_req_node->list, &bat_priv->tt_req_list);
  unlock:
  	spin_unlock_bh(&bat_priv->tt_req_list_lock);
  	return tt_req_node;
  }
058d0e269   Antonio Quartulli   batman-adv: keep ...
978
979
980
  /* data_ptr is useless here, but has to be kept to respect the prototype */
  static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
  {
48100bac8   Antonio Quartulli   batman-adv: creat...
981
  	const struct tt_common_entry *tt_common_entry = entry_ptr;
058d0e269   Antonio Quartulli   batman-adv: keep ...
982

48100bac8   Antonio Quartulli   batman-adv: creat...
983
  	if (tt_common_entry->flags & TT_CLIENT_NEW)
058d0e269   Antonio Quartulli   batman-adv: keep ...
984
985
986
  		return 0;
  	return 1;
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
987
988
  static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
  {
48100bac8   Antonio Quartulli   batman-adv: creat...
989
990
  	const struct tt_common_entry *tt_common_entry = entry_ptr;
  	const struct tt_global_entry *tt_global_entry;
a73105b8d   Antonio Quartulli   batman-adv: impro...
991
  	const struct orig_node *orig_node = data_ptr;
48100bac8   Antonio Quartulli   batman-adv: creat...
992
  	if (tt_common_entry->flags & TT_CLIENT_ROAM)
cc47f66e6   Antonio Quartulli   batman-adv: impro...
993
  		return 0;
48100bac8   Antonio Quartulli   batman-adv: creat...
994
995
  	tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
  				       common);
a73105b8d   Antonio Quartulli   batman-adv: impro...
996
997
998
999
1000
1001
1002
1003
1004
1005
  	return (tt_global_entry->orig_node == orig_node);
  }
  
  static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
  					      struct hashtable_t *hash,
  					      struct hard_iface *primary_if,
  					      int (*valid_cb)(const void *,
  							      const void *),
  					      void *cb_data)
  {
48100bac8   Antonio Quartulli   batman-adv: creat...
1006
  	struct tt_common_entry *tt_common_entry;
a73105b8d   Antonio Quartulli   batman-adv: impro...
1007
1008
1009
1010
1011
1012
1013
  	struct tt_query_packet *tt_response;
  	struct tt_change *tt_change;
  	struct hlist_node *node;
  	struct hlist_head *head;
  	struct sk_buff *skb = NULL;
  	uint16_t tt_tot, tt_count;
  	ssize_t tt_query_size = sizeof(struct tt_query_packet);
c90681b85   Antonio Quartulli   batman-adv: fixed...
1014
  	uint32_t i;
a73105b8d   Antonio Quartulli   batman-adv: impro...
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  
  	if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
  		tt_len = primary_if->soft_iface->mtu - tt_query_size;
  		tt_len -= tt_len % sizeof(struct tt_change);
  	}
  	tt_tot = tt_len / sizeof(struct tt_change);
  
  	skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
  	if (!skb)
  		goto out;
  
  	skb_reserve(skb, ETH_HLEN);
  	tt_response = (struct tt_query_packet *)skb_put(skb,
  						     tt_query_size + tt_len);
  	tt_response->ttvn = ttvn;
a73105b8d   Antonio Quartulli   batman-adv: impro...
1030
1031
1032
1033
1034
1035
1036
  
  	tt_change = (struct tt_change *)(skb->data + tt_query_size);
  	tt_count = 0;
  
  	rcu_read_lock();
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
48100bac8   Antonio Quartulli   batman-adv: creat...
1037
  		hlist_for_each_entry_rcu(tt_common_entry, node,
a73105b8d   Antonio Quartulli   batman-adv: impro...
1038
1039
1040
  					 head, hash_entry) {
  			if (tt_count == tt_tot)
  				break;
48100bac8   Antonio Quartulli   batman-adv: creat...
1041
  			if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
a73105b8d   Antonio Quartulli   batman-adv: impro...
1042
  				continue;
48100bac8   Antonio Quartulli   batman-adv: creat...
1043
1044
  			memcpy(tt_change->addr, tt_common_entry->addr,
  			       ETH_ALEN);
a73105b8d   Antonio Quartulli   batman-adv: impro...
1045
1046
1047
1048
1049
1050
1051
  			tt_change->flags = NO_FLAGS;
  
  			tt_count++;
  			tt_change++;
  		}
  	}
  	rcu_read_unlock();
9d8523931   Antonio Quartulli   batman-adv: corre...
1052
1053
1054
  	/* store in the message the number of entries we have successfully
  	 * copied */
  	tt_response->tt_data = htons(tt_count);
a73105b8d   Antonio Quartulli   batman-adv: impro...
1055
1056
1057
  out:
  	return skb;
  }
a943cac14   Marek Lindner   batman-adv: merge...
1058
1059
1060
  static int send_tt_request(struct bat_priv *bat_priv,
  			   struct orig_node *dst_orig_node,
  			   uint8_t ttvn, uint16_t tt_crc, bool full_table)
a73105b8d   Antonio Quartulli   batman-adv: impro...
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
  {
  	struct sk_buff *skb = NULL;
  	struct tt_query_packet *tt_request;
  	struct neigh_node *neigh_node = NULL;
  	struct hard_iface *primary_if;
  	struct tt_req_node *tt_req_node = NULL;
  	int ret = 1;
  
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
  		goto out;
  
  	/* The new tt_req will be issued only if I'm not waiting for a
  	 * reply from the same orig_node yet */
  	tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
  	if (!tt_req_node)
  		goto out;
  
  	skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
  	if (!skb)
  		goto out;
  
  	skb_reserve(skb, ETH_HLEN);
  
  	tt_request = (struct tt_query_packet *)skb_put(skb,
  				sizeof(struct tt_query_packet));
  
  	tt_request->packet_type = BAT_TT_QUERY;
  	tt_request->version = COMPAT_VERSION;
  	memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
  	memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
  	tt_request->ttl = TTL;
  	tt_request->ttvn = ttvn;
  	tt_request->tt_data = tt_crc;
  	tt_request->flags = TT_REQUEST;
  
  	if (full_table)
  		tt_request->flags |= TT_FULL_TABLE;
  
  	neigh_node = orig_node_get_router(dst_orig_node);
  	if (!neigh_node)
  		goto out;
  
  	bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM "
  		"[%c]
  ", dst_orig_node->orig, neigh_node->addr,
  		(full_table ? 'F' : '.'));
  
  	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
  	ret = 0;
  
  out:
  	if (neigh_node)
  		neigh_node_free_ref(neigh_node);
  	if (primary_if)
  		hardif_free_ref(primary_if);
  	if (ret)
  		kfree_skb(skb);
  	if (ret && tt_req_node) {
  		spin_lock_bh(&bat_priv->tt_req_list_lock);
  		list_del(&tt_req_node->list);
  		spin_unlock_bh(&bat_priv->tt_req_list_lock);
  		kfree(tt_req_node);
  	}
  	return ret;
  }
  
  static bool send_other_tt_response(struct bat_priv *bat_priv,
  				   struct tt_query_packet *tt_request)
  {
  	struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
  	struct neigh_node *neigh_node = NULL;
  	struct hard_iface *primary_if = NULL;
  	uint8_t orig_ttvn, req_ttvn, ttvn;
  	int ret = false;
  	unsigned char *tt_buff;
  	bool full_table;
  	uint16_t tt_len, tt_tot;
  	struct sk_buff *skb = NULL;
  	struct tt_query_packet *tt_response;
  
  	bat_dbg(DBG_TT, bat_priv,
  		"Received TT_REQUEST from %pM for "
  		"ttvn: %u (%pM) [%c]
  ", tt_request->src,
  		tt_request->ttvn, tt_request->dst,
  		(tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
  
  	/* Let's get the orig node of the REAL destination */
eb7e2a1e2   Antonio Quartulli   batman-adv: use o...
1150
  	req_dst_orig_node = orig_hash_find(bat_priv, tt_request->dst);
a73105b8d   Antonio Quartulli   batman-adv: impro...
1151
1152
  	if (!req_dst_orig_node)
  		goto out;
eb7e2a1e2   Antonio Quartulli   batman-adv: use o...
1153
  	res_dst_orig_node = orig_hash_find(bat_priv, tt_request->src);
a73105b8d   Antonio Quartulli   batman-adv: impro...
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
  	if (!res_dst_orig_node)
  		goto out;
  
  	neigh_node = orig_node_get_router(res_dst_orig_node);
  	if (!neigh_node)
  		goto out;
  
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
  		goto out;
  
  	orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
  	req_ttvn = tt_request->ttvn;
015758d00   Antonio Quartulli   batman-adv: corre...
1167
  	/* I don't have the requested data */
a73105b8d   Antonio Quartulli   batman-adv: impro...
1168
1169
1170
  	if (orig_ttvn != req_ttvn ||
  	    tt_request->tt_data != req_dst_orig_node->tt_crc)
  		goto out;
015758d00   Antonio Quartulli   batman-adv: corre...
1171
  	/* If the full table has been explicitly requested */
a73105b8d   Antonio Quartulli   batman-adv: impro...
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
  	if (tt_request->flags & TT_FULL_TABLE ||
  	    !req_dst_orig_node->tt_buff)
  		full_table = true;
  	else
  		full_table = false;
  
  	/* In this version, fragmentation is not implemented, then
  	 * I'll send only one packet with as much TT entries as I can */
  	if (!full_table) {
  		spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
  		tt_len = req_dst_orig_node->tt_buff_len;
  		tt_tot = tt_len / sizeof(struct tt_change);
  
  		skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
  				    tt_len + ETH_HLEN);
  		if (!skb)
  			goto unlock;
  
  		skb_reserve(skb, ETH_HLEN);
  		tt_response = (struct tt_query_packet *)skb_put(skb,
  				sizeof(struct tt_query_packet) + tt_len);
  		tt_response->ttvn = req_ttvn;
  		tt_response->tt_data = htons(tt_tot);
  
  		tt_buff = skb->data + sizeof(struct tt_query_packet);
  		/* Copy the last orig_node's OGM buffer */
  		memcpy(tt_buff, req_dst_orig_node->tt_buff,
  		       req_dst_orig_node->tt_buff_len);
  
  		spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
  	} else {
  		tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
  						sizeof(struct tt_change);
  		ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
  
  		skb = tt_response_fill_table(tt_len, ttvn,
  					     bat_priv->tt_global_hash,
  					     primary_if, tt_global_valid_entry,
  					     req_dst_orig_node);
  		if (!skb)
  			goto out;
  
  		tt_response = (struct tt_query_packet *)skb->data;
  	}
  
  	tt_response->packet_type = BAT_TT_QUERY;
  	tt_response->version = COMPAT_VERSION;
  	tt_response->ttl = TTL;
  	memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
  	memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
  	tt_response->flags = TT_RESPONSE;
  
  	if (full_table)
  		tt_response->flags |= TT_FULL_TABLE;
  
  	bat_dbg(DBG_TT, bat_priv,
  		"Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)
  ",
  		res_dst_orig_node->orig, neigh_node->addr,
  		req_dst_orig_node->orig, req_ttvn);
  
  	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
  	ret = true;
  	goto out;
  
  unlock:
  	spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
  
  out:
  	if (res_dst_orig_node)
  		orig_node_free_ref(res_dst_orig_node);
  	if (req_dst_orig_node)
  		orig_node_free_ref(req_dst_orig_node);
  	if (neigh_node)
  		neigh_node_free_ref(neigh_node);
  	if (primary_if)
  		hardif_free_ref(primary_if);
  	if (!ret)
  		kfree_skb(skb);
  	return ret;
  
  }
  static bool send_my_tt_response(struct bat_priv *bat_priv,
  				struct tt_query_packet *tt_request)
  {
  	struct orig_node *orig_node = NULL;
  	struct neigh_node *neigh_node = NULL;
  	struct hard_iface *primary_if = NULL;
  	uint8_t my_ttvn, req_ttvn, ttvn;
  	int ret = false;
  	unsigned char *tt_buff;
  	bool full_table;
  	uint16_t tt_len, tt_tot;
  	struct sk_buff *skb = NULL;
  	struct tt_query_packet *tt_response;
  
  	bat_dbg(DBG_TT, bat_priv,
  		"Received TT_REQUEST from %pM for "
  		"ttvn: %u (me) [%c]
  ", tt_request->src,
  		tt_request->ttvn,
  		(tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
  
  
  	my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
  	req_ttvn = tt_request->ttvn;
eb7e2a1e2   Antonio Quartulli   batman-adv: use o...
1278
  	orig_node = orig_hash_find(bat_priv, tt_request->src);
a73105b8d   Antonio Quartulli   batman-adv: impro...
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
  	if (!orig_node)
  		goto out;
  
  	neigh_node = orig_node_get_router(orig_node);
  	if (!neigh_node)
  		goto out;
  
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
  		goto out;
  
  	/* If the full table has been explicitly requested or the gap
  	 * is too big send the whole local translation table */
  	if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
  	    !bat_priv->tt_buff)
  		full_table = true;
  	else
  		full_table = false;
  
  	/* In this version, fragmentation is not implemented, then
  	 * I'll send only one packet with as much TT entries as I can */
  	if (!full_table) {
  		spin_lock_bh(&bat_priv->tt_buff_lock);
  		tt_len = bat_priv->tt_buff_len;
  		tt_tot = tt_len / sizeof(struct tt_change);
  
  		skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
  				    tt_len + ETH_HLEN);
  		if (!skb)
  			goto unlock;
  
  		skb_reserve(skb, ETH_HLEN);
  		tt_response = (struct tt_query_packet *)skb_put(skb,
  				sizeof(struct tt_query_packet) + tt_len);
  		tt_response->ttvn = req_ttvn;
  		tt_response->tt_data = htons(tt_tot);
  
  		tt_buff = skb->data + sizeof(struct tt_query_packet);
  		memcpy(tt_buff, bat_priv->tt_buff,
  		       bat_priv->tt_buff_len);
  		spin_unlock_bh(&bat_priv->tt_buff_lock);
  	} else {
  		tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
  						sizeof(struct tt_change);
  		ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
  
  		skb = tt_response_fill_table(tt_len, ttvn,
  					     bat_priv->tt_local_hash,
058d0e269   Antonio Quartulli   batman-adv: keep ...
1327
1328
  					     primary_if, tt_local_valid_entry,
  					     NULL);
a73105b8d   Antonio Quartulli   batman-adv: impro...
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
  		if (!skb)
  			goto out;
  
  		tt_response = (struct tt_query_packet *)skb->data;
  	}
  
  	tt_response->packet_type = BAT_TT_QUERY;
  	tt_response->version = COMPAT_VERSION;
  	tt_response->ttl = TTL;
  	memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
  	memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
  	tt_response->flags = TT_RESPONSE;
  
  	if (full_table)
  		tt_response->flags |= TT_FULL_TABLE;
  
  	bat_dbg(DBG_TT, bat_priv,
  		"Sending TT_RESPONSE to %pM via %pM [%c]
  ",
  		orig_node->orig, neigh_node->addr,
  		(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
  
  	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
  	ret = true;
  	goto out;
  
  unlock:
  	spin_unlock_bh(&bat_priv->tt_buff_lock);
  out:
  	if (orig_node)
  		orig_node_free_ref(orig_node);
  	if (neigh_node)
  		neigh_node_free_ref(neigh_node);
  	if (primary_if)
  		hardif_free_ref(primary_if);
  	if (!ret)
  		kfree_skb(skb);
  	/* This packet was for me, so it doesn't need to be re-routed */
  	return true;
  }
  
  bool send_tt_response(struct bat_priv *bat_priv,
  		      struct tt_query_packet *tt_request)
  {
  	if (is_my_mac(tt_request->dst))
  		return send_my_tt_response(bat_priv, tt_request);
  	else
  		return send_other_tt_response(bat_priv, tt_request);
  }
  
  static void _tt_update_changes(struct bat_priv *bat_priv,
  			       struct orig_node *orig_node,
  			       struct tt_change *tt_change,
  			       uint16_t tt_num_changes, uint8_t ttvn)
  {
  	int i;
  
  	for (i = 0; i < tt_num_changes; i++) {
5fbc1598c   Antonio Quartulli   batman-adv: unify...
1387
  		if ((tt_change + i)->flags & TT_CLIENT_DEL)
a73105b8d   Antonio Quartulli   batman-adv: impro...
1388
1389
  			tt_global_del(bat_priv, orig_node,
  				      (tt_change + i)->addr,
cc47f66e6   Antonio Quartulli   batman-adv: impro...
1390
1391
  				      "tt removed by changes",
  				      (tt_change + i)->flags & TT_CLIENT_ROAM);
a73105b8d   Antonio Quartulli   batman-adv: impro...
1392
1393
  		else
  			if (!tt_global_add(bat_priv, orig_node,
bc2790808   Antonio Quartulli   batman-adv: detec...
1394
1395
1396
  					   (tt_change + i)->addr, ttvn, false,
  					   (tt_change + i)->flags &
  							TT_CLIENT_WIFI))
a73105b8d   Antonio Quartulli   batman-adv: impro...
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
  				/* In case of problem while storing a
  				 * global_entry, we stop the updating
  				 * procedure without committing the
  				 * ttvn change. This will avoid to send
  				 * corrupted data on tt_request
  				 */
  				return;
  	}
  }
  
  static void tt_fill_gtable(struct bat_priv *bat_priv,
  			   struct tt_query_packet *tt_response)
  {
  	struct orig_node *orig_node = NULL;
  
  	orig_node = orig_hash_find(bat_priv, tt_response->src);
  	if (!orig_node)
  		goto out;
  
  	/* Purge the old table first.. */
  	tt_global_del_orig(bat_priv, orig_node, "Received full table");
  
  	_tt_update_changes(bat_priv, orig_node,
  			   (struct tt_change *)(tt_response + 1),
  			   tt_response->tt_data, tt_response->ttvn);
  
  	spin_lock_bh(&orig_node->tt_buff_lock);
  	kfree(orig_node->tt_buff);
  	orig_node->tt_buff_len = 0;
  	orig_node->tt_buff = NULL;
  	spin_unlock_bh(&orig_node->tt_buff_lock);
  
  	atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
  
  out:
  	if (orig_node)
  		orig_node_free_ref(orig_node);
  }
a943cac14   Marek Lindner   batman-adv: merge...
1435
1436
1437
1438
  static void tt_update_changes(struct bat_priv *bat_priv,
  			      struct orig_node *orig_node,
  			      uint16_t tt_num_changes, uint8_t ttvn,
  			      struct tt_change *tt_change)
a73105b8d   Antonio Quartulli   batman-adv: impro...
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
  {
  	_tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
  			   ttvn);
  
  	tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
  			    tt_num_changes);
  	atomic_set(&orig_node->last_ttvn, ttvn);
  }
  
  bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
  {
7683fdc1e   Antonio Quartulli   batman-adv: prote...
1450
1451
  	struct tt_local_entry *tt_local_entry = NULL;
  	bool ret = false;
a73105b8d   Antonio Quartulli   batman-adv: impro...
1452

a73105b8d   Antonio Quartulli   batman-adv: impro...
1453
  	tt_local_entry = tt_local_hash_find(bat_priv, addr);
7683fdc1e   Antonio Quartulli   batman-adv: prote...
1454
1455
  	if (!tt_local_entry)
  		goto out;
058d0e269   Antonio Quartulli   batman-adv: keep ...
1456
1457
  	/* Check if the client has been logically deleted (but is kept for
  	 * consistency purpose) */
48100bac8   Antonio Quartulli   batman-adv: creat...
1458
  	if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
058d0e269   Antonio Quartulli   batman-adv: keep ...
1459
  		goto out;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
1460
1461
  	ret = true;
  out:
a73105b8d   Antonio Quartulli   batman-adv: impro...
1462
  	if (tt_local_entry)
7683fdc1e   Antonio Quartulli   batman-adv: prote...
1463
1464
  		tt_local_entry_free_ref(tt_local_entry);
  	return ret;
a73105b8d   Antonio Quartulli   batman-adv: impro...
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
  }
  
  void handle_tt_response(struct bat_priv *bat_priv,
  			struct tt_query_packet *tt_response)
  {
  	struct tt_req_node *node, *safe;
  	struct orig_node *orig_node = NULL;
  
  	bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for "
  		"ttvn %d t_size: %d [%c]
  ",
  		tt_response->src, tt_response->ttvn,
  		tt_response->tt_data,
  		(tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
  
  	orig_node = orig_hash_find(bat_priv, tt_response->src);
  	if (!orig_node)
  		goto out;
  
  	if (tt_response->flags & TT_FULL_TABLE)
  		tt_fill_gtable(bat_priv, tt_response);
  	else
  		tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
  				  tt_response->ttvn,
  				  (struct tt_change *)(tt_response + 1));
  
  	/* Delete the tt_req_node from pending tt_requests list */
  	spin_lock_bh(&bat_priv->tt_req_list_lock);
  	list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
  		if (!compare_eth(node->addr, tt_response->src))
  			continue;
  		list_del(&node->list);
  		kfree(node);
  	}
  	spin_unlock_bh(&bat_priv->tt_req_list_lock);
  
  	/* Recalculate the CRC for this orig_node and store it */
a73105b8d   Antonio Quartulli   batman-adv: impro...
1502
  	orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
cc47f66e6   Antonio Quartulli   batman-adv: impro...
1503
1504
1505
  	/* Roaming phase is over: tables are in sync again. I can
  	 * unset the flag */
  	orig_node->tt_poss_change = false;
a73105b8d   Antonio Quartulli   batman-adv: impro...
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
  out:
  	if (orig_node)
  		orig_node_free_ref(orig_node);
  }
  
  int tt_init(struct bat_priv *bat_priv)
  {
  	if (!tt_local_init(bat_priv))
  		return 0;
  
  	if (!tt_global_init(bat_priv))
  		return 0;
  
  	tt_start_timer(bat_priv);
  
  	return 1;
  }
cc47f66e6   Antonio Quartulli   batman-adv: impro...
1523
  static void tt_roam_list_free(struct bat_priv *bat_priv)
a73105b8d   Antonio Quartulli   batman-adv: impro...
1524
  {
cc47f66e6   Antonio Quartulli   batman-adv: impro...
1525
  	struct tt_roam_node *node, *safe;
a73105b8d   Antonio Quartulli   batman-adv: impro...
1526

cc47f66e6   Antonio Quartulli   batman-adv: impro...
1527
  	spin_lock_bh(&bat_priv->tt_roam_list_lock);
a73105b8d   Antonio Quartulli   batman-adv: impro...
1528

cc47f66e6   Antonio Quartulli   batman-adv: impro...
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
  	list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
  		list_del(&node->list);
  		kfree(node);
  	}
  
  	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
  }
  
  static void tt_roam_purge(struct bat_priv *bat_priv)
  {
  	struct tt_roam_node *node, *safe;
  
  	spin_lock_bh(&bat_priv->tt_roam_list_lock);
  	list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
  		if (!is_out_of_time(node->first_time,
  				    ROAMING_MAX_TIME * 1000))
  			continue;
  
  		list_del(&node->list);
  		kfree(node);
  	}
  	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
  }
  
  /* This function checks whether the client already reached the
   * maximum number of possible roaming phases. In this case the ROAMING_ADV
   * will not be sent.
   *
   * returns true if the ROAMING_ADV can be sent, false otherwise */
  static bool tt_check_roam_count(struct bat_priv *bat_priv,
  				uint8_t *client)
  {
  	struct tt_roam_node *tt_roam_node;
  	bool ret = false;
  
  	spin_lock_bh(&bat_priv->tt_roam_list_lock);
  	/* The new tt_req will be issued only if I'm not waiting for a
  	 * reply from the same orig_node yet */
  	list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
  		if (!compare_eth(tt_roam_node->addr, client))
  			continue;
  
  		if (is_out_of_time(tt_roam_node->first_time,
  				   ROAMING_MAX_TIME * 1000))
  			continue;
  
  		if (!atomic_dec_not_zero(&tt_roam_node->counter))
  			/* Sorry, you roamed too many times! */
  			goto unlock;
  		ret = true;
  		break;
  	}
  
  	if (!ret) {
  		tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
  		if (!tt_roam_node)
  			goto unlock;
  
  		tt_roam_node->first_time = jiffies;
  		atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
  		memcpy(tt_roam_node->addr, client, ETH_ALEN);
  
  		list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
  		ret = true;
  	}
  
  unlock:
  	spin_unlock_bh(&bat_priv->tt_roam_list_lock);
  	return ret;
  }
  
  void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
  		   struct orig_node *orig_node)
  {
  	struct neigh_node *neigh_node = NULL;
  	struct sk_buff *skb = NULL;
  	struct roam_adv_packet *roam_adv_packet;
  	int ret = 1;
  	struct hard_iface *primary_if;
  
  	/* before going on we have to check whether the client has
  	 * already roamed to us too many times */
  	if (!tt_check_roam_count(bat_priv, client))
  		goto out;
  
  	skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
  	if (!skb)
  		goto out;
  
  	skb_reserve(skb, ETH_HLEN);
  
  	roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
  					sizeof(struct roam_adv_packet));
  
  	roam_adv_packet->packet_type = BAT_ROAM_ADV;
  	roam_adv_packet->version = COMPAT_VERSION;
  	roam_adv_packet->ttl = TTL;
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
  		goto out;
  	memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
  	hardif_free_ref(primary_if);
  	memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
  	memcpy(roam_adv_packet->client, client, ETH_ALEN);
  
  	neigh_node = orig_node_get_router(orig_node);
  	if (!neigh_node)
  		goto out;
  
  	bat_dbg(DBG_TT, bat_priv,
  		"Sending ROAMING_ADV to %pM (client %pM) via %pM
  ",
  		orig_node->orig, client, neigh_node->addr);
  
  	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
  	ret = 0;
  
  out:
  	if (neigh_node)
  		neigh_node_free_ref(neigh_node);
  	if (ret)
  		kfree_skb(skb);
  	return;
a73105b8d   Antonio Quartulli   batman-adv: impro...
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
  }
  
  static void tt_purge(struct work_struct *work)
  {
  	struct delayed_work *delayed_work =
  		container_of(work, struct delayed_work, work);
  	struct bat_priv *bat_priv =
  		container_of(delayed_work, struct bat_priv, tt_work);
  
  	tt_local_purge(bat_priv);
cc47f66e6   Antonio Quartulli   batman-adv: impro...
1662
  	tt_global_roam_purge(bat_priv);
a73105b8d   Antonio Quartulli   batman-adv: impro...
1663
  	tt_req_purge(bat_priv);
cc47f66e6   Antonio Quartulli   batman-adv: impro...
1664
  	tt_roam_purge(bat_priv);
a73105b8d   Antonio Quartulli   batman-adv: impro...
1665
1666
1667
  
  	tt_start_timer(bat_priv);
  }
cc47f66e6   Antonio Quartulli   batman-adv: impro...
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
  
  void tt_free(struct bat_priv *bat_priv)
  {
  	cancel_delayed_work_sync(&bat_priv->tt_work);
  
  	tt_local_table_free(bat_priv);
  	tt_global_table_free(bat_priv);
  	tt_req_list_free(bat_priv);
  	tt_changes_list_free(bat_priv);
  	tt_roam_list_free(bat_priv);
  
  	kfree(bat_priv->tt_buff);
  }
058d0e269   Antonio Quartulli   batman-adv: keep ...
1681

697f25314   Antonio Quartulli   batman-adv: gener...
1682
1683
1684
1685
  /* This function will enable or disable the specified flags for all the entries
   * in the given hash table and returns the number of modified entries */
  static uint16_t tt_set_flags(struct hashtable_t *hash, uint16_t flags,
  			     bool enable)
058d0e269   Antonio Quartulli   batman-adv: keep ...
1686
  {
c90681b85   Antonio Quartulli   batman-adv: fixed...
1687
  	uint32_t i;
697f25314   Antonio Quartulli   batman-adv: gener...
1688
  	uint16_t changed_num = 0;
058d0e269   Antonio Quartulli   batman-adv: keep ...
1689
1690
  	struct hlist_head *head;
  	struct hlist_node *node;
48100bac8   Antonio Quartulli   batman-adv: creat...
1691
  	struct tt_common_entry *tt_common_entry;
058d0e269   Antonio Quartulli   batman-adv: keep ...
1692
1693
  
  	if (!hash)
697f25314   Antonio Quartulli   batman-adv: gener...
1694
  		goto out;
058d0e269   Antonio Quartulli   batman-adv: keep ...
1695
1696
1697
1698
1699
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
  
  		rcu_read_lock();
48100bac8   Antonio Quartulli   batman-adv: creat...
1700
  		hlist_for_each_entry_rcu(tt_common_entry, node,
058d0e269   Antonio Quartulli   batman-adv: keep ...
1701
  					 head, hash_entry) {
697f25314   Antonio Quartulli   batman-adv: gener...
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
  			if (enable) {
  				if ((tt_common_entry->flags & flags) == flags)
  					continue;
  				tt_common_entry->flags |= flags;
  			} else {
  				if (!(tt_common_entry->flags & flags))
  					continue;
  				tt_common_entry->flags &= ~flags;
  			}
  			changed_num++;
058d0e269   Antonio Quartulli   batman-adv: keep ...
1712
1713
1714
  		}
  		rcu_read_unlock();
  	}
697f25314   Antonio Quartulli   batman-adv: gener...
1715
1716
  out:
  	return changed_num;
058d0e269   Antonio Quartulli   batman-adv: keep ...
1717
1718
1719
1720
1721
1722
  }
  
  /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
  static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
  {
  	struct hashtable_t *hash = bat_priv->tt_local_hash;
48100bac8   Antonio Quartulli   batman-adv: creat...
1723
  	struct tt_common_entry *tt_common_entry;
058d0e269   Antonio Quartulli   batman-adv: keep ...
1724
1725
1726
1727
  	struct tt_local_entry *tt_local_entry;
  	struct hlist_node *node, *node_tmp;
  	struct hlist_head *head;
  	spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b85   Antonio Quartulli   batman-adv: fixed...
1728
  	uint32_t i;
058d0e269   Antonio Quartulli   batman-adv: keep ...
1729
1730
1731
1732
1733
1734
1735
1736
1737
  
  	if (!hash)
  		return;
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
  		list_lock = &hash->list_locks[i];
  
  		spin_lock_bh(list_lock);
48100bac8   Antonio Quartulli   batman-adv: creat...
1738
  		hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
058d0e269   Antonio Quartulli   batman-adv: keep ...
1739
  					  head, hash_entry) {
48100bac8   Antonio Quartulli   batman-adv: creat...
1740
  			if (!(tt_common_entry->flags & TT_CLIENT_PENDING))
058d0e269   Antonio Quartulli   batman-adv: keep ...
1741
1742
1743
  				continue;
  
  			bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
48100bac8   Antonio Quartulli   batman-adv: creat...
1744
1745
  				"(%pM): pending
  ", tt_common_entry->addr);
058d0e269   Antonio Quartulli   batman-adv: keep ...
1746
1747
1748
  
  			atomic_dec(&bat_priv->num_local_tt);
  			hlist_del_rcu(node);
48100bac8   Antonio Quartulli   batman-adv: creat...
1749
1750
1751
  			tt_local_entry = container_of(tt_common_entry,
  						      struct tt_local_entry,
  						      common);
058d0e269   Antonio Quartulli   batman-adv: keep ...
1752
1753
1754
1755
1756
1757
1758
1759
1760
  			tt_local_entry_free_ref(tt_local_entry);
  		}
  		spin_unlock_bh(list_lock);
  	}
  
  }
  
  void tt_commit_changes(struct bat_priv *bat_priv)
  {
697f25314   Antonio Quartulli   batman-adv: gener...
1761
1762
1763
1764
1765
  	uint16_t changed_num = tt_set_flags(bat_priv->tt_local_hash,
  					    TT_CLIENT_NEW, false);
  	/* all the reset entries have now to be effectively counted as local
  	 * entries */
  	atomic_add(changed_num, &bat_priv->num_local_tt);
058d0e269   Antonio Quartulli   batman-adv: keep ...
1766
1767
1768
1769
1770
1771
  	tt_local_purge_pending_clients(bat_priv);
  
  	/* Increment the TTVN only once per OGM interval */
  	atomic_inc(&bat_priv->ttvn);
  	bat_priv->tt_poss_change = false;
  }
59b699cde   Antonio Quartulli   batman-adv: imple...
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
  
  bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
  {
  	struct tt_local_entry *tt_local_entry = NULL;
  	struct tt_global_entry *tt_global_entry = NULL;
  	bool ret = true;
  
  	if (!atomic_read(&bat_priv->ap_isolation))
  		return false;
  
  	tt_local_entry = tt_local_hash_find(bat_priv, dst);
  	if (!tt_local_entry)
  		goto out;
  
  	tt_global_entry = tt_global_hash_find(bat_priv, src);
  	if (!tt_global_entry)
  		goto out;
  
  	if (_is_ap_isolated(tt_local_entry, tt_global_entry))
  		goto out;
  
  	ret = false;
  
  out:
  	if (tt_global_entry)
  		tt_global_entry_free_ref(tt_global_entry);
  	if (tt_local_entry)
  		tt_local_entry_free_ref(tt_local_entry);
  	return ret;
  }
a943cac14   Marek Lindner   batman-adv: merge...
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
  
  void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
  		    const unsigned char *tt_buff, uint8_t tt_num_changes,
  		    uint8_t ttvn, uint16_t tt_crc)
  {
  	uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
  	bool full_table = true;
  
  	/* the ttvn increased by one -> we can apply the attached changes */
  	if (ttvn - orig_ttvn == 1) {
  		/* the OGM could not contain the changes due to their size or
  		 * because they have already been sent TT_OGM_APPEND_MAX times.
  		 * In this case send a tt request */
  		if (!tt_num_changes) {
  			full_table = false;
  			goto request_table;
  		}
  
  		tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
  				  (struct tt_change *)tt_buff);
  
  		/* Even if we received the precomputed crc with the OGM, we
  		 * prefer to recompute it to spot any possible inconsistency
  		 * in the global table */
  		orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
  
  		/* The ttvn alone is not enough to guarantee consistency
  		 * because a single value could represent different states
  		 * (due to the wrap around). Thus a node has to check whether
  		 * the resulting table (after applying the changes) is still
  		 * consistent or not. E.g. a node could disconnect while its
  		 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
  		 * checking the CRC value is mandatory to detect the
  		 * inconsistency */
  		if (orig_node->tt_crc != tt_crc)
  			goto request_table;
  
  		/* Roaming phase is over: tables are in sync again. I can
  		 * unset the flag */
  		orig_node->tt_poss_change = false;
  	} else {
  		/* if we missed more than one change or our tables are not
  		 * in sync anymore -> request fresh tt data */
  		if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
  request_table:
  			bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
  				"Need to retrieve the correct information "
  				"(ttvn: %u last_ttvn: %u crc: %u last_crc: "
  				"%u num_changes: %u)
  ", orig_node->orig, ttvn,
  				orig_ttvn, tt_crc, orig_node->tt_crc,
  				tt_num_changes);
  			send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
  					full_table);
  			return;
  		}
  	}
  }